$30 off During Our Annual Pro Sale. View Details »

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

ryo nakamaru
September 27, 2017

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

GCPUG Tokyo DevOps Day, Sep 27, 2017

ryo nakamaru

September 27, 2017
Tweet

More Decks by ryo nakamaru

Other Decks in Technology

Transcript

  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.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  5. 早速ですが

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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
    ɹɹ…

    View Slide

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

    View Slide

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

    View Slide

  19. API 開発のお供に

    View Slide

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

    View Slide

  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
    ɹɹ…

    View Slide

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

    View Slide

  23. GAE への継続的デプロイ

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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%

    View Slide

  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

    View Slide

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

    View Slide

  31. Cloud Endpoints で守る・把握する

    View Slide

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

    View Slide

  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”
    {
    ]
    }

    View Slide

  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”
    {
    ]
    }

    View Slide

  35. つまりこうなる
    35

    View Slide

  36. つまりこうなる
    36

    View Slide

  37. つまりこうなる
    37

    View Slide

  38. つまりこうなる
    38

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  52. 実際にやってみよう

    View Slide

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

    View Slide

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

    View Slide

  55. CAUTION .

    View Slide

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

    View Slide

  57. そもそも API の Docker 化が・・

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide