GitLabのReview appsはMRパイプラインの構築がおすすめ

AWS

はじめに

GitLabのReview appsの実装を行った。

Review appの削除の動作に苦戦したのでその点を説明する。

要点はブランチパイプラインではなくMRパイプラインを使うこと。

本来であれば一から説明していきたいところだが、今回は要点のみ書いていく。

対象者

GitLab CI/CDにある程度精通しており、以下の点を理解できる人。

  • Review appとは何かわかる
  • GitLabのパイプラインにはいくつかの種類がある
  • Review appの削除はGitLabのenvironmentの機能を利用する

実装

デプロイするアプリケーションはCDKで構築。

この記事で使う.gitlab-ci.ymlは下記のとおり。

全ての詳細を説明するのは本記事の範囲を超えるため省略。

.gitlab-ci.yml

.cdk_review_job:
    image: node:lts
    stage: deploy
    rules:
      - if: $CI_MERGE_REQUEST_ID
    variables:
      ENV: $CI_COMMIT_REF_SLUG
      AWS_DEFAULT_REGION: us-east-1
    id_tokens:
      GITLAB_OIDC_TOKEN:
        aud: <https://gitlab.com>
    before_script:
      - uname -m
      # - curl "<https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip>" -o "awscliv2.zip"
      - curl "<https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip>" -o "awscliv2.zip"
      - unzip awscliv2.zip
      - ./aws/install
      - npm install -g aws-cdk 
      - aws --version
      - cdk --version
      - >
        export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
        $(aws sts assume-role-with-web-identity
        --role-arn ${ROLE_ARN}
        --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
        --web-identity-token ${GITLAB_OIDC_TOKEN}
        --duration-seconds 3600
        --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
        --output text))
      - aws sts get-caller-identity
      - npm i

cdk_deploy_review:
  extends:
    - .cdk_review_job
  environment:
      name: review/$CI_COMMIT_REF_SLUG
      on_stop: cdk_stop_review
  rules:
    - if: $CI_MERGE_REQUEST_ID
  script:
    - cdk synth
    - cdk diff
    - cdk deploy --require-approval never

cdk_stop_review:
  extends:
    - .cdk_review_job
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    action: stop
  rules:
    - if: $CI_MERGE_REQUEST_ID
      when: manual
  script:
    - cdk destroy --force

cdk_deploy_review_branch_pipeline:
  extends:
   - .cdk_review_job
  environment:
    name: review/$CI_COMMIT_REF_SLUG/brahch_pipeline
    on_stop: cdk_stop_review_branch_pipeline
  rules:
    - if: $CI_COMMIT_BRANCH
  variables:
    ENV: "${CI_COMMIT_REF_SLUG}-brahch-pipeline"
  script:
   - cdk deploy --require-approval never

cdk_stop_review_branch_pipeline:
  extends:
    - .cdk_review_job
  environment:
    name: review/$CI_COMMIT_REF_SLUG/brahch_pipeline
    action: stop
  rules:
    - if: $CI_COMMIT_BRANCH
      when: manual
  variables:
    ENV: "${CI_COMMIT_REF_SLUG}-brahch-pipeline"
    # branchパイプラインのときは必要 <https://docs.gitlab.com/ee/ci/environments/index.html#stop-an-environment-when-a-branch-is-deleted>
    # GIT_STRATEGY: none
  script:
    - echo "gitリポジトリがもう削除されていて、checkout(pull)できないからそもそもエラーになる。つまりcdkコマンドは実行できない"
    - cdk destroy --force
    # 回避策としては、awscliのcfnでスタック名を指定して削除
    # 下記、スタック名をハードコードしているからより好ましいのは前段ジョブにてスタック名を抽出してartifactsにしてdependenciesで参照など
    # - aws cloudformation delete-stack --stack-name GitlabReviewAppWithTsCdkStack$ENV
  # 下記はaws cloudformation delete-stackのシナリオを試すときに有効にする必要あり(共通からnpm iを消したもの)
  # before_script:
  #     - curl "<https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip>" -o "awscliv2.zip"
  #     - unzip awscliv2.zip
  #     - ./aws/install
  #     - npm install -g aws-cdk 
  #     - >
  #       export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
  #       $(aws sts assume-role-with-web-identity
  #       --role-arn ${ROLE_ARN}
  #       --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
  #       --web-identity-token ${GITLAB_OIDC_TOKEN}
  #       --duration-seconds 3600
  #       --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
  #       --output text))

