Study & Practice

北海道札幌市のプログラマによる技術とか雑記のブログ

CodeDeployを使ってEC2インスタンスにLaravelプロジェクトをデプロイする

AWSを有効活用するためCI/CD系をとりあえず試している中でCodeDeployの使い方は少しずつ分かってきたので、手順をまとめる。

EC2インスタンスの起動

まずはデプロイするサーバーとしてEC2インスタンスを起動します。
AWSマネジメントコンソールを開き、こちらの記事の「EC2インスタンスの作成」までを行ってください。

carametal.hatenablog.com

ただ、注意点としてステップ 3: インスタンスの詳細の設定で「AmazonEC2RoleforAWSCodeDeploy」ポリシーをもったIAMロールを設定するようにしてください。
なお、本記事ではEC2にKey=Name,Value=CodeDeployTrialというタグをつけたと仮定して進めていきます。

CodeDeployエージェントのインストール

次にCodeDeployを実行に必要なパッケージをEC2インスタンスにインストールします。

sshでEC2インスタンスに入ったら以下のコマンドを実行します。

sudo yum update -y
sudo yum -y install ruby
sudo yum install -y wget
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto

5つ目のwgetコマンドに渡しているURLはEC2がどのリージョンにあるかによって変わります。
詳しくは以下をご覧ください。
CodeDeploy リソースキットリファレンス - AWS CodeDeploy

以上のコマンドが正常に終了したらCodeDeployエージェントのインストールは完了です。

Laravelプロジェクトの作成

ローカルの開発マシンにlaravel newコマンドでLaravelプロジェクトを作成します。Composerを使いますのでもしインストールをされていない方は以下からダウンロードしてください。
https://getcomposer.org/download/

以下のコマンドを実行するとcode-deploy-tiralというディレクトリを作成されます。その中にLaravelに必要なパッケージが揃った状態になっています。

laravel new code-deploy-trial

CodeDeployに必要なファイルを作成

code-deploy-trialディレクトリに入ります。

cd code-deploy-trial

以下の構成になるようにファイル、ディレクトリを作ります。

scripts
└ install_dependencies.sh
└ start_server.sh
└ stop_server.sh
appspec.yml

code-deploy-trialディレクトリ直下にappspec.ymlとscriptsディレクトリ、scriptsディレクトリに.shファイルが3つです。

そして各ファイルは以下の内容になります。

appspec.yml

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html
hooks:
  BeforeInstall:
    - location: scripts/install_dependencies.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server.sh
      timeout: 300
      runas: root

install_dependencies.sh

#!/bin/bash
yum install -y httpd
amazon-linux-extras install php7.3


start_server.sh

#!/bin/bash
systemctl start httpd.service

stop_server.sh

#!/bin/bash
isExistApp=`pgrep httpd`
if [[ -n  $isExistApp ]]; then
	systemctl stop httpd
fi

install_dependencies.shのyum installは-yオプションを付け忘れると後々デプロイを失敗することがあります。注意してください。

これで設定ファイルの準備ができました。

ソースコードをデプロイするためのS3バケットの準備

s3バケットを作ります。
code-deploy-trialというバケット名は既に使われていたのでcarametal-code-deploy-trialとしました。

aws s3 mb s3://carametal-code-deploy-trial

S3バケットにCodeDeploy用のポリシーを設定します。

bucket-policy.jsonというファイルを以下の内容で作成してください。
バケット名、使用しているIAMユーザーのID、EC2を作るときに設定したIAMロールのARNとなっている部分は皆さんの環境に合わせて入れ替えてください。

