🔥
GitHubActions 複数のCodeDeployのデプロイを新コンテナが立ち上がるまで待機するためのShell芸
GitHubActionsでCodeDeployのデプロイを行い、新コンテナが立ち上がるまで待機したい...しかも複数環境...なんてことはないでしょうか?
私はあります、そんなときに使えるShell芸を紹介します。
コード例
name: example workflow
on:
workflow_call:
inputs:
ENVIRONMENT:
required: true
type: string
AWS_REGION:
required: false
type: string
default: ap-northeast-1
secrets:
AWS_ROLE_ARN:
required: true
permissions:
contents: read
id-token: write
jobs:
call-build-image:
# 省略、buildをするジョブ
call-deploy-app1:
needs: call-build-image
# 省略、CodeDeployでデプロイを実行するジョブその1
# CodeDeployのデプロイメントIDを返すようにしています、app2とapp3も同様
call-deploy-app2:
needs: call-build-image
# 省略、CodeDeployでデプロイを実行するジョブその2
call-deploy-app3:
needs: call-build-image
# 省略、CodeDeployでデプロイを実行するジョブその3
save-deployment-metadata:
needs:
[
call-build-image,
call-deploy-app1,
call-deploy-app2,
call-deploy-app3,
]
runs-on: ubuntu-latest
steps:
- name: Create deployment_metadata.json
run: |
# 一時的な配列を作成
DEPLOYMENT_IDS=()
# app1のデプロイメントIDが存在する場合、配列に追加
if [[ -n "${{ needs.call-deploy-app1.outputs.codedeploy-deployment-id }}" ]]; then
DEPLOYMENT_IDS+=("\"${{ needs.call-deploy-app1.outputs.codedeploy-deployment-id }}\"")
fi
# app2のデプロイメントIDが存在する場合、配列に追加
if [[ -n "${{ needs.call-deploy-app2.outputs.codedeploy-deployment-id }}" ]]; then
DEPLOYMENT_IDS+=("\"${{ needs.call-deploy-app2.outputs.codedeploy-deployment-id }}\"")
fi
# app3のデプロイメントIDが存在する場合、配列に追加
if [[ -n "${{ needs.call-deploy-app3.outputs.codedeploy-deployment-id }}" ]]; then
DEPLOYMENT_IDS+=("\"${{ needs.call-deploy-app3.outputs.codedeploy-deployment-id }}\"")
fi
# 配列の要素をカンマで結合
IDS_STRING=$(IFS=,; echo "${DEPLOYMENT_IDS[*]}")
# JSONファイルを作成
cat << EOF > deployment_metadata.json
{
"codedeploy_deployment_ids": [
${IDS_STRING}
]
}
EOF
- name: Upload deployment_metadata.json
uses: actions/upload-artifact@v4
with:
name: deployment-metadata
path: deployment_metadata.json
retention-days: 1
wait-for-codedeploy-ready:
needs: save-deployment-metadata
runs-on: ubuntu-latest
environment:
name: ${{ inputs.ENVIRONMENT }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ inputs.AWS_REGION }}
- name: Download deployment_metadata.json
uses: actions/download-artifact@v4
with:
name: deployment-metadata
- name: Wait for CodeDeploy deployments to be ready
run: |
DEPLOYMENT_IDS=$(jq -r '.codedeploy_deployment_ids[]' deployment_metadata.json)
for DEPLOYMENT_ID in $DEPLOYMENT_IDS; do
DEPLOYMENT_ID=$(echo $DEPLOYMENT_ID | tr -d '"')
echo "Waiting for deployment: $DEPLOYMENT_ID"
SECONDS=0
TIMEOUT=600 # 10分(600秒)
while true; do
STATUS=$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query 'deploymentInfo.status' --output text)
echo "Current status: $STATUS"
if [[ "$STATUS" == "Ready" ]]; then
echo "Deployment $DEPLOYMENT_ID is ready."
break
elif [[ "$STATUS" == "Failed" ]]; then
echo "Deployment $DEPLOYMENT_ID failed or stopped."
exit 1
fi
if [[ $SECONDS -ge $TIMEOUT ]]; then
echo "Timeout: Deployment $DEPLOYMENT_ID did not become Ready within 10 minutes."
exit 1
fi
sleep 10
done
done
echo "All deployments are ready."
ざっくり解説
- コンテナのビルド、デプロイの処理は省略しています
- デプロイ時にこちらのActionを使い、CodeDeployのデプロイメントIDを戻り値としています
- 戻り値から取得したデプロイメントIDをjsonでアーティファクトとして保存します
- アーティファクトから取り出したデプロイメントIDを使って、ループしながら
aws deploy get-deployment
を実行しています- ステータスが
Ready
となったデプロイはbreak
してループを抜けます - 全てが
Ready
となるか、10分間のタイムアウトとなった場合にワークフローを終了します
- ステータスが
余談
AIが発達して本当に気軽にShell芸ができるようになりました、万歳。
参考
Discussion