Slide 1

Slide 1 text

1 PythonでもPythonじゃなくても使える汎用 的なMicroservice実行環境 PyConJP2016 Yosuke Suzuki Nikkei Inc. Development and Infrastructure for Microservice Architecture

Slide 2

Slide 2 text

About me Engineer at Nikkei Inc. 2 Yosuke Suzuki @yosukep Python, Golang, JavaScript ウェブの運用とか編集者とか記者の仕事歴も長い

Slide 3

Slide 3 text

スポンサーしてます! 3

Slide 4

Slide 4 text

日経電子版について 4 ● 2010年3月に創刊 ● 有料会員48万人以上 のニュースサービス ● 月間アクセス3億件

Slide 5

Slide 5 text

日経電子版の開発チーム 5 ● API開発 ● モバイルアプリ ● ブラウザー向け ● インフラ ● データ分析 内製での開発体制を強化、エンジニアを絶賛採用中

Slide 6

Slide 6 text

FinancialTimesとの連携 6 ● 2015年12月買収 ● 開発ノウハウの共有 ● 英語力++ 英語をコミュニケーションの主言語として使うチームもある

Slide 7

Slide 7 text

本題 7

Slide 8

Slide 8 text

Microservicesとは 8 ● サイズが小さい✔ ● 自律的に開発が可能✔ ● 独立してデプロイが可能✔ ● デプロイやビルドプロセスの自動化✔ ● 分散化する、中央集権化しない O’Reilly: Microservice Architectureより

Slide 9

Slide 9 text

日経電子版ではGateway方式を採用 9 Cache/router (Fastly) UI service UI service Internet API gateway Search Content Auth DNS (Internal / Route53) API service API service Image API gatewayが中央集権的ではある

Slide 10

Slide 10 text

Gateway方式 10 ● 認証、認可も担当 ○ 認可は結局サービス側のレイヤーでやる ことも多い ● 概念上はGateway方式でも画像の配信 サービスなどは直接通信 ● 旧APIのラッパー的役割も

Slide 11

Slide 11 text

サイズが小さい✔ 11 ● PythonはDjangoベース ○ 基本的には2−3個のアプリケーションフォ ルダがあるだけ ○ Gatewayだけはフォルダ多い ● NodeJSはexpressベース ○ 数百行レベルのコード

Slide 12

Slide 12 text

自律的に開発が可能✔ 12 ● DBなどリソースのシェアはしない ○ S3を経由してシェアとかはある ● サービス間はAPI経由でのやり取り ● 基本的にステートレス ● 自律的にできるが、各自バラバラに作ると 非生産的 ● 雛形からベースのサービスを作成

Slide 13

Slide 13 text

雛形からサービスを作成 13

Slide 14

Slide 14 text

雛形に含まれているもの 14 ● requirements.txt ● tox.ini ○ テスト実行とflake8による静的解析 ● Djangoアプリケーション ● Dockerfile ● ElasticBeanstalkの設定ファイル ● CircleCIの設定ファイル など

Slide 15

Slide 15 text

cookiecutterで対話的に作成 15 pip install cookiecutter cookiecutter gh:Nikkei/django-project-template 対話形式でいくつか値を入力 ● repo_name: GitHub用のリポジトリ名 ● project_name: Djangoプロジェクトの名前 ● subdomin: サーバーのサブドメインに使用する文字列 ● short_description: リポジトリの一行での説明

Slide 16

Slide 16 text

雛形への追随 16 pip install git+https://github.com/hirokiky/cookiepatcher cookiepatcher ● レガシー化させない ● KYさん作 ● 最新のテンプレートに追随 ○ Djangoなどのライブラリのアップデート ● cookiepatcher.jsonで差分を管理

Slide 17

Slide 17 text

Private PyPI 17 ● 各サービスで使う固有の処理を共通化 ○ 記事のIDの変換 ○ CMS独自の専用タグの置き換え処理 requirements.txt: --extra-index-url https://xxx.x/xxxxx/packages/simple/ nikkei-utils==0.6 PyPIの自社専用版、各リポジトリでのコードの重複を避ける

Slide 18

Slide 18 text

Private PyPI (2) 18 1. python setup.py sdist を実行 2. dist/ 以下にできた xx.0.1.tar.gz のようなファイルを packages リポジトリの 指定ディレクトリにコピー 3. ファイルを add してpushするとCircleCIから自動でアッ プロードされる 通常のPyPIへの登録とやることはあまり変わらない

Slide 19

