使用dockerfile克隆私人git repo


240

我已经从似乎各种各样的工作dockerfile中复制了此代码,这是我的:

FROM ubuntu

MAINTAINER Luke Crooks "luke@pumalo.org"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git python-virtualenv

# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN chown -R root:root /root/.ssh

# Create known_hosts
RUN touch /root/.ssh/known_hosts

# Remove host checking
RUN echo "Host bitbucket.org\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config

# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:Pumalo/docker-conf.git /home/docker-conf

这给我错误

Step 10 : RUN git clone git@bitbucket.org:Pumalo/docker-conf.git /home/docker-conf
 ---> Running in 0d244d812a54
Cloning into '/home/docker-conf'...
Warning: Permanently added 'bitbucket.org,131.103.20.167' (RSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
2014/04/30 16:07:28 The command [/bin/sh -c git clone git@bitbucket.org:Pumalo/docker-conf.git /home/docker-conf] returned a non-zero code: 128

这是我第一次使用dockerfiles,但是从我阅读的内容(以及从有效的配置中获取的内容)中我看不到为什么这不起作用。

我的id_rsa与我的dockerfile位于同一文件夹中,并且是我的本地密钥的副本,可以克隆此存储库。

编辑:

在我的dockerfile中,我可以添加:

RUN cat /root/.ssh/id_rsa

而且它会打印出正确的密钥,因此我知道它已正确复制。

我也尝试按照诺亚的建议去做:

RUN echo "Host bitbucket.org\n\tIdentityFile /root/.ssh/id_rsa\n\tStrictHostKeyChecking no" >> /etc/ssh/ssh_config

可悲的是这也行不通。

Answers:


300

我的密钥受到密码保护,这是导致问题的原因,下面列出了一个工作文件(以帮助将来的Google员工)

FROM ubuntu

MAINTAINER Luke Crooks "luke@pumalo.org"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git
# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
ADD id_rsa /root/.ssh/id_rsa

# Create known_hosts
RUN touch /root/.ssh/known_hosts
# Add bitbuckets key
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:User/repo.git

11
为了以防万一,这里有个链接描述了如何删除密钥的密码保护
Thomas Thomas

82
仅供参考,在运行RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts之后,映像会将其保存为图层。如果有人拥有您的图像,他们可以检索密钥...即使您在以后的层中删除该文件,b / c他们也可以在添加文件时返回到步骤7。
伯尼·佩雷斯2015年

23
感谢您的帮助。但是对于我们来说,构建是随机失败的,经过调查,我们注意到ssh-keyscan默认的超时时间为5秒,而这通常会超过位桶。ssh-keyscan甚至不会报告错误。因此,最好运行RUN ssh-keyscan -T 60 bitbucket.org >> /root/.ssh/known_hosts以确保安全。
fluidsonic

5
有人可以解释为什么跑步ssh-keyscan是一个问题吗?我的理解是,它只会拉出Github / Bitbucket的公钥。可以使用哪种替代方法,以使它不会出现在一层中?
佩德罗(Pedro)

9
@Pedro特别是keyscan步骤根本不是问题,您显然是正确的。如果有的话,这些主机公钥应尽可能多地散布。有关该known_hosts文件的详细信息,请参见sshd(8)。当人们听起来足够令人震惊时,他们只会对随机的事物进行投票。
TNE

99

您应该为该Docker映像创建新的SSH密钥集,因为您可能不想在其中嵌入自己的私钥。为了使其工作,您必须将该密钥添加到git存储库中的部署密钥中。这是完整的食谱:

  1. 生成ssh密钥,使用ssh-keygen -q -t rsa -N '' -f repo-key它们可以得到repo-key和repo-key.pub文件。

  2. 将repo-key.pub添加到您的存储库部署密钥。
    在GitHub上,转到[您的存储库]->设置->部署密钥

  3. 在您的Dockerfile中添加以下内容:

    添加回购密钥/
    跑 \
      chmod 600 /回购键&& \  
      回显“ IdentityFile / repo-key” >> / etc / ssh / ssh_config && \  
      echo -e“ StrictHostKeyChecking no” >> / etc / ssh / ssh_config && \  
      //您的git clone命令在这里...
    

请注意,上面关闭了StrictHostKeyChecking,因此您不需要.ssh / known_hosts。尽管我可能更喜欢上面答案之一中的ssh-keyscan解决方案。


6
警告:在我的配置中,echo -e“ ...”也在文件内写入-e。只需删除标志,它就可以正常工作。
Conchylicultor

您的回答绝对可以帮助我解决问题。谢谢!
David Pointer

我仍然遇到相同的问题:fatal: Could not read from remote repository.
Alex

1
谢谢数百万!我正向你宣布爱。您解决了一个我奋斗了几天的问题!
亚历山德拉(亚历山大),

为此问题选择的答案不再是一个好的答案。在2014年是正确的,但在2020年,这是正确的答案。
Bikal Basnet

70

无需摆弄ssh配置。使用包含环境变量的配置文件(而非Dockerfile),并使用Shell脚本在运行时更新您的Docker文件。您可以将令牌保留在Dockerfile中,并且可以通过https进行克隆(无需生成或传递ssh密钥)。

转到设置>个人访问令牌

  • 生成repo启用了范围的个人访问令牌。
  • 像这样克隆: git clone https://MY_TOKEN@github.com/user-or-org/repo

一些评论者指出,如果您使用共享的Dockerfile,则可能会将您的访问密钥暴露给项目中的其他人。尽管这可能与您的特定用例无关,但可以通过以下一些方法来解决:

  • 使用Shell脚本来接受可能包含您的键作为变量的参数。用sed或类似名称替换Dockerfile中的变量,即调用sh rundocker.sh MYTOKEN=foo将替换为的脚本https://{{MY_TOKEN}}@github.com/user-or-org/repo。请注意,您还可以使用配置文件(.yml或所需的任何格式)来执行相同的操作,但要使用环境变量。
  • 仅为该项目创建一个github用户(并为其生成访问令牌)

您在说什么背景Settings > Applications
turboladen

1
这种方法的缺点是,您在Dockerfile中存储了专用存储库的凭据,而不是@crooksey的方法,后者允许您引用与Dockerfile分开存储的密钥。没有关于OP如何存储Dockerfile的上下文信息,我们无法确定这是否会引起问题,但是根据个人经验,我想将Dockerfiles存储在VCS中,并且不想提交任何包含凭据的文件。一旦Docker实现了传递环境变量来构建命令的能力,那么我同意这将是最干净的解决方案。
贾斯伯德(Jabbslad)

2
@CalvinFroedge在本地我假设您是说您的房东?我不知道在构建时将主机上的环境变量暴露给容器的方法,这就是为什么我们有像github.com/docker/docker/issues/6822这样的开放问题。请您澄清一下吗?
贾斯伯德(Jabbslad)

1
甚至更干净(关注点分离):克隆存储库的链接卷+仅用于克隆任务的专用容器+仅包含SSH密钥(或您建议的令牌)的链接卷。参见stackoverflow.com/a/30992047,可能与stackoverflow.com/a/29981990结合使用。
Peterino

9
同样的问题是BITBUCKET仓库,而不是github仓库。
Michael Draper

25

另一个选择是使用多阶段docker构建,以确保您的SSH密钥不包含在最终映像中。

如我的帖子所述,您可以准备具有git clone所需依赖项的中间映像,然后COPY将所需文件放入最终映像中。

另外,如果我们有LABEL中间层,甚至可以在完成后将它们从计算机中删除。

# Choose and name our temporary image.
FROM alpine as intermediate
# Add metadata identifying these images as our build containers (this will be useful later!)
LABEL stage=intermediate

# Take an SSH key as a build argument.
ARG SSH_KEY

# Install dependencies required to git clone.
RUN apk update && \
    apk add --update git && \
    apk add --update openssh

# 1. Create the SSH directory.
# 2. Populate the private key file.
# 3. Set the required permissions.
# 4. Add github to our list of known hosts for ssh.
RUN mkdir -p /root/.ssh/ && \
    echo "$SSH_KEY" > /root/.ssh/id_rsa && \
    chmod -R 600 /root/.ssh/ && \
    ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts

# Clone a repository (my website in this case)
RUN git clone git@github.com:janakerman/janakerman.git

# Choose the base image for our final image
FROM alpine

# Copy across the files from our `intermediate` container
RUN mkdir files
COPY --from=intermediate /janakerman/README.md /files/README.md

然后我们可以构建:

MY_KEY=$(cat ~/.ssh/id_rsa)
docker build --build-arg SSH_KEY="$MY_KEY" --tag clone-example .

证明我们的SSH密钥已消失:

docker run -ti --rm clone-example cat /root/.ssh/id_rsa

从构建机器中清除中间映像:

docker rmi -f $(docker images -q --filter label=stage=intermediate)

ARG SSH_PRIVATE_KEY需要替换为ARG SSH_KEY
Joseph Persie

一旦git clone完成,我们就不能删除密钥吗?
Broncha

1
您可以这样做,但是您需要将其作为单个文件的一部分来执行,RUN因此不必将密钥保留在上一个图像层中。从Docker开始,1.13您可以使用--squash 实验性 参数,该参数也会在最终图像层中删除SSH密钥。
jaker

19

对于bitbucket存储库,生成具有对存储库和项目的读取访问权限的App Password(Bitbucket设置->访问管理-> App Password,请参见图片)。

位桶用户菜单

然后,您应该使用的命令是:

git clone https://username:generated_password@bitbucket.org/reponame/projectname.git

1
最简单的:)我必须承认,我宁愿一个基于SSH的做法,但我无法得到任何上述工作...文件都没有找到,等等
亚诺什

