Docker多容器环境下如何共享SSH密钥?
实现Docker容器间无密码SSH登录的方案
我来帮你搞定从f-app容器无密码SSH登录其他容器的问题,结合你的现有配置,咱们分两种实用方案来实现,分别对应构建阶段预置密钥和运行阶段动态交换密钥,你可以根据场景选合适的:
方案一:构建阶段预置密钥(适合固定镜像、测试环境)
这种方式把SSH密钥提前打包进镜像,容器启动后直接就能用,优点是启动快,不需要额外的初始化步骤。
步骤1:本地生成SSH密钥对
先在你的宿主机上生成一对无密码的RSA密钥:
ssh-keygen -t rsa -f ./id_rsa -N ""
执行后会得到id_rsa(私钥)和id_rsa.pub(公钥)两个文件。
步骤2:修改Dockerfile,注入公钥
因为所有容器都需要接受f-app的登录请求,所以我们把公钥放到所有容器的authorized_keys里;而f-app需要持有私钥,后续单独处理。修改你的Dockerfile:
FROM openjdk:8 RUN apt-get update && \ apt-get install -y openssh-server EXPOSE 22 # 创建用户(和原配置一致) RUN useradd -s /bin/bash -p $(openssl passwd -1 myuser) -d /home/myuser/ -m myuser # 创建.ssh目录并设置权限 RUN mkdir -p /home/myuser/.ssh && \ chown myuser:myuser /home/myuser/.ssh && \ chmod 700 /home/myuser/.ssh # 复制公钥到authorized_keys,允许持有对应私钥的客户端登录 COPY id_rsa.pub /home/myuser/.ssh/authorized_keys # SSH对权限要求严格,必须设置为600 RUN chown myuser:myuser /home/myuser/.ssh/authorized_keys && \ chmod 600 /home/myuser/.ssh/authorized_keys ENTRYPOINT service ssh start && bash
步骤3:给f-app容器挂载私钥
在docker-compose.yml里给f-app添加volume,把宿主机的私钥挂载到容器内myuser的.ssh目录下:
f-app: image: f-app tty: true container_name: f-app hostname: f-app.info.my ports: - "22:22" networks: my-ntwk: ipv4_address: 172.20.0.5 extra_hosts: - "f-db.info.my:172.20.0.6" - "p-app.info.my:172.20.0.7" - "p-db.info.my:172.20.0.8" depends_on: - f-db - p-app - p-db # 新增:挂载私钥到容器内 volumes: - ./id_rsa:/home/myuser/.ssh/id_rsa # 新增:启动时修正私钥权限(避免权限问题) command: > bash -c "chown myuser:myuser /home/myuser/.ssh/id_rsa && chmod 600 /home/myuser/.ssh/id_rsa && service ssh start && bash"
方案二:运行阶段动态交换密钥(适合生产环境、动态场景)
这种方式不在镜像里打包密钥,而是容器启动后自动生成/交换密钥,安全性更高,适合需要频繁更换密钥或者不想把密钥暴露在镜像中的场景。
步骤1:修改Dockerfile,安装sshpass
需要用sshpass自动输入初始密码来完成密钥交换,所以更新Dockerfile:
FROM openjdk:8 RUN apt-get update && \ apt-get install -y openssh-server sshpass # 新增sshpass EXPOSE 22 RUN useradd -s /bin/bash -p $(openssl passwd -1 myuser) -d /home/myuser/ -m myuser ENTRYPOINT service ssh start && bash
步骤2:编写密钥交换脚本
在宿主机创建setup_ssh.sh脚本,内容如下:
#!/bin/bash # 启动SSH服务 service ssh start # 切换到myuser用户执行操作 su - myuser << EOF # 如果没有密钥对则生成无密码密钥 if [ ! -f ~/.ssh/id_rsa ]; then ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" fi # 遍历所有目标主机,自动添加主机指纹并复制公钥 for host in f-db.info.my p-app.info.my p-db.info.my; do # 自动接受主机指纹,避免交互 ssh-keyscan \$host >> ~/.ssh/known_hosts # 用sshpass自动输入密码,完成公钥复制 sshpass -p 'myuser' ssh-copy-id -o StrictHostKeyChecking=no myuser@\$host done EOF # 保持容器运行 bash
给脚本添加执行权限:
chmod +x setup_ssh.sh
步骤3:在docker-compose中配置f-app使用脚本启动
修改docker-compose.yml里的f-app配置,挂载脚本并设置为入口:
f-app: image: f-app tty: true container_name: f-app hostname: f-app.info.my ports: - "22:22" networks: my-ntwk: ipv4_address: 172.20.0.5 extra_hosts: - "f-db.info.my:172.20.0.6" - "p-app.info.my:172.20.0.7" - "p-db.info.my:172.20.0.8" depends_on: - f-db - p-app - p-db # 挂载脚本到容器内 volumes: - ./setup_ssh.sh:/home/myuser/setup_ssh.sh # 设置脚本为启动入口 entrypoint: /bin/bash /home/myuser/setup_ssh.sh
关键注意事项
- 权限要求:SSH对
.ssh目录和文件权限极其严格,必须保证:~/.ssh目录权限为700id_rsa和authorized_keys权限为600
否则会直接拒绝登录请求。
- 服务就绪问题:
depends_on只保证容器启动顺序,不保证SSH服务已经就绪。如果用方案二,建议在脚本里加重试逻辑,比如循环检查目标主机的SSH端口是否开放,再执行密钥交换。 - 安全性建议:如果用方案一,建议给
f-app单独构建镜像,不要和其他容器共享同一个带私钥的镜像,降低密钥泄露风险。
内容的提问来源于stack exchange,提问作者flywell
相关产品推荐
相关产品推荐

