AWS Lightsail Containers に GitLab CI でデプロイする
実際に動かしたもの
実際に試したコードのリポジトリはこちらです。
IAM 権限
AWS Console の GUI で設定しようとしたらコンテナ関係はまだ GUI には設定がないっぽい?
Resource も制限できればなお良いです。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"lightsail:CreateContainerServiceRegistryLogin",
"lightsail:RegisterContainerImage",
"lightsail:GetContainerImages",
"lightsail:CreateContainerServiceDeployment"
],
"Resource": "*"
}
]
}
.gitlab-ci.yml
本体を deploy.sh に分離しているので短いです。
services:
- docker:dind
app-deploy:
image: ytoune/aws-lightsail-cli
stage: deploy
script:
- echo start
- sh ./deploy.sh
only:
- main
ytoune/aws-lightsail-cli
使用しているイメージはこちらです。
今回の用途のために新規作成しました。
後述する aws lightsail push-container-image
が aws-cli と lightsailctl と docker をすべて要求するので
docker をベースに aws-cli と lightsailctl を入れました。
json 加工用に Node.js も入れてます。
deploy.sh
$AWS_ACCESS_KEY_ID
と $AWS_SECRET_ACCESS_KEY
を使ってくれないみたいなので ~/.aws/credentials
を生成してます。
docker build
したのち
aws lightsail push-container-image
でイメージを push して
aws lightsail create-container-service-deployment
でデプロイしています。
set -Ceu
mkdir ~/.aws || echo pass
echo '[default]' >| ~/.aws/credentials
echo "aws_access_key_id=$AWS_ACCESS_KEY_ID" >> ~/.aws/credentials
echo "aws_secret_access_key=$AWS_SECRET_ACCESS_KEY" >> ~/.aws/credentials
echo '[default]' >| ~/.aws/config
echo 'region=ap-northeast-1' >> ~/.aws/config
echo 'output=json' >> ~/.aws/config
docker build -t myapp .
aws lightsail push-container-image --region ap-northeast-1 --service-name ${APP_SERVICE_NAME} --label api --image myapp
aws lightsail get-container-images --service-name ${APP_SERVICE_NAME} | node scripts/make-container.js
aws lightsail create-container-service-deployment --service-name ${APP_SERVICE_NAME} --cli-input-json file://$(pwd)/container.json
scripts/make-container.js
aws lightsail create-container-service-deployment
で使用する container.json
を生成してます。
const fs = require('fs/promises')
const path = require('path')
Promise.resolve()
.then(async () => {
const data = await fs.readFile('/dev/stdin', 'utf-8')
const r = JSON.parse(data)
const image = r.containerImages[0].image
await fs.writeFile(
path.join(__dirname, '../container.json'),
JSON.stringify({
containers: {
api: {
image,
command: ['sh', 'start.sh'],
environment: {},
ports: {
80: 'HTTP',
},
},
},
publicEndpoint: {
containerName: 'api',
containerPort: 80,
healthCheck: {
healthyThreshold: 2,
unhealthyThreshold: 2,
timeoutSeconds: 3,
intervalSeconds: 5,
path: '/api/health',
successCodes: '200-499',
},
},
}),
)
})
.catch(x => {
console.error(x)
process.exit(1)
})
改善案
docker build がどうしても時間がかかると思うのでどうにかしたいですね。
下記のようにビルド済のイメージを毎回どこかに push して
次回それを pull するようにすれば速くなるかもしれません。
docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY_IMAGE
docker pull $CI_REGISTRY_IMAGE:latest || true
docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest .
docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
docker push $CI_REGISTRY_IMAGE:latest
参考
プライベートなコンテナイメージを Amazon Lightsail コンテナサービスで使う
Amazon Lightsail API Reference
AWS Lightsail Containers に GitHub Actions でデプロイする。
Building Docker images with GitLab CI/CD # Using Docker caching
Discussion