Docker中的Docker无法安装卷

Zep*_*LUS 49 linux containers jenkins docker

我正在运行一个Jenkins集群,在Master和Slave中,它们都作为Docker容器运行.

主机是在MacOS上运行的最新boot2docker VM.

为了让Jenkins能够使用Docker执行部署,我已将docker.sock和docker客户端从主机安装到Jenkins容器,如下所示: -

docker run -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):/usr/bin/docker -v $HOST_JENKINS_DATA_DIRECTORY/jenkins_data:/var/jenkins_home -v $HOST_SSH_KEYS_DIRECTORY/.ssh/:/var/jenkins_home/.ssh/ -p 8080:8080 jenkins
Run Code Online (Sandbox Code Playgroud)

将卷安装到在Jenkins容器内运行的Docker容器时,我遇到了问题.例如,如果我需要在Jenkins容器中运行另一个Container,我会执行以下操作: -

sudo docker run -v $JENKINS_CONTAINER/deploy.json:/root/deploy.json $CONTAINER_REPO/$CONTAINER_IMAGE 
Run Code Online (Sandbox Code Playgroud)

上面运行容器,但文件"deploy.json"不是作为文件挂载,而是作为"目录"挂载.即使我将目录作为卷安装,我也无法查看生成的容器中的文件.

这是一个问题,因为Docker在Docker案例中由于文件权限?

任何指针都会有用!

谢谢!

Zep*_*LUS 73

Docker容器中的Docker容器使用父HOST的Docker守护程序,因此,"docker-in-docker"情况下安装的任何卷仍然是从HOST引用的,而不是从Container引用的.

因此,从主机中的Jenkins容器安装的实际路径"不存在".因此,在"docker-in-docker"容器中创建一个新目录,该目录为空.当目录安装到Container内的新Docker容器时,同样适用.

我错过了非常基本和明显的事情,但很快我就输入了问题.

  • 那么解决方案是什么?因为docker文档引用了https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/,它说这样使用docker.但是这种方式无法将数据库从docker容器安装到另一个容器.数据量? (18认同)
  • 这篇文章并没有真正解决问题。它只是进一步解释了问题。 (9认同)
  • @ZephyrPLUSPLUS你可以发布你拥有的和你改变的内容,以便其他人可以从你的答案中受益吗? (3认同)
  • 很高兴知道你解决了这个问题,但实际的解决方案是什么.你是怎么装这个文件夹的? (2认同)
  • 我们还想知道@JulioGuerra致力于该博客文章中的推荐方法,该方法说“看起来像Docker-in-Docker [并且]感觉像Docker-in-Docker”,但是没有提及这一巨大警告! (2认同)

Rya*_*ugh 11

另一种方法是使用命名卷或数据卷容器.这样,内部容器不必知道有关主机的任何信息,Jenkins容器和构建容器都以相同的方式引用数据卷.

我尝试过类似于你正在做的事情,除了使用代理而不是使用Jenkins master.问题是相同的,因为我无法在内部容器中安装Jenkins工作区.对我有用的是使用数据卷容器方法,工作区文件对代理容器和内部容器都是可见的.我喜欢这种方法的是两个容器以相同的方式引用数据量.使用内部容器挂载目录会很棘手,因为内部容器现在需要了解其父容器正在运行的主机.

我在这里有关于我的方法的详细博客文章:

http://damnhandy.com/2016/03/06/creating-containerized-build-environments-with-the-jenkins-pipeline-plugin-and-docker-well-almost/

以及代码在这里:

https://github.com/damnhandy/jenkins-pipeline-docker

在我的具体情况下,并非所有内容都按照Jenkins Pipeline插件的方式运行.但它确实解决了内部容器能够访问Jenkins工作空间目录的问题.

  • 这很好,除了我需要一个运行docker-compose的解决方案.任何线索? (3认同)
  • 我不敢相信有人否决了这个答案。这太棒了,并且触及了问题的核心。这个解决方案感觉就像是因为它们存在的原因而使用了 docker 的功能。 (2认同)

mpe*_*rin 9

关于与Jenkins相关的用例,您可以通过在主机上创建符号链接来伪造路径:

ln -s $HOST_JENKINS_DATA_DIRECTORY/jenkins_data /var/jenkins_home
Run Code Online (Sandbox Code Playgroud)


Oli*_*ver 9

这些帖子中有很多很好的信息,但我发现没有一个人非常清楚他们指的是哪个容器。因此,让我们标记 3 个环境:

  • 主持人:H
  • 在 H:D 上运行的 docker 容器
  • 在 D 中运行的 docker 容器:D2

我们都知道如何将文件夹从 H 挂载到 D:以 D 开头

docker run ... -v <path-on-H>:<path-on-D> -v /var/run/docker.sock:/var/run/docker.sock ...
Run Code Online (Sandbox Code Playgroud)

挑战是:您希望path-on-H在 D2 中作为path-on-D2.

但是当我们尝试将相同的path-on-H东西安装到 D2时我们都被咬了,因为我们开始 D2

docker run ... -v <path-on-D>:<path-on-D2> ...
Run Code Online (Sandbox Code Playgroud)

当你与 D 共享 H 上的 docker 套接字时,那么在 D 中运行 docker 命令本质上是在 H 上运行它们。 事实上,如果你像这样启动 D2,一切正常(一开始很意外,但仔细想想是有道理的):

docker run ... -v <path-on-H>:<path-on-D2> ...
Run Code Online (Sandbox Code Playgroud)

下一个棘手的一点是,对于我们中的许多人来说,path-on-H将根据运行它的人而改变。有很多方法可以将数据传递给 D,因此它知道要用于什么path-on-H,但最简单的方法可能是环境变量。为了使这种 var 的目的更清楚,我以DIND_. 然后从H开始 D 像这样:

docker run ... -v <path-on-H>:<path-on-D> --env DIND_USER_HOME=$HOME \
    --env DIND_SOMETHING=blabla -v /var/run/docker.sock:/var/run/docker.sock ...
Run Code Online (Sandbox Code Playgroud)

D开始 D2 像这样:

docker run ... -v $DIND_USER_HOME:<path-on-D2> ...
Run Code Online (Sandbox Code Playgroud)


dam*_*j07 5

如果你像我一样,不想搞乱 Jenkins 设置,或者懒得去经历所有这些麻烦,这里有一个简单的解决方法,我可以让这个工作适合我。

步骤 1 - 将以下变量添加到管道的环境部分

environment {
    ABSOLUTE_WORKSPACE = "/home/ubuntu/volumes/jenkins-data/workspace" 
    JOB_WORKSPACE = "\${PWD##*/}"
}
Run Code Online (Sandbox Code Playgroud)

步骤 2 - 使用以下 Jenkins 管道命令运行容器,如下所示。

    steps {
        sh "docker run -v ${ABSOLUTE_WORKSPACE}/${JOB_WORKSPACE}/my/dir/to/mount:/targetPath imageName:tag"
    }
Run Code Online (Sandbox Code Playgroud)

请注意上述语句中的双引号,如果引号格式不正确或添加了单引号,Jenkins 将不会转换环境变量。


每个变量代表什么意思?

  • ABSOLUTE_WORKSPACE 是我们在启动 Jenkins Docker 容器时安装的 Jenkins 卷的路径。就我而言,docker run 命令如下。

    sudo docker run \ -p 80:8080 \ -v /home/ubuntu/volumes/jenkins-data:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ -d -t jenkinsci/blueocean

因此变量 ABSOLUTE_WORKSPACE=/home/ubuntu/volumes/jenkins-data + /workspace

  • JOB_WORKSPACE 命令为我们提供了代码所在的当前工作空间目录。这也是代码库的根目录。只是按照这个答案作为参考。

这是如何运作的 ?

这非常简单,正如@ZephyrPLUSPLUS(鸣谢)答案中提到的,在 Jenkins 管道中运行的 docker 容器的源路径不是当前容器中的路径,而是采用的路径是主机的路径。我们在这里所做的就是构建 Jenkins 管道运行的路径。并将其安装到我们的容器上。瞧!

这里有一个小插图可以帮助澄清...... 在此输入图像描述