Slide 19 text

Private PyPI (3) 19 各アプリで呼び出し from nikkei_utils.kiji import extract_snippet from nikkei_utils.region import region_info def hoge(): snippet = extract_snippet(article.body)

Slide 20

Slide 20 text

NodeJSアプリの場合はPrivate npm 20 package.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サーバーから社内専用の共通ライブラリを取得できる

Slide 21

Slide 21 text

ローカル開発環境 21 ● API開発なら特に問題なし ○ python manage.py runserver ○ Dockerも使わなくていい ○ 単独で動作確認しやすい ● フロントエンド開発の時はややこしい ○ ルーティングの際に一部のドメインをロー カルに振り向ける

Slide 22

Slide 22 text

みんな大好きRest Framework 22 ● Django Rest Framework ● Django Rest Framework Swagger Python/DjangoでAPI作るなら圧倒的な生産性

Slide 23

Slide 23 text

Rest Framework(2) 23 class FeedAnArticleView(APIView): http_method_names = ['get'] permission_classes = (IsAuthenticated,) def get(self, request, kiji_id_raw): """ # 検索エンジン用フィード --- parameters: - name: kiji_id paramType: path description: 対象の記事ID """ article = Article.objects.get(kiji_id_raw=kiji_id_raw, status=Article.POST) return Response(data={'article': feed_article_mapper(article)})

Slide 24

Slide 24 text

独立してデプロイが可能✔ 24 ● サービスごとにインフラは 完全分離 ● ElasticBeanstalk+Docker のアプリとして稼働 ● スケールアウトも容易

Slide 25

Slide 25 text

デプロイやビルドプロセスの自動化✔ 25 masterブランチが開発系に、deployment/productionブランチが本番系に

Slide 26

Slide 26 text

ElasticBeanstalk(ebコマンド)の課題 26 ● 開発系と本番系の設定ファイル (Dockerrun.aws.json)を分けられない ● Blue/Greenデプロイメントできない

Slide 27

Slide 27 text

そこで ebi コマンド 27 pip install ebi ebi deploy ● KYさん作 ● Dockerrun.aws.jsonを環境(本番・開発)に 合わせて分けられる ● Blue/Greenデプロイが可能

Slide 28

Slide 28 text

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 --profile default --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

Slide 29

Slide 29 text

バッチ処理 29 Docker アプリコンテナ Docker アプリコンテナ Rundeckでのバッチ処理は ElasticBeanstalkにデプロイ しているものがそのまま使え る Spotインスタンス Docker アプリコンテナ

Slide 30

Slide 30 text

Rundeck 30 Dockerコンテナを定期タスクで実行

Slide 31

Slide 31 text

監視、エラーログ 31 ● アプリとは別コンテナーのfluentdでログを 収集 ○ github.com/bungoume/log-sender ● Sentryでエラーログを収集 ● New Relicでメトリクスデータを収集 ● CloudWatch すべて同じパターンに共通化

Slide 32

Slide 32 text

ログの集約 32 各サービス Docker アプリコンテナ Docker fluentd コンテナ ログ集約サービス

Slide 33

Slide 33 text

障害対応 33 Slackに通知ししつつ、対応が必要な障害はPagerDuty経由で電話呼び出し

Slide 34

Slide 34 text

かなり幅広く適用可能なインフラ 34 ● Djangoアプリ ● NodeJS(express)アプリ ● WordPress ● Rundeck ● Jenkins ● Kibana ● Nginx+プラグイン 日経電子版でこれまで実績のあるパターン

Slide 35

Slide 35 text

クラウドの乗り換えもしやすい(はず 35 FinancialTimes社のNodeJSのアプリはHeroku上で運用 同じものがアプリの変更なく、ElasticBeanstalk環境で動かせた

Slide 36

Slide 36 text

課題 36 ● スケールアウトは起動的ではない ○ 想定以上のスパイクが来ると間に合わない ○ 予測可能場合はスケジューリングして増やす ● マメにメンテは必要 ○ Djangoは1.7 → 1.10に順次更新 ○ 定期的にrequirements.txtを更新していく ● AWS側のバグと付き合う

Slide 37

Slide 37 text

Thanks 37 だいたいはこの2人が作ってくれた

Slide 38

Slide 38 text

Thank you! 38

Slide 39

Slide 39 text

We're hiring! s.nikkei.com/saiyo Pythonエンジニア (機械学習できるひと歓迎) フロントエンドエンジニア アプリエンジニア デザイナー 39