自己紹介
こんにちは、松岡です。
私はコマース事業部でインフラ兼バックエンドエンジニアをやっています。
器用貧乏に幅広くいろいろなことができることを売りにしてきましたが、本格派の方々が続々と加入しているため居場所がなくなりつつあります笑。
この記事はdelyアドベントカレンダー4日目の投稿です。
昨日は偉大なEMのtakaoさんの「delyで働くパパエンジニアの日常を紹介」でした。偉大なEMは偉大な父親でもありました。ぜひご覧ください。
事業の紹介
最初に私が所属するコマース事業部を紹介させてください。
コマース事業部はクラシルデリバリーというサービスを運営しています。
「あらゆるスーパーマーケットで最短30分配送を実現するグロサリーデリバリーサービス」です。
詳細は次のプレスリリースをご覧ください。
クラシルデリバリーは大きく分類すると生鮮食品EC市場のサービスになります。
この生鮮食品EC市場は近年で最も熱い市場の1つではないでしょうか。
私たちもこの市場で刺激のある毎日を送っています。
こんな毎日にご興味がある方はぜひ次の採用情報をご覧ください。
https://delyjp.notion.site/dely-kurashiru-delivery-2c5199d383cd4ce8ac50942e65da2fb6delyjp.notion.site
CIを改善した話
それでは本題のCIについてお話しします。 *この投稿内でのCIの定義はコードをプッシュするとデプロイしてくれるやつをあらわします。
改善前の様子
コマース事業部はCIをAWSのCodePipeline、CodeBuild、CodeDeployで行っていました。以後、この3サービスをCode3兄弟と呼びます。
GitHubとAWS CodePipelineを連携してプッシュするブランチとデプロイする環境を1対1に関連づけます。具体的な例は次のとおりです。
main
ブランチにプッシュするとプロダクション環境にコードをデプロイする。test1
ブランチにプッシュするとテスト環境その1にコードをデプロイする。test2
ブランチにプッシュするとテスト環境その2にコードをデプロイする。
開発の流れは次のとおりです。
main
ブランチからトピックブランチを作り、トピックブランチで開発する。- 開発が終わったら
test1
~test2
のいずれかの1ブランチにトピックブランチをマージしてテスト環境にデプロイし、テスト環境でテストする。 - テストが終わったら
main
ブランチにトピックブランチをマージし、プロダクション環境にリリースする。
Code3兄弟は基本的には最高ですが、1つ不満がありました。
それは学習コストが高いことです(私は何度か心が折れました)。そしてそれによりCIを運用・改善するエンジニアが特定の人に限られていました。
CIには開発で行う様々なことを自動化できる力があるため、その開発を行っているアプリケーションエンジニア自身も運用・改善できたほうがよいと私は思っています。
そのほうがきっとよい改善が行われるでしょう。
ですが、、、学習コストの高さが壁になり、それが行いづらい状況でした。
GitHub Actionsは上記の不満を解決してくれるよい選択肢でしたが、私たちの事業部ではできる限りAWSのアクセスキーを発行しないという方針を持っているため、AWSと連携させていませんでした。
GitHub Actionsの大きなニュース
こんな状況でしたが今年の9月にうれしいニュースを知ります。AWSのアクセスキーなしでGitHub ActionsとAWSが連携できるようになりました。
何がどのくらい最高かと言いますと!
— Tori Hara (@toricls) 2021年9月15日
GitHub Actions に AWS クレデンシャルを直接渡さずに IAM ロールが使えるようになることがまず最高で!
クレデンシャル直渡しを回避するためだけの Self-hosted runner が必要なくなるところも最高です!!✨✨✨ https://t.co/IUQmfzkIB0
GitHub ActionsとCode3兄弟の連携
さっそく私たちはこの方法でGitHub ActionsとCode3兄弟を連携します。
具体的なコードは次のとおりです。ECSにデプロイする例です。
GitHubとAWSの連携をいままではWebhookで行っていましたが、この機会にS3のバケット経由に変更しました。 こうするとWebhookに必要だったGitHubのアクセストークン等の管理も不要になります(ここも意外と大きな改善)。
GitHub Actions
on: push: branches: - 'main' jobs: push-to-bucket: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - name: Configure AWS uses: aws-actions/configure-aws-credentials@master with: aws-region: ap-northeast-1 role-to-assume: arn:aws:iam::123456789012:role/github-actions role-session-name: <session-name> - run: aws sts get-caller-identity - uses: actions/checkout@v2 - run: echo $GITHUB_SHA > github_sha env: GITHUB_SHA: ${{ github.sha }} - run: zip -r source.zip . -x *.git/* - run: aws s3api put-object --bucket bucket-to-deploy --key backend.zip --body source.zip
aws-actions/configure-aws-credentials
のバージョンは強気のmaster
です。安定版をお勧めします。echo $GITHUB_SHA > github_sha
はDockerイメージのタグをコミットIDにしたいための手段です。 SourceをS3バケットにするとCodeBuildのCODEBUILD_RESOLVED_SOURCE_VERSIONがコミットIDではなく、S3オブジェクトのバージョンIDになります。
そこで上記のとおりgithub.shaをファイルに書き出してZIPファイルに格納しています。書き出したファイルは後続のCodeBuild内で行うDockerイメージのビルドに使います。
IAM ロールその他
すみません、Terraformな表現です。
resource "aws_iam_openid_connect_provider" "github_actions" { url = "https://token.actions.githubusercontent.com" client_id_list = [ "sts.amazonaws.com" ] thumbprint_list = [ "a031c46782e6e6c662c2c87c76da9aa62ccabd8e" ] } resource "aws_iam_role" "github_actions" { name = "github-actions" assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [ { "Sid" : "", Action = "sts:AssumeRoleWithWebIdentity", Principal = { Federated = aws_iam_openid_connect_provider.github_actions.arn } Condition = { StringLike = { "token.actions.githubusercontent.com:sub" = [ "repo:dely-no/repository-dayo:*" ] } }, Effect = "Allow" } ] }) }
thumbplint_list
のa031c46782e6e6c662c2c87c76da9aa62ccabd8e
は公式サンプルの引用です。公式のサンプルもご覧ください。
Code3兄弟
CodePipeline
- SourceはGitHub Actionsのワークフローで指定したS3バケットのオブジェクトです。
- run: aws s3api put-object --bucket bucket-to-deploy --key backend.zip --body source.zip
CodeBuild
version: 0.2 phases: pre_build: commands: - aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com - echo $DOCKER_HUB_PASSWORD | docker login -u $DOCKER_HUB_USERNAME --password-stdin - COMMIT_ID=$(cat github_sha) - TAG=$ECR_REPOSITORY_URL:$COMMIT_ID build: commands: - docker build -f Dockerfile -t $TAG . - docker push $TAG
*出力アーティファクトに関する部分は省略しています。
連携方法は以上です。
結果発表〜〜〜
GitHub Actionsと連携した結果、CIの学習コストが下がったためか自分を含めアプリケーションエンジニアの方々がCIを運用・改善するようになりました(あっさり)。
アプリケーションエンジニアが作ったワークフローが爆誕し、運用されています。
いかがでしたでしょうか!
この投稿を最後まで読んでくださった皆様方に少しでも役に立てたらうれしいです!!!