DevOps チームの うすい と申します。よろしくお願いします。 昨年11月にハーフマラソンに出てから膝に矢を受けてしまった状態が続いています。困っています。
今回は最近作ったシステムにおけるデプロイについてお話したいと思います。
前提
弊社の主だった環境は AWS 上にあります。また、ソースコード管理には GitLab を使用していて、GitLab CI も元気に稼働しています。 本システムは小規模で、リリース後のデプロイは多くないことが想定されています。
デプロイフロー
フローとしては下記のようになっています。
- master マージ
- GitLab CI で成果物を S3 にアップロード
- S3 にファイルが作成されたことをトリガーとして CodePipeline がスタート
- ステージング環境にて CodeDeploy でデプロイ
- 本番環境デプロイ承認のためのメール送信と Slack 通知
- 承認権限を持った人が CodePipeline の中で
承認
- 本番環境にデプロイ
少し細かく見ていきましょう。
GitLab CI
GitLab CI の中でcomposer install
やnpm install
をしています。各ツールのバージョンを簡単に固定したかったため、今回は PHP 用のイメージの中で npm をインストールしたりするのではなく、バージョンを指定したイメージを使用し作成した成果物を次のジョブに引き継ぐ方式をとりました。
.gitlab-ci.yml の概要です。
stages: - npm - composer - upload npm: stage: npm image: node:12.14.1-alpine3.11 script: - npm install - npm audit fix - npm run production - tar czf node_modules.tar.gz node_modules artifacts: paths: - node_modules.tar.gz composer: stage: composer image: composer:1.9 script: - composer install - zip -r ./${CI_PIPELINE_ID}.zip . artifacts: paths: - ./${CI_PIPELINE_ID}.zip s3upload: stage: upload image: alpine:latest before_script: - apk add --no-cache python3 - pip3 install awscli script: - aws s3 cp ./${CI_PIPELINE_ID}.zip s3://${S3BUCKET}/${APP}.zip
実際にはbefore_script
と呼ばれる文字通りscript
の前に実行されるセクションで環境変数ファイルに秘匿情報を埋め込んだりもしています。それらの秘匿情報は GitLab のSecret
に保存しています。
このようにして作成された成果物を最終的に S3 にアップロードしています。
また、これまでは nginx や php-fpm の設定ファイルは DevOps チームの Ansible のリポジトリで管理されていることが多く、開発チームで変更したい場合には
依頼&マージリクエスト作成(開発チーム) → マージ&反映(DevOps チーム) → 確認(開発チーム)
となっていましたが、開発チームで使用しているリポジトリに必要なファイルをすべて含め、CodeDeploy の中で反映を行うようにしました(後述)。
CodePipeline
CodePipeline は S3 にファイルが置かれたことをトリガーとしてスタートします。特に込み入ったことはしておらず、シンプルなパイプラインとなっています。
イメージ図
SNS との連携も上記画像の真ん中の上にあるNotify
から簡単に作成することができて、今回はパイプラインの成功
、スタート
、失敗
、そして承認
時に SNS に通知を送って Lambda を起動し Slack の Incoming Webhooks で通知、といったことをしていますが、AWS Chatbot でも検証中です(下記図)。Lambda 内でメッセージをパースする必要もないので、こだわりがなければ AWS Chatbot で良いかと思います。
承認
部分に関してはメールでの通知も行っています。
CodeDeploy
今回は AutoScaling と EC2 を組み合わせたシステム構成になっているので、コンピューティングプラットフォーム
はEC2/オンプレミス
、またデプロイ設定
はリリース後の修正が多くないこと、また利用される時間があらかじめ把握することができることから、時間の節約のためデプロイタイプ
はインプレース
にしました。
CodeDeployはイベントという形で順々に処理を実行していきます。
こちらのAfterInstall
の中で設定ファイルのアップデートや nginx の再起動などを行っています。
また、余談ですがインスタンス起動時のユーザーデータに登録したスクリプトで CloudWatch Alarm の作成を行い、ステージング環境など夜間休日にインスタンスを停止する環境において残り続けてしまう CloudWatch Alarm は AWS Batch で削除しています。 AWS Batch のコンテナイメージはこんな感じで作って ECR に push しています。
delete-insufficient-cloudwatch-alarm.sh
#!/usr/bin/env bash aws cloudwatch describe-alarms --state-value INSUFFICIENT_DATA --region ap-northeast-1 | grep AlarmName | awk '{print $2}' > ./result.txt sed -i -e 's/"//g' ./result.txt sed -i -e 's/,$//g' ./result.txt for name in $(cat ./result.txt) do aws cloudwatch delete-alarms --alarm-names ${name} --region ap-northeast-1 done
Dockerfile
FROM amazonlinux:latest ENV LANG C.UTF-8 RUN yum -y install unzip aws-cli ADD delete-insufficient-cloudwatch-alarm.sh /usr/local/bin/delete-insufficient-cloudwatch-alarm.sh ENTRYPOINT ["/usr/local/bin/delete-insufficient-cloudwatch-alarm.sh"]
まとめ
今回は EC2 を選択しましたが、別のプロジェクトでは ECS(Fargate)を使用していたり他にも IaC や CI / CD の強化といったこともしています。DevOps チームのメンバーは現在絶賛募集中ですので、興味を持たれた方はご連絡いただければと思います。また、もっといいやり方や改善点を指摘してくれる方もカジュアル面談でお越しいただければと思います。