AWS CodeDeployでEC2にデプロイする時のポイント5選

記事タイトルとURLをコピーする

こんにちは。アプリケーションサービス部の兼安です。
以前AWS CodePipelineを使ってCI/CDを構築した時に、CodeDeployで結構つまずいたため、押さえるべきポイントをまとめてみました。

はじめに

本記事ではAWS CodeDeployを用いてEC2にデプロイする場合を想定しています。
他のサービスへのデプロイや、AWS CodePipelineそのものやビルドに関する内容は今回の対象外としています。
また、デプロイ対象のEC2は、Linuxを想定しています。

CI/CDパイプラインの考え方については、こちらをご覧ください。
blog.serverworks.co.jp

本記事の対象者

CI/CDパイプラインの初心者を想定しています。
概念は知っているが、構築は初めてという方のヒントになれば幸いです。

[前提知識] AWSで構築するCI/CDパイプラインの基礎知識

CI/CDパイプラインとは

CI/CDパイプラインとは、Continuous Integration(継続的インテグレーション)とContinuous Deployment(継続的デプロイメント)の略で、ソフトウェア開発プロセスを自動化するための手法です。
一般的には、Gitのリポジトリにコードをプッシュすると、自動的にビルド、テスト、デプロイが行われる仕組みのことを指します。

AWSで構築するCI/CDパイプラインの基本構成

AWSでCI/CDパイプラインを構築する場合、AWS CodePipelineというサービスを使うことが一般的です。
AWS CodePipelineは、何をトリガーにして起動し、ビルド、デプロイをどのように行うかを定義することができます。
ビルド、デプロイは、AWS CodeBuild、AWS CodeDeployという専用サービスが存在します。

トリガーは、AWS CodeCommit、外部リポジトリ(GitHub、Bitbucketなど)、Amazon S3、Amazon SNS、Amazon CloudWatch Eventsなどが利用できます。
例えば、AWS CodeCommitへのプッシュをトリガーにしてビルド、デプロイを行うとしたら、図のような三段階になります。

CI/CDパイプラインの基本構成

各段階はステージと呼ばれます。
図中にS3があるのは、ステージ間でソースコードやビルド済みファイルのやり取りにS3を使用するためです。
各ステージで生成されたファイルはアーティファクト(Artifact)と呼ばれ、アーティファクトをS3に保存することで、次のステージに引き継ぎます。

サーバーにビルド済みファイルをデプロイするAWS CodeDeploy

AWS CodeDeployは、EC2やLambdaなどにファイルをデプロイするためのサービスです。
一般的にAWS CodeDeployでデプロイするのはビルド済ファイルです。
ビルド済ファイルというのは、コンパイル・ビルドした実行可能ファイル、スクリプト言語ならソースコードそのもの、あとはライブラリや静的ファイルなどです。
ビルド済ファイルもAWS CodePipelineおよびAWS CodeDeploy上ではアーティファクトと表現されます。

ビルド済ファイルをAWS CodeDeployeでデプロイ

AWS CodeDeployはビルド済ファイルをアーティファクトとして引き継ぎ、これらをサーバー上の適切な場所に配置、場合によってはパーミッションの設定などを行います。

AWS CodeDeployでEC2にデプロイする時のポイント

1. EC2側にCodeDeployエージェントのインストールが必要

AWS CodeDeployでEC2にデプロイする場合、まずEC2側にCodeDeployエージェントをインストールする必要があります。

docs.aws.amazon.com

AWS CodeDeployによるEC2へのデプロイは、ファイルを送るイメージではなく、EC2上のCodeDeployエージェントが動いてファイルを取りに行くイメージです。

CodeDeployエージェントがビルド済ファイルを読み取る

デプロイ対象となるEC2は、AWS CloudFormationテンプレートなどを用いて、事前にCodeDeployエージェントをインストールしておくと良いと思います。

AWS CloudFormationテンプレートなら、EC2のUserDataで起動時にCodeDeployエージェントをインストールすることができます。
このようなイメージです。

UserData:
    Fn::Base64: !Sub |
    #cloud-config
    package_update: true
    package_upgrade: true
    packages:
        - wget
    runcmd:
        - echo "Starting CodeDeploy agent installation"
        - cd
        - dnf update -y
        - dnf install -y ruby
        - wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
        - chmod +x ./install
        - ./install auto
        - systemctl enable codedeploy-agent
        - systemctl start codedeploy-agent

docs.aws.amazon.com

