DockerでDockerを実行しています(具体的には、Jenkinsを実行し、Docker Builderコンテナーを実行してプロジェクトイメージをビルドし、次にこれらを実行してからテストコンテナーを実行します)。
これは、jenkinsイメージが構築および開始される方法です。
docker build --tag bb/ci-jenkins .
mkdir $PWD/volumes/
docker run -d --network=Host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-v $PWD/volumes/jenkins_home:/var/jenkins_home \
--name ci-jenkins bb/ci-jenkins
Jenkinsは正常に動作します。しかし、これを実行するJenkinsfile
ベースのジョブがあります。
docker run -i --rm -v /var/jenkins_home/workspace/forkMV_jenkins-VOLTRON-3057-KQXKVJNXOU4DGSUG3P27IR3QEDHJ6K7HPDEZYN7W6HCOTCH3QO3Q:/tmp/build collab/collab-services-api-mvn-builder:2a074614 mvn -B -T 2C install
そして、これはエラーで終わります:
指定した目標を実行するにはプロジェクトが必要ですが、このディレクトリ(/ tmp/build)にPOMがありません。
私がする時 docker exec -it sh
コンテナに、/tmp/build
は空です。しかし、私がJenkinsコンテナにいるとき、パス/var/jenkins_home/...QO3Q/
が存在し、すべてのファイルがチェックアウトされて準備されたワークスペースが含まれています。
だから私は疑問に思います---Dockerはどのようにしてボリュームをうまくマウントし、それからそれは空になりますか?*
さらに紛らわしいのは、この設定はMacの同僚にとってはうまくいくということです。 Linux、Ubuntu 17.10、Docker最新を使用しています。
いくつかの調査、落ち着き、そして考えた後、Docker-in-Dockerは本当にそれほど「-in-」ではなく、むしろ「Docker-next-to-Docker」であることに気付きました。
コンテナが別のコンテナを実行できるようにする秘訣は、ボリュームを介して/var/run/docker.sock
を共有することです:-v /var/run/docker.sock:/var/run/docker.sock
そして、コンテナ内のdocker
クライアントは、実際にはホスト上のDockerを呼び出します。
ボリュームソースパス(:
の左側)は、中央のコンテナではなく、ホストファイルシステムを参照しています。
それを認識した後の修正は、Jenkins workspace
ディレクトリへのパスをホストファイルシステムとJenkins(中央)コンテナで同じにすることです。
docker run -d --network=Host \
...
-v /var/jenkins_home:/var/jenkins_home
そしてボイラ!できます。 (移動する代わりにシンボリックリンクを作成しましたが、機能しているようです。)
同僚のMacを見ると、Dockerの実装が少し異なるため、少し複雑です。AlpineLinuxベースのVMで実行されていますが、そうではないふりをしています。(100%ではありません)それについては確かです。)Windowsでは、パスに別の抽象化レイヤーがあることを読みました。C:/somewhere/...
からLinuxのようなパスへのマッピングです。
私は誰かが理解する時間を節約できることを願っています:)
KubernetesのJenkinsサーバーで実行されているDockerコンテナで実行されているビルドからボリュームをマウントするという同じ問題に直面していました。 docker-in-docker
、dind
を使用しているため、ここで提案した方法でボリュームをマウントできませんでした。理由はまだわかりませんが、別の方法を見つけました。docker cp
を使用してビルドアーティファクトをコピーします。
ユニット+統合テストに次のDockerfileステージを使用しています。
#
# Build stage to for building the Jar
#
FROM maven:3.2.5-jdk-8 as builder
MAINTAINER [email protected]
# Only copy the necessary to pull only the dependencies from registry
ADD ./pom.xml /opt/build/pom.xml
# As some entries in pom.xml refers to the settings, let's keep it same
ADD ./settings.xml /opt/build/settings.xml
WORKDIR /opt/build/
# Prepare by downloading dependencies
RUN mvn -s settings.xml -B -e -C -T 1C org.Apache.maven.plugins:maven-dependency-plugin:3.0.2:go-offline
# Run the full packaging after copying the source
ADD ./src /opt/build/src
RUN mvn -s settings.xml install -P embedded -Dmaven.test.skip=true -B -e -o -T 1C verify
# Building only this stage can be done with the --target builder switch
# 1. Build: docker build -t config-builder --target builder .
# When running this first stage image, just verify the unit tests
# Overriden them by removing the "!" for integration tests
# 2. docker run --rm -ti config-builder mvn -s settings.xml -Dtest="*IT,*IntegrationTest" test
CMD mvn -s settings.xml -Dtest="!*IT,!*IntegrationTest" -P jacoco test
docker cp
を使用して、名前付きコンテナーでテストを実行した後に開始できるテストDockerコンテナー内からビルドアーティファクトをコピーします。Post
ステージに運ぶこともできます。この時点で、docker run --name test:SHA
で問題を解決し、次にdocker start test:SHA
、次にdocker cp test:SHA:/path .
を使用します。ここで、.
は現在のワークスペースディレクトリであり、これは私たちと同じです。現在のディレクトリにマウントされたDockerボリュームが必要です。
stage('Build Test Image') {
steps {
script {
currentBuild.displayName = "Test Image"
currentBuild.description = "Building the docker image for running the test cases"
}
echo "Building docker image for tests from build stage ${env.GIT_COMMIT}"
sh "docker build -t tests:${env.GIT_COMMIT} -f ${paas.build.docker.dockerfile.runtime} --target builder ."
}
}
stage('Tests Execution') {
parallel {
stage('Execute Unit Tests') {
steps {
script {
currentBuild.displayName = "Unit Tests"
currentBuild.description = "Running the unit tests cases"
}
sh "docker run --name tests-${env.GIT_COMMIT} tests:${env.GIT_COMMIT}"
sh "docker start tests-${env.GIT_COMMIT}"
sh "docker cp tests-${env.GIT_COMMIT}:/opt/build/target ."
// https://jenkins.io/doc/book/pipeline/jenkinsfile/#advanced-scripted-pipeline#using-multiple-agents
stash includes: '**/target/*', name: 'build'
}
}
stage('Execute Integration Tests') {
when {
expression { paas.integrationEnabled == true }
}
steps {
script {
currentBuild.displayName = "Integration Tests"
currentBuild.description = "Running the Integration tests cases"
}
sh "docker run --rm tests:${env.GIT_COMMIT} mvn -s settings.xml -Dtest=\"*IT,*IntegrationTest\" -P jacoco test"
}
}
}
}
より良いアプローチは、 Jenkins Dockerプラグイン を使用して、すべてのマウントを実行させ、inside
関数の引数に-v /var/run/docker.sock:/var/run/docker.sock
を追加することです。
例えば。
docker.build("bb/ci-jenkins")
docker.image("bb/ci-jenkins").inside('-v /var/run/docker.sock:/var/run/docker.sock')
{
...
}