我看不到“访问管理” ...我想它已经过时了?
马丁·托马

1
工作了!简单明了...太好了!
何塞米

2
当然...您只需要单击左侧栏中的个人资料图片,然后单击Bitbucket设置,您将看到类似以下内容:imgur.com/EI33zj3
Josemy,

1
这对我有用。但是,我有子模块,--recursive无法正常工作。我必须git clone为每个子模块添加一个,这很好,但是如果它可以递归地工作,那将会很棒。
Zailyn Tamayo

12

您通常不希望git clone在Docker构建中执行私有回购。在此处进行克隆涉及将私有ssh凭据放置在映像中,以后任何有权访问您的映像的人都可以提取它们。

相反,通常的做法是在您选择的CI工具中从docker外部克隆git repo,然后COPY将文件简单地复制到映像中。这有第二个好处:Docker缓存。Docker缓存会查看正在运行的命令,它包含的环境变量,输入文件等,如果它们与同一父步骤中的先前构建相同,则会重用该先前的缓存。使用git clone命令,命令本身是相同的,因此即使更改了外部git repo,docker也将重用缓存。但是,COPY命令将在构建上下文中查看文件,并查看它们是否相同或已被更新,并且仅在适当时使用缓存。


如果要向构建中添加凭据,请考虑采用多阶段构建,并仅将这些凭据放置在从未标记过并推送到构建主机之外的早期阶段。结果看起来像:

