バンクーバーに行ってきた
OpenStack Summitに参加するため、バンクーバーに行ってきました。そっちの感想等は他のブログにまとめています。
最近は仕事で英語が必要になり、レアジョブで英会話レッスンをひたすらしてたけど不安といえば少しは不安でしたが、心強い英語が堪能な同僚が4名いたし、実際に一緒に行動する時間はランチとディナーの時だけだったけど、それでも困ることは無かったです。
そんなバンクーバーでのサミット以外のことをまとめておこうと思います。
バンクーバー(カナダ)
電車が無人運転でゆりかもめみたいな感じになってて、先頭と最後部は外を覗ける席になっていて、ちょっとしたアトラクションっぽくなってて、飛行機で寝なかったからウトウトしながら景色を楽しめました。 Compassカードというのを買ってタッチする仕組み。空港があるSea Islandエリアから電車に乗ろうとすると特別料金が発生し、+5カナダドル必要になります。
生活について
まず、ご飯とかどこでもカードがあれば大体の支払いはどうにかなる。どうにかならなそうなのハウスキーピングのチップぐらいな気がする。そのぐらい支払いはカードで対応出来てた。
交通網も大体compassカードというスイカみたいのでなんとかなるっぽいし本当にカードで困らなかった。
最終日は念のため持ってったカナダドルをどう使おうか悩みになやんだぐらいだ。
次に意外と思うかもしれないが、緯度が高い割に暖かいこと。日本の北海道より少し高いかもしれない。日陰に10分ぐらいいると少し肌寒くなるけど、基本的に暖かい。タンクトップの人もたくさんいた。そして緯度が高いから21時ぐらいまで明るい。20時過ぎに撮った外の様子
時間感覚がすごく狂いそうになった(むしろ時差ボケで狂ってた)けど、不思議な感覚だった。
でもサミット最終日の終了後スタンレーパークを散歩してたら、仕事帰りに自転車でサイクリングしてる人が居て、とても良いなーと思った。
明るいし、仕事のオン・オフがハッキリしてるのか、すごく楽しんでるように見えた。
スタンレーパークは自転車道と歩道がしっかり分かれてて、皆好き好きに楽しんでいた。終わってしまったサミット会場を眺めてもう終わったなーと感慨深くなれた。そんな場所だった。
全く関係ないけど、ここの水族館は、ドリーにでてくる水族館のモデルにも少しなってるらしい。
食事について
まずは太りそうな食事が多かった。これが初日に食べたハンバーガーとポテトのセット。寝不足の身体には重かったけどとても美味しかった。ポテトはおかわりしたいぐらいに。
次にマクドナルド。まず驚いたのは注文が行った店舗ではタッチパネル式で、支払いもカード決済で楽ちんなやつになってたこと。
あと、カナダの伝統料理のプーティンが注文できます。プーティンとは、ポテトにチーズが乗っていて、その上からグレイビーソースがかかったカナダの伝統料理。マクドナルドで4ドル20セントぐらいだった気がするので結構お手軽です。
コーラは空のコップだけ渡されるので、大体ドリンクバーの要領で出来るんだけど、まぁ最初は何が何だかわかんなくてあたふたしてました。
あと、ドリンクと、ポテトはSサイズにしても、日本のSよりは大きく、日本のMよりは若干小さいかなーぐらいのサイズ感でかなり満腹になれます。
自動販売機とコンビニが少なく、tim hortonsやマクドナルド、スターバックスがやたらと多かった。
感想
子連れでの旅行は子供が小学生になるぐらいまで難しいかなーという気はしたけど、今回の目的はサミットであって、とても良い場所でサミットに参加出来てとても良い体験ができました。が、英語でのコミュニケーションがもっと取れるともっと楽しめたんだろうなと思うので、今後も継続して練習する必要性を感じました。
OpenStack Summit Vancouver 2018
最近仕事でOpenStackの開発・運用に関わっていてその関係もあり、OpenStack Summitに参加させてもらいました。
OpenStack Summit | Vancouver 2018
OpensStackって何?
そもそもOpenStackって何?って思った方もいるかと思いますが、プライベートクラウドをいい感じに構築するソフトウェア群のことをさします。
2010年ごろに始まって当初はIaaS環境の構築が主な仕組みだったようですが、最近では、containerにも積極的です。 今後もvGPU機能に対応してく姿勢を持っていたり、柔軟に今やこれからをフォローしている印象が強いです。
セッションについて
セッションは、初心者がアップストリームにコミットしていけるようにハンズオンを開催したり、流行りのコンテナーサービスに関する発表だったり、コアコンポーネントに関する今後の議論をするだけのセッションだったり、多岐に渡っています。
今回のサミットで参加しようと考えたセッションは、OpenStackのコアコンポーネントの現状と今後について聞きけるセッションを考えていましたが、k8sやedge computingなどの話も豊富でだったので、ざっくばらんに参加してきました。
参加セッション
05/21
- Let's Build the Open Infrastructure Economy
- OpenStack community-wide goals and project updates
- Meet Zuul V3 (release 28/march 2018)
- Kata Containers Overview
- OpenStack and Kubernetes in a Hybrid Cloud World
- Open Source Infrastructure
- Integration testing on an OpenStack public cloud
- Canonical Sponsored Keynote
- Marrying OpenStack’s Virtual & Bare Metal Cloud Networks
- Non-native English speakers in OpenStack communities: A True Story
- Excitingly simple multi-path OpenStack networking: LAG-less, L2-less, yet fully redundant
0522
- How did OpenStack improve for Public Cloud in recent releases and what are we still missing
- Integrating Keystone with large-scale centralized authentication.
- Evolution of OpenStack Networking at CERN: Nova Network, Neutron and SDN
- Build Your Serverless Container Cloud with OpenStack and Kubernetes
- Upgrading OpenStack - war stories
- nova/neutron + ops cross-project session
- Ansible Lightning Talk
- CI/CD Build and Pipelines For OpenStack At Scale
- Kubernetes network-policies and Neutron security groups - two sides of the same coin?
- Highly resilient, multi-region Keystone deployments
- OpenDev CI/CD Happy Hour
0523
- OpenStack Roadmap: Learn what's coming in the Rocky release
- Delivering Next Generation Integrated Infrastructure Solutions for Private and Public Cloud Environments
- Add intelligence to your CI/CD with Spinnaker
- Nova - Project Onboarding
- Lesson learned and best practices for large-scale Enterprise Private Cloud
- OpenStack for AWS Architects - Similarities, differences and bridging the gap
- Better SSH management for clouds. Introducing Tatu: "SSH as a Service"
0524
- Cloud Operational Data at your finger tips
- Istio: How to make multicloud applications Real
- Monitoring and Logging your kubernetes cluster using OpenStack helm
発表については、最終日の Istioと helmの話が面白いかなーと思いました。k8sが今後標準的につかわれていくんだろうとは思うので、各社の考え方や取り組みがたくさん聞けたのが収穫でした。
最後の日は現地で知り合った人と話す時間が多かった気がします。
同僚の発表
また今回は同僚も発表しました。
OpenStack Summit | Summit Schedule
新しいリージョンを作ったので、その時の弊社の取り組みです。
ネットワーク周りもレイヤーが低いので参加者も多く発表後はたくさんの質問や意見をいただいていたので、興味がある方はリンクから動画も確認できるので、見ていただければ幸いです。
OpenStack Summitで良かったなと思った事
- フレンドリーなコミュニティ
- 電源やwifiも机がいたるところにあり、雑談や仕事ができるスペースが十分にあったこと
- 朝ご飯, 昼ご飯, 夕ご飯, おやつ, 飲み物が用意されてたらホテルと会場の往復でだいたいどうにかなる
感想
初めて参加した感想としては、OpenStackについて知りたければ参加すると良いと思います。
OpenStackのコンポーネントに関わりだして2ヶ月ぐらいですが、
疑問をもった部分や修正したい部分などの質問もできとても良い時間を過ごせたかと思います。
コミュニティは初心者に優しく入りやすい印象を持てました。
サミット会場で食事まで用意されてるので、本当にサミットに集中できる環境が整っていて、余分な心配をしなくても良い環境で助かりました。
openstackのnovaclient使ってvm instanceを立ち上げる
最近まで知らないことだらけだったので、vm instanceを作るときはnovaclient
以外にも
neutronclient
とかglanceclient
とかを使いnetworkやIamageやflavorの情報をとってinstanceを作成してました。
今回は、novaclientでできることはnovaclientでやることにしたので、novaclient以外は使ってません。
なぜnovaclientにまとめたかというと、multi-regionでopenstackの運用を行うとclientを宣言する時にregionの指定が必要になります。
その時に、修正漏れが発生する可能性がありそうだなと思いなるべく必要なさそうなclientは使わないようにしてみました。
# -*- coding: utf-8 -*- from novaclient import client as nova_client from keystoneauth1 import session from keystoneauth1.identity import v3 def get_keystone_session(): params = { 'auth_url': KEYSTONE_ENDPOINT, 'username': USERNAME, 'password': PASSWORD, 'user_domain_name': 'Default', 'project_id': PROJECT_ID, } auth = v3.Password(**params) sess = session.Session(auth=auth) return session def create_instance(my_session): nova = nova_client.Client(YOUR_NOVA_VERSION, session=my_session) # When your environment uses the multi-region, you need the region_name. # nova = nova_client.Client(YOUR_NOVA_VERSION, session=my_session, region_name='RegionOne') net = nova.neutron.find_network(NETWORK_TYPE) flavor = nova.flavors.find(name=FLAVOR_NAME) image = nova.glance.find_image(OS_NAME) instance = nova.servers.create(name=INSTANCE_NAME, flavor=flavor, image=image, nics=[{'net-id': net.id}]) return instance if __name__ == '__main__': my_session = get_keystone_session() result = create_instance(my_session) print(result)
コメントアウトしてありますが、もしregion情報必要な場合はregion_name
を指定すると問題なく作成できます。
ちなみに、今までは
neutron = neutron_client.Client(session=YOUR_SESSION) net = neutron.list_networks(name=NETWORK_TYPE)
のように、必要なcomponentから必要な情報をとってくるために、各clientを使うというやり方をしてたけどその必要がないととてもラクですね。
configでのエラー対応
python3.5を使っていて、import config
したらパッケージ内部でエラーが出てきた。
まずは、例外処理がpython2での書き方だったっぽく Exception as e
みたいに書き直せば大丈夫
File "/home/develop/.pyenv/versions/3.5.3/lib/python3.5/site-packages/config.py", line 733 except Exception, e: ^ SyntaxError: invalid syntax File "/home/develop/.pyenv/versions/3.5.3/lib/python3.5/site-packages/config.py", line 1308 except Exception, e: ^ SyntaxError: invalid syntax
こっちも from types import *
と修正するとpython3でも問題なく使える。
File "/home/develop/.pyenv/versions/3.5.3/lib/python3.5/site-packages/config.py", line 91, in <module> from types import StringType, UnicodeType werkzeug.utils.ImportStringError: import_string() failed for 'config'. Possible reasons are:
使っていたconfig
のバージョンは0.3.9
。
Python3 compatibility · Issue #3 · pep-dortmund/pars · GitHub
issueだったり、stackoverflowにも上がってるから既知の問題なんだろうな。
MongoDBを使う時に使うODM
mongoDBでデータを管理する
MongoDBとは
スキーマを定義しなくても使用できるドキュメント指向データベースである。 MySQLなどと違い、スキーマを定義しなくても使えるということ。でもそれってwebアプリケーションを作るとき 危なくないのかなーという思いもあり、今まで使ってこなかった。 なおかつ、過去に一回みたことあるコードで本当に定義されてなく、これがwebサービスだったら怖いなーと思ったりもした。 どんなデータが入っているのか未知数。そういったコードに限ってドキュメントが整備されてなかったりもする。
MySQLとの違いは
普段使ってるMySQLとの違いは当然あるので、簡単に MongoDBの情報をMySQLとの比較をまとめる。
- メリット
- 高パフォーマンスかつスケービリティを保持してること
- 比較的簡単に使えること
- デメリット
ざっくりまとめたが、トランザクションについては今後サポートされる見込み。 2018年の夏にリリースされる4.0に組み込まれる予定である。 参照元: https://techcrunch.com/2018/02/15/mongodb-gets-support-for-multi-document-acid-transactions/
意味するものは同じでも言葉が違っているので、それも覚えておいた方が良いかもしれない。
MongoDB | MySQL |
---|---|
Database | Database |
Collection | Table |
Document | Raw |
Field | Column |
実際に使う
検索してみると、MongoEngineというODM(Object Document Mapper)がよく使われてるようだけど、
今回はFlask-MongoAlchemyを使って、なるべく普段使ってるFlask-SQLAlchemyと同じように使えるようにしてみた。
https://pythonhosted.org/Flask-MongoAlchemy/
MongoEngineを使ってもさほど使い方は変わらないし、一般的に使われてるのはMongoEngineっぽい。
MongoEngineは機能が豊富でとても便利そうだということもわかったけど、とりあえずSQLAlchemyをずっと使っていたというだけで、
mongoalchemyを選択した。
mongoengineとmongoalchemyの検索件数の比較: mongoengine, mongoalchemy - Google トレンド
webアプリケーションを作る
その前に整合性を求められるようなシステムならそもそも使うなよって話ではあるけど。
このように型の整合性やvaldationを使いながら使えばデータの不備は回避できるんじゃないかなーと思ったり。
bsonで返ってくるからresponseを返すときは、from bson.json_util import dumps
を使って、dumpすると良い感じに
結果を返却できる。
$ curl -X POST http://127.0.0.1:5000/api/user -d '{"name":"hoge", "age":30, "address": {"prefecture":"hogehoge", "city":"shizuoka"}}' -H 'Content-Type:application/json' "registered" $ curl http://127.0.0.1:5000/api/user { "data": [ { "name": "hoge", "age": 30, "address": { "prefecture": "hogehoge", "city": "shizuoka" }, } ] }
テストで作ったコード。 https://github.com/hirosetakahito/mongodb-sample
実際作ってみると、Flask-SQLAlchemy つかうのとそんなに変わらない感じで使えるのでとても使いやすい。
また、MongoEngineもMongoAlchemyと使い勝手は変わらないからどちらか気に入ってるほうを使えばいいんじゃないかな。
Flask-MongoEngine — Flask-MongoEngine 0.9.5 documentation
キャッシュのデータを削除しても参照できてしまう。
今回のケースはpythonでsimplecacheを使っていて、キャッシュを消しても消えてないという事象に遭遇したので原因を調べてまとめてみました。
from werkzeug.contrib.cache import SimpleCache import threading import time import datetime class TestThread(threading.Thread): def __init__(self, number, sleep_time): super(TestThread, self).__init__() self.number = number self.sleep_time = sleep_time def run(self): for i in range(self.number): print('{}: thread-0: {}'.format(i, cache.get('key1'))) if i == 1: cache.delete('key1') print('cache delete') cache.set('key1', 'test-data2') time.sleep(self.sleep_time) def sub_thread(number, sleep_time, no): for i in range(number): print('{}: thread-{}: {}'.format(i, no, cache.get('key1'))) time.sleep(sleep_time) if __name__ == '__main__': cache = SimpleCache(10) cache.set('key1', 'test-data1') thread_main = TestThread(3, 2) thread_main.start() for i in range(1, 5): thread_sub = threading.Thread(target=sub_thread, name="th", args=(3, 2, i)) thread_sub.start()
これを何回か実行してたらたしかに残ってた
$ python sample.py 0: thread-0: test-data1 0: thread-1: test-data1 0: thread-2: test-data1 0: thread-3: test-data1 0: thread-4: test-data1 1: thread-1: test-data1 1: thread-0: test-data1 cache delete 1: thread-3: test-data1 1: thread-2: test-data1 1: thread-4: test-data1 2: thread-1: test-data2 2: thread-0: test-data2 2: thread-3: test-data2 2: thread-2: test-data2 2: thread-4: test-data2
こういった場合は、素直にredisとか使うのが早そうだなと思い、redisに変更
import redis import threading import time import datetime class TestThread(threading.Thread): def __init__(self, number, sleep_time): super(TestThread, self).__init__() self.number = number self.sleep_time = sleep_time def run(self): for i in range(self.number): print('{}: thread-0: {}'.format(i, cache.get('key1'))) if i == 1: cache.delete('key1') print('cache delete') cache.set('key1', 'test-data2') time.sleep(self.sleep_time) def sub_thread(number, sleep_time, no): for i in range(number): print('{}: thread-{}: {}'.format(i, no, cache.get('key1'))) time.sleep(sleep_time) if __name__ == '__main__': cache = redis.StrictRedis(host='localhost', port=6379, db=0) cache.set('key1', 'test-data1') thread_main = TestThread(3, 2) thread_main.start() for i in range(1, 5): thread_sub = threading.Thread(target=sub_thread, name="th", args=(3, 2, i)) thread_sub.start()
このように変更することで、deleteされてからの挙動は、
$ python sample-redis.py 0: thread-0: b'test-data1' 0: thread-1: b'test-data1' 0: thread-2: b'test-data1' 0: thread-3: b'test-data1' 0: thread-4: b'test-data1' 1: thread-3: b'test-data1' 1: thread-0: b'test-data1' 1: thread-1: b'test-data1' cache delete 1: thread-2: None 1: thread-4: None 2: thread-2: b'test-data2' 2: thread-3: b'test-data2' 2: thread-1: b'test-data2' 2: thread-0: b'test-data2' 2: thread-4: b'test-data2'
のように、登録される前かと思いますが、消されたデータを参照するようなことはなくすことはできました。 原因はなんだよ?って思って調べてたら、しっかりドキュメントにも、以下のように書かれてました。
class werkzeug.contrib.cache.SimpleCache(threshold=500, default_timeout=300) Simple memory cache for single process environments. This class exists mainly for the development server and is not 100% thread safe. It tries to use as many atomic operations as possible and no locks for simplicity but it could happen under heavy load that keys are added multiple times.
Parameters:
threshold – the maximum number of items the cache stores before it starts deleting some. default_timeout – the default timeout that is used if no timeout is specified on set(). A timeout of 0 indicates that the cache never expires.
引用元: http://werkzeug.pocoo.org/docs/0.14/contrib/cache/
thread saveじゃないなら仕方ないね... しっかりドキュメント読みましょうということですね。 開発環境以外で一時的に保持したいデータがあるなら、simplecacheじゃなくて別のものを使うようにしよう。