生産性向上ブログ@miyajan

圧倒的生産性向上を目指すエンジニアのためのブログ

CircleCI 2.0 で Docker イメージをビルドして Docker Hub に push する

CircleCI 2.0 の小ネタです。

TL; DR

リポジトリのルートに Dockerfile がある前提です。

  1. CircleCI 2.0 で対象のリポジトリをプロジェクトとして有効にする
  2. CircleCI 2.0 上で環境変数に Docker Hub のユーザー名を DOCKER_USER に、パスワードを DOCKER_PASS に登録する
  3. .circleci/config.yml に以下のように記述する
version: 2
jobs:
  build:
    docker:
      - image: docker:17.07.0-ce-git
    steps:
      - checkout
      - setup_remote_docker
      - run:
          command: docker build -t miyajan/test-circleci-docker .
      - run:
          command: docker login -u ${DOCKER_USER} -p ${DOCKER_PASS}
      - run:
          command: docker push miyajan/test-circleci-docker

もう少し実用的に、セマンティックバージョンのタグ(1.0.1とか)が作成されたときだけ Docker イメージの build & push を行いたい場合は以下のようになります。

version: 2
jobs:
  buildh:
    docker:
      - image: docker:17.07.0-ce-git
    steps:
      - checkout
      - setup_remote_docker
      - run:
          command: docker build -t miyajan/test-circleci-docker:${CIRCLE_TAG} .
      - run:
          command: docker login -u ${DOCKER_USER} -p ${DOCKER_PASS}
      - run:
          command: docker push miyajan/test-circleci-docker:${CIRCLE_TAG}
workflows:
  version: 2
  build:
    jobs:
      - build:
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /^[0-9]+\.[0-9]+\.[0-9]+$/

説明

CircleCI で Docker イメージの build を扱うための公式ドキュメントは以下にあります。

circleci.com

setup_remote_docker のステップを実行すると、Docker Engine 用のホストがリモートに立ち上がります。これ以降のステップの実行も image で指定されたメインのコンテナの中で実行されますが、docker コマンドは TCP 経由でリモートホストの Docker Engine を使用するようです。これは、メインのコンテナ内で docker コマンドの実行を許すと、いわゆる Docker in Docker のセキュリティ問題に直面するためこのような構成になっていると思われます。

なので、image に使用するイメージは、docker コマンドとチェックアウトのための git コマンドがあるものが望ましいと考えられます。幸いなことに、公式の Docker イメージ に git 入りのイメージ(*-git でタグが付いてるイメージ)が存在するので、それを使うのが楽です。

特定のタグのみでビルドが実行されるようにするためには、CircleCI の Workflow の機能を使う必要があります。

circleci.com

上記の公式ドキュメントに書いてありますが、タグのみでビルドが実行されるようにするための条件は少し複雑です。CircleCI 2.0 はデフォルトですべてのブランチでビルドが実行され、タグでは実行されないようになっています。なので、上記の例のように、すべてのブランチを ignore して、ビルドされてほしいタグ名を正規表現で記述するという2つの設定が必要になります。

まとめ

CircleCI 2.0 で Docker イメージをビルドして Docker Hub に push する方法と、それを特定のタグでのみ実行されるようにする方法について記述しました。

もう少し実用化を考えるとイメージのキャッシュを行って高速化したいところですが、ちょっと複雑になりそうなのでまたいつか気が向いたら書くことにします。