很多时候,系统管理员需要通过 SSH 服务来远程登录管理服务器,但是 Docker 的很多镜像是不带 SSH 服务的,那么用户怎样才能管理容器呢?

在第一部分中介绍了一些进入容器的办法,比如用 attach、exec 等命令,但是这些命令都无法解决远程管理容器的问题。因此,当读者需要远程登录到容器内进行一些操作的时候,就需要 SSH 的支持了。

这节将介绍如何自行创建一个带有 SSH 服务的镜像,并介绍了两种创建容器的方法:基于 docker commit 命令创建和基于 Dockerfile 创建。

基于commit创建

下面是通过 docker commit 来创建 ssh 服务。

  1. 生成需要登录的公钥信息

生成需要登录的公钥信息,后续需要用到。

  1. > ssh-keygen -t rsa # 在宿主主机上生成
  2. > ls ~/.ssh # 查看该目录下的生成的文件

image.png

为了后续不需要退出容器,这里可以先复制出来:

  1. id_rsa.pub的内容如下
  2. > cat id_rsa.pub
  3. ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/DrfQ6f9yJDiqxoRj7RSyEe1nwVoGlrOTQkIt9Zoo5B2K8G96L84r5TVDCoLDfm11wAslcCpSEwvnrfq4oIpppNpt9dQuxK1yuJz8zE7zt6ClO/hpVWSwMs7Wk0rkWR0XbpTrxSVpSnsycmC7sOc7B8IhIWRJw2YlThdJzzLWjjrsI0q/Cd5wR0PrQlWQDOdGkMS4Bb9y/8Rk4zVUTOP10lIvn6zK3GZY1uCXFL1WlWy0pNSG5QxOCG97F06gx1e5BW5+PIyQQUX5bL+i7E7Mzjk2tsaSdO9PLoF9K7IN/YcEX4I2m5xw8dToSTx5TjPrb7s0wQmPudubW6fnDcrt root@localhost.localdomain
  1. 获取镜像

获取 ubuntu:18.04 镜像,并创建一个容器:

  1. > docker pull ubuntu:18.04 # 获取基础镜像
  2. > docker run --name ssh-test -it ubuntu:18.04 bash # 运行容器并进入
  1. 检查软件源

并使用 apt-get update 命令来更新软件源信息。由于默认的官方源速度慢,这里替换为国内163镜像的源。以163源为例,备份 /etc/apt/sources.list 文件:

  1. # 备份源列表
  2. root@55cf350cf18d:/# cp /etc/apt/sources.list /etc/apt/sources.list.bak
  3. # 在该文件最前面添加下面的内容,
  4. # docker 纯净 ubuntu 镜像里面是没有 vi 命令的,所以这里只能通过echo来设置
  5. root@55cf350cf18d:/#
  6. echo "deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/sources.list
  7. echo "deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
  8. echo "deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
  9. echo "deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse" >> /etc/apt/sources.list
  10. echo "deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
  11. echo "deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
  12. # 执行apt-get update更新
  13. root@55cf350cf18d:/# apt-get update


  1. 安装和配置 SSH 服务: ```shell

    更新软件包缓存后可以安装SSH服务,选择主流的openssh-server作为服务端

    root@55cf350cf18d:/# apt-get install openssh-server

如果需要正常启动SSH服务,则目录/var/run/sshd必须存在。下面手动创建它,并启动SSH服务

root@55cf350cf18d:/# mkdir -p /var/run/sshd root@55cf350cf18d:/# /usr/sbin/sshd -d & [1] 3254

查看容器的22端口(SSH服务默认监听的端口),可见此端口已经处于监听状态

root@55cf350cf18d:/# apt-get install net-tools root@55cf350cf18d:/# netstat -tunlp

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/557114/1611408672806-65c6fb6d-a222-4abe-a575-e8147f332565.png#align=left&display=inline&height=307&margin=%5Bobject%20Object%5D&name=image.png&originHeight=307&originWidth=921&size=61804&status=done&style=stroke&width=921)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/557114/1611408687382-aff07697-cdc1-43f5-8c8c-ffe1a9f5296d.png#align=left&display=inline&height=122&margin=%5Bobject%20Object%5D&name=image.png&originHeight=122&originWidth=965&size=36909&status=done&style=stroke&width=965)
  2. 修改SSH服务的安全登录配置,取消pam登录限制:
  3. ```shell
  4. root@55cf350cf18d:/# sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd

在 root 用户目录下创建 .ssh 目录,并复制需要登录的公钥信息(步骤一中生成的 .ssh/id_rsa.pub 文件内容)到 authorized_keys 文件中:

  1. root@55cf350cf18d:/# mkdir /root/.ssh
  2. # 先安装上 vim 才能使用
  3. root@55cf350cf18d:/# apt-get install -y vim
  4. # 复制步骤一中生成的.ssh/id_rsa.pub内容,保存
  5. root@55cf350cf18d:/# vi /root/.ssh/authorized_keys

image.png

