Slide 1

Slide 1 text

CI/CD for REST APIs on GAE with Cloud Endpoints & OpenAPI GCPUG Tokyo DevOps Day, Sep 27, 2017 Ryo NAKAMARU, SUPINF Inc. / Rescale, Inc.

Slide 2

Slide 2 text

これの GAE+α 版です https://www.youtube.com/watch?v=bR9hEyZ9774 Google Cloud Endpoints: serving your API to the world (Google Cloud Next '17)

Slide 3

Slide 3 text

彼の 45 分+ ( 重めの ) α を 15 分で話すので

Slide 4

Slide 4 text

Google Cloud 初心者の方には 不親切かもしれません !

Slide 5

Slide 5 text

早速ですが

Slide 6

Slide 6 text

  Google App Engine を使ってみよう (フレキシブル環境)

Slide 7

Slide 7 text

$ gcloud app create --region asia-northeast1 リージョンを決める

Slide 8

Slide 8 text

例) $ cat << EOF > Dockerfile FROM pottava/http-re ENV APP_PORT=8080 EOF should be listening on port 8080

Slide 9

Slide 9 text

$ cat << EOF > app.yaml runtime: custom env: flex liveness_check: path: '/' readiness_check: path: '/' app_start_timeout_sec: 30 EOF 例)

Slide 10

Slide 10 text

$ gcloud app deploy app.yaml 初期デプロイ 10 分後・・

Slide 11

Slide 11 text

$ curl -s https://your-project-id.appspot.com/ | jq . { ɹ“Application”: { ɹɹ“EnvVars”: [ ɹɹɹ“PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”, ɹɹɹ“HOSTNAME=6ca6de377f29”, ɹɹɹ“APPENGINE.GOOOGLEAPIS.INTERNAL_NAME=/gaeapp/appengine.googleapis.internal”, ɹɹɹ“GAE_DEPLOYMENT_ID=404173836720469531”, ɹɹɹ“GAE_MEMOMY_MB=614”, ɹɹɹ“GAE_SEVICE=default”, ɹɹɹ“GAE_VERSION=20170918t011225”, ɹɹɹ“GAE_INSTANCE=aef-default-20170918t011225-7b2q”, ɹɹɹ“GCLOUD_PROJECT=your-project-id”, ɹɹɹ“GOOGLE_CLOUD_PROJECT=your-project-id”, ɹɹɹ“PORT=8080”, ɹɹɹ“APP_PORT=8080”, ɹɹɹ“HOME=/root” ɹɹ], ɹɹ.. ɹ}, ɹ..

Slide 12

Slide 12 text

