当 运行 在 DC/OS 中的 docker 容器中时,ssh-agent 不记得身份

ssh-agent does not remember identities when running inside a docker container in DC/OS

我正在尝试 运行 使用 DC/OS 和 Docker 的服务。我使用 here 中适合我所在地区的模板创建了 Stack。我还创建了以下 Docker 文件:

FROM ubuntu:16.04
RUN apt-get update && apt-get install -y expect openssh-client

WORKDIR "/root"
ENTRYPOINT eval "$(ssh-agent -s)" && \
           mkdir -p .ssh && \
           echo $PRIVATE_KEY > .ssh/id_rsa && \
           chmod 600 /root/.ssh/id_rsa && \
           expect -c "spawn ssh-add /root/.ssh/id_rsa; expect \"Enter passphrase for /root/.ssh/id_rsa:\" send \"\"; interact " && \
           while true; do ssh-add -l; sleep 2; done

我有一个私有存储库,我想在 docker 容器启动时 clone/pull 使用它。这就是我尝试将私钥添加到 ssh-agent.

的原因

如果我 运行 此图像作为本地 docker 容器并使用 PRIVATE_KEY 环境变量提供私钥,一切正常。我看到添加了身份。

我遇到的问题是,当我尝试使用 docker 图像在 DC/OS 上 运行 服务时,ssh-agent 似乎不记得使用私钥添加的身份。

我检查了 DC/OS 的错误日志。没有错误。

有谁知道为什么 运行 在 DC/OS 上安装 docker 容器与 运行 在本地安装它有什么不同?

编辑: 我添加了 DC/OS 服务描述的详细信息以防有帮助:

{
 "id": "/SOME-ID",
 "instances": 1,
  "cpus": 1,
  "mem": 128,
  "disk": 0,
  "gpus": 0,
  "constraints": [],
  "fetch": [],
  "storeUrls": [],
  "backoffSeconds": 1,
  "backoffFactor": 1.15,
  "maxLaunchDelaySeconds": 3600,
  "container": {
                "type": "DOCKER",
                "volumes": [],
                "docker": {
                "image": "IMAGE NAME FROM DOCKERHUB",
                "network": "BRIDGE",
                "portMappings": [{
                                  "containerPort": SOME PORT NUMBER,
                                  "hostPort": SOME PORT NUMBER,
                                  "servicePort": SERVICE PORT NUMBER,
                                  "protocol": "tcp",
                                  "name": “default”
                                 }],
                "privileged": false,
                "parameters": [],
                "forcePullImage": true
               }
  },
  "healthChecks": [],
  "readinessChecks": [],
  "dependencies": [],
  "upgradeStrategy": {
                      "minimumHealthCapacity": 1,
                      "maximumOverCapacity": 1
                     },
  "unreachableStrategy": {
                          "inactiveAfterSeconds": 300,
                          "expungeAfterSeconds": 600
                         },
  "killSelection": "YOUNGEST_FIRST",
  "requirePorts": true,
  "env": {
          "PRIVATE_KEY": "ID_RSA PRIVATE_KEY WITH \n LINE BREAKS",
         }
  }

通过 PRIVATE_KEY 传递的密钥文件内容最初包含换行符。将 PRIVATE_KEY 变量内容回显到 ~/.ssh/id_rsa 后,换行符将消失。您可以通过用双引号将 $PRIVATE_KEY 变量括起来来解决该问题。

当容器在没有附加 TTY 的情况下启动时会出现另一个问题,通常是通过 -i -t 命令行参数到 docker run。密码请求将失败,并且不会将 ssh 密钥添加到 ssh-agent。对于 运行 in DC/OS 的容器,交互可能没有意义,因此您应该相应地更改入口点脚本。这将要求您的 ssh 密钥是无密码的。

这个更改后的 Dockerfile 应该可以工作:

ENTRYPOINT eval "$(ssh-agent -s)" && \
           mkdir -p .ssh && \
           echo "$PRIVATE_KEY" > .ssh/id_rsa && \
           chmod 600 /root/.ssh/id_rsa && \
           ssh-add /root/.ssh/id_rsa && \
           while true; do ssh-add -l; sleep 2; done

Docker版本

检查您的 Docker 本地版本是否与安装在 DC/OS 代理上的版本匹配。默认情况下,DC/OS 1.9.3 AWS CloudFormation 模板使用 CoreOS 1235.12.0, which comes with Docker 1.12.6。从那时起,入口点行为可能发生了变化。

Docker 命令

检查有问题的 Marathon 应用程序的 Mesos 任务日志,看看执行了什么 docker 运行 命令。在本地测试时,您可能会传递略有不同的参数。

脚本错误

如另一个答案中所述,您提供的脚本有几个错误,这些错误可能与失败有关,也可能无关。

  1. echo $PRIVATE_KEY 应该是 echo "$PRIVATE_KEY" 以保留换行符。否则密钥解密将失败 Bad passphrase, try again for /root/.ssh/id_rsa:.
  2. expect -c "spawn ssh-add /root/.ssh/id_rsa; expect \"Enter passphrase for /root/.ssh/id_rsa:\" send \"\"; interact " 应该是 expect -c "spawn ssh-add /root/.ssh/id_rsa; expect \"Enter passphrase for /root/.ssh/id_rsa:\"; send \"\n\"; interact "。它缺少分号和换行符。否则 expect 命令会失败而不会执行。

基于文件的秘密

Enterprise DC/OS 1.10(现在推出 1.10.0-rc1)有一个名为 File Based Secrets 的新功能,它允许注入文件(如 id_rsa 文件)而不将其内容包含在 Marathon 中应用程序定义,将它们安全地存储在 Vault using DC/OS Secrets.

基于文件的机密不会为您执行 ssh-add,但它应该可以更轻松、更安全地将文件放入容器。

Mesos 错误

Mesos 1.2.0 切换到使用 Docker --env_file 而不是 -e 来传递环境变量。这会触发 Docker env_file bug that it doesn't support line breaks. A workaround was put into Mesos and DC/OS,但修复可能不在您使用的次要版本中。

手动解决方法是将 Marathon 定义的 rsa_id 转换为 base64,然后返回到您的入口点脚本中。