关于bitbucket:用dockerfile克隆私人git repo

Clone private git repo with dockerfile

我复制了这段代码,从周围的各种工作文件中,这里是我的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
FROM ubuntu

MAINTAINER Luke Crooks"[email protected]"

# 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
\tStrictHostKeyChecking no
">> /root/.ssh/config

# Clone the conf files into the docker container
RUN git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf

这给了我错误

1
2
3
4
5
6
7
8
9
10
Step 10 : RUN git clone [email protected]: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 [email protected]:Pumalo/docker-conf.git /home/docker-conf] returned a non-zero code: 128

这是我第一次使用dockerfiles,但从我读过的(和从工作配置中获取的)内容来看,我看不出这为什么不起作用。

我的ID_rsa和我的dockerfile在同一个文件夹中,是本地密钥的副本,可以克隆这个repo。没问题。

编辑:

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

1
RUN cat /root/.ssh/id_rsa

它会打印出正确的钥匙,所以我知道它是正确复制的。

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

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

很遗憾,这也行不通。


我的密钥受密码保护,这导致了问题的发生,下面列出了一个工作文件(供将来的谷歌用户使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
FROM ubuntu

MAINTAINER Luke Crooks"[email protected]"

# 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 [email protected]:User/repo.git


您应该为那个docker映像创建新的ssh密钥集,因为您可能不想在其中嵌入您自己的私钥。要使其工作,您必须将该密钥添加到Git存储库中的部署密钥中。以下是完整的配方:

  • 使用ssh-keygen -q -t rsa -N '' -f repo-key生成ssh密钥,它将提供repo-key和repo-key.pub文件。

  • 将repo-key.pub添加到存储库部署密钥中。在GitHub上,转到[Your Repository]->Settings->Deploy Keys

  • 在Dockerfile中添加类似的内容:

    1
    2
    3
    4
    5
    6
    ADD repo-key /
    RUN \
      chmod 600 /repo-key && \  
      echo"IdentityFile /repo-key">> /etc/ssh/ssh_config && \  
      echo -e"StrictHostKeyChecking no">> /etc/ssh/ssh_config && \  
      // your git clone commands here...
  • 请注意,上面关闭了严格的hostkeychecking,因此您不需要.ssh/known_主机。尽管我可能更喜欢上面其中一个答案中使用ssh-keyscan的解决方案。


    没有必要乱弄ssh配置。使用包含环境变量的配置文件(而不是docker file),并让shell脚本在运行时更新docker文件。您将令牌保存在dockerfiles之外,并且可以通过https克隆(不需要生成或传递ssh密钥)。

    转到设置>个人访问令牌

    • 生成启用repo作用域的个人访问令牌。
    • 像这样的克隆:git clone https://[email protected]/user-or-org/repo

    一些评论指出,如果您使用共享dockerfile,这可能会向项目中的其他人公开您的访问密钥。虽然这可能是或可能不是您的特定用例所关注的问题,但您可以通过以下几种方法来处理:

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


    对于BitBucket存储库,生成对repo和project具有读访问权限的app password(BitBucket设置->访问管理->app password,请参见图)。

    bitbucket user menu

    那么您应该使用的命令是:

    1
    git clone https://username:[email protected]/reponame/projectname.git


    另一个选项是使用多阶段Docker构建,以确保最终映像中不包含ssh密钥。

    正如我在文章中所描述的,您可以准备具有Git克隆所需依赖项的中间映像,然后将所需文件COPY放入最终映像中。

    此外,如果我们使用cx1(7)中间层,甚至可以在完成后从机器中删除它们。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    # 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 [email protected]: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

    然后我们可以建立:

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

    证明我们的ssh密钥已丢失:

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

    从生成计算机中清除中间图像:

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


    上述解决方案对BitBucket无效。我想这就是诀窍:

    1
    2
    3
    4
    RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts \
        && eval `ssh-agent` \
        && ssh-add ~/.ssh/[key] \
        && git clone [email protected]:[team]/[repo].git


    您通常不想在Docker构建中执行私有回购的git clone。在那里进行克隆涉及到将私有的ssh凭证放在映像中,以后任何有权访问您的映像的人都可以从中提取它们。

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

    如果要将凭据添加到构建中,请考虑使用多阶段构建进行此操作,并且只将这些凭据放在早期阶段,而这些早期阶段永远不会标记并推送到构建主机之外。结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    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 [email protected]:User/repo.git

    FROM ubuntu as release
    LABEL maintainer="Luke Crooks <[email protected]>"

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

    最近,buildKit测试了一些实验性功能,这些功能允许您将ssh密钥作为从未写入映像的挂载传递:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # syntax=docker/dockerfile:experimental
    FROM ubuntu as clone
    LABEL maintainer="Luke Crooks <[email protected]>"

    # 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 [email protected]:User/repo.git

    你可以用以下方法建立它:

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

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

    buildkit还为ssh添加了一个功能,它允许您仍然拥有受密码保护的ssh密钥,结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # syntax=docker/dockerfile:experimental
    FROM ubuntu as clone
    LABEL maintainer="Luke Crooks <[email protected]>"

    # 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 [email protected]:User/repo.git

    你可以用以下方法建立它:

    1
    2
    3
    4
    5
    $ 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,即使之前的行已被缓存,也可以注入一个build参数,该参数随每个build而更改,以中断缓存。看起来像:

    1
    2
    3
    4
    5
    # 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 [email protected]:User/repo.git

    然后,在docker build命令中注入更改的参数:

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