CI/CD for REST APIs on GAE with Cloud Endpoints & OpenAPI

1e5a15f4dc65c207a04a1e82a3f92e92?s=47 ryo nakamaru
September 27, 2017

CI/CD for REST APIs on GAE with Cloud Endpoints & OpenAPI

GCPUG Tokyo DevOps Day, Sep 27, 2017

1e5a15f4dc65c207a04a1e82a3f92e92?s=128

ryo nakamaru

September 27, 2017
Tweet

Transcript

  1. 1.

    CI/CD for REST APIs on GAE with Cloud Endpoints &

    OpenAPI GCPUG Tokyo DevOps Day, Sep 27, 2017 Ryo NAKAMARU, SUPINF Inc. / Rescale, Inc.
  2. 8.

    例) $ cat << EOF > Dockerfile FROM pottava/http-re ENV

    APP_PORT=8080 EOF should be listening on port 8080
  3. 9.

    $ cat << EOF > app.yaml runtime: custom env: flex

    liveness_check: path: '/' readiness_check: path: '/' app_start_timeout_sec: 30 EOF 例)
  4. 11.

    $ 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” ɹɹ], ɹɹ.. ɹ}, ɹ..
  5. 12.

    ɹ“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”] ɹɹ}, ɹɹ.. ɹ} }
  6. 14.

    OpenAPI って? 14 • RESTful API 仕様: OpenAPI Initiative (

    The Linux Foundation 配下) 主導 • もとは Swagger 仕様として知られていた • API を開発運用するのにとても便利
  7. 16.

    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 ɹɹ…
  8. 17.

    • 2 を使って残りを実装! • API 定義とソースコードは 別リポジトリでの管理 が好ましい ‣ API

    定義はサーバ、クライアント各種で利用想定 ‣ 別 CI でそれぞれに応じたテストが書ける ‣ API 定義は CI から Cloud Endpoints へデプロイ(後述) OpenAPI での実装 3 17
  9. 18.

    OpenAPI で実装するメリット 18 • インターフェイス を使うメリットはたくさん ‣ 疎結合な開発、モックサーバ、テスト駆動・・などなど • ソースコードの自動生成

    ‣ ビジネスロジック実装に集中 ‣ データバリデーションからも(ある程度)解放される ‣ API 定義ファースト、定義がないとビジネスロジックが書けない
  10. 21.

    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 ɹɹ…
  11. 22.

    Postman を API 開発に使うメリット 22 • API 定義をベースに(実装者でなくても)実装を待たずにテストが書ける ‣ そのまま単純に

    CI を回すともちろん赤くなるけど・・ • ユーザの 想定行動フロー もバージョン管理下に入る ‣ フローに沿ったテストデータを 表から 作れる ‣ DB マイグレーションが基本的なマスタデータのみでもテストできる • クッキーはもちろん、JWT でのデータ持ち回しも簡単 ‣ curl 使うよりずっと簡単に API が叩ける
  12. 25.

    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
  13. 26.

    例)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
  14. 27.

    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
  15. 28.

    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%
  16. 29.

    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
  17. 30.

    確認がとれたら? 30 ɹɹ$ newman run --environment postman_env_gae.json postman_collection.json • 例えばこんな感じ

    • 破壊的トランザクションの起こる collection はもちろんダメ ‣ 管理者用マスタ更新 API など
  18. 32.

    Google Cloud Endpoints? 32 • API 定義に基づき、実装された API を拡張してくれるもの •

    Auth0 や Firebase、独自 JWT による API コールの検証・保護 • Stackdriver Monitoring / Logging / Trace との連携 ‣ トラフィック、エラー率、レイテンシ の可視化 ‣ API ごとのログも簡易的なトレース情報もぱっと追える
  19. 33.

    つまりこうなる 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” { ] }
  20. 34.

    つまりこうなる 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” { ] }
  21. 39.

    仕組み 39 • Extensible Service Proxy (esp) か Endpoints Frameworks

    を導入 • GAE flex env は esp のみ利用可 • GKE ではサイドカーとして   API と同じ Pod に esp をおく https://cloud.google.com/endpoints/docs/architecture-overview
  22. 41.

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

    Cloud Endpoints Service Control 実行時チェック & レポートの送信
  23. 42.

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

    • 存在しないエンドポイントだったら esp が 404 Not Found を返す
  24. 43.

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

    • ユーザの検証に失敗したら    esp が 401, 403 などを返す
  25. 44.

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

    Proxy • 問題なければバックエンドに • この一連の挙動を 1ms 程度で
  26. 46.

    Cloud Endpoints のバージョン管理 46 Google App Engine service v1.2 esp

    v1 service v1.1 例)gcloud app deploy https://project.appspot.com
  27. 47.

    Cloud Endpoints のバージョン管理 47 Google App Engine service v1.2 esp

    v1 esp v2 service v1.1 https://project.appspot.com 例)gcloud service-management deploy
  28. 48.

    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
  29. 49.

    GAE で使うには 1 49 • Google Service Management に API

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

    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 にデプロイ!
  31. 53.

    github.com/supinf/apis-on-gae 53 • サンプル swagger.yaml から Go ソースを自動生成(go-swagger) • Stackdriver

    Error Reporting、カスタム Logging も実装済 • API サーバをローカルでのビルド、テスト • GAE、Cloud Endpoints へデプロイ • README.md に従い全部試して 15 分程度
  32. 56.

    運用上の注意点 56 • App Engine フレキシブル環境 ‣ 週一で、避けられない再起動 がかかる(サーバ 1

    台だと確実に死)     https://cloud.google.com/appengine/docs/flexible/java/how-instances-are-managed#restarts • Cloud Endpoints ‣ 自動生成コードとは異なるエラーコードを返すことがある - e2e テストを書くときには注意が必要 ‣ API の定義と実装、異なるバージョンがあたると悲劇
  33. 62.

    中丸 良 @pottava • Google Certified Professional - Cloud Architect •

    AWS Certified Solutions Architect - Professional • AWS Certified DevOps Engineer - Professional Ask me 62
  34. 63.

    Ask us 63 • クラウド / コンテナ関連を特に強みに、受託開発運用 • 2015 年から

    Docker の本番運用を開始 • スピンフ、と読みます・・
  35. 65.

    ご静聴ありがとうございました :) 参考文献: • 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