AWS Lightsail ContainersにGitHub Actionsでデプロイする。
AWS Lightsail Containersとは
Lightsail Containersとは2020年11月に発表されたAWS Lightsailの新機能です。Dokcerイメージを直接起動することができ、自動的にHTTP/HTTPSのエンドポイントが付与されます。コンテナをスケールアウトさせることもできます。GCPのCloudRunに似ています。CloudRunと比べると同時に複数のコンテナを起動できるというところが大きな違いです。
Lightsail Containersの公式記事
Lightsail Containersへのデプロイ方法
Lightsail Containersには2つのデプロイ方法があります。残念ながら、Elastic Container Registryなどのプライベートリポジトリを直接指定する方法は今のところ用意されていないようです。(2020年11月時点)
- 公開リポジトリのコンテナを指定してデプロイする
-
aws lightsail push-container-image
を使って登録したイメージを指定してデプロイする
GitHub Actionsからデプロイする
おおまかな流れとしては、下記になります。
- Dockerイメージをビルドする
-
aws lightsail push-container-image
でイメージをLightsail Containersに登録する -
aws lightsail create-container-service-deployment
で登録済みのイメージをデプロイする
起動時パラメータのファイル化
現実のシステムでは起動時に複雑な設定をすることになると思うので、CIで実行するコマンドラインを単純にできるように、コマンドラインパラメータをJSONで指定できるようにします。AWSのコマンドでは--generate-cli-skeleton
と--cli-input-json
のオプションを使ってJSONでパラメータを渡すことができますので、これを活用します。また、JSON内にCI上でしか取得できない値を変数として記述する必要があるため、ここではERBを使ったJSONテンプレートからCI上で最終的なJSONファイルを出力できるようにします。
コンテナを起動するコマンドのJSONは下記のコマンドで出力できます。
aws lightsail create-container-service-deployment --generate-cli-skeleton
下記のように設定用のJSONのスケルトンが出力されます。
{
"serviceName": "",
"containers": {
"KeyName": {
"image": "",
"command": [
""
],
"environment": {
"KeyName": ""
},
"ports": {
"KeyName": "HTTPS"
}
}
},
"publicEndpoint": {
"containerName": "",
"containerPort": 0,
"healthCheck": {
"healthyThreshold": 0,
"unhealthyThreshold": 0,
"timeoutSeconds": 0,
"intervalSeconds": 0,
"path": "",
"successCodes": ""
}
}
}
これに必要なパラーメータを埋めていきます。serviceNameはコマンドラインパラメータとして指定するので削除します。
下記はRuby on Railsを起動する例です。変数となる部分はERBの書式に則っています。
ここではファイル名をcontainer.json.erb
とします。
{
"containers": {
"api": {
"image": "<%= image %>",
"command": [
"rails",
"server",
"-e",
"production"
],
"environment": {
"RAILS_LOG_TO_STDOUT": "true",
"RAILS_MASTER_KEY": "<%= master_key %>",
"SOME_ENV_VARS": "HOGEHOGE"
},
"ports": {
"3000": "HTTP"
}
}
},
"publicEndpoint": {
"containerName": "api",
"containerPort": 3000,
"healthCheck": {
"healthyThreshold": 2,
"unhealthyThreshold": 2,
"timeoutSeconds": 3,
"intervalSeconds": 5,
"path": "/api/v1/health",
"successCodes": "200-499"
}
}
}
GitHub Actionsのワークフローを作る
こちらもRuby on Railsの場合の例です。
GitHubのSecretsに下記が必要です。
- AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY : AWS Lightsailのコマンドの実行に必要な権限を持ったAWSアクセスキー
- RAILS_MASTER_KEY : Ruby on Railsのcredentialsを復号するためのキー情報
name: deploy rails
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Utilities
run: sudo apt-get install -y jq ruby
- name: Install AWS Client and LightsailControl Plugin
run: |
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
curl "https://s3.us-west-2.amazonaws.com/lightsailctl/latest/linux-amd64/lightsailctl" -o "lightsailctl"
sudo mv "lightsailctl" "/usr/local/bin/lightsailctl"
sudo chmod +x /usr/local/bin/lightsailctl
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Build Docker Image
run: |
docker build -t example-image:latest .
- name: Push and Deploy
env:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
run: |
service_name=container-service-1
aws lightsail push-container-image \
--region ap-northeast-1 \
--service-name ${service_name} \
--label api \
--image example-image:latest
aws lightsail get-container-images --service-name ${service_name} | jq --raw-output ".containerImages[0].image" > image.txt
erb image=$(cat image.txt) master_key=$RAILS_MASTER_KEY container.json.erb > container.json
aws lightsail create-container-service-deployment --service-name ${service_name} --cli-input-json file://$(pwd)/container.json
ポイントは最後のPush and Deployのジョブにまとまっており、下記の流れになっています。
(ここではLightsail Containersのサービス名が container-service-1
である想定です。)
-
aws lightsail push-container-image
でビルドしたDockerイメージを登録する。 - 登録したイメージのLightsailにおけるイメージ名を取得する必要があるため、
aws lightsail get-container-images
でイメージの一覧を取得してイメージ名を抜き出しています。JSONで情報が返ってくるためjqコマンドで情報を抜き出します。 - イメージ名やSecretsの情報を使って設定テンプレート
container.json.erb
から起動用の設定ファイルcontainer.json
を作成します。 -
aws lightsail create-container-service-deployment
にcontainer.json
を指定してデプロイを実行します。
Discussion