2. EC2側にS3へのアクセス権限が必要

CodeDeployエージェントがS3からビルト済ファイル=アーティファクトを取得するには、EC2にS3へのアクセス権限が必要です。
アーティファクトが格納されているS3バケットに対してGetObject権限を付与しておく必要があります。

3. デプロイスクリプトはEC2の台数分実行される

CodeDeployエージェントは、S3からアーティファクトを取得し、中のデプロイスクリプトに従ってデプロイを行います。
このデプロイスクリプトを、AppSpec ファイルと呼びます。

docs.aws.amazon.com

ソースディレクトリの直下にappspec.ymlというファイルを配置すると、CodeDeployエージェントがAppSpec ファイル=デプロイスクリプトとして認識します。
(パスは変更可能です。 )

AppSpec ファイルによるデプロイ処理は、EC2の台数分実行されます。
したがって、S3のような外部ストレージやデータベースサーバーに対する処理をAppSpecファイルに記述する場合、複数回実行されることによる矛盾を考慮する必要があります。
SQLの実行などは、冪等性(何度実行しても問題ない作り)を検討してください。

AppSpecファイルによるデプロイはEC2の数だけ起動する

4. AppSpec ファイルのフック処理とユーザー

こちらは、AppSpec ファイルのサンプルです。
詳細は省かせていただきますが、PHPのアプリケーションをApacheで動かす場合の例です。

version: 0.0
os: linux
files:
  - source: /httpd_example.conf
    destination: /etc/httpd/conf.d/
  - source: /
    destination: /var/www/html
hooks:
  BeforeInstall:
    - location: deploy_scripts/before_install.sh
      timeout: 300
      runas: root
  AfterInstall:
    - location: deploy_scripts/after_install.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: deploy_scripts/application_start.sh
      timeout: 300
      runas: root

filesがどのファイルをどこに配置するかを指定します。
この例の場合、/httpd_example.conf/etc/httpd/conf.d/に、//var/www/htmlに配置します。
sourceの/はビルド済ファイルの全体を指します。
したがって、全ファイルを/var/www/htmlという意味になります。

hooksは、デプロイの各段階で実行するスクリプトを指定します。
スクリプトは別途用意して、そのパスを指定します。
ここに直接スクリプトを書くことはできないようです。

この例の場合、BeforeInstallAfterInstallApplicationStartの3つの段階でそれぞれスクリプトを実行します。
AppSpec ファイルにおけるInstallとは、ファイルを配置することを指します。
従って、BeforeInstallAfterInstallは、ファイルを配置する前後に実行されるスクリプトを指定することになります。

そして、runasは、スクリプトを実行するユーザーを指定します(Linux限定です)。
従って、各スクリプト内で、sudoなどを書く必要は必ずしもありません。
runasでユーザーを指定するのか、スクリプト内でsudoを使うのか、どちらかを統一しておかないと矛盾が生じる可能性があるので注意してください。

hooksの更なる詳細は、こちらを参照してください。

docs.aws.amazon.com

5. CodeDeployエージェントのログ

CodeDeployエージェントは、AppSpec ファイルに従ってデプロイを行います。
デプロイ中にエラーが発生した場合、デプロイが失敗しますが、AWS CodePipelineやAWS CodeDeployの画面上にはあまり詳細なエラーメッセージが表示されません。

EC2の中にCodeDeployエージェントのログが出ているので、こちらを見るのがオススメです。

docs.aws.amazon.com

場所はこちらです。
セッションマネージャーでEC2に入って見ると良いと思います。

/var/log/aws/codedeploy-agent/codedeploy-agent.log

docs.aws.amazon.com

また、CodeDeployエージェントがS3から読み込んだファイルは、こちらにあります。
ここを見ることで、デプロイに正しくファイルが渡ってきているかを確認できます。
なお、ファイルはZip圧縮されているため解凍する必要があります。

/opt/codedeploy-agent/deployment-root/

docs.aws.amazon.com

最後に

本記事が皆様のお役に立てれば幸いです。
他のサービスへのデプロイや、AWS CodePipelineそのものやビルドに関する内容は、別の機会にまとめたいと思います。


サーバーワークスはDevOpsを支援するサービスを提供しています。

www.serverworks.co.jp

兼安 聡(執筆記事の一覧)

アプリケーションサービス部 DS3課所属
2024 Japan AWS Top Engineers (Database)
2024 Japan AWS All Certifications Engineers
認定スクラムマスター
広島在住です。今日も明日も修行中です。