地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

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

4933248c9e81c3a6e1dd7ecbd06090d0-png.png

概要

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

yaml

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

ryuichi1208/py-dep-kun

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上で見えるタグはこの値となります。

スクリーンショット 2019-10-13 22.27.32.png

環境変数の使い方

    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 で制御する

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

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

     - 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: /.*/

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