Docker コマンドの実行手順
他の場所にデプロイしたり、高度なテストを行ったりするための Docker イメージのビルド方法や、リモート Docker 環境でサービスを開始する方法について説明します。
概要
デプロイする Docker イメージを作成するには、セキュリティのために各ビルドに独立した環境を作成する特別な setup_remote_docker
キーを使用する必要があります。 この環境はリモートで、完全に隔離され、Docker コマンドを実行するように構成されています。 ジョブで docker
または docker-compose
のコマンドが必要な場合は、.circleci/config.yml
に setup_remote_docker
ステップを追加します。
jobs:
build:
steps:
# ... アプリのビルド・テストに関する記述 ...
- setup_remote_docker
setup_remote_docker
が実行されるとリモート環境が作成され、現在のプライマリ コンテナは、それを使用するように構成されます。 これで、使用するすべての Docker 関連コマンドが、この新しい環境で安全に実行されます。
メモ: setup_remote_docker
キーは、プライマリ Executor を Docker コンテナとするよう指定した設定ファイルで使用することが想定されています。 Executor が machine
または macos
の場合 (および設定ファイルで Docker コマンドを使用する場合)、setup_remote_docker
キーを使用する必要はありません。
仕様
リモート Docker 環境の技術仕様は以下のとおりです (CircleCI Server をお使いの場合は、システム管理者にお問い合わせください)。
CPU 数 | プロセッサー | RAM | HD |
---|---|---|---|
2 | Intel(R) Xeon(R) @ 2.3GHz | 8 GB | 100GB |
例
以下の例では、デフォルトのイメージの machine
Executor を使用して Docker イメージを構築しています。この場合はリモート Docker を使用する必要がありません。
version: 2
jobs:
build:
machine: true
steps:
- checkout
# UI に格納された認証情報とプライベート Docker イメージを
# 使用して、固有 DB を開始します
- run: |
echo "$DOCKER_PASS" | docker login --username $DOCKER_USER --password-stdin
docker run -d --name db company/proprietary-db:1.2.3
# アプリケーション イメージをビルドします
- run: docker build -t company/app:$CIRCLE_BRANCH .
# イメージをデプロイします
- run: docker push company/app:$CIRCLE_BRANCH
以下に、リモート Docker で Docker Executor を使用して Docker デモ プロジェクト用の Docker イメージをビルドし、デプロイする例を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: 2.1 jobs: build: docker:
- image: circleci/golang:1.13-alpine
steps:
- checkout
# ... アプリのビルド・テストに関する記述 ...
- setup_remote_docker:
docker_layer_caching: true
# Docker イメージをビルドしプッシュします
- run: |
TAG=0.1.$CIRCLE_BUILD_NUM
docker build -t CircleCI-Public/circleci-demo-docker:$TAG .
echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
docker push CircleCI-Public/circleci-demo-docker:$TAG
使用するプライマリ コンテナに Docker CLI をまだインストールしていない場合はインストールする必要があります。
# Alpine ベースのイメージに APK でインストールします
- run:
name: Docker クライアントのインストール
command: apk add docker-cli
ビルド中に何が行われているのか詳しく見てみましょう。
- すべてのコマンドがプライマリ コンテナで実行されます。 (5 行目)
-
setup_remote_docker
が呼び出されると、新しいリモート環境が作成され、それを使用するようにプライマリ コンテナが構成されます。 Docker 関連のコマンドもすべてプライマリ コンテナで実行されますが、イメージのビルドおよびプッシュとコンテナの実行はリモート Docker Engine で行われます。 (10 行目) - ここで Docker レイヤー キャッシュ (DLC) を有効化して、イメージのビルドを高速化します (メモ:
docker_layer_caching: true
オプションは、Performance プランと Custom プランで提供され、Free プランでは提供されません。 また、DLC は CircleCI Server で利用できます)。 (11 行目) - プロジェクト環境変数を使用して、Docker Hub の認証情報を格納します。 (17 行目)
Docker のバージョン
ジョブで特定の Docker バージョンが必要な場合は、version
属性でバージョンを設定できます。
- setup_remote_docker:
version: 18.06.0-ce
CircleCI は複数の Docker バージョンをサポートしており、デフォルトでは 17.09.0-ce
が使用されます。 以下に、サポートされている安定版とエッジ版を示します。
17.03.0-ce
17.05.0-ce
17.06.0-ce
17.06.1-ce
17.07.0-ce
17.09.0-ce
17.10.0-ce
17.11.0-ce
17.12.0-ce
17.12.1-ce
18.01.0-ce
18.02.0-ce
18.03.0-ce
18.03.1-ce
18.04.0-ce
18.05.0-ce
18.06.0-ce
18.09.3
メモ: version
キーは、現在 CircleCI Server 環境ではサポートされていません。 お使いのリモート Docker 環境にインストールされている Docker バージョンについては、システム管理者にお問い合わせください。
環境の分離
ジョブとリモート Docker は、独立した環境で実行されます。 したがって、ジョブ実行用に指定している Docker コンテナは、リモート Docker で実行されているコンテナと直接やり取りできません。
サービスへのアクセス
リモート Docker でサービスを開始してプライマリ コンテナから直接 ping することや、リモート Docker 内のサービスに ping できるプライマリ コンテナを開始することはできません。 これを解決するには、リモート Docker から同じコンテナを通してサービスとやり取りする必要があります。
#...
- run:
name: "サービスの開始および実行チェック"
command: |
docker run -d --name my-app my-app
docker exec my-app curl --retry 10 --retry-connrefused http://localhost:8080
#...
同じネットワーク内で動作する別のコンテナをターゲット コンテナとして使用する方法もあります
#...
- run: |
docker run -d --name my-app my-app
docker run --network container:my-app appropriate/curl --retry 10 --retry-connrefused http://localhost:8080
#...
フォルダーのマウント
ジョブ空間からリモート Docker 内のコンテナにボリュームをマウントすること (およびその逆) はできません。 docker cp
コマンドを使用して、この 2 つの環境間でファイルを転送することは可能です。 たとえば以下のように、ソース コードから設定ファイルを使用してリモート Docker でコンテナを開始します。
- run: |
# 設定ファイルとボリュームを保持するダミー コンテナを作成します
docker create -v /cfg --name configs alpine:3.4 /bin/true
# このボリュームに設定ファイルをコピーします
docker cp path/in/your/source/code/app_config.yml configs:/cfg
# このボリュームを使用してアプリケーション コンテナを開始します
docker run --volumes-from configs app-image:1.2.3
同様に、保存する必要があるアーティファクトをアプリケーションが生成する場合は、以下のようにリモート Docker からコピーできます。
- run: |
# アプリケーションとコンテナを開始します
# `--rm` オプションは使用しません (使用すると、終了時にコンテナが強制終了されます)
docker run --name app app-image:1.2.3
- run: |
# アプリケーション コンテナの終了後、そこからアーティファクトを直接コピーします
docker cp app:/output /path/in/your/job/space
以下の circle-dockup.yml
設定ファイルの例に示すように、https://github.com/outstand/docker-dockup などのバックアップ・復元用イメージを使用してコンテナをスピンアップすることもできます。
version: '2'
services:
bundler-cache:
image: outstand/dockup:latest
command: restore
container_name: bundler-cache
tty: true
environment:
COMPRESS: 'false'
volumes:
- bundler-data:/source/bundler-data
次に、以下の CircleCI .circleci/config.yml
スニペットで bundler-cache
コンテナにデータを挿入し、バックアップを行います。
# CircleCI キャッシュから bundler-data コンテナにデータを挿入します
- restore_cache:
keys:
- v4-bundler-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
- v4-bundler-cache-{{ arch }}-{{ .Branch }}
- v4-bundler-cache-{{ arch }}
- run:
name: Docker ボリュームへの Bundler キャッシュの復元
command: |
NAME=bundler-cache
CACHE_PATH=~/bundler-cache
set -x
mkdir -p $CACHE_PATH
docker-compose -f docker-compose.yml -f docker/circle-dockup.yml up --no-start $NAME
docker cp $CACHE_PATH/. $NAME:/backup
docker-compose -f docker-compose.yml -f docker/circle-dockup.yml up --no-recreate $NAME
docker rm -f $NAME
# 同じボリュームを CircleCI キャッシュにバックアップします
- run:
name: Docker ボリュームからの Bundler キャッシュのバックアップ
command: |
NAME=bundler-cache
CACHE_PATH=~/bundler-cache
set -x
docker-compose -f docker-compose.yml -f docker/circle-dockup.yml run --name $NAME $NAME backup
docker cp $NAME:/backup/. $CACHE_PATH
docker rm -f $NAME
- save_cache:
key: v4-bundler-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
paths:
- ~/bundler-cache
リモート Docker 環境へのアクセス
リモート Docker 環境が起動されると、SSH エイリアスが作成され、リモート Docker 仮想マシンに対して SSH 接続できます。 SSH 接続は、ビルドをデバッグする場合や、Docker または VM ファイルシステムの構成を変更する場合に便利です。 リモート Docker 仮想マシンに SSH 接続するには、プロジェクトを構成するジョブ ステップ内で、または SSH 再実行中に、以下を実行します。
ssh remote-docker
メモ: 上記の例は、docker
Executor で動作しないボリューム マウントを使用する方法を示しています。 この他に、ボリューム マウントが動作する machine
Executor を使用する方法もあります。
この例は、ryansch のご協力によって作成されました。