首页 > 解决方案 > 如何从 Docker 容器克隆 Git 存储库

问题描述

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

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

我们有一个约束列表:

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

问题:如果可能的话,我们怎样才能做到这一点?

有关的:

标签: gitdockerssh-keys

解决方案


你可以使用类似的东西:

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(不存在于 中)的基于 linux 的容器(例如alpine或)时,命令可能会导致错误并显示如下消息:debian/etc/passwdgit 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(或可能在映像构建期间创建的另一个目录),我们确保我们有一个可写的 HOME 目录,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"


推荐阅读