動機: CircleCI Orbs を使ったときに困ったこと
CircleCI Orbs を使うことで、AWS ECRへのイメージPushなどを行ってくれますが、ブランチごとに別々のリポジトリにpushしたい場合などは少し困ったことになります。
以下、正しく動作しないケースです。
version: 2.1
orbs:
aws-ecr: circleci/aws-ecr@6.15.1
aws-ecs: circleci/aws-ecs@1.4.0
# 中略
workflows:
build:
jobs:
# 中略
# Staging 用のデプロイ
- aws-ecr/build-and-push-image
repo: "Staging用リポジトリ"
tag: "${CIRCLE_SHA1}"
requires:
- test
- lint
filters: &staging-filter
branches:
only:
- staging
- aws-ecs/deploy-service-update:
requires:
- aws-ecr/build-and-push-image
family: 'Staging用ファミリー'
cluster-name: 'Staging用クラスター名'
container-image-name-updates: 'container=Staging用コンテナ名,tag=${CIRCLE_SHA1}'
filters: *staging-filter
# Production用のデプロイ
- aws-ecr/build-and-push-image
repo: "Production用リポジトリ"
tag: "${CIRCLE_SHA1}"
requires:
- test
- lint
filters: &master-filter
branches:
only:
- master
- aws-ecs/deploy-service-update:
requires:
- aws-ecr/build-and-push-image
family: 'Production用ファミリー'
cluster-name: 'Production用クラスター名'
container-image-name-updates: 'container=Production用コンテナ名,tag=${CIRCLE_SHA1}'
filters: *master-filter
こんなかんじのエラーが出てしまいます。
Job 'aws-ecs/deploy-service-update' requires 'aws-ecr/build-and-push-image', which is the name of 2 other jobs in workflow 'build'
You can give a job within a workflow an explicit name by adding a `name` key
Orbs に定義されている、 aws-ecs/deploy-service-update
job 実行の前提として必要としている、aws-ecr/build-and-push-image
が Staging 用と、Production 用の2つ用意してしまっているため、うまく動作しないとのことです。
ヘルプメッセージに従って、name
を Workflow の job に指定すれば良さそうです。
ひとまず、ドキュメントを読んでみたのですが、 今の所 (2021年1月8日現在) この点についての記載はなさそうです。。。
2021/1/9 14:00 修正
ドキュメントに記載はありました。 ドキュメントの解釈を誤っており、name
は requires
の下で使えるものだと勘違いしておりました。
job
の下で name
が requires
のために使えるという記載っぽいです。 @PanonCotta さんご指摘ありがとうございます。
修正後
version: 2.1
orbs:
aws-ecr: circleci/aws-ecr@6.15.1
aws-ecs: circleci/aws-ecs@1.4.0
# 中略
workflows:
build:
jobs:
# 中略
# Staging 用のデプロイ
- aws-ecr/build-and-push-image
name: "ecr-build-and-push-image-stg"
repo: "Staging用リポジトリ"
tag: "${CIRCLE_SHA1}"
requires:
- test
- lint
filters: &staging-filter
branches:
only:
- staging
- aws-ecs/deploy-service-update:
name: "ecs-deploy-stg"
requires:
- ecr-build-and-push-image-stg
family: 'Staging用ファミリー'
cluster-name: 'Staging用クラスター名'
container-image-name-updates: 'container=Staging用コンテナ名,tag=${CIRCLE_SHA1}'
filters: *staging-filter
# Production用のデプロイ
- aws-ecr/build-and-push-image
name: "ecr-build-and-push-image-prod"
repo: "Production用リポジトリ"
tag: "${CIRCLE_SHA1}"
requires:
- test
- lint
filters: &master-filter
branches:
only:
- master
- aws-ecs/deploy-service-update:
name: "ecs-deploy-prod"
requires:
- ecr-build-and-push-image-prod
family: 'Production用ファミリー'
cluster-name: 'Production用クラスター名'
container-image-name-updates: 'container=Production用コンテナ名,tag=${CIRCLE_SHA1}'
filters: *master-filter
これで、ECRにpushするイメージ作成と、ECSによるサービス展開までについてを環境別に分けることができました。
この設定のやりかたは、同じjobを再利用しつつ、環境別にパラメータを変えるといったときにも便利そうです。
検証用に、以下のようなサンプルを作ってみて実行してみたところ、job1, job2 を再利用することができました。
version: 2.1
executors:
ruby-executor:
docker:
- image: circleci/ruby:3.0.0
jobs:
job1:
executor: ruby-executor
# https://circleci.com/docs/2.0/reusing-config/#authoring-parameterized-jobs
# Workflow からパラメータを渡すことができる
parameters:
env:
type: string
default: development
steps:
- checkout
- run: 'ruby --version'
# パラメータを使う時は、<<parameters.キー>> で呼び出しできる
- run: 'echo <<parameters.env>>'
job2:
executor: ruby-executor
parameters:
env:
type: string
default: development
steps:
- checkout
- run: 'ruby --version'
- run: 'echo <<parameters.env>>'
workflows:
build:
jobs:
# master のみ
- job1:
name: job1-master
# env パラメータを production として job にわたす
env: production
filters: &master-filter
branches:
only:
- master
- job2:
name: job2-master
env: production
filters: *master-filter
requires:
- job1-master
# master 以外
- job1:
name: job1-non-master
# env パラメータを指定してないので、job の `<<parameters.env>>` は、
# default にセットしている、development に置き換わる
filters: &non-master-filter
branches:
ignore:
- master
- job2:
name: job2-non-master
filters: *non-master-filter
requires:
- job1-non-master
まとめ
Workflow Job に名前が使えるようになったのも、Jobにパラメータが渡せるようになったのも、
ドキュメントの雰囲気を見るに2.1からのようです。
昔から運用している、 .circleci/config.yml
の場合、環境ごとに別々にjobを作ったり、
command で以下のように書いているケースがありました。
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
bundle exec cap production deploy
elif [ "${CIRCLE_BRANCH}" == "staging" ]; then
bundle exec cap staging deploy
fi
なかなか難儀なのでコンパクトに
command: bundle exec cap <<parameters.env>> deploy
などに変更するなどして、スマートなCiecleCI設定ライフを送りたいものです。