【AWS】CodeBuild ~ 各開発フェーズで設定を切り替えることを考える ~

■ はじめに

https://dk521123.hatenablog.com/entry/2020/04/16/113816

で触れた以下の開発フェーズで設定を切り替えることを考えてみた

1)開発環境(dev)
2)検証環境 (stage)
3)本番環境 (prod)

例えば、各フェーズによってS3バケット名を変更したいなどが
でてくると思うので、その実装案についてのメモ。

■ 実装案

【案1】すべての値を環境変数でもらう
【案2】設定値を各フェーズに紐づけて命名する
【案3】各設定値が保存されているJSONから取得する
【案4】外部シェルから取得する

などなど、、、

【案1】すべての値を環境変数でもらう

CodeBuldには、環境変数があるので、
ごり押しのパワープレー。

【案2】設定値を各フェーズに紐づけて命名する

フェーズが識別できる環境変数(ここでは、環境タイプ:${ENV}とする)をもらい、
設定値(リソース名)は、その環境タイプに紐づけて設計(命名)する
(例えば、"s3-buket-prod-001"など)

サンプル

環境変数の環境タイプ ENV(dev/stage/prod)を受け取り、
S3バケット名をそれぞれ「s3-bucket-【環境タイプ】001~3」のように
設計した場合の例を記す。

buildspec.yml

version: 0.2

env:
  variables:
    # 本来であれば、外部から取得する
    ENV: "dev"

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
  pre_build:
    commands:
      - export S3_BUCKET_1=”s3-bucket-${ENV}001”
      - export S3_BUCKET_2=”s3-bucket-${ENV}002”
      - export S3_BUCKET_3=”s3-bucket-${ENV}003”

【案3】各設定値が保存されているJSONから取得する

設定が保存されているJSONからjqコマンドを使って取得する
以下の関連記事を参照

jq コマンド ~ コマンドで JSON を扱う ~
https://dk521123.hatenablog.com/entry/2020/02/01/000000

サンプル

環境変数の環境タイプ ENV(dev/stage/prod)を受け取り、
S3バケット名は、JSONファイル(s3-setting.json)に格納した場合

buildspec.yml

version: 0.2

env:
  variables:
    # 本来であれば、外部から取得する
    ENV: "dev"

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
  pre_build:
    commands:
      - export S3_BUCKET_1=”cat s3-setting.json | jq -r '.${ENV}.s3_bucket1'- export S3_BUCKET_2=”cat s3-setting.json | jq -r '.${ENV}.s3_bucket2'- export S3_BUCKET_3=”cat s3-setting.json | jq -r '.${ENV}.s3_bucket3'

s3-setting.json

{
  "prod": {
    "s3_bucket1":"s3-bucket-pd001",
    "s3_bucket2":"s3-bucket-pd002",
    "s3_bucket3":"s3-bucket-pd003"
  },
  "stage": {
    "s3_bucket1":"s3-bucket-sg001",
    "s3_bucket2":"s3-bucket-sg002",
    "s3_bucket3":"s3-bucket-pd003"
  },
  "dev": {
    "s3_bucket1":"s3-bucket-dv001",
    "s3_bucket2":"s3-bucket-dv002",
    "s3_bucket3":"s3-bucket-dv003"
  }
}

【案4】外部シェルから取得する

サンプル(1)外部シェル + caseで取得する

外部シェルとその中でcaseを使って、対応する

条件分岐 ~ if / case ~
https://dk521123.hatenablog.com/entry/2015/05/01/000043
buildspec.yml

version: 0.2

env:
  variables:
    # 本来であれば、外部から取得する
    ENV: "dev"

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
  pre_build:
    commands:
      - export S3_BUCKET_1=`get-value-by-env-n-key.sh ${ENV} 's3_bucket1'`
      - export S3_BUCKET_2=`get-value-by-env-n-key.sh ${ENV} 's3_bucket2'`
      - export S3_BUCKET_3=`get-value-by-env-n-key.sh ${ENV} 's3_bucket3'`