上記コードのMRパイプラインとブランチパイプライン。

これは既にマージを行いソースブランチが削除されて、review appの削除ジョブが実行された後。

ブランチパイプラインの場合、既にソースブランチが削除されているので見つからずエラーになる。

MRパイプラインは問題なくChekoutできる。

この理由はこのあたりで軽く触れられている。

GitLab generates the special ref refs/pipelines/<id> during a running pipeline job. This ref can be created even after the associated branch or tag has been deleted. It’s therefore useful in some features such as automatically stopping an environment, and merge trains that might run pipelines after branch deletion.

https://docs.gitlab.com/ee/ci/pipelines/index.html#ref-specs-for-runners

上記のエラーは要件次第では回避できる。

ジョブの設定でgitリポジトリを取得しないようにすればよい。

具体的にはGIT_STRATEGY: noneを設定する。

• If you can’t use merge request pipelines, set GIT_STRATEGY to none or empty in the stop_review job. Then, the runner doesn’t try to check out the code after the branch is deleted.

https://docs.gitlab.com/ee/ci/environments/#stop-an-environment-when-a-branch-is-deleted

これで上記エラーは回避できるが、 cdk destoryをするときにリポジトリが空なのでcdkコマンドでエラーになる。

この回避策は2通り考えられる。

  1. aws cloudformation delete-stack
  2. cdk synthでcdk.outを生成してそれをartifacts経由で取得して cdk destory --app cdk.out

1つ目は下記のように成功する。

GIT_STRATEGY: noneを設定済み。

ここまでの内容をみてもらうとわかるが、MRパイプラインのほうが楽である。

この件についての公式ドキュメントの見解は見つけられないので適宜判断することになるだろう。

参考)

https://docs.gitlab.com/ee/ci/review_apps/

https://docs.gitlab.com/ee/ci/environments/#stopping-an-environment

Enable review apps buttonのサンプルでもMRパイプラインになっているので

特に理由がなければMRパイプラインを使うみたいな判断でもよいかもしれない。

おわりに

各パイプラインでのgitリポジトリの取得の振る舞いに違いがあることを確認した。

その特性を踏まえてReview appの削除をスムーズに行うには、MRパイプラインを選択することをおすすめする。

おまけ

.gitlab-ci.ymlの中身について補足する。

imageのnode:lts)

今回のサンプルとしては問題ないが、Lambdaをデプロイする場合は別のimageを使うことを推奨する。

理由はLambdaでバンドリングする際にdokcerが必要になるからである。なのでLambda以外でもdockerが必要になるケースでは別のimageを選択するほうがよい。

順当に考えるとdocker:dindになるだろう。

サンプルとしてnodeを選択している理由は主に下記のとおり。

  • cdk cliのため
  • aws cliが普通にインストールできる
    • aws-cliをベースにする案はあったが、nodeと相性が悪かった
  • 記事には載せてないがCDKの言語もTSにしているので一石二鳥

パイプライン種類のハンドリング)

MRパイプラインとして実行条件として - if: $CI_MERGE_REQUEST_IDを使っているが、

要件に合わせて他のCI変数を検討したほうがよいだろう。

参考: https://docs.gitlab.com/ee/ci/jobs/job_rules.html#run-jobs-only-in-specific-pipeline-types

.cdk_review_jobについて)

この内容は標題の検証には無関係。

GitLab CICD機能の1つであり、設定内容を各ジョブで継承できるもの。

AWS_DEFAULT_REGION: us-east-1について)

aws sts assume-role-with-web-identityのくだりではリージョンを設定していないので直接定義しているだけ。

awscliコマンドによってはリージョンの指定が必要なため。

ENV: $CI_COMMIT_REF_SLUGについて)

このENVはCDKのアプリケーションスタックidのサフィックスなどに使うことで動的にリソースを定義できるようにして、Review appに対応させている。

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!