30分でできる!CodePipelineを利用してAmazon Lightsailに継続的にデプロイする方法

f:id:abist-sugiyama:20200831013132p:plain Illustration by Freepik Stories

CodePipelineは、AWSが提供するCD(継続的デリバリー)サービスです。GitHubやBitBucket等のリポジトリにPushされたアプリケーションを、検証環境や本番環境に自動的にビルド・デプロイできます。 今回はCodePipelineを利用して、GitHubにPushしたアプリケーションをAmazon Lightsailのインスタンスにデプロイする環境を構築します。

作成する環境

この記事では、以下のようなCD環境の構築を目指します。

  1. GitHubリポジトリのmasterブランチに変更を加える
  2. CodePipelineが実行される
  3. Amazon Lightsailのインスタンスに自動的にデプロイされる

全体の流れ

以下のような流れで環境を構築します。

  1. IAMロールを作成
  2. S3バケットを作成
  3. IAMポリシーを作成
  4. IAMユーザーを作成
  5. Lightsailインスタンスを作成/CodeDeployエージェントをインストール
  6. CodeDeployでデプロイするアプリケーションを設定
  7. GitHubリポジトリとCodePipelineを連携
  8. appspec.ymlを作成/masterブランチに統合

おおよその作業内容はAWS公式のブログに従います。 適宜参照してください。

メモを用意

すべての工程を完了するまでに、以下のメモを完成させる必要があります。 テキストエディター等にコピーして、必要なタイミングで埋めましょう。

  • S3 Bucket Name: <S3のバケットの名称>
  • Access Key ID: <アクセスキーID>
  • Secret Key: <シークレットキー>
  • IAM User ARN: <IAMユーザーARN>

1. IAMロールを作成

はじめにCodeDeploy用のIAMロールを作成します。

IAMのコンソールにアクセスしましょう。

1.1. 「ロール」→「ロールの作成」をクリック

画面左側のペインから「ロール」を選択し「ロールの作成」をクリックします。

f:id:abist-sugiyama:20200821224701p:plain

1.2. 「AWSサービス」→「CodeDeploy」を選択

ロールの作成画面で「AWSサービス」→「CodeDeploy」を選択します。

f:id:abist-sugiyama:20200821224751p:plain

1.3.「CodeDeploy」を選択

「ユースケースの選択」で「CodeDeploy」を選択します。

f:id:abist-sugiyama:20200821224838p:plain

1.4. 確認画面まで進む

確認画面まで「次のステップ」をクリックして進みます。

1.5. 「ロール名」と「ロールの説明」を入力

確認画面で「ロール名」と「ロールの説明」を入力します。

f:id:abist-sugiyama:20200821224942p:plain

1.6. 「ロールの作成」をクリック

「ロールの作成」をクリックするとロールが作成されます。

2. S3バケットを作成

続いて、S3にバケットを作成します。 GitHubのリポジトリにPushしたコードは、このバケットに保存された後、CodeDeployによってデプロイされます。

S3のコンソールにアクセスします。

2.1.「バケットを作成する」をクリック

f:id:abist-sugiyama:20200821225539p:plain

2.2.「バケット名」を入力

f:id:abist-sugiyama:20200821225630p:plain

2.3. バケットを作成

他の設定はそのままに、Step4まで進んでバケットを作成してください。

2.4. バケット名をメモ

バケット名を冒頭で示したメモに記録しましょう。後で使います。

3. IAMポリシーを作成

次に、IAMポリシーを作成します。

再度IAMのコンソールにアクセスします。

3.1. ナビゲーションペインから「ポリシー」を選択→「ポリシーの作成」

画面左側のナビゲーションペインから「ポリシー」を選択します。

f:id:abist-sugiyama:20200821225935p:plain

そして「ポリシーの作成」をクリックします。

f:id:abist-sugiyama:20200821230007p:plain

3.2. ポリシーをJOSNで設定

「ポリシーの作成」画面で「JSON」のタブをクリックします。

f:id:abist-sugiyama:20200821230112p:plain