get-value-by-env-n-key.sh

#!/bin/bash

ENV="$1"
KEY="$2"

case "${ENV}" in
  prod)
    case "${KEY}" in
      s3_bucket1)
        RETURN_VALUE="s3-buket-pd001"
        ;;
      s3_bucket2)
        RETURN_VALUE="s3-buket-pd002"
        ;;
      s3_bucket3)
        RETURN_VALUE="s3-buket-pd003"
        ;;
    esac
    ;;
  stage)
    case "${KEY}" in
      s3_bucket1)
        RETURN_VALUE="s3-buket-sg001"
        ;;
      s3_bucket2)
        RETURN_VALUE="s3-buket-sg002"
        ;;
      s3_bucket3)
        RETURN_VALUE="s3-buket-sg003"
        ;;
    esac
    ;;
  dev | *)
    case "${KEY}" in
      s3_bucket1)
        RETURN_VALUE="s3-buket-${ENV}001"
        ;;
      s3_bucket2)
        RETURN_VALUE="s3-buket-${ENV}002"
        ;;
      s3_bucket3)
        RETURN_VALUE="s3-buket-${ENV}003"
        ;;
    esac
    ;;
esac

echo "${RETURN_VALUE}"

サンプル(2)外部シェル + 連結配列で取得する

case文をネストする形が可読性を下げるので、
連結配列を使ってみる

連想配列(Associative arrays)については、以下の関連記事を参照。

https://dk521123.hatenablog.com/entry/2015/02/20/001600
buildspec.yml

サンプル・その1と同じなので省略

get-value-by-env-n-key.sh

#!/bin/bash

ENV="$1"
KEY="$2"

declare -A SETTINGS;

SETTINGS=(
  # for prod
  ["prod@s3_bucket1"]="s3-buket-pd001"
  ["prod@s3_bucket2"]="s3-buket-pd002"
  ["prod@s3_bucket3"]="s3-buket-pd003"
  # for stage
  ["stage@s3_bucket1"]="s3-buket-sg001"
  ["stage@s3_bucket2"]="s3-buket-sg002"
  ["stage@s3_bucket3"]="s3-buket-sg003"
  # for dev
  ["dev@s3_bucket1"]="s3-buket-dv001"
  ["dev@s3_bucket2"]="s3-buket-dv002"
  ["dev@s3_bucket3"]="s3-buket-dv003"
  # others
  ["s3_bucket1"]="s3-buket-${ENV}001"
  ["s3_bucket2"]="s3-buket-${ENV}002"
  ["s3_bucket3"]="s3-buket-${ENV}003"
)

case "${ENV}" in
  prod | stage | dev)
    RETURN_VALUE=${SETTINGS[${ENV}@${KEY}]}
    ;;
  *)
    RETURN_VALUE=${SETTINGS[${KEY}]}
    ;;
esac

echo "${RETURN_VALUE}"

■ 総括:個人的な意見

以下に色々書いたが、状況によって使い分ければいい、、、

【案1】について

規模がデカければ、物凄い環境変数の量になる。
ただし、小規模なら、楽だし、分かりやすい。

【案2】について

設計(各の命名規則含む)をしっかりしてたら、一番いいが
仕様変更などのイレギュラーなことに対して、柔軟性に欠ける。

【案3】について

JSONにより、データと処理を分離できるので、可読性はあがるかも。
ただ、全環境JSONに記載しないとならないので、若干、柔軟性に欠けるかも。

【案4】について

一番、柔軟に対処できるかも。

関連記事

CodeBuild ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/01/21/221122
各開発フェーズにおける環境の呼び方
https://dk521123.hatenablog.com/entry/2020/04/16/113816
jq コマンド ~ コマンドで JSON を扱う ~
https://dk521123.hatenablog.com/entry/2020/02/01/000000
条件分岐 ~ if / case ~
https://dk521123.hatenablog.com/entry/2015/05/01/000043
シェル について ~基本構文編~
https://dk521123.hatenablog.com/entry/2015/02/20/001600