创建可直接用 root 用户 ssh 登陆的 Docker 镜像

有时候我们在 Mac OS X  或 Windows 平台下需要开发以 Linux 为运行时的应用,IDE 或可直接使用 Docker 容器,或 SSH 远程连接。本地命令行下操作虽然可以用 docker exec 连接正在运行的容器,但 IDE 远程连接的话 SSH 总是一种较为通用的连接方式,所以我们希望做一个能进行 SSH 连接的 Docker 容器。因为是本地运行的 Docker,我们想直接用 root 连接,以获得在容器中最大的运行权限。下面以 ubuntu:2004 基础镜像为例,看如何安装启用 ssh 服务以及允许 root 连接。

创建允许 root + 密码登陆的镜像

我们创建一个基本的 Dockerfile 文件,内容为
1FROM ubuntu:20.04
2
3RUN apt-get update && apt-get install -y openssh-server && \
4    mkdir /var/run/sshd && \
5    echo 'root:your_password' | chpasswd && \
6    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
7
8CMD ["/usr/sbin/sshd", "-D"]

注:

  1. mkdir /var/run/sshd: 在启动 /usr/sbin/sshd 需用到,否则无法启动
  2. sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config: 允许 root 用户登陆,安装 openssh-server 后,PermitRootLogin 行默认被注释掉了
  3. 如果登陆验证有问题,在构建镜像时加上 sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd 试试

构建镜像
$ docker build -t demo-ssh .
创建了一个 tag 为 demo-ssh:latest 的镜像

启动容器
$ docker run -d -p 2022:22 demo-ssh
895e8c689c44b806da82d87980a292f55fd316bbfcce2ac3a174d7710511f272
映射主机上的端口号 2022 容器的 22

SSH 登陆
$ ssh root@localhost -p 2022
由于使用了非默认的 22 端口号,所以需加上 -p 2022 指定连接端口号。

第一次登陆会提示 Are you sure you want to continue connecting (yes/no/[fingerprint])?

回答 yes 后,再输入前面构建镜像时的密码(your_password)就登陆成功了。

就是下面的过程
 1The authenticity of host '[localhost]:2022 ([::1]:2022)' can't be established.
 2ED25519 key fingerprint is SHA256:PPAA8h/AKQS9n0myXjWn32i2Sr6d9bX+fZ9IynavXNg.
 3This key is not known by any other names.
 4Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
 5Warning: Permanently added '[localhost]:2022' (ED25519) to the list of known hosts.
 6root@localhost's password:
 7Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 6.6.26-linuxkit x86_64)
 8
 9 * Documentation:  https://help.ubuntu.com
10 * Management:     https://landscape.canonical.com
11 * Support:        https://ubuntu.com/pro
12
13This system has been minimized by removing packages and content that are
14not required on a system that users do not log into.
15
16To restore this content, you can run the 'unminimize' command.
17
18The programs included with the Ubuntu system are free software;
19the exact distribution terms for each program are described in the
20individual files in /usr/share/doc/*/copyright.
21
22Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
23applicable law.
24
25root@895e8c689c44:~#

fingerprint 记录在了本地的 ~/.ssh/known_hosts 文件中。如修改了镜像(重新构建了镜像),还是在相同的映射端口上启动容器后,比如重新构建了 demo-ssh 镜像,停掉了原来的容器,再次用
$ docker run -d p 2022:22 demo-ssh
在相同的 2022 端口上映射容器内的 22 端口号
$ ssh root@localhost -p 2022
将会看到如下的信息
 1ssh root@localhost -p 2022
 2@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 3@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
 4@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 5IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
 6Someone could be eavesdropping on you right now (man-in-the-middle attack)!
 7It is also possible that a host key has just been changed.
 8The fingerprint for the ED25519 key sent by the remote host is
 9SHA256:hKgsTk2QbpGoA3SS3qPGfbWKLZe3F5yTaYTBI4zBCck.
10Please contact your system administrator.
11Add correct host key in /Users/yanbin/.ssh/known_hosts to get rid of this message.
12Offending ECDSA key in /Users/yanbin/.ssh/known_hosts:38
13Host key for [localhost]:2022 has changed and you have requested strict checking.
14Host key verification failed.

我们需要在 ~/.ssh/known_hosts 中把 [localhost]:2022 行删除掉才能重新回答 yes 来用密码登陆。

相同的镜像多次启动,或是用不同的映射端口启动容器都用不着从 ~/.ssh/known_hosts 中删除相应的条目。

创建免密登陆的镜像

如果镜像不欲分享,那么参考 如何无需密码进行 SSH 连接[翻译],我们可以创建一个不用输入密码就能 SSH 登陆的 Docker 镜像。

首先在本地用 ssh-keygen -t rsa 在目录 ~/.ssh 下生成 id_rsa 和 id_rds.pub 密钥文件,记住在询问 Enter passphrase 是直接回车过掉。

然后在构建 Docker 镜像是把本地的 ~/.ssh/id_rsa.pub 的内容放到镜像的 /root/.ssh/authorized_keys 文件中。

相应的 Dockerfile 是
 1FROM ubuntu:20.04
 2
 3ARG ssh_pub_key
 4
 5RUN apt-get update && apt-get install -y openssh-server && \
 6    mkdir /var/run/sshd && \
 7    mkdir /root/.ssh && \
 8    echo "$ssh_pub_key" > /root/.ssh/authorized_keys
 9
10CMD ["/usr/sbin/sshd", "-D"]

由于无需用户/密码登陆,所以关于启于 root 用户登陆相关的内容也用不着了。

构建命令
$ docker build -t demo-ssh --build-arg ssh_pub_key="$(cat ~/.ssh/id_rsa.pub)" .
这样本地的 ~/.ssh/id_rsa.pub 文件内容就会跑到镜像的 /root/.ssh/authorized_keys 中去

同样的方式启动容器,但 SSH 连接容器时不用输入密码了
$ ssh root@localhost -p 2022
~/.ssh/known_hosts 的处理方式会是一样的,现在不需要输入密码就能登陆了。

另外还能配置默认的用户和端口号,在 ~/.ssh/config 文件中
1Host localhost
2  User root
3  Port 2022

这样的话,输入
$ ssh localhost
就相当于下面的全命令
$ ssh root@localhost -p 2022

而且配置了 ssh key 的话,ssh localhost 就直接登陆了。
 1$ ssh localhost
 2Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 6.6.26-linuxkit x86_64)
 3
 4 * Documentation:  https://help.ubuntu.com
 5 * Management:     https://landscape.canonical.com
 6 * Support:        https://ubuntu.com/pro
 7
 8This system has been minimized by removing packages and content that are
 9not required on a system that users do not log into.
10
11To restore this content, you can run the 'unminimize' command.
12Last login: Wed Jun  5 20:32:05 2024 from 192.168.65.1
13root@0474baf1a1ff:~#

只有第一次必须回答 yes 接受 fingerprint, 以后只需像上面那样输入 ssh localhost 就非常顺滑进入到容器的终端。

用 scp 命令在本地和 SSH 主机上搬运文件和 ssh 的验证方式是一样的,比如拷贝一个文件进到容器可以用命令
$ scp test.txt localhost:/
因为是 Docker 容器,大可不必用 scp, 用 docker cp 就行,不依赖于 ssh, 只要写上可定位唯一容器的 ID 前缀
$ docker cp test.txt 89:/
永久链接 https://yanbin.blog/create-root-ssh-docker-image/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。