CircleCI上でコンテナをビルドしてDockerHubへpush

![4933248c9e81c3a6e1dd7ecbd06090d0-png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258841/89b245b2-fbad-1dd6-2e34-b9391d73e3b5.png)

## 概要

DockerHubでのビルドが遅い！ってことが多いのでCircleCI上でビルドしてしまえばいいのではと思ったので環境を構築してみたメモです。

## yaml

全体は下記で公開してます。
記事では抜粋して簡略化した部分を紹介してます。

[ryuichi1208/py-dep-kun](https://github.com/ryuichi1208/py-dep-kun/blob/master/.circleci/config.yml)

``` yaml
version: 2.1

executors:
  py-builder:
    machine:
      enabled: true
      image: circleci/classic:201808-01
      docker_layer_caching: true

  build_and_deploy:
    executor:
      name: builder
    steps:
      - run:
          name: Build container
          when: always
          command: |
            docker image build -t py-dep-kun .
      - run:
          name: Add container tag
          when: always
          command: |
            docker login -u ${DOCKERHUB_USER} -p ${DOCKERHUB_PASS}
            docker tag py-dep-kun ${DOCKERHUB_USER}/${DOCKERHUB_REPOS}:${CIRCLE_TAG}
            docker image push ${DOCKERHUB_USER}/${DOCKERHUB_REPOS}:${CIRCLE_TAG}
workflows
  version: 2
  defaultWorkflow:
    jobs
      - build_and_deploy:
          filters:
            tags:
              only: /v.*/
            branches:
              ignore: /.*/
```

#### CircleCI上でビルド

下記では変数をCircleCI上で設定しています。
CIRCLE_TAGにはGitタグで指定した値を取得して設定しています。
DockerHub上で見えるタグはこの値となります。

<img width="848" alt="スクリーンショット 2019-10-13 22.27.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258841/30b83ee0-7550-010b-d93d-c8e7663ca3da.png">

[環境変数の使い方](https://circleci.com/docs/ja/2.0/env-vars/)

``` yaml
    steps:
      - run:
          name: Build container
          when: always
          command: |
            docker image build -t py-dep-kun .
      - run:
          name: Add container tag
          when: always
          command: |
            docker login -u ${DOCKERHUB_USER} -p ${DOCKERHUB_PASS}
            docker tag py-dep-kun ${DOCKERHUB_USER}/${DOCKERHUB_REPOS}:${CIRCLE_TAG}
            docker image push ${DOCKERHUB_USER}/${DOCKERHUB_REPOS}:${CIRCLE_TAG}
```

#### tag付きのpushのみに反応するように設定

下記のような要件があるとします。

* mergeのときではなく任意のタイミングでデプロイしたい
* master mergeのみ特殊な状態のデプロイをしたい
* デプロイ後のトラブルのためにロールバックする方法の確率

上記のうちに任意のタイミングでデプロイする方法があります。
その方法が下記です。
[ジョブの実行を Workflow で制御する](https://circleci.com/docs/ja/2.0/workflows/)

``` yaml
    jobs
      - build_and_deploy:
          filters:
            tags:
              only: /v.*/
            branches:
              ignore: /.*/
```

この時注意が必要です。
tagsは全部のjobに記述しないといけないのです。
仮に他のjobsにタグを書かない場合はジョブがスキップされたりと意図しない動作が起こります。
(正直ここが死ぬほどはまりました。)

``` yaml
     - test_for_prd:
          requires:
            - build
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/

      - approval:
          type: approval
          requires:
            - build
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/

      - deploy:
          requires:
            - approval
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/
```

上記のように指定することで問題は解決します。
(ちなみに公式ドキュメントに注意書きされてるのでただ見落としてました。。。)