以下のJSONを入力します。「バケット名」には、先ほどメモしたバケット名を入力します。 たとえば、バケット名が「code-deploy」なら "arn:aws:s3:::/code-deploy*" とします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Resource": [
        "arn:aws:s3:::<メモしたS3バケット名>/*"
      ]
    }
  ]
}

入力が完了したら「ポリシーの確認」をクリックします。

3.3. ポリシーの確認

「ポリシーの確認」の画面でポリシーの名前を設定します。 ここでは「CodeDeployS3BucketPolicy」としました。

f:id:abist-sugiyama:20200821230521p:plain

「ポリシーの作成」をクリックして完了します。

4. IAMユーザーの作成

次に、IAMユーザーを作成します。

再度IAMのコンソールにアクセスしましょう。

4.1. ナビゲーションペインから「ユーザー」を選択

画面左側のナビゲーションペインから「ユーザー」を選択します。

f:id:abist-sugiyama:20200821230848p:plain

4.2. 「ユーザーを追加」をクリック

「ユーザーを追加」をクリックします。

f:id:abist-sugiyama:20200821230925p:plain

4.3. 「プログラムによるアクセス」にチェック

「ユーザーを追加」の画面で、ユーザー名を入力し、「プログラムによるアクセス」にチェックを入れます。

f:id:abist-sugiyama:20200821231023p:plain

4.4. ポリシーをアタッチ

「アクセス許可の設定」で「既存のポリシーを直接アタッチ」をクリックし、先ほど作成したポリシーを検索してチェックを入れます。

f:id:abist-sugiyama:20200821231216p:plain

4.5. ユーザーを作成

確認画面まで進み「ユーザーの作成」をクリックします。

4.6. キーIDをメモ

ユーザー作成直後の画面でアクセスキーIDとシークレットキーIDをメモします。

f:id:abist-sugiyama:20200821231544p:plain

4.7. ARNをメモ

「閉じる」をクリックした後に表示されるユーザーの一覧から、作成したユーザー名をクリックします。 「概要」画面でユーザーのARNを確認してメモします。

f:id:abist-sugiyama:20200821231849p:plain

ここまでで、冒頭に示したメモが完成します。

5. Lightsailのインスタンスを作成し、CodeDeployのエージェントをインストールする

続いて、Amazon Lightsailのインスタンスを作成します。 インスタンスの作成と同時にCodeDeployエージェントのインストールもします。

Lightsailのホームページに移動しましょう。

5.1. 「インスタンスの作成」をクリック

「インスタンスの作成」をクリックします。

f:id:abist-sugiyama:20200831002212p:plain

5.2. 「OSのみ」→「Amazon Linux」を選択

「プラットフォームの選択」で「Linux/Unix」を選択、 「設計図の選択」で「OSのみ」を選択して「Amazon Linux」を選択します。

f:id:abist-sugiyama:20200821232330p:plain

5.3. 起動スクリプトの追加

「起動スクリプトの追加」をクリックすると、以下の画像のようなフォームが出てきます。

f:id:abist-sugiyama:20200821232439p:plain

ここに起動スクリプトとして、以下のテキストを入力します。 <>で囲まれた部分は、これまでに作成したメモの値で置き換えます。 <リージョン>には任意のリージョンを入力します。

mkdir /etc/codedeploy-agent/

mkdir /etc/codedeploy-agent/conf

cat <<EOT >> /etc/codedeploy-agent/conf/codedeploy.onpremises.yml

---

aws_access_key_id: <アクセスキーID>

aws_secret_access_key: <シークレットアクセスキー>

iam_user_arn: <IAMユーザーARN>

region: <リージョン>

EOT

wget https://aws-codedeploy-us-west-2.s3.us-west-2.amazonaws.com/latest/install

chmod +x ./install

sudo ./install auto

5.4. インスタンスを作成

「インスタンスプランの選択」以下で、任意のプランを選択し「インスタンス名」を入力して「インスタンスの作成」をクリックします。

f:id:abist-sugiyama:20200831002538p:plain f:id:abist-sugiyama:20200831002623p:plain

