はじめに
Docker コンテナを作成している中、エンバグしても気が付かなかったことがあったため、
docker-compose を使って Docker コンテナの build と実行を行うインテグレーションテスト(e2e.sh)を作成しました。
(インテグレーションテストのソースコードはこちらにあります)
今回、その作成したインテグレーションテストを CI 環境に乗せるべく Wercker と CircleCI を使ってみることにしました。
結果的に Wercker は internal/docker-build により起動したコンテナから外部ネットワークの名前解決が出来ないため構築することはできず、CircleCI では構築することが出来そうだと分かりました。
Wercker で試してダメだった点も記載しますので、これからインテグレーションテストを作成しようとしている/した方への何か参考になれば幸いです。
Wercker とは
Wercker とは CI を実現するための SaaS です。
Wercker アカウントを作成した後、Web 画面の指示に従って設定を行えば簡単に CI 環境が構築できます。
詳細な設定を行いたい場合は、基本的にはwercker の公式ドキュメントを参考にすることになります。
Wercker クイックスタート
wercker を使い始める概要は次のとおり。
- Wercker アカウントを登録する (GitHub OAuth あり)
- Wercker に対象アプリケーション設定を登録する
- GitHub のアプリケーション設定に WebHook の設定が追加される
- そのため、リポジトリに対して WebHook 設定を追加できる権限が必要
- リポジトリルートに wercker.yml を用意して pipeline の
build
を定義する - リポジトリに push する
すると wercker.yml に記載された内容でビルド処理が行われる。
- wercker.yml は 1 から作成しても Wercker の Web ウィザードに従って作成したものをコピペしてもどちらでもよい
- 独自の pipeline を定義して実行したい場合は wercker.yml に定義を記載し、Wercker の Workflows > Editor から設定する
- Wercker の internal/docker-build は EC2 container 内部は外部の名前解決が出来ない
Wercker のビルド制限について
'18/06/28 現在未確認。(ビルド回数等の制限はない?)
ビルドステップで Docker container を使う
Wercker のビルドステップ自体も Docker container で行われます。
メインとなるステップで使うコンテナイメージは wercker.yml の box オプションで指定されます。(個人リポジトリ指定も可能)
※ wercker-labs/docker イメージは '18/06/28 現在、Docker Hub に存在しません。詳細はこちら。
ここでは、メインステップの中でコンテナを使う方法について簡単に説明します。
ステップの中で常に動作させたいのか、単発で実行させたいのかによって、次の2種類の方法があります。
どちらの方法で起動したコンテナも、メインステップのコンテナ及び internal/docker-run で実行したコンテナにアクセスできる。(未確認だがそのような記載がある)
- service
- ビルドステップが開始されるタイミングでコンテナを起動させ、常に起動したままにしてビルドステップが終了するタイミングで終了させたい場合に使う
- 用途例としてはアプリケーションが DB を使う場合の DB を起動する場合
- internal/docker-run
- ビルドステップ内で、一度実行したい場合に使う
- 用途例としては Docker container を開発していて起動テストをする場合
- internal/docker-build
- ビルドステップ内で、イメージをビルドする場合に使う
- 用途例としては Docker container を開発していてビルドを行う場合
- '18/07/01 現在、container 内から外部ネットワークの名前解決が出来ない(詳細は本記事内のこちらを参照)。そのため、wercker を使って Docker compose を使ったテストを使うことは諦めた。
Wercker にて docker-compose を使ったインテグレーションテスト e2e.sh を実行する設定(動作せず)
'18/07/01 現在、container 内から外部ネットワークの名前解決が出来ないため、結果的に動作しない設定です。internal/docker-build, internal/docker-run を使った設定ファイルの内容をぼんやりイメージするために利用してください。
box: debian:jessie
# build mongodb-awesome-backup
build: &build_pipeline
steps:
- internal/docker-build:
dockerfile: Dockerfile
image-name: mongodb-awesome-backup
# test mongodb-awesome-backup
test: &test_pipeline
steps:
- internal/docker-build:
dockerfile: test/Dockerfile.e2e
image-name: mongodb-awesome-backup-e2e-test
- internal/docker-run:
image: mongodb-awesome-backup-e2e-test
name: mongodb-awesome-backup-e2e-test
# --- For wercker.yml developer
# build and test mongodb-awesome-backup by wercker CLI
dev:
<<: [ *build_pipeline, *test_pipeline ]
CircleCI とは
CircleCI とは CI を実現するための SaaS です。Wercker と同様のサービスです。
CircleCI アカウントを作成した後、Web 画面の指示に従って設定を行えば簡単に CI 環境が構築できます。
詳細な設定を行いたい場合は、基本的にはCircleCI の公式ドキュメントを参考にすることになります。
結果的に、CircleCI の方ではインテグレーションテストを実行することが出来ました。
CircleCI のビルド制限
Free プランの場合は次の制約がある。
詳細や有料プランについては https://circleci.com/pricing/ を参照のこと。
- repos数 無制限
- users数 無制限
- 1,500 build minutes per month
- 1 container
- 1 concurrent job
- community support
CircleCI クイックスタート
基本的には Circle CI のウィザードに従えばよい。
- CircleCI アカウントを登録する (GitHub OAuth あり)
- CircleCI に対象アプリケーション設定を登録する
- GitHub のアプリケーション設定に WebHook の設定が追加される
- そのため、リポジトリに対して WebHook 設定を追加できる権限が必要
- リポジトリルートに ./circleci/config.yml を用意して build を設定する
- リポジトリに push する
ビルドステップで Docker container を使う
CircleCI のビルドステップ自体も Docker container で行われます。
docker/docker-compose コマンドを使うためには、それぞれインストールを行い、- setup_remote_docker
step を追加します。
下記、設定の参考です。
version: 2
jobs:
build:
docker:
- image: ubuntu:xenial
environment:
DOCKER_VER: 17.03.0-ce
DOCKER_COMPOSE_VER: 1.11.2
steps:
- checkout
# Install some packages
- run:
name: Install packages
command: |
apt-get update
apt-get install -y curl
# Install docker client
# ref. https://github.com/CircleCI-Public/circleci-demo-docker/blob/docker-compose/.circleci/config.yml
- run:
name: Install Docker client
command: |
set -x
curl -L -o /tmp/docker-${DOCKER_VER}.tgz https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VER}.tgz
tar -xz -C /tmp -f /tmp/docker-${DOCKER_VER}.tgz
mv /tmp/docker/* /usr/bin
# Install docker-compose
# ref. https://github.com/CircleCI-Public/circleci-demo-docker/blob/docker-compose/.circleci/config.yml
- run:
name: Install Docker Compose
command: |
set -x
curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VER}/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
# It is needed to activate the remote docker environment
# see. https://circleci.com/docs/2.0/docker-compose/
- setup_remote_docker
# Build and run integration test
- run:
name: Run integration tests
command: |
test/e2e.sh
その他
wercker-labs/docker イメージは '18/06/28 現在、Docker Hub に存在しない
wercker のビルドステップ内で Docker container を起動する方法を探すと、いつかの記事で wercker-labs/docker
イメージを使った例が紹介がされていますが、'18/06/28 現在 image は リポジトリ内に存在しませんでした。('14 - '15 辺りでは利用できたのでしょう)
Running wercker version: 1.0.1271 (Compiled at: 2018-06-25T20:30:14Z, Git commit: c09a42cc4d0da2eab5d045a06c73d20609ca8c98)
Using config:
box: wercker-labs/docker
build:
steps:
- script:
name: docker version
code: docker version
- script:
name: docker ps
code: docker ps -a
- script:
name: uname
code: uname -a
Pulling repository docker.io/wercker-labs/docker
Error: image wercker-labs/docker:latest not found
internal/docker-build で起動した Docker コンテナは外部の名前解決が出来ない
結論として、'18/07/01 現在解決方法は見つかってません。
発覚したきっかけは Alpine で作成していた Dockerfile で apk add
コマンドが実行できなかったこと。
temporary error と書かれていたため何度か実行してみたが必ず失敗した。
: <snip>
RUN apk add --no-cache coreutils bash tzdata py2-pip mongodb-tools
---> Running in fd671d634a35
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz: temporary error (try again later)
WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz: temporary error (try again later)
: <snip>
そこで、名前と IP アドレス双方に対して ping を打ってみたところ、名前は bad address 'dl-cdn.alpinelinux.org'
となり、IP アドレスは ping が通じたことから、名前解決が出来ていない様子だった。
resolv.conf の設定を見るに、Amazon EC2 を使っている様子。
EC2 search に書かれていた名前から調べてみると内部のみの名前解決しかできないとの説明文を発見した。
(https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-instance-addressing.html)
: <snip>
Step 3 : RUN ping -c 5 dl-cdn.alpinelinux.org || true
---> Running in af467fb100d3
ping: bad address 'dl-cdn.alpinelinux.org'
---> d8e7416565b0
Removing intermediate container af467fb100d3
Step 4 : RUN ping -c 5 151.101.72.249 || true
---> Running in f110121c573f
PING 151.101.72.249 (151.101.72.249): 56 data bytes
64 bytes from 151.101.72.249: seq=0 ttl=37 time=180.290 ms
64 bytes from 151.101.72.249: seq=1 ttl=37 time=179.775 ms
64 bytes from 151.101.72.249: seq=2 ttl=37 time=179.742 ms
64 bytes from 151.101.72.249: seq=3 ttl=37 time=179.736 ms
64 bytes from 151.101.72.249: seq=4 ttl=37 time=179.813 ms
--- 151.101.72.249 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 179.736/179.871/180.290 ms
---> 3632b71d66a3
Removing intermediate container f110121c573f
Step 5 : RUN cat /etc/resolv.conf || true
---> Running in 9414407c1ae8
# This file is managed by systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known DNS servers.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 10.0.0.2
search ec2.internal
---> 8459f7337687
Removing intermediate container 9414407c1ae8
Step 6 : RUN cat /etc/hosts || true
---> Running in 7344c4a3665e
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.100.2 efd5d06095fb
---> 22037b37d78c
Removing intermediate container 7344c4a3665e
Step 7 : RUN apk add --no-cache coreutils bash tzdata py2-pip mongodb-tools
---> Running in e52cebc6e900
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz: temporary error (try again later)
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz: temporary error (try again later)
ERROR: unsatisfiable constraints:
: <snip>
internal/docker-build のソースコードを読んでみて、extra_hosts を使って解決が出来そうだが、実際に追加してみても /etc/hosts にホストが追加されなかった。
Docker API を見てみると docker build 時に extrahosts が設定できるようになったのは v1.28 からでだが、Wercker 実行環境の Docker Deamon のバージョンが古いのか?
(ref. https://docs.docker.com/engine/api/v1.28/#operation/ImageBuild)
- internal/docker-build ステップでは NewDockerBuildStep が実行されている
- dockerOption に Docker build 時のオプションを設定している
- Docker build 時のオプションは次の項目がある
-
Dockerfile
,Tags
,BuildArgs
,SuppressOutput
,Remove
,ForceRemove
,Labels
,ExtraHosts
,Squash
,PullParent
,NoCache
- https://github.com/wercker/wercker/blob/65ae606c9b5a9fe95085d580356ceae58e17224e/docker/docker_build.go#L228-L240
-