创建自动启动 SSH 服务的可执行文件 run.sh,并添加可执行权限:

  1. root@55cf350cf18d:/# vi /tmp/run.sh
  2. root@55cf350cf18d:/# chmod +x run.sh

run.sh 内容如下:

  1. #! /bin/bash
  2. /usr/sbin/sshd -D

最后 exit 退出容器。
image.png

  1. 保存镜像

将退出容器用 docker commit 保存为一个新的镜像,查看新镜像。

  1. > docker commit 55cf sshd:test
  2. > docker images

image.png

  1. 启动镜像并查看运行情况
    1. > docker run --name sshd-test -p 10022:22 -d sshd:test /tmp/run.sh
    2. > docker ps
    image.png

在宿主主机(10.0.2.15)或其他主机上,可以通过 SSH 访问 10022 端口来登录容器:

  1. > ssh 10.0.2.15 -p 10022

image.png

:::info 提示:
这里在测试第一次连接时报了个连接失败的错误:xxxx…..Host key verification failed,百度之后发现是个安全验证失败,这里由于是测试,就简单地先直接在 known_hosts 中对相关 IP 的 RSA 信息进行删除操作,之后就可以 ssh 连接上了。 :::

基于Dockerfile创建

  1. 生成秘钥

在宿主主机上生成秘钥,并创建 authorized_keys 文件:

  1. > ssh-keygen -t rsa
  2. > mkdir -p /tmp/docker-test
  3. > touch /tmp/docker-test/authorized_keys
  4. > cat ~/.ssh/id_rsa.pub > /tmp/docker-test/authorized_keys

image.png

  1. 创建工作目录

首先创建 /tmp/docker-test/sshd_ubuntu 目录,并在其中创建两个文件 Dockerfile 和 run.sh。

  1. > mkdir -p /tmp/docker-test/sshd_ubuntu
  2. > cd /tmp/docker-test/sshd_ubuntu
  3. > touch Dockerfile run.sh

run.sh 内容如下:

  1. #! /bin/bash
  2. /usr/sbin/sshd -D

接着,编写 Dockerfile 中的内容,操作与基于 commit 创建的操作基本一致:

  1. # 基础镜像
  2. FROM ubuntu:18.04
  3. # 提供作者信息
  4. MAINTAINER docker_user(user@docker.com)
  5. # 备份原来的源,更改ubuntu源为163源
  6. RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak
  7. RUN echo "deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/sources.list
  8. RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
  9. RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
  10. RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse" >> /etc/apt/sources.list
  11. RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list
  12. RUN apt-get update
  13. # 安装ssh服务
  14. RUN apt-get install -y openssh-server
  15. RUN mkdir -p /var/run/sshd
  16. RUN mkdir -p /root/.ssh
  17. # 取消pam限制
  18. RUN sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd
  19. # 复制配置文件到相应位置,并赋予脚本可执行权限
  20. ADD /tmp/docker-test/authorized_keys /root/.ssh/authorized_keys
  21. ADD /tmp/docker-test/sshd_ubuntu/run.sh /tmp/run.sh
  22. RUN chmod 755 /tmp/run.sh
  23. # 开发端口
  24. EXPOSE 22
  25. # 设置自启动命令
  26. CMD ["/tmp/run.sh"]
  1. 创建镜像

在 /tmp/docker-test/sshd_ubuntu 目录下,使用 docker build 命令创建镜像。需要注意在最后还有一个“.”,表示使用当前目录中的 Dockerfile:

  1. > cd /tmp/docker-test/sshd_ubuntu
  2. > docker build -t sshd:dockerfile .
  3. > docker images # 可以看到生成的镜像

:::danger 这里执行构建时一直没成功,以后有时间再研究~。。。。 :::

  1. 运行容器

使用创建的镜像来启动容器,映射容器的22端口到本地的10122端口:

  1. > docker run --name sshd-dockerfile -d -p 10022:22 sshd:dockerfile
  2. > docker ps # 查看运行的容器

在宿主主机(10.0.2.15)或其他主机上,可以通过 SSH 访问 10022 端口来登录容器:

  1. > ssh 10.0.2.15 -p 10022

总结

在 Docker 社区中,对于是否需要为 Docker 容器启用 SSH 服务一直有争论。

一方的观点是:Docker 的理念是一个容器只运行一个服务。因此,如果每个容器都运行一个额外的 SSH 服务,就违背了这个理念。而且认为根本没有从远程主机进入容器进行维护的必要。

另外一方的观点是:虽然使用 docker exec 命令可以从本地进入容器,但是如果要从其他远程主机进入依然没有更好的解决方案。

这两种说法各有道理,其实是在讨论不同的容器场景:作为应用容器,还是作为系统容器。应用容器行为围绕应用生命周期,较为简单,不需要人工的额外干预;而系统容器则需要支持管理员的登录操作,这个时候,对 SSH 服务的支持就变得十分必要了。

因此,在 Docker 推出更加高效、安全的方式对系统容器进行远程操作之前,容器的 SSH 服务还是比较重要的,而且它对资源的需求不高,同时安全性可以保障。

to be continue…