5.5. ターミナルを開く

インスタンスが起動するまで少し待ちます。 起動したら、右上にあるターミナルのアイコンをクリックし、ターミナルを開きます。

f:id:abist-sugiyama:20200821233258p:plain

f:id:abist-sugiyama:20200821233344p:plain

5.6. CodeDeployエージェントの起動確認

起動スクリプトが正しく実行され、CodeDeployエージェントが起動していることを確認します。 以下のコマンドを実行します。

sudo service codedeploy-agent status

以下が出力されれば、正しくできています。

The AWS CodeDeploy agent is running as PID <任意のPID>

5.7. インスタンスの登録

続いて、LightsailのインスタンスをCodeDeployに登録します。

ローカルPCのコンソール(ターミナルやコマンドプロンプトなど)を開きます。 下記のコマンドを実行します。<>の部分は、ご自身のメモの値で置き換えてください。

aws deploy register-on-premises-instance --instance-name <インスタンスの名前> --iam-user-arn <IAMユーザーARN> --region <リージョン>

※上記のコマンドはローカルPCのコンソールで実行します。操作の流れでLightsail上のターミナルで実行すると上手く動きません。 参考までに、Lightsail上で実行してしまうと以下のようなエラーになります。LightsailのコンソールではなくローカルPCで実行しましょう。

An error occurred (AccessDeniedException) when calling the RegisterOnPremisesInstance operation: User: arn:aws:sts:: xxx
 is not authorized to perform: codedeploy:RegisterOnPremisesInstance on resource: arn:aws:codedeploy:xxx

コマンドが正常に実行された場合、何も出力せずに完了します。

5.8. タグ付け

次に、タグを付与します。以下のコマンドをローカルPCのターミナルで実行します。 これまでと同様に<>の部分は、ご自身のメモの値で置き換えてください。

ここで付与したタグは、後でインスタンスを特定するのに使用します。 ここでは「key=Name, Value=CodeDeployLightsail」としました。

aws deploy add-tags-to-on-premises-instances --instance-names <インスタンスの名前> --tags Key=Name,Value=CodeDeployLightsail --region <リージョン>

こちらも正常に実行された場合は何も出力せずに完了します。

5.9. インスタンスの登録を確認

最後に、インスタンスが正常に登録されたことを、以下のコマンドで確認します。

aws deploy list-on-premises-instances --region <リージョン>

作成したインスタンスの名前が表示されたら完了です。

{
    "instanceNames": [
        "作成したインスタンスの名前" 
    ]
}

6. CodeDeploy にデプロイするアプリケーションを設定する

さて、いよいよCodeDeployを設定します。

CodeDeployのコンソールにアクセスしましょう。

6.1.「アプリケーションの作成」をクリック

「アプリケーションの作成」をクリックします。

f:id:abist-sugiyama:20200821235805p:plain

6.2.「アプリケーション名」を入力→「EC2/オンプレミス」を選択

「アプリケーション名」を入力し、「コンピューティングプラットフォーム」に「EC2/オンプレミス」を選択します。 選択したら「アプリケーションの作成」をクリックします。

f:id:abist-sugiyama:20200821235923p:plain

6.3.「デプロイグループの作成」をクリック

「デプロイグループの作成」をクリックします。

f:id:abist-sugiyama:20200822000027p:plain

6.4.「デプロイグループ名」を入力→「サービスロール」を選択

「デプロイグループ名」を入力します。 「サービスロール」は冒頭で作成したロールを選択します。

f:id:abist-sugiyama:20200822000241p:plain

6.5.「オンプレミスインスタンス」を選択→Lightsailのインスタンスを指定

「オンプレミスインスタンス」を選択し、先ほど5.8で aws deploy add-tags-to-on-premises-instances ...のコマンドで設定した key value を入力します。 この記事通りに指定した場合「key=Name, Value=CodeDeployLightsail」です。

f:id:abist-sugiyama:20200822000542p:plain

6.6.「ロードバランシングを有効にする」のチェックを外す

Load balancerの項目で「ロードバランシングを有効にする」のチェックを外します。

