Terraform Provider Mackerel を利用したメンテナンス表示自動化例
本記事は以下の18日目のエントリです。
今年は随所でだいぶ CircleCI に取り組んだ1年でした。
記事にはしてないのですが、コストを意識しつつ、ダイナミックコンフィグ、テストの並列分割、インサイト、といったあたりを工夫する日々だったように思います。
今年前半で一旦プロトタイプ開発がひと区切りとなり引き渡してメンテナンスフェーズとなったプロジェクトがあります。こちらで CircleCI と Terraform Provider Mackerel、その他いろいろを組み込んで、自分史上最高にオペレーション自動化を実現できました。小規模ながら決まった名前でブランチを切り出せば staging へ[3]、それを main にマージすれば production へ、全自動デプロイができた、という感じです。こちらをご紹介します。何かの参考となれば幸いです。
メンテナンス表示の概要
- デプロイ中は「メンテナンス表示」する
- 表示するのは簡単なHTML。static な HTML を表示するのを Fargate で実現(S3でよかったのかも)
- 処理の流れはだいたい次の通り
- メンテナンス開始
- メンテナンス表示 Fargate 起動
- Mackerel の外形監視を mute にする
- ALB リスナーの先頭(優先順位最高)に「メンテナンス表示する」ルールを terraform で apply
- メンテナンス解除
- ALB リスナーの先頭(優先順位最高)から「メンテナンス表示する」ルールを terraform destroy で 除去
- Mackerel の外形監視の mute を解除
- メンテナンス表示 Fargate 停止
- メンテナンス開始
.circleci/config.yml をご紹介
- (抜粋です。これだけではちゃんと動かないかも。)
- _ar は
auto release
の略です - 自作 Orb
-
sogaoh/orb-tfenv
- tfenv をインストールする Orb。つくった時の記事↓
-
sogaoh/orb-tfenv
version,orbs,executers,parameters
- バージョン、使用Orb・Executer、それと parameter の定義をまとめてます
- run_deploy は個別に API を使ってパイプラインをトリガーする を利用していた時の「名残」です。一方で個別手動実行も実現可能。
(Header部(?))
version: 2.1
orbs:
aws-ecr: circleci/aws-ecr@6.15.3
ecspresso: fujiwara/ecspresso@0.0.15
tfenv: sogaoh/orb-tfenv@0.0.1
slack : circleci/slack@3.4.2
executors:
amzn2:
docker:
- image: XXXXXX/image-builder-amzn2:latest
auth:
username: $DOCKER_LOGIN
password: $DOCKER_PWD
parameters:
branch:
type: string
default: development
suffix:
type: string
default: ""
environment:
type: string
default: development
# Job Trigger: execute by API v2
run_deploy:
type: boolean
default: false
anchors,commands
- 小分類レベルの使用している自動処理の定義です
- なるべく細かめにしていて、失敗した時に問題箇所を特定しやすくしています
(サブルーチン群)
anchors:
- install_ecspresso: &install_ecspresso
ecspresso/install:
version: v1.7.13
- terraform_version: &terraform_version
TERRAFORM_VERSION: 1.1.7
- install_terraform: &install_terraform
run:
name: Install terraform & Show Version
command: |
tfenv install ${TERRAFORM_VERSION}
tfenv use ${TERRAFORM_VERSION}
terraform --version
- download_maintenance_envrc_ar: &download_maintenance_envrc_ar
run:
name: Download .envrc for ecs/maintenance
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/maintenance
aws s3 cp s3://XXXXXX-envrc-store/environments/<< parameters.environment >>/ecs/.envrc ./.envrc
- scale1_maintenance_ar: &scale1_maintenance_ar
run:
name: Maintenance Service set desiredCount 1
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/maintenance
direnv allow . && eval "$(direnv export bash)"
make verify
make scale1
- scale0_maintenance_ar: &scale0_maintenance_ar
run:
name: Maintenance Service set desiredCount 0
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/maintenance
direnv allow . && eval "$(direnv export bash)"
make verify
make scale0
- download_monitor_mute_on_off_tfvars_ar: &download_monitor_mute_on_off_tfvars_ar
run:
name: Download terraform.tfvars for monitor mute on/off
command: |
cd surroundings/mackerel/external-monitor/<< parameters.environment >>
aws s3 cp s3://XXXXXX-tf-store/mackerel/external-monitor/terraform.tfvars ./terraform.tfvars
- change_monitor_mute_on_ar: &change_monitor_mute_on_ar
run:
name: Change External Monitor is_mute ON
command: |
cd surroundings/mackerel/external-monitor/<< parameters.environment >>
terraform init
terraform plan -var 'is_mute=true'
terraform apply -auto-approve -var 'is_mute=true'
- change_monitor_mute_off_ar: &change_monitor_mute_off_ar
run:
name: Change External Monitor is_mute OFF
command: |
cd surroundings/mackerel/external-monitor/<< parameters.environment >>
terraform init
terraform plan -var 'is_mute=false'
terraform apply -auto-approve -var 'is_mute=false'
- download_maintenance_tfvars_ar: &download_maintenance_tfvars_ar
run:
name: Download terraform.tfvars for alb_listener_rule_maintenance
command: |
cd infrastructures/environments/<< parameters.environment >>/alb_listener_rule_maintenance
aws s3 cp s3://XXXXXX-tf-store/<< parameters.environment >>/alb_listener_rule_maintenance/terraform.tfvars ./terraform.tfvars
- insert_alb_maintenance_rule_ar: &insert_alb_maintenance_rule_ar
run:
name: Insert Maintenance ALB Listener Rule
command: |
cd infrastructures/environments/<< parameters.environment >>/alb_listener_rule_maintenance
terraform init
terraform plan
terraform apply -auto-approve
- delete_alb_maintenance_rule_ar: &delete_alb_maintenance_rule_ar
run:
name: Delete Maintenance ALB Listener Rule
command: |
cd infrastructures/environments/<< parameters.environment >>/alb_listener_rule_maintenance
terraform init
terraform plan -destroy
terraform apply -destroy -auto-approve
- aws_ecr_login: &aws_ecr_login
aws-ecr/ecr-login:
account-url: AWS_ECR_ACCOUNT_URL
aws-access-key-id: AWS_ACCESS_KEY_ID
aws-secret-access-key: AWS_SECRET_ACCESS_KEY
region: AWS_DEFAULT_REGION
- download_ecs_service_envrc_ar: &download_ecs_service_envrc_ar
run:
name: Download .envrc for ecs/sodachi2
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/sodachi2
aws s3 cp s3://XXXXXX-envrc-store/environments/<< parameters.environment >>/ecs/.envrc ./.envrc
- ecspresso_deploy_ar: &ecspresso_deploy_ar
run:
name: ECS Deploy
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/sodachi2
direnv allow . && eval "$(direnv export bash)"
make verify
make dry-deploy
make deploy
make dereg
- download_one_time_task_envrc_ar: &download_one_time_task_envrc_ar
run:
name: Download .envrc for ecs/one-time-task
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/one-time-task
aws s3 cp s3://XXXXXX-envrc-store/environments/<< parameters.environment >>/ecs/.envrc ./.envrc
- db_migrate_ar: &db_migrate_ar
run:
name: Database Migration
command: |
cd infrastructures/environments/<< parameters.environment >>/ecs/one-time-task
direnv allow . && eval "$(direnv export bash)"
make verify
make mg-run
make dereg
commands:
start-notify:
steps:
- slack/notify:
title: "${MARK_S}"
color: '#FFC300'
message: "\n
:neutral_face: ${CIRCLE_USERNAME} :evergreen_tree: ${CIRCLE_BRANCH} \n
Job: ${CIRCLE_JOB} \n"
webhook: "${SLACK_ENDPOINT}"
end-notify:
steps:
- slack/status:
fail_only: true
failure_message: "\n
:neutral_face: ${CIRCLE_USERNAME} :evergreen_tree: ${CIRCLE_BRANCH} \n
Workflow: https://circleci.com/workflow-run/${CIRCLE_WORKFLOW_ID} \n
Job: ${CIRCLE_JOB} \n
Build URL: ${CIRCLE_BUILD_URL} \n"
webhook: "${SLACK_ENDPOINT}"
- slack/notify:
title: "${MARK_E}"
color: '#42f486'
message: "\n
:neutral_face: ${CIRCLE_USERNAME} :evergreen_tree: ${CIRCLE_BRANCH} \n
Workflow: https://circleci.com/workflow-run/${CIRCLE_WORKFLOW_ID} \n
Job: ${CIRCLE_JOB} \n
Build URL: ${CIRCLE_BUILD_URL} \n"
webhook: "${SLACK_ENDPOINT}"
jobs
- 中分類レベルの処理の流れ(steps)の定義です
- 流れを概観できるレベルにしているつもりです
(job:Executerに何を使って、変数の定義が何で(environments,parameters)、何をするか(steps))
jobs:
auto-begin-maintenance-prod:
executor:
name: amzn2
environment:
<<: *terraform_version
MARK_S: ":earth_asia: ENV : << parameters.environment >>"
MARK_E: ":hammer_and_wrench: ENV : << parameters.environment >>"
parameters:
environment:
type: string
steps:
- start-notify
- checkout
- setup_remote_docker:
docker_layer_caching: false
- <<: *install_ecspresso
- <<: *download_maintenance_envrc_ar
- <<: *scale1_maintenance_ar
- tfenv/install
- <<: *install_terraform
- <<: *download_monitor_mute_on_off_tfvars_ar
- <<: *change_monitor_mute_on_ar
- <<: *download_maintenance_tfvars_ar
- <<: *insert_alb_maintenance_rule_ar
- end-notify
auto-finish-maintenance-prod:
executor:
name: amzn2
environment:
<<: *terraform_version
MARK_S: ":hammer_and_wrench: ENV : << parameters.environment >>"
MARK_E: ":earth_asia: ENV : << parameters.environment >>"
parameters:
environment:
type: string
steps:
- start-notify
- checkout
- setup_remote_docker:
docker_layer_caching: false
- tfenv/install
- <<: *install_terraform
- <<: *download_maintenance_tfvars_ar
- <<: *delete_alb_maintenance_rule_ar
- <<: *download_monitor_mute_on_off_tfvars_ar
- <<: *change_monitor_mute_off_ar
- <<: *install_ecspresso
- <<: *download_maintenance_envrc_ar
- <<: *scale0_maintenance_ar
- end-notify
auto-release-prod:
executor:
name: amzn2
environment:
MARK_S: ":truck: ENV : << parameters.environment >>"
MARK_E: ":checkered_flag: ENV : << parameters.environment >>"
<<: *node_version
parameters:
branch:
type: string
suffix:
type: string
environment:
type: string
steps:
- start-notify
- checkout
- setup_remote_docker:
docker_layer_caching: false
- <<: *download_environment_envrc_ar
- <<: *vue_js_build
- <<: *docker_image_build_ar
- <<: *aws_ecr_login
- <<: *aws_ecr_push_ar
- <<: *install_ecspresso
- <<: *download_ecs_service_envrc_ar
- <<: *ecspresso_deploy_ar
- end-notify
auto-migrate-prod:
executor:
name: amzn2
environment:
MARK_S: ":seedling: ENV : << parameters.environment >>"
MARK_E: ":checkered_flag: ENV : << parameters.environment >>"
parameters:
branch:
type: string
environment:
type: string
steps:
- start-notify
- checkout
- setup_remote_docker:
docker_layer_caching: false
- <<: *install_ecspresso
- <<: *download_one_time_task_envrc_ar
- <<: *db_migrate_ar
- end-notify
workflows
- 大分類レベルの処理の流れ(jobs)の定義です
- 起動条件の指定はここに集約するように自分はしています
(workflows:どのjobをどういう条件のときに(when,filters,requires,...)どういう流れで実行するか)
workflows:
version: 2
auto-release-production:
when:
and:
- equal: [false, << pipeline.parameters.run_deploy >>]
jobs:
- auto-begin-maintenance-prod:
environment: production
filters:
branches:
only:
- main
- auto-release-prod:
branch: main
suffix: ""
environment: production
requires:
- auto-begin-maintenance-prod
- auto-migrate-prod:
branch: main
environment: production
requires:
- auto-release-prod
- auto-finish-maintenance-prod:
environment: production
requires:
- auto-migrate-prod
Terraform Provider Mackerel の利用
当初利用し始めた頃は 0.0.6 くらいだった Terraform Provider Mackerel、現在は 0.2.0 となっており、AWSインテグレーションも IaC で設定できるように進化してます。
まだ自身はこのあたり利用を深められていないのですが、上手に使ってマイクロホストメトリック数を 30 以内に収めることもちゃんと定義できそうで、機会が巡ってきたらしっかりと定義していこうと思っています。
おまけで、昨年の自身のアドベントカレンダー記事を置いておきます。
最近は一般的になりつつあると思っていますが、IaC で監視設定を定義する際の参考にしていただければ幸いです。
明日19日目の予定は以下になっています。お楽しみに。
-
Mackerel : 「shimesaba使ってみた」by cm-watanabeseigo さん
-
17日目は Kidapan さんの Mackerelの新機能を振り返ってみた~2022年版~ でした。 ↩︎
-
17日目は ・・・12/17 20:00 時点で未定です。 ↩︎
-
staging へのデプロイに関してはこの記事で紹介してません。production のと同じ内容です。 ↩︎
Discussion