FROM ubuntu as clone

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git
# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
COPY id_rsa /root/.ssh/id_rsa

# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:User/repo.git

FROM ubuntu as release
LABEL maintainer="Luke Crooks <luke@pumalo.org>"

COPY --from=clone /repo /repo
...

最近,BuildKit一直在测试一些实验性功能,这些功能允许您将ssh密钥作为永远不会写入映像的挂载来传递:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <luke@pumalo.org>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=secret,id=ssh_id,target=/root/.ssh/id_rsa \
    git clone git@bitbucket.org:User/repo.git

您可以使用以下命令进行构建:

$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --secret id=ssh_id,src=$(pwd)/id_rsa .

请注意,这仍然要求您的ssh密钥不受密码保护,但是您至少可以在一个阶段中运行构建,删除COPY命令,并避免ssh证书成为映像的一部分。


BuildKit还为ssh添加了一个功能,该功能使您仍然可以使用受密码保护的ssh密钥,结果如下所示:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <luke@pumalo.org>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=ssh \
    git clone git@bitbucket.org:User/repo.git

您可以使用以下命令进行构建:

$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --ssh default=$SSH_AUTH_SOCK .

再次,将其注入到构建中而无需写入图像层,从而消除了凭据可能意外泄漏的风险。


要强制docker git clone在缓存之前的行时运行偶数,您可以注入一个随每个构建更改的构建ARG,以中断缓存。看起来像:

# inject a datestamp arg which is treated as an environment variable and
# will break the cache for the next RUN command
ARG DATE_STAMP
# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:User/repo.git

然后将变化的arg注入docker build命令中:

date_stamp=$(date +%Y%m%d-%H%M%S)
docker build --build-arg DATE_STAMP=$date_stamp .

您建议从Docker外部使用git,但是无论如何,您都将说明如何处理ssh密钥。您何时认为这是必要/适当的?
JCarlosR

1
@JCarlosR(如果您没有用于运行内部版本的外部系统)(例如,可以预先运行克隆的CI / CD系统)。可能会有例外,但是Dockerfile中的克隆是一种代码味道。
BMitch

1

上述解决方案不适用于bitbucket。我认为这可以解决问题:

RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts \
    && eval `ssh-agent` \
    && ssh-add ~/.ssh/[key] \
    && git clone git@bitbucket.org:[team]/[repo].git
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.