1PythonでもPythonじゃなくても使える汎用的なMicroservice実行環境PyConJP2016Yosuke SuzukiNikkei Inc.Development and Infrastructure for Microservice Architecture
View Slide
About meEngineer at Nikkei Inc.2Yosuke Suzuki @yosukepPython, Golang, JavaScriptウェブの運用とか編集者とか記者の仕事歴も長い
スポンサーしてます!3
日経電子版について4● 2010年3月に創刊● 有料会員48万人以上のニュースサービス● 月間アクセス3億件
日経電子版の開発チーム5● API開発● モバイルアプリ● ブラウザー向け● インフラ● データ分析内製での開発体制を強化、エンジニアを絶賛採用中
FinancialTimesとの連携6● 2015年12月買収● 開発ノウハウの共有● 英語力++英語をコミュニケーションの主言語として使うチームもある
本題7
Microservicesとは8● サイズが小さい✔● 自律的に開発が可能✔● 独立してデプロイが可能✔● デプロイやビルドプロセスの自動化✔● 分散化する、中央集権化しないO’Reilly: Microservice Architectureより
日経電子版ではGateway方式を採用9Cache/router (Fastly)UI service UI serviceInternetAPI gatewaySearch Content AuthDNS (Internal / Route53)API service API serviceImageAPI gatewayが中央集権的ではある
Gateway方式10● 認証、認可も担当○ 認可は結局サービス側のレイヤーでやることも多い● 概念上はGateway方式でも画像の配信サービスなどは直接通信● 旧APIのラッパー的役割も
サイズが小さい✔11● PythonはDjangoベース○ 基本的には2−3個のアプリケーションフォルダがあるだけ○ Gatewayだけはフォルダ多い● NodeJSはexpressベース○ 数百行レベルのコード
自律的に開発が可能✔12● DBなどリソースのシェアはしない○ S3を経由してシェアとかはある● サービス間はAPI経由でのやり取り● 基本的にステートレス● 自律的にできるが、各自バラバラに作ると非生産的● 雛形からベースのサービスを作成
雛形からサービスを作成13
雛形に含まれているもの14● requirements.txt● tox.ini○ テスト実行とflake8による静的解析● Djangoアプリケーション● Dockerfile● ElasticBeanstalkの設定ファイル● CircleCIの設定ファイル など
cookiecutterで対話的に作成15pip install cookiecuttercookiecutter gh:Nikkei/django-project-template対話形式でいくつか値を入力● repo_name: GitHub用のリポジトリ名● project_name: Djangoプロジェクトの名前● subdomin: サーバーのサブドメインに使用する文字列● short_description: リポジトリの一行での説明
雛形への追随16pip install git+https://github.com/hirokiky/cookiepatchercookiepatcher● レガシー化させない● KYさん作● 最新のテンプレートに追随○ Djangoなどのライブラリのアップデート● cookiepatcher.jsonで差分を管理
Private PyPI17● 各サービスで使う固有の処理を共通化○ 記事のIDの変換○ CMS独自の専用タグの置き換え処理requirements.txt:--extra-index-url https://xxx.x/xxxxx/packages/simple/nikkei-utils==0.6PyPIの自社専用版、各リポジトリでのコードの重複を避ける
Private PyPI (2)181. python setup.py sdist を実行2. dist/ 以下にできた xx.0.1.tar.gz のようなファイルをpackages リポジトリの 指定ディレクトリにコピー3. ファイルを add してpushするとCircleCIから自動でアップロードされる通常のPyPIへの登録とやることはあまり変わらない
Private PyPI (3)19各アプリで呼び出しfrom nikkei_utils.kiji import extract_snippetfrom nikkei_utils.region import region_infodef hoge():snippet = extract_snippet(article.body)
NodeJSアプリの場合はPrivate npm20package.json:"dependencies": {"@nikkei/nikkei-ui": "^6.2.0","@nikkei/rnikkei-express": "^2.32.2","denodeify": "^1.2.1","dom-delegate": "^2.0.3","express-validator": "^2.20.8","open-graph-scraper": "^2.2.2"}privateなnpmサーバーから社内専用の共通ライブラリを取得できる
ローカル開発環境21● API開発なら特に問題なし○ python manage.py runserver○ Dockerも使わなくていい○ 単独で動作確認しやすい● フロントエンド開発の時はややこしい○ ルーティングの際に一部のドメインをローカルに振り向ける
みんな大好きRest Framework22● Django Rest Framework● Django Rest Framework SwaggerPython/DjangoでAPI作るなら圧倒的な生産性
Rest Framework(2)23class FeedAnArticleView(APIView):http_method_names = ['get']permission_classes = (IsAuthenticated,)def get(self, request, kiji_id_raw):""" # 検索エンジン用フィード---parameters:- name: kiji_idparamType: pathdescription: 対象の記事ID"""article = Article.objects.get(kiji_id_raw=kiji_id_raw, status=Article.POST)return Response(data={'article': feed_article_mapper(article)})
独立してデプロイが可能✔24● サービスごとにインフラは完全分離● ElasticBeanstalk+Dockerのアプリとして稼働● スケールアウトも容易
デプロイやビルドプロセスの自動化✔25masterブランチが開発系に、deployment/productionブランチが本番系に
ElasticBeanstalk(ebコマンド)の課題26● 開発系と本番系の設定ファイル(Dockerrun.aws.json)を分けられない● Blue/Greenデプロイメントできない
そこで ebi コマンド27pip install ebiebi deploy ● KYさん作● Dockerrun.aws.jsonを環境(本番・開発)に合わせて分けられる● Blue/Greenデプロイが可能
CircleCIの設定ファイル28- sudo pip install --ignore-installed awsebcli- sudo pip install -U ebi- aws configure set aws_access_key_id $PROD_AWS_ACCESS_KEY_ID- aws configure set aws_secret_access_key $PROD_AWS_SECRET_ACCESS_KEY- aws configure set default.region ap-northeast-1- aws configure set default.output json- ebi bgdeploy app-name env-name-blue env-name-green cname_prefix --profiledefault --noswap --region ap-northeast-1 --dockerrun Dockerrun.aws.prod.json- sleep 10- sudo pip install -r e2etests/requirements.txt- py.test e2etests/tests.py- eb swap env-name-blue --profile default --destination_name env-name-green
バッチ処理29DockerアプリコンテナDockerアプリコンテナRundeckでのバッチ処理はElasticBeanstalkにデプロイしているものがそのまま使えるSpotインスタンスDockerアプリコンテナ
Rundeck30Dockerコンテナを定期タスクで実行
監視、エラーログ31● アプリとは別コンテナーのfluentdでログを収集○ github.com/bungoume/log-sender● Sentryでエラーログを収集● New Relicでメトリクスデータを収集● CloudWatchすべて同じパターンに共通化
ログの集約32各サービスDockerアプリコンテナDockerfluentd コンテナログ集約サービス
障害対応33Slackに通知ししつつ、対応が必要な障害はPagerDuty経由で電話呼び出し
かなり幅広く適用可能なインフラ34● Djangoアプリ● NodeJS(express)アプリ● WordPress● Rundeck● Jenkins● Kibana● Nginx+プラグイン日経電子版でこれまで実績のあるパターン
クラウドの乗り換えもしやすい(はず35FinancialTimes社のNodeJSのアプリはHeroku上で運用同じものがアプリの変更なく、ElasticBeanstalk環境で動かせた
課題36● スケールアウトは起動的ではない○ 想定以上のスパイクが来ると間に合わない○ 予測可能場合はスケジューリングして増やす● マメにメンテは必要○ Djangoは1.7 → 1.10に順次更新○ 定期的にrequirements.txtを更新していく● AWS側のバグと付き合う
Thanks37だいたいはこの2人が作ってくれた
Thank you!38
We're hiring!s.nikkei.com/saiyoPythonエンジニア(機械学習できるひと歓迎)フロントエンドエンジニアアプリエンジニアデザイナー39