ɹ“Request”: { ɹɹ“Headers”: { ɹɹɹ“Accept”: [“*/*”], ɹɹɹ“User-Agent”: [“curl/7.54.0”], ɹɹɹ“Via”: [“1.1 google”], ɹɹɹ“X-Appengine-City”: [“shibuya”], ɹɹɹ“X-Appengine-Citylatlong”: [“35.664035,139.698212”], ɹɹɹ“X-Appengine-Country”: [“JP”], ɹɹɹ“X-Appengine-Region”: [“07”], ɹɹɹ“X-Cloud-Trace-Context”: [“b1496d42cf7c793e5894a1986fead1792/13886833712306987270”], ɹɹɹ“X-Forwarded-For”: [“2001:db8:85a3::8a2e:370:7334, 2001:db8:4004:81v::2014”], ɹɹɹ“X-Forwarded-Proto”: [“https”] ɹɹ}, ɹɹ.. ɹ} }

Slide 13

Slide 13 text

今日のお話 • 初期デプロイ • OpenAPI での実装、Postman でのテスト • GAE への継続的デプロイ • Cloud Endpoints で API を守る、利用状況を把握する 13

Slide 14

Slide 14 text

OpenAPI って? 14 • RESTful API 仕様: OpenAPI Initiative ( The Linux Foundation 配下) 主導 • もとは Swagger 仕様として知られていた • API を開発運用するのにとても便利

Slide 15

Slide 15 text

OpenAPI での実装 1 • API 定義を yaml で書く 15

Slide 16

Slide 16 text

OpenAPI での実装 2 • yaml からソースコードが生成できる 16 ɹɹ$ swagger-codegen generate -i swagger.yaml -o generated -l javascript ɹɹ[main] INFO io.swagger.parser.Swagger20Parser - reading from /src/swagger.yaml ɹɹ[main] WARN io.swagger.codegen.ignore.CodegenIgnoreProcessor - Output directory does not exist, or is inaccessible. No file (.swager-codegen-ignore) will be evaluated. ɹɹ[main] INFO io.swagger.codegen.languages.JavascriptClientCodegen - Using JS ES5 templates ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/src/model/Error.js ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/test/model/Error.spec.js ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/docs/Error.md ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/src/model/Version.js ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/test/model/Version.spec.js ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/docs/Version.md ɹɹ[main] INFO io.swagger.codegen.AbstractGenerator - writing file /src/generated/src/api/ServicesApi.js ɹɹ…

Slide 17

Slide 17 text

• 2 を使って残りを実装! • API 定義とソースコードは 別リポジトリでの管理 が好ましい ‣ API 定義はサーバ、クライアント各種で利用想定 ‣ 別 CI でそれぞれに応じたテストが書ける ‣ API 定義は CI から Cloud Endpoints へデプロイ(後述) OpenAPI での実装 3 17

Slide 18

Slide 18 text

OpenAPI で実装するメリット 18 • インターフェイス を使うメリットはたくさん ‣ 疎結合な開発、モックサーバ、テスト駆動・・などなど • ソースコードの自動生成 ‣ ビジネスロジック実装に集中 ‣ データバリデーションからも(ある程度)解放される ‣ API 定義ファースト、定義がないとビジネスロジックが書けない

Slide 19

Slide 19 text

API 開発のお供に

Slide 20

Slide 20 text

Postman で e2e テストを書いておくと 20

Slide 21

Slide 21 text

Newman で CLI から実行できる 21 ɹɹ$ newman run --environment postman_environment.json postman_collection.json ɹɹDemoAPIs ɹɹ! 1. όʔδϣϯ͕औಘͰ͖Δ (200) ɹɹ GET http://localhost:8080/version [200 OK, 127B, 26ms] ɹɹ ✓ Successful HTTP request ɹɹ ✓ Returns OK status ɹɹ ✓ It has a `version` string ɹɹ! 2. ڐՄ͞Ε͍ͯͳ͍ϝιου (405) ɹɹ POST http://localhost:8080/version [405 Method Not Allowed, 216B, 2ms] ɹɹ ✓ Successful HTTP request ɹɹ ✓ It has an error code ɹɹ ✓ It has an error message ɹɹ…

Slide 22

Slide 22 text

Postman を API 開発に使うメリット 22 • API 定義をベースに(実装者でなくても)実装を待たずにテストが書ける ‣ そのまま単純に CI を回すともちろん赤くなるけど・・ • ユーザの 想定行動フロー もバージョン管理下に入る ‣ フローに沿ったテストデータを 表から 作れる ‣ DB マイグレーションが基本的なマスタデータのみでもテストできる • クッキーはもちろん、JWT でのデータ持ち回しも簡単 ‣ curl 使うよりずっと簡単に API が叩ける

Slide 23

Slide 23 text

GAE への継続的デプロイ

Slide 24

Slide 24 text

App Engine のバージョン管理 24 Google App Engine https://project.appspot.com service v1.0 https://v1-0-dot-project.appspot.com service v0.1 stopped

Slide 25

Slide 25 text

App Engine のバージョン管理 25 Google App Engine service v0.1 service v1.1 service v1.0 stopped stopped 例)gcloud app deploy https://project.appspot.com https://v1-1-dot-project.appspot.com

Slide 26

Slide 26 text

例)deploy --no-stop-previous-version App Engine のバージョン管理 26 Google App Engine service v0.1 service v1.1 service v1.2 service v1.0 https://v1-1-dot-project.. https://v1-2-dot-project.. stopped stopped https://project.appspot.com

Slide 27

Slide 27 text

App Engine のバージョン管理 27 Google App Engine service v0.1 service v1.1 service v1.2 service v2.0 service v1.0 https://v1-1-dot-project.. https://v1-2-dot-project.. https://v2-0-dot-project.appspot.com stopped stopped https://project.appspot.com 例)deploy --no-stop-previous-version --no-promote

Slide 28

Slide 28 text

App Engine のバージョン管理 28 Google App Engine service v0.1 service v1.1 service v1.2 service v2.0 service v1.0 例)services set-traffic --splits=v1-2=0.9,v2-0=0.1 https://project.appspot.com 90% 10%

Slide 29

Slide 29 text

App Engine へのデプロイ 29 ɹɹ$ gcloud app deploy --no-promote —no-stop-previous-version --version ${version} --quiet • こうすれば version-dot つきホスト名で最終的な動作確認もできる • 確認がとれたら、本番トラフィックを新バージョンに流す ‣ gcloud app services set-traffic ${service_name} --splits ${version}=1

Slide 30

Slide 30 text

確認がとれたら? 30 ɹɹ$ newman run --environment postman_env_gae.json postman_collection.json • 例えばこんな感じ • 破壊的トランザクションの起こる collection はもちろんダメ ‣ 管理者用マスタ更新 API など

Slide 31

Slide 31 text

Cloud Endpoints で守る・把握する

Slide 32

Slide 32 text

Google Cloud Endpoints? 32 • API 定義に基づき、実装された API を拡張してくれるもの • Auth0 や Firebase、独自 JWT による API コールの検証・保護 • Stackdriver Monitoring / Logging / Trace との連携 ‣ トラフィック、エラー率、レイテンシ の可視化 ‣ API ごとのログも簡易的なトレース情報もぱっと追える

Slide 33

Slide 33 text

つまりこうなる 33 • 存在しないエンドポイント $ curl -s -X POST -d ‘{“foo”:”bar”}’ https://your-project-id.appspot.com/endpoint | jq . { “code”: 5, “message”: “Method does not exist.”, “details”: [ “@type”: “type.googleapis.com/google.rpc.DebugInfo”, “stackEntries”: [], “detail”: “service_control” { ] }

Slide 34

Slide 34 text

つまりこうなる 34 • 許可されていないユーザからの要求(一例) $ curl -s https://your-project-id.appspot.com/needauth | jq . { “code”: 16, “message”: “Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.”, “details”: [ “@type”: “type.googleapis.com/google.rpc.DebugInfo”, “stackEntries”: [], “detail”: “service_control” { ] }

Slide 35

Slide 35 text

つまりこうなる 35

Slide 36

Slide 36 text

つまりこうなる 36

Slide 37

Slide 37 text

つまりこうなる 37

Slide 38

Slide 38 text

つまりこうなる 38

Slide 39

Slide 39 text

仕組み 39 • Extensible Service Proxy (esp) か Endpoints Frameworks を導入 • GAE flex env は esp のみ利用可 • GKE ではサイドカーとして   API と同じ Pod に esp をおく https://cloud.google.com/endpoints/docs/architecture-overview

Slide 40

Slide 40 text

仕組み 40 Google App Engine esp v1 service v1.1 https://project.appspot.com

Slide 41

Slide 41 text

仕組み 41 Google App Engine esp v1 service v1.1 https://project.appspot.com Cloud Endpoints Service Control 実行時チェック & レポートの送信

Slide 42

Slide 42 text

仕組み 42 Google App Engine esp v1 service v1.1 https://project.appspot.com • 存在しないエンドポイントだったら esp が 404 Not Found を返す

Slide 43

Slide 43 text

仕組み 43 Google App Engine esp v1 service v1.1 https://project.appspot.com • ユーザの検証に失敗したら    esp が 401, 403 などを返す

Slide 44

Slide 44 text

仕組み 44 Google App Engine esp v1 service v1.1 https://project.appspot.com Proxy • 問題なければバックエンドに • この一連の挙動を 1ms 程度で

Slide 45

Slide 45 text

Cloud Endpoints のバージョン管理 45 Google App Engine esp v1 service v1.1 https://project.appspot.com

Slide 46

Slide 46 text

Cloud Endpoints のバージョン管理 46 Google App Engine service v1.2 esp v1 service v1.1 例)gcloud app deploy https://project.appspot.com

Slide 47

Slide 47 text

Cloud Endpoints のバージョン管理 47 Google App Engine service v1.2 esp v1 esp v2 service v1.1 https://project.appspot.com 例)gcloud service-management deploy

Slide 48

Slide 48 text

Cloud Endpoints のバージョン管理 48 Google App Engine service v1.2 service v2.0 esp v1 esp v2 service v1.1 https://project.appspot.com 例)gcloud app deploy --no-stop-previous-version

Slide 49

Slide 49 text

GAE で使うには 1 49 • Google Service Management に API 定義を渡し、新版をデプロイ • ユーザ検証をするなら OpenAPI v2, securityDefinitions として定義 ‣ v3 は securitySchemes だが、そもそも v3 には未対応 ɹɹ$ gcloud service-management deploy swagger.yaml

Slide 50

Slide 50 text

GAE で使うには 2 50 • API にかぶせたいバージョンの config_id をゲットして ɹɹ$ gcloud service-management configs list

Slide 51

Slide 51 text

GAE で使うには 3 51 ɹɹ$ cat << EOF > app.yaml runtime: custom env: flex endpoints_api_service: name: 'your-project-id.appspot.com' config_id: '2017-09-01r0' EOF $ gcloud app deploy app.yaml • app.yaml に endpoints_api_service を定義して GAE にデプロイ!

Slide 52

Slide 52 text

実際にやってみよう

Slide 53

Slide 53 text

github.com/supinf/apis-on-gae 53 • サンプル swagger.yaml から Go ソースを自動生成(go-swagger) • Stackdriver Error Reporting、カスタム Logging も実装済 • API サーバをローカルでのビルド、テスト • GAE、Cloud Endpoints へデプロイ • README.md に従い全部試して 15 分程度

Slide 54

Slide 54 text

これまでの情報で CI/CD が書けるはず・・!

Slide 55

Slide 55 text

CAUTION .

Slide 56

Slide 56 text

運用上の注意点 56 • App Engine フレキシブル環境 ‣ 週一で、避けられない再起動 がかかる(サーバ 1 台だと確実に死)     https://cloud.google.com/appengine/docs/flexible/java/how-instances-are-managed#restarts • Cloud Endpoints ‣ 自動生成コードとは異なるエラーコードを返すことがある - e2e テストを書くときには注意が必要 ‣ API の定義と実装、異なるバージョンがあたると悲劇

Slide 57

Slide 57 text

そもそも API の Docker 化が・・

Slide 58

Slide 58 text

REST API ってどう作るのがいいの・・

Slide 59

Slide 59 text

CI/CD スクリプトどう書けば・・?

Slide 60

Slide 60 text

Firebase など他の製品と繋げるには・・?

Slide 61

Slide 61 text

GCS に置いた静的 HTML から 安全に API にアクセスするには・・?

Slide 62

Slide 62 text

中丸 良 @pottava • Google Certified Professional - Cloud Architect • AWS Certified Solutions Architect - Professional • AWS Certified DevOps Engineer - Professional Ask me 62

Slide 63

Slide 63 text

Ask us 63 • クラウド / コンテナ関連を特に強みに、受託開発運用 • 2015 年から Docker の本番運用を開始 • スピンフ、と読みます・・

Slide 64

Slide 64 text

次回 64 2017 / 10 / 09(月) @ お台場国際交流館 11:30 - 12:10 会議室2

Slide 65

Slide 65 text

ご静聴ありがとうございました :) 参考文献: • Google Cloud Endpoints: serving your API to the world (Google Cloud Next '17) https://www.youtube.com/watch?v=bR9hEyZ9774 • Getting Started with Endpoints on App Engine Flexible Environment https://cloud.google.com/endpoints/docs/openapi/get-started-app- engine • Configuring your App with app.yaml | Custom runtimes for the App Engine flexible environment | Google Cloud Platform      https://cloud.google.com/appengine/docs/flexible/custom-runtimes/ configuring-your-app-with-app-yaml#updated_health_checks