カスタムビルドの Docker イメージの使用
このページでは、CircleCI でカスタム Docker イメージを作成および使用する方法について説明します。
概要
CircleCI は Docker をサポートしています。 Docker を使用すると、プロジェクトの依存関係を簡単に指定できます。 CircleCI イメージがお客様のニーズを満たさない場合は、お客様のジョブ用のカスタム Docker イメージを作成することができます。 カスタム Docker イメージの使用により、主に以下の 2 つのメリットがあります。
-
ジョブの迅速な実行 – 必要なツールが 1 つのカスタムイメージにパッケージ化されるため、ジョブごとにツールをインストールする必要がなくなります。
-
設定ファイルの簡潔化 – 長いインストールスクリプトをカスタムイメージに追加することにより、
config.yml
ファイルのコード行数を減らすことができます。
注: デフォルトでは、Docker イメージのビルド時にエントリポイントは維持されません。 詳細については、「 エントリポイントの追加」を参照してください。
カスタムイメージの手動作成
以下のセクションでは、カスタム イメージを手動で作成する方法について、手順を追って説明します。 プライマリ コンテナのカスタム イメージが作成されることが多いため、ここではその方法に焦点を当てます。 以下の内容を応用して、コンテナをサポートするためのイメージも作成できます。
前提条件
- Docker のインストールが完了し、動作していること。 詳細については、Docker の 入門ドキュメントを参照してください。
Dockerfile
の作成
カスタムイメージを作成するには、 Dockerfile
を作成する必要があります。 これは、Docker がイメージのアセンブルに使用するコマンドが格納されたテキストドキュメントです。 この Docker デモプロジェクトに示されているように、Dockerfile
はできるだけ .circleci/images
フォルダーに保存してください。
基本イメージの選択と設定
カスタムイメージを作成する前に、カスタムイメージの拡張元となる別のイメージを選択する必要があります。 Docker ハブ には、ほぼすべての一般的な言語とフレームワーク用に、正式なビルド済みイメージが用意されています。 特定の言語やフレームワークごとに、豊富なイメージバリアントから選択できます。 これらのバリアントは、 Docker タグで指定されます。
たとえば、 公式 Alpine イメージのバージョン 3.5 を使用したい場合、フルイメージ名は alpine:3.5
となります。
Dockerfile で、 FROM
コマンドを使ってベースイメージを拡張します。
FROM golang:1.8.0
追加ツールのインストール
追加ツールをインストールする、または他のコマンドを実行するには、 RUN
コマンドを使用します。
RUN apt-get update && apt-get install -y netcat
RUN go get github.com/jstemmer/go-junit-report
プライマリコンテナに必要なツール
CircleCI でカスタム Docker イメージをプライマリコンテナとして使用するには、以下のツールをインストールする必要があります。
- Bash(すでにインストールされているはずですが、パッケージマネージャ経由で入手可能です。 )
- git
- SSH
- tar
- gzip
- ca-certificates
これらのツールがインストールされていないと、一部の CircleCI サービスが動作しません。
注: パッケージ マネージャーと一緒にこれらのツールをインストールしない場合は、RUN
命令の代わりに ADD
命令を使用する必要があります (以下を参照)。
他のファイルとディレクトリの追加
パッケージ マネージャーに存在しないファイルとディレクトリを追加するには、 ADD
コマンドを使用します。
ADD ./workdir/contacts /usr/bin/contacts
ADD ./db/migrations /migrations
エントリポイントの追加
コンテナを実行可能ファイルとして実行するには、 ENTRYPOINT
コマンドを使用します。 デフォルトでは、ジョブのプライマリコンテナのエントリポイントは無視されます。 イメージがプライマリコンテナに使用されている場合でもエントリポイントを保持するには、以下のように LABEL
コマンドを使用します。
LABEL com.circleci.preserve-entrypoint=true
ENTRYPOINT contacts
注: エントリポイントコマンドは、失敗せずに最後まで実行される必要があります。 失敗した場合、またはビルドの途中で停止した場合は、ビルドも停止します。 ログまたはビルドステータスにアクセスする必要がある場合は、エントリポイントの代わりにバックグラウンドステップを使用します。
イメージのビルド
Dockerfile
で必要なツールをすべて指定したら、イメージをビルドできます。
$ docker build <path-to-dockerfile>
Dockerfile
で指定したすべてのコマンドがどのように実行されるか表示されます。 エラーが発生した場合は、画面に表示されます。 これらは作業を続行する前に修正する必要があります。 ビルドが正常に終了したら、最後に以下のようなメッセージが表示されます。
...
Successfully built e32703162dd4
docker build
コマンドの詳細については、 こちらを参照してください。
これで、最初のイメージがビルドされました! 次に、CircleCI で使用できるように、このイメージを保存する必要があります。
Docker レジストリへのイメージの保存
CircleCI でカスタムイメージを使用できるようにするには、イメージをパブリックの Docker レジストリ に保存する必要があります。 Docker ハブ では無料でパブリック イメージを無制限に保存できるため、 Docker ハブ にアカウントを作成する方法が最も簡単です。 既に Docker ハブ を使用している場合は、既存のアカウントを使用できます。
注: イメージを CircleCI Docker Executor で使用する場合は、パブリック リポジトリが必要です。 イメージをプライベートのままにする場合は、 認証済みの Docker プルを使用するで手順を参照してください。
この例では Docker ハブ を使用していますが、必要に応じて別のレジストリを使用することも可能です。 使用するレジストリに合わせて変更してください。
レジストリとイメージの準備
ご自身のアカウントで Docker ハブにログインし、 リポジトリ追加ページで新しいリポジトリを作成します。 リポジトリ名には、 <project-name>-<container-name>
のようなパターンを使用することをお勧めします(例: cci-demo-docker-primary
)。
次に、アカウントとリポジトリ名を使用してイメージをリビルドします。
$ docker build -t circleci/cci-demo-docker-primary:0.0.1 <path-to-dockerfile>
この t
キーは、新しいイメージの名前とタグを指定するキーです。
circleci
- Docker ハブでのアカウントcci-demo-docker-primary
- リポジトリ名0.0.1
- イメージのタグ (バージョン)。Dockerfile
の内容を変更した場合は、必ずタグを更新してください。 更新しないと予想外の結果を招く可能性があります。
レジストリへのイメージのプッシュ
イメージを Docker ハブにプッシュします。
$ docker login
$ docker push circleci/cci-demo-docker-primary:0.0.1
注: まず CircleCIでは、docker login
を使用して Docker ハブ での認証を実行しています。 Docker ハブ以外のレジストリを使用する場合は、関連ドキュメントを参照して、イメージをそのレジストリにプッシュする方法を確認してください。
CircleCI でのイメージの使用
イメージが正常にプッシュされたら、以下のように指定することで、イメージを .circleci/config.yml
で使用できます。
version: 2.0
jobs:
build:
docker:
- image: circleci/cci-demo-docker-primary:0.0.1
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # コンテキスト/プロジェクト UI 環境変数を参照
ご不明な点がありましたら、 コミュニティフォーラムにアクセスしてください。CircleCI または他のユーザーからのサポートを受けることができます。
Ruby 用のカスタム Dockerfile の例
このセクションでは、Ruby コンテナをビルドして CircleCI で使用する方法について説明します。 注: このセクションでは、Docker ログインをローカルで使用していることを前提としています。
以下の例では、最初に Ruby 2.1 イメージを使用しています。 ただし、ここでは FROM ruby:2.1 を基本イメージとして使用する方法ではなく、コンテナのビルド方法について説明します。 Ruby Docker ハブのページから、 2.1/Dockerfile に移動してください。 また、正しいバージョンをプルするために使用されている環境変数に注目してください。
FROM buildpack-deps:jessie
# gem ドキュメントのインストールをスキップします。
RUN mkdir -p /usr/local/etc \
&& { \
echo 'install: --no-document'; \
echo 'update: --no-document'; \
} >> /usr/local/etc/gemrc
ENV RUBY_MAJOR 2.1
ENV RUBY_VERSION 2.1.10
ENV RUBY_DOWNLOAD_SHA256 5be9f8d5d29d252cd7f969ab7550e31bbb001feb4a83532301c0dd3b5006e148
ENV RUBYGEMS_VERSION 2.6.10
# Ruby のビルド スクリプトは一部が Ruby で記述されています。
# 最終イメージではビルドしたものだけが使用されるように、後からシステムの Ruby を削除します。
RUN set -ex \
\
&& buildDeps=' \
bison \
libgdbm-dev \
ruby \
' \
&& apt-get update \
&& apt-get install -y --no-install-recommends $buildDeps \
&& rm -rf /var/lib/apt/lists/* \
\
&& wget -O ruby.tar.xz "https://cache.ruby-lang.org/pub/ruby/${RUBY_MAJOR%-rc}/ruby-$RUBY_VERSION.tar.xz" \
&& echo "$RUBY_DOWNLOAD_SHA256 *ruby.tar.xz" | sha256sum -c - \
\
&& mkdir -p /usr/src/ruby \
&& tar -xJf ruby.tar.xz -C /usr/src/ruby --strip-components=1 \
&& rm ruby.tar.xz \
\
&& cd /usr/src/ruby \
\
# 以下を非表示にするために "ENABLE_PATH_CHECK" を無効にします。
# warning: Insecure world writable dir
&& { \
echo '#define ENABLE_PATH_CHECK 0'; \
echo; \
cat file.c; \
} > file.c.new \
&& mv file.c.new file.c \
\
&& autoconf \
&& ./configure --disable-install-doc --enable-shared \
&& make -j"$(nproc)" \
&& make install \
\
&& apt-get purge -y --auto-remove $buildDeps \
&& cd / \
&& rm -r /usr/src/ruby \
\
&& gem update --system "$RUBYGEMS_VERSION"
ENV BUNDLER_VERSION 1.14.3
RUN gem install bundler --version "$BUNDLER_VERSION"
# グローバルにインストールします。
# すべてのアプリケーションで ".bundle" を作成しません。
ENV GEM_HOME /usr/local/bundle
ENV BUNDLE_PATH="$GEM_HOME" \
BUNDLE_BIN="$GEM_HOME/bin" \
BUNDLE_SILENCE_ROOT_WARNING=1 \
BUNDLE_APP_CONFIG="$GEM_HOME"
ENV PATH $BUNDLE_BIN:$PATH
RUN mkdir -p "$GEM_HOME" "$BUNDLE_BIN" \
&& chmod 777 "$GEM_HOME" "$BUNDLE_BIN"
CMD [ "irb" ]
これで Ruby 2.1 イメージが作成されます。 次に、node:7.4 Dockerfile を使用してノードモジュール、awscli
、および PostgreSQL 9.5 をインストールします。
FROM buildpack-deps:jessie
RUN groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node
# gpg keys listed at https://github.com/nodejs/node
RUN set -ex \
&& for key in \
9554F04D7259F04124DE6B476D5A82AC7E37093B \
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \
FD3A5288F042B6850C66B31F09FE44734EB7990E \
71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
B9AE9905FFD7803F25714661B63B535A4C206CA9 \
C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
; do \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
done
ENV NPM_CONFIG_LOGLEVEL info
ENV NODE_VERSION 7.4.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep "node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
CMD [ "node" ]
両方の Dockerfile で同じ基本イメージ buildpack-deps:jessie
が使用されます。 両方のイメージを結合し、Python をインストールして awscli
を入手できるという大きなメリットがあります。
関連ファイルを削除してから、Docker イメージをコミットし、apt
を使用してインストールします。 インストールしたファイルはすべて後から削除できますが、apt-get update
は 2 回以上実行しないでください。 カスタムリポジトリがある場合は、事前に追加されます。
Ruby イメージには Git がプリインストールされているので、再インストールする必要はありません。 最後に、sudo、python2.7、postgresql-9.5 をインストールリストに追加します。 次に、yarn と npm をインストールします。
FROM buildpack-deps:jessie
RUN groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node
# gpg keys listed at https://github.com/nodejs/node
RUN set -ex \
&& for key in \
9554F04D7259F04124DE6B476D5A82AC7E37093B \
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \
FD3A5288F042B6850C66B31F09FE44734EB7990E \
71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
B9AE9905FFD7803F25714661B63B535A4C206CA9 \
C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
; do \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
done
ENV NPM_CONFIG_LOGLEVEL info
ENV NODE_VERSION 7.4.0
ENV YARN_VERSION 0.18.1
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep "node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
# Postgres 9.5
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main" >> /etc/apt/sources.list \
&& wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 58118E89F3A912897C070ADBF76221572C52609D 514A2AD631A57A16DD0047EC749D6EEC0353B12C
# skip installing gem documentation
RUN mkdir -p /usr/local/etc \
&& { \
echo 'install: --no-document'; \
echo 'update: --no-document'; \
} >> /usr/local/etc/gemrc
ENV RUBY_MAJOR 2.1
ENV RUBY_VERSION 2.1.10
ENV RUBY_DOWNLOAD_SHA256 5be9f8d5d29d252cd7f969ab7550e31bbb001feb4a83532301c0dd3b5006e148
ENV RUBYGEMS_VERSION 2.6.10
# some of ruby's build scripts are written in ruby
# we purge system ruby later to make sure our final image uses what we just built
RUN set -ex \
\
&& buildDeps=' \
bison \
libgdbm-dev \
ruby \
' \
&& apt-get update \
&& apt-get install -y --no-install-recommends $buildDeps python2.7 sudo postgresql-9.5 \
&& rm -rf /var/lib/apt/lists/* \
\
&& wget -O ruby.tar.xz "https://cache.ruby-lang.org/pub/ruby/${RUBY_MAJOR%-rc}/ruby-$RUBY_VERSION.tar.xz" \
&& echo "$RUBY_DOWNLOAD_SHA256 *ruby.tar.xz" | sha256sum -c - \
\
&& mkdir -p /usr/src/ruby \
&& tar -xJf ruby.tar.xz -C /usr/src/ruby --strip-components=1 \
&& rm ruby.tar.xz \
\
&& cd /usr/src/ruby \
\
# hack in "ENABLE_PATH_CHECK" disabling to suppress:
# warning: Insecure world writable dir
&& { \
echo '#define ENABLE_PATH_CHECK 0'; \
echo; \
cat file.c; \
} > file.c.new \
&& mv file.c.new file.c \
\
&& autoconf \
&& ./configure --disable-install-doc --enable-shared \
&& make -j"$(nproc)" \
&& make install \
\
&& apt-get purge -y --auto-remove $buildDeps \
&& cd / \
&& rm -r /usr/src/ruby \
\
&& gem update --system "$RUBYGEMS_VERSION"
ENV BUNDLER_VERSION 1.14.3
RUN gem install bundler --version "$BUNDLER_VERSION"
RUN npm install -g yarn@0.18.1
ENV PATH "$PATH:/root/.yarn/bin/:/usr/local/bin"
# install things globally, for great justice
# and don't create ".bundle" in all our apps
ENV GEM_HOME /usr/local/bundle
ENV BUNDLE_PATH="$GEM_HOME" \
BUNDLE_BIN="$GEM_HOME/bin" \
BUNDLE_SILENCE_ROOT_WARNING=1 \
BUNDLE_APP_CONFIG="$GEM_HOME"
ENV PATH $BUNDLE_BIN:$PATH
RUN mkdir -p "$GEM_HOME" "$BUNDLE_BIN" \
&& chmod 777 "$GEM_HOME" "$BUNDLE_BIN"
CMD [ "irb" ]
これをビルドするには、以下のコマンドを実行します。
docker build -t ruby-node:0.1 .
コマンドの実行が完了すると、次のようなメッセージが表示されます。
Removing intermediate container e75339607356
Successfully built 52b773cf50e2
コンパイルが終了したら、Docker 出力から SHA を取り出し、以下のように実行します。
$ docker run -it 52b773cf50e2 /bin/bash
root@6cd398c7b61d:/# exit
次に、以下のように指定してそのホスト名をコミットし、ruby-node を Docker ハブ でのユーザー名に置き換えます。
docker commit 6cd398c7b61d username/ruby-node:0.1
docker push username/ruby-node:0.1
カスタムイメージを使用するには、.circleci/config.yml
イメージキーから ruby-node/bar:0.1 を参照します。 これで、プライマリコンテナによってイメージが実行されます。 Gist を使用して Dockerfile をコミットし、Docker ハブからリンクすると、設定が失われることを回避できます。
Docker イメージのキャッシュ
Docker イメージのキャッシュ方法については、 Docker イメージのキャッシュを確認してください。