f:id:abist-sugiyama:20200822000808p:plain

6.7. デプロイグループの作成

「デプロイグループの作成」をクリックします。

7. GitHubリポジトリとCodePipelineを連携する

デプロイの設定ができたら、GitHubとCodePipelineを連携します。 これによって、コードの変更をGitHubのリポジトリにPushしたときに、Lightsailインスタンスに自動的にデプロイされるようにします。

CodePipelineのコンソールにアクセスします。

7.1. 「パイプラインの作成」をクリック

「パイプラインの作成」をクリックします。

f:id:abist-sugiyama:20200822001449p:plain

7.2. パイプラインの名前を入力

パイプラインの名前を入力します。

f:id:abist-sugiyama:20200822001534p:plain

7.3.「高度な設定」→「カスタムロケーション」→ S3バケットを選択

「高度な設定」をクリックし、カスタムロケーションを選択して、冒頭で作成したS3バケットを選択します。 f:id:abist-sugiyama:20200822001644p:plain

7.4. GitHubアカウントを連携

次のソースプロバイダーの画面でGitHubを選択します。 f:id:abist-sugiyama:20200822001845p:plain

「GitHubに接続する」をクリックして、GitHubアカウントを連携します。

7.5. リポジトリとブランチを選択

連携が完了したら、CodePipelineに組み込むリポジトリとブランチを選択します。

f:id:abist-sugiyama:20200822002108p:plain

7.6.「ビルドステージを追加する」をスキップ

次の「ビルドステージを追加する」の画面はスキップします。

7.7. 「デプロイステージを追加」→「デプロイプロバイダー」→「AWS CodeDeploy」

「デプロイステージを追加する」画面で「デプロイプロバイダー」に「AWS CodeDeploy」を選択します。

アプリケーション名とデプロイグループはこれまでに設定したものを選択します。

f:id:abist-sugiyama:20200822002439p:plain

7.8. パイプラインを作成

「パイプラインを作成する」をクリックします。これでパイプラインが作成され、GitHub上のコードがデプロイされます。

8. appspec.ymlを用意してリポジトリに追加

さて、以上で「GitHubにPush」→「CodePipelineを実行」ができるようになりました。 最後に「appspec.yml」という設定ファイルを作成して、リポジトリに追加します。

appspec.ymlはCodeDeployがデプロイ時に実行することを指示するファイルです。 appspec.ymlに、デプロイ時に実行したいことを記述し、GitHubのリポジトリのルートディレクトリに配置します。

appspec.ymlに何を書くべきかはデプロイするアプリケーションの構成によって異なるため詳細は割愛しますが、 例として以下のようなファイルを用意します。

version: 0.0
os: linux
files:
  - source: / # インスタンスにコピーするファイル・ディレクトリを指定します
    destination: /home/ec2-user/sample-app # インスタンス上でアプリケーションを配置するディレクトリを指定します
hooks:
  ApplicationStart:
    - location: start_app.sh # アプリケーションを起動するshファイルを指定できます
      timeout: 300
      runas: ec2-user # shを実行するユーザーを指定します 

これによって、S3バケットのルートディレクトリ以下にあるファイルやディレクトリが、インスタンスの/home/ec2-user/sample-app以下に配置されます。 その後ec2-userの権限でstart_app.shが実行されます。

サーバーの起動コマンドなどをこのshファイルの中に仕込んでおけば、Codepipelineを実行するたびに、サーバーが起動できるようになります。

※appspec.ymlに関する詳細は、公式ドキュメントを参照してください。

docs.aws.amazon.com

まとめ

今回は、CodePipelineを利用してアプリケーションをAmazon Lightsailのインスタンスに継続的にデプロイする方法について書きました。

株式会社アビストAIソリューション事業部では、このような技術者向けの記事を今後も公開する予定です。 Twitterアカウントもあるので、ぜひフォローしてください。

記事の内容に関するご指摘や、コメントもお待ちしております。

AIソリューション事業部 公式Twitterアカウント @abist_ai

参考

aws.amazon.com