如何从 Docker 容器克隆 Git 存储库

Posted

技术标签:

【中文标题】如何从 Docker 容器克隆 Git 存储库【英文标题】:How to clone a Git repository from a Docker container 【发布时间】:2019-10-22 18:57:30 【问题描述】:

我们有一个工具需要克隆多个 Git 存储库来聚合文档数据。我们希望将该工具放入 Docker 容器中,以便在本地和使用 Jenkins 轻松运行它,并实现可重复性。

Git 存储库托管在需要使用 SSH 密钥进行身份验证的私有服务器上。因此,Docker 容器必须以某种方式访问​​运行容器的用户的 SSH 密钥。

我们有一个约束列表:

    我们确实想在 Docker 映像中嵌入 SSH 密钥 我们确实希望用户构建 Docker 映像。我们认为Dockerfile 不能实现可重复性,而已经生成的 Docker 映像则可以 我们确实希望容器以root 用户身份运行 我们想要使用运行容器的主机用户的 SSH 密钥 可以为启动容器的命令提供参数(-v-u、...)

问题:如果可能,我们如何实现这一目标?

相关:

Using SSH keys inside docker container(SSH 密钥在构建时传递 - 我们想要运行时) Clone private git repo with dockerfile(同样的问题) Inject host's SSH keys into Docker Machine with Docker Compose(以root 运行)

【问题讨论】:

我很好奇你为什么认为 Dockerfile 不能实现可重复性。 抛开 Dockerfile 问题不谈,我原以为您可以简单地将本地用户的 /home/user/.ssh 文件夹(只读)挂载到容器中。然后做一个git clone git@your.git/repo 应该使用他们的ssh 密钥。 @SiHa 参见例如this 或 this。 Docker 映像是一个自给自足且自包含的快照 - Dockerfile 是依赖于可以更改的依赖项(其他映像、主机等)的指令列表。至于您的建议:由于所有权不同,容器的用户无法读取主机用户的密钥。 没有理由不能更改用户的成员资格,我想。 也许给主机和docker用户一个特定的组,并给这个组读取ssh密钥的权限? 【参考方案1】:

你可以使用类似的东西:

echo "git-user:x:$(id -u):$(id -g):Git User:/tmp:/bin/bash" > /tmp/fake_passwd # See below why to use this
docker run \
   -u $(id -u):$(id -g) \
   -w /tmp \
   -v $HOME/.ssh:/path/to/.ssh \
   -v /tmp/fake_passwd:/etc/passwd  \
   --entrypoint sh \
   -it \
   alpine/git

  # commands in the container:
  $ export GIT_SSH_COMMAND='ssh -i /path/to/.ssh/id_rsa -o "StrictHostKeyChecking=no"'
  $ git clone [path to git repo]

这将确保容器以与主机用户相同的 UID/GID 运行,从而能够在不更改其权限或使用 root 权限的情况下读取密钥。详情:

-u $(id -u):$(id -g)设置容器用户匹配宿主用户 -w /tmp 确保我们在一个可以写入的目录中工作(我们也可以挂载一个我们具有读/写权限的卷或使用该目录构建映像) -v $HOME/.ssh:/path/to/.ssh 从主机挂载本地用户 SSH 密钥 --entrypoint sh-it 特定于 alpine/git 以进行交互式 shell 会话,您的图像可能不需要它

为什么要挂载一个伪造的/etc/passwd 文件?

当您运行具有未知 UID/GID(/etc/passwd 中不存在的 UID/GID)的基于 linux 的容器(例如 alpinedebian)时,git clone 命令可能会导致错误消息如:

Cloning into 'myrepo'...
No user exists for uid 1000
fatal: Could not read from remote repository.

通过挂载这个“假”密码文件,我们确保操作系统能够识别运行容器的用户并允许我们的 git clone 命令工作。我们的密码文件如下所示:

git-user:x:1000:1000:Git User:/tmp:/bin/bash

大致意思是:

git-user 存在 UID 1000 和 GID 1000 它的 HOME 目录是 /tmp(它是可选的,但是这个目录是可写的并且避免来自 git clone 的一些警告)

通过设置/tmp(或可能在映像构建期间创建的另一个目录),我们确保我们有一个git-user 的可写主目录,这将防止来自git clone 的警告说它无法创建.ssh目录

但是,如果您打算使用容器运行不同的任务,这可能会产生其他副作用。

为什么要使用GIT_SSH_COMMAND

GIT_SSH_COMMAND='ssh -i /path/to/.ssh/id_rsa' 将确保 git clone 正在使用我们的密钥,但这也可以使用 ssh-agent 来完成 - 请参阅 https://serverfault.com/questions/447028/non-interactive-git-clone-ssh-fingerprint-prompt

在示例中我使用-o "StrictHostKeyChecking=no" 但它可能不安全,另一种解决方案是使用 git repo 服务器主机密钥并使用 -o "UserKnownHostsFile=/path/to/KnownHostFile" 在容器中挂载已知主机文件/p>

【讨论】:

这确实有效,尽管即使known_hosts 文件被UserKnownHostsFile 引用,克隆也会发送垃圾邮件Could not create directory '/.ssh'。不幸的是,所有这一切都感觉像是一种黑客攻击——但在这一点上,我希望所有的解决方案都能解决,尤其是像this 这样的问题。不过,我很想看到其他解决方案。 我明白,假的passwd 文件确实有点像黑客(我第一次尝试不使用它,但由于我提到的问题而不得不这样做),但对于其余部分,我相信这是一个使用 git 和 ssh 的完美方式。 could not create directory 的垃圾邮件似乎是 SSH 客户端的错误 - 也许可以通过将用户的主目录设置为可写目录来解决 我不确定如何做到这一点,因为在运行时设置用户的主目录需要 root 权限,包括 self.并且在构建时用户还不知道,因此无法创建其主页。 您可以通过在伪造的passwd 文件中将可写目录设置为主目录来执行此操作,例如:git-user:x:1000:1000:Git User:/tmp:/bin/bash/tmp 作为git-user 的主目录(您也可以创建构建期间映像中的目录并使用它)。 git clone 不会再抱怨了(似乎 .ssh/known_hosts 文件是在 set home dir 中创建的),我编辑了答案以提及这一点 相关:running git or ssh client in docker as user: No user exists for uid 和 docker: set running user while launch container。【参考方案2】:

在主机上克隆存储库并在 docker 映像中挂载目录可以吗?

例如:

git clone github:repo1
git clone github:repo2
  ...

docker run -v repo1:/path/to/repo1 -v repo2:/path/to/repo2 ...

【讨论】:

例如,它不适用于缺少 Git 的客户端。这就是为什么我们要“dockerizing”我们的工具,以实现可重复性。

以上是关于如何从 Docker 容器克隆 Git 存储库的主要内容,如果未能解决你的问题,请参考以下文章

Git - 如何从存储库(devops)中删除文件而不在本地克隆它

如何从服务器端口 9418 克隆存储库?

如何在 Jenkins 中通过 *** 拉取/克隆 git 存储库?

从 Dockerfile 克隆私有 git 存储库

如何使用私钥克隆 GIT 存储库

无法从 linode 服务器克隆托管的 git 存储库