CircleCIからCodePipelineを開始させる


背景

先日会社のステージング環境をEC2からFargateにリプレイスし、
CodePipelineを使ってFargateへの自動デプロイがされるようにしました

その際にCIはCircleCIをそのまま使ってCDをCodeDeployに任せたかったのですが
developブランチの変更をトリガーにCodePipelineを開始すると
CircleCIと並行して走ってしまうためCircleCIが正常終了した時のみCodePipelineが実行されるようにしました

いろいろ調べて「これだ」っていうのがなかったので自分の考えたこの方法が同じ状況の人に参考になったら嬉しいな〜と

概要

ざっくり書くと

CircleCI -> S3 -> CodePipeline -> CodeBuild -> CodeDeploy

CircleCIからS3へbuildspec.ymlとコミットハッシュを持つファイル(commit)を送り
そのbuildspec.ymlcommitを使ってビルド、デプロイしていきます

あらかじめCodeBuildには環境変数でgit cloneできるように認証情報入れておき
buildspec.ymlの中身はgit cloneしてcommitをもとにチェックアウトしてビルド
といった感じにします

S3の設定

適当に非公開のバケットを作ります
仮でバケット名はsample-deploy-hookとしておきます

IAMの設定

S3のポリシーをアタッチしたユーザを作成してアクセスキーIDシークレットアクセスキーをメモっておきます

CircleCIの設定

環境変数を設定

IAMでユーザを作った際にメモったアクセスキーID/シークレットキー
それぞれAWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYという環境変数で設定する

.circleci/config.ymlを設定

jobを追加

deploy-staging:
    docker:
      - image: circleci/python:3.7
    working_directory: ~/project
    steps:
      - checkout
      - run:
          name: Install awscli
          command: |
            sudo pip install awscli
      - run:
          name: Setup AWS credentials
          command: |
            mkdir -p ~/.aws
            printf "[default]\nregion = ${AWS_REGION}\naws_access_key_id = ${AWS_ACCESS_KEY_ID}\naws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}" > ~/.aws/config
            printf "[default]\naws_access_key_id = ${AWS_ACCESS_KEY_ID}\naws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}" > ~/.aws/credentials
            chmod 600 ~/.aws/*
      - run:
          name: Create commit hash file
          command: echo -n $CIRCLE_SHA1 > /tmp/commit
      - run:
          name: Create zip for deploy
          command: zip -j build buildspec.yml /tmp/commit
      - run:
          name: Upload zip to s3 for hook deploy staging
          command: aws s3 mv ./build.zip s3://sample-deploy-hook/build.zip

内容的には
- awscliをインストール
- AWSのcredential情報をファイルに吐き出す
- コミットハッシュを持つファイル(commit)を作成
- buildspec.ymlcommitをzipに固める
- zipをS3へアップロード

workflowへjobを追加

- deploy-staging:
  requires:
    - rspec
    - rubocop
    - db_seed

rspecやrubocopなどが正常に終了することを条件とするためにrequiresしてます

CodePipelineの設定

最初のステージのアクションプロバイダーソース > Amazon S3を選び、
バケットは上で作ったもの
検出オプションはCloudWatchに任せます
S3オブジェクトキーは任意のファイル名(CIからアップするzipと同名)にします

これでCIが通った時にS3にzipがアップされ、それをトリガーにCodePipelineが走るようになります