{
  "Statement": [
      {
          "Action": [
              "s3:PutObject"
          ],
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::バケット名/*",
          "Principal": {
              "AWS": [
                  "使用しているIAMユーザーのID"
              ]
          }
      },
      {
        "Action": [
            "s3:Get*",
            "s3:List*"
        ],
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::バケット名/*",
        "Principal": {
            "AWS": [
                "EC2を作るときに設定したIAMロールのARN"
            ]
        }
    }
  ]
}

ちなみに使用しているIAMユーザーのIDは以下のコマンドでとれます。ちなみにIAMユーザーのARNを設定しても問題ありません。

aws sts get-caller-identity

EC2を作るときに設定したIAMロールのARNは以下のコマンドで取れます。

 aws iam get-role --role-name CodeDeployTrialRole

bucket-policy.jsonの準備ができたらS3バケットにポリシーを紐づけします。

aws s3api put-bucket-policy --bucket carametal-code-deploy-trial --policy file://bucket-policy.json

これでS3バケットの準備は完了です。

CodeDeployのセットアップ

CodeDeployにデプロイするため必要な準備を行っていきます。

まずはCodeDeployで扱うアプリケーションを作成します。
今回はCodeDeployTrialという名前でアプリケーションを作成します。

aws deploy create-application --application-name CodeDeployTrial

デプロイグループを作成します。
「EC2に設定したNameタグの値」と「AWSCodeDeployRoleを持つIAMロールのARN」はみなさんの環境に応じて変更してください。

aws deploy create-deployment-group --application-name CodeDeployTrial \
  --deployment-group-name CodeDeployTrialGroup \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --ec2-tag-filters Key=Name,Value=EC2に設定したNameタグの値,Type=KEY_AND_VALUE \
  --service-role-arn AWSCodeDeployRoleを持つIAMロールのARN

アプリケーションのデプロイ

そしていよいよアプリ―ケーションのデプロイを行います。
まずはソースコードをS3にアップロードします。

aws deploy push \
  --application-name CodeDeployTrial \
  --s3-location s3://carametal-code-deploy-trial/code-deploy-trial.zip

※以下のコマンドを実行するとLaravelプロジェクトのすべてのファイルがs3にアップロードされます。本来.envファイルやvendorディレクトリなどはサーバーごとで別のものを用意するべきと言われています。注意してください

そしてEC2インスタンスへのデプロイです。

aws deploy create-deployment \
  --application-name CodeDeployTrial\
  --deployment-group-name CodeDeployTrialGroup \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --s3-location bucket=carametal-code-deploy-trial,bundleType=zip,key=code-deploy-trial.zip,eTag=s3オブジェクトのETag

s3オブジェクトのETagとなっている部分は以下のコマンドで取得できます。

    • bucketバケット名、--keyは取得したいファイルのパスを引数とします。
aws s3api head-object --bucket carametal-code-deploy-trial --key code-deploy-trial.zip

これでデプロイの完了です。ただまだ終わりません。

Apacheの設定をLaravel向けにする

この状態でEC2インスタンスIPアドレスにアクセスしてみてもApacheのテストページが表示されてしまいます。設定ファイルの内容を変更してLaravelに向けるようにします。
/etc/httpd/conf/httpd.confをテキストエディタで開いて編集します。

sudo vim /etc/httpd/conf/httpd.conf

DocumentRootを"/var/www/html"から"/var/www/html/public"に変更します。

# DocumentRoot "/var/www/html"
DocumentRoot "/var/www/html/public"

これでIPへのアクセスがLaravelに向きます。

それともう一つの中にあるAllowOverrideをNoneからAllに変更します。
コメントがたくさんあると思いますが、コメントを除くと以下のようになります。
これはドキュメントルート以外にアクセスするために必要な設定です。

<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    # AllowOverride None
    AllowOverride All
    Require all granted
</Directory>

このままだとLogが書き込めなかったというエラーになるので以下を実行します。
/var/www/html配下のディレクトリとファイルがapacheの所有物になりLogへの書き込みが可能になります。

sudo chown -R apache:apache /var/www/html/*

ようやくEC2のIPアドレスへブラウザからアクセスするとLaravelのwelcomページが表示されます。

これでLaravelプロジェクトをEC2インスタンスにデプロイできました。が、もう少しだけ続きます。

再デプロイ

先ほどAllowOverrideを変更してドキュメントルート以外へのアクセスを有効にしましたが、まだ実際に動くコードがありません。
なのでコードを追加し、EC2インスタンスに再デプロイして確かめてみます。
Laravelプロジェクトのroutes/web.phpの末尾に以下を追加します。

Route::get('info', function() {
    phpinfo();
});

S3へのaws deploy pushとaws deploy create-deploymentを再度実行します。create-deploymentのeTagはpushするたびに更新されるので新しい値を入力してください。

これでIPアドレス/infoにブラウザからアクセスするとPHPの詳細情報が表示されるはずです。

まとめ

なんとかCodeDeployの初歩的な使い方は理解できたかなと思います。ただ、.envとかvendorとかもまとめてデプロイしちゃってるから実際に運用するには向いてない。もっというとCI/CDにはまだほど遠いので、次回はCodePipelineも使ってより実践的な手法を身に着けたい。