如何从 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 的容器(例如 alpine
或 debian
)时,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)中删除文件而不在本地克隆它