CircleCI で複数のディレクトリ(Dockerfile)に対して、別々にビルドやデプロイを行う

CircleCI で 複数フォルダのDockerビルドを行おうとして少し詰まったので備忘録としておいておきます。

# 実現したかったこと

- 複数のディレクトリに対して、別々にビルドやデプロイを行いたかった
  - 対象ディレクトリは Dockerfile を持っている
  - rootディレクトリ から docker-compose で操作する

# 主に使った機能(?)

## executors

同一リポジトリ内に、 CI/CD 対象が複数存在している場合は、 `executors` で切り分けることができる。

ref: https://circleci.com/docs/2.0/configuration-reference/#executors-requires-version-21

```yaml
executors:
  first: # executor に付けた任意の名前
    machine:
      image: circleci/classic:edge
      docker_layer_caching: true
  second: # executor に付けた任意の名前
    machine:
      image: circleci/classic:edge
      docker_layer_caching: true
```

## environment


[executors](#executors) ごとに設定したい変数がある場合、 `environment` で設定できる。

ref: https://circleci.com/docs/2.0/configuration-reference/#executors-requires-version-21

```yaml
executors:
  first: # executor に付けた任意の名前
    machine:
      image: circleci/classic:edge
      docker_layer_caching: true
    environment:
      CONTAINER_REPOSITORY_NAME: iemarco-crawler-ecr # 任意の変数名
      TARGET_DIR: . # 任意の変数名
      SERVICE_NAME: app # 任意の変数名
```

## parameters

`parameters` を使うことで変数の宣言を行うことができる。
`<< parameters.変数名 >>` とすることで、該当スコープ内で変数を使用することができる。

**入っている値がそのまま評価される** みたいなので、 quote 等を使う場合は `"<< parameters.変数名 >>"` こういった形で使ってあげる。


ref: https://circleci.com/docs/2.0/configuration-reference/#parameters-requires-version-21

```yaml
jobs:
  exec_test: # job に付けた任意の名前
    parameters:
      executor: # 変数名
        type: string # 変数の型
        default: first # 初期値の設定も可能
    executor: << parameters.executor >> # 変数の呼び出し
```

# サンプル


```yaml

version: 2.1

executors:
  first:
    machine:
      image: circleci/classic:edge
      docker_layer_caching: true
    environment:
      CONTAINER_REPOSITORY_NAME: iemarco-crawler-ecr
      TARGET_DIR: ./app
      SERVICE_NAME: ./app
  second:
    machine:
      image: circleci/classic:edge
      docker_layer_caching: true
    environment:
      CONTAINER_REPOSITORY_NAME: iemarco-crawl-batch-manager-ecr
      TARGET_DIR: ./db
      SERVICE_NAME: db

commands:
  push_docker_image:
    steps:
      - run: |
          eval $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
          docker build -t $DOCKER_REGISTORY_HOST/$CONTAINER_REPOSITORY_NAME:$STAGE $TARGET_DIR
          docker push $DOCKER_REGISTORY_HOST/$CONTAINER_REPOSITORY_NAME:$STAGE

jobs:
  exec_test:
    parameters:
      executor:
        type: string
    executor: << parameters.executor >>
    steps:
      - checkout
      - run: touch $TARGET_DIR/.env
      - run: mkdir $TARGET_DIR/lib && chmod 777 $TARGET_DIR/lib
      - run: docker-compose run $SERVICE_NAME shards
      - run: | # environment を使って条件分岐
          if [[ `cat $SERVICE_NAME` == "app" ]]; then
            docker-compose run $SERVICE_NAME /bin/bash -c "./bin/micrate up";
          fi
      - run: docker-compose run $SERVICE_NAME crystal spec

  image_push:
    parameters:
      executor:
        type: string
    executor: << parameters.executor >>
    environment:
      STAGE: production
    steps:
      - checkout
      - push_docker_image

workflows:
  build_and_test:
    jobs:
      - exec_test:
          executor: first
      - image_push:
          executor: first
          filters:
            branches:
              only:
                - master
          requires:
            - exec_test
  build_and_test_for_second:
    jobs:
      - exec_test:
          executor: second
      - image_push:
          executor: second
          filters:
            branches:
              only:
                - master
          requires:
            - exec_test

```


もっと良い感じの書き方があれば教えていただきたいですm(_ _)m
主に jobs でexecutor を毎回渡してるところとかをすっきりさせたい…