どうしてもGitHub ActionsのEnvironmentを使いたいから、CodePipelineの承認を流用することにした
日記
ゆ「今日は新規開発の環境づくりか......CI/CDはActionsでいいしEnvironment使って承認プロセス追加して...」カタカタ
しばらく後
ゆ「このOrganization、Enterpriseじゃないじゃん!!!!!」
GitHub ActionsのEnvironmentとは
GitHub Actionsから呼び出すことで、devやprodなど各環境ごとの処理を実行することができます。パブリックリポジトリかEnterprise版でのみ利用可能です。
設定できる内容は下記の通りです。
- protection rule
- reviewer → 指定した人数の承認を貰うまではActionsをストップできる
- timer → 指定した時間Actionsをストップする
- branch → 指定したブランチでのみActionsを実行できる
- secrets → 環境ごとのsecretを設定できる(リポジトリのsecretsとマージされる)
secretsの方は DEV-AWS-SECRET
みたいに各環境ごとに設定すればなんとかできるのでいいとして、reviewerの方はないと困りました。
AWS CodePipelineの方にも承認プロセスはあるので、そちらをActionsから叩ければ万事OKなのでやってみます。
CodePipelineの構築
こちらによると、
- パイプラインには少なくとも2つのステージを含める
- パイプラインの最初のステージにはソースアクションが1つ以上ある
- ソースアクションはパイプラインの最初にのみ含める
とあるので、ソース+承認(approval)のみのパイプラインを作ります。
なお、ソースとして1番手っ取り早いのはS3なので、S3を使います。
terraformだとこんな感じです
resource "aws_codepipeline" "pipeline" {
name = "approval-pipeline"
role_arn = aws_iam_role.codepipeline_role.arn
artifact_store {
location = aws_s3_bucket.source.bucket
type = "S3"
}
stage {
name = "Start"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "S3"
version = "1"
output_artifacts = [ "source" ]
configuration = {
"S3Bucket" = aws_s3_bucket.source.bucket
"S3ObjectKey" = "source.txt"
"PollForSourceChanges" = false
}
}
}
stage {
name = "Approval"
action {
name = "Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = "1"
}
}
}
ここで指定した configuration.S3ObjectKey
のファイル名でS3に適当なファイルをアップロードしておいてください。
GitHub Actionsの構築
要はさっきのpipelineをGitHub Actionsから起動して、承認をもらうまで(=成功するまで)待てばいいわけです。
ワンライナーだときついと思うのでシェルスクリプトを書きます。
#!/bin/bash
# 指定したcodepipelineを実行して、完了するまで待つ。
if [ ! $# -eq 1 ]; then
echo '呼び出し失敗'
exit 1
fi
# 引数取得
pipeline_name=$1
# pipelineを実行する
execution_id=$(aws codepipeline start-pipeline-execution --name "${pipeline_name}" \
| jq -r '.pipelineExecutionId')
# 環境変数に登録(GitHub Actions)
echo "codepipeline_execution_id=${execution_id}" >> $GITHUB_ENV
echo "
次に進むためには下記のpipelineを承認してください。
pipeline name: ${pipeline_name}
execution id: ${execution_id}
"
status=""
# 空文字(最初) OR InProgress の時に繰り返す
while [ -z "$status" ] || [ "$status" = "InProgress" ]; do
sleep 10
# 現在の状況
status=$(aws codepipeline get-pipeline-execution --pipeline-name "${pipeline_name}" --pipeline-execution-id "${execution_id}" \
| jq -r '.pipelineExecution.status')
now=$(date "+%Y-%m-%dT%H:%M:%S")
echo "[${now}] 現在の状態: ${status} execution_id: ${execution_id}"
done
if [ "$status" = "Succeeded" ]; then
echo "承認を確認しました"
exit 0
elif [ "$status" = "Stopped" ]; then
echo "停止されました"
exit 1
elif [ "$status" = "Superseded" ]; then
echo "後発のpipelineが優先されました"
exit 1
elif [ "$status" = "Failed" ]; then
echo "失敗・却下しました"
exit 1
else
echo "想定外のステータスです"
exit 1
fi
あとはこれを呼び出せるようにworkflowを書くだけです。この時、上記スクリプトを呼ぶstepは絶対にtimeoutを設定してください。お金がまずいです。
name: approval
on:
workflow_dispatch
jobs:
approval:
runs-on: ubuntu-latest
steps:
-
uses: actions/checkout@v2
-
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: wait approval
timeout-minutes: 2
run: ./bin/wait-codepipeline-approval.sh approval-pipeline
CodePipelineを正しく停止させる
ここまででやっても承認プロセスはうまく使えますが、CodePipelineは同じパイプラインを同時に動かすと1つのみキューに溜まり、2つ以上になった場合古いものは捨てられてしまいます。GitHub Actionsから投げっぱなしだと、timeoutした場合のパイプラインが留まってしまい、問題が発生します。
ので、timeoutで終了した場合にパイプラインを止めます。
#!/bin/bash
if [ ! $# -eq 1 ]; then
echo '呼び出し失敗'
exit 1
fi
# 引数取得
pipeline_name=$1
execution_id=$codepipeline_execution_id
status=$(aws codepipeline get-pipeline-execution --pipeline-name "${pipeline_name}" --pipeline-execution-id "${execution_id}" \
| jq -r '.pipelineExecution.status')
if [ "$status" = "InProgress" ]; then
execution_id=$(aws codepipeline stop-pipeline-execution --pipeline-name "${pipeline_name}" --pipeline-execution-id "${execution_id}" \
| jq -r '.pipelineExecutionId')
echo "停止しました:${execution_id}"
fi
コード内の $codepipeline_execution_id
はGitHub Actionsの環境変数を使って受け渡しています。
完成形がこれです。
name: approval
on:
workflow_dispatch
jobs:
approval:
concurrency:
group: approval
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
-
uses: actions/checkout@v2
-
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: wait approval
timeout-minutes: 2
run: ./bin/wait-codepipeline-approval.sh approval-pipeline
-
name: stop pipeline
if: failure()
run: ./bin/cancel-codepipeline.sh approval-pipeline
stepに設定したtimeoutによって終了した場合も、失敗としてマークされるので、以後の if: failure()
でキャッチできます。
GitHub ActionsからAWSにアクセスする部分などは他の人の方が詳しく書いてあると思うのでそちらを見てください。
これとか ↓
実行時の画面
Author And Source
この問題について(どうしてもGitHub ActionsのEnvironmentを使いたいから、CodePipelineの承認を流用することにした), 我々は、より多くの情報をここで見つけました https://qiita.com/taittide/items/e415efe17d357c8beb4f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .