很多时候,系统管理员需要通过 SSH 服务来远程登录管理服务器,但是 Docker 的很多镜像是不带 SSH 服务的,那么用户怎样才能管理容器呢?
在第一部分中介绍了一些进入容器的办法,比如用 attach、exec 等命令,但是这些命令都无法解决远程管理容器的问题。因此,当读者需要远程登录到容器内进行一些操作的时候,就需要 SSH 的支持了。
这节将介绍如何自行创建一个带有 SSH 服务的镜像,并介绍了两种创建容器的方法:基于 docker commit 命令创建和基于 Dockerfile 创建。
基于commit创建
下面是通过 docker commit 来创建 ssh 服务。
- 生成需要登录的公钥信息
生成需要登录的公钥信息,后续需要用到。
> ssh-keygen -t rsa # 在宿主主机上生成
> ls ~/.ssh # 查看该目录下的生成的文件
为了后续不需要退出容器,这里可以先复制出来:
id_rsa.pub的内容如下
> cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/DrfQ6f9yJDiqxoRj7RSyEe1nwVoGlrOTQkIt9Zoo5B2K8G96L84r5TVDCoLDfm11wAslcCpSEwvnrfq4oIpppNpt9dQuxK1yuJz8zE7zt6ClO/hpVWSwMs7Wk0rkWR0XbpTrxSVpSnsycmC7sOc7B8IhIWRJw2YlThdJzzLWjjrsI0q/Cd5wR0PrQlWQDOdGkMS4Bb9y/8Rk4zVUTOP10lIvn6zK3GZY1uCXFL1WlWy0pNSG5QxOCG97F06gx1e5BW5+PIyQQUX5bL+i7E7Mzjk2tsaSdO9PLoF9K7IN/YcEX4I2m5xw8dToSTx5TjPrb7s0wQmPudubW6fnDcrt root@localhost.localdomain
- 获取镜像
获取 ubuntu:18.04 镜像,并创建一个容器:
> docker pull ubuntu:18.04 # 获取基础镜像
> docker run --name ssh-test -it ubuntu:18.04 bash # 运行容器并进入
- 检查软件源
并使用 apt-get update
命令来更新软件源信息。由于默认的官方源速度慢,这里替换为国内163镜像的源。以163源为例,备份 /etc/apt/sources.list 文件:
# 备份源列表
root@55cf350cf18d:/# cp /etc/apt/sources.list /etc/apt/sources.list.bak
# 在该文件最前面添加下面的内容,
# docker 纯净 ubuntu 镜像里面是没有 vi 命令的,所以这里只能通过echo来设置
root@55cf350cf18d:/#
echo "deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/sources.list
echo "deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
# 执行apt-get update更新
root@55cf350cf18d:/# apt-get update
- 安装和配置 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
<br />
修改SSH服务的安全登录配置,取消pam登录限制:
```shell
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 文件中:
root@55cf350cf18d:/# mkdir /root/.ssh
# 先安装上 vim 才能使用
root@55cf350cf18d:/# apt-get install -y vim
# 复制步骤一中生成的.ssh/id_rsa.pub内容,保存
root@55cf350cf18d:/# vi /root/.ssh/authorized_keys
创建自动启动 SSH 服务的可执行文件 run.sh,并添加可执行权限:
root@55cf350cf18d:/# vi /tmp/run.sh
root@55cf350cf18d:/# chmod +x run.sh
run.sh 内容如下:
#! /bin/bash
/usr/sbin/sshd -D
最后 exit 退出容器。
- 保存镜像
将退出容器用 docker commit 保存为一个新的镜像,查看新镜像。
> docker commit 55cf sshd:test
> docker images
- 启动镜像并查看运行情况
> docker run --name sshd-test -p 10022:22 -d sshd:test /tmp/run.sh
> docker ps
在宿主主机(10.0.2.15)或其他主机上,可以通过 SSH 访问 10022 端口来登录容器:
> ssh 10.0.2.15 -p 10022
:::info
提示:
这里在测试第一次连接时报了个连接失败的错误:xxxx…..Host key verification failed,百度之后发现是个安全验证失败,这里由于是测试,就简单地先直接在 known_hosts 中对相关 IP 的 RSA 信息进行删除操作,之后就可以 ssh 连接上了。
:::
基于Dockerfile创建
- 生成秘钥
在宿主主机上生成秘钥,并创建 authorized_keys 文件:
> ssh-keygen -t rsa
> mkdir -p /tmp/docker-test
> touch /tmp/docker-test/authorized_keys
> cat ~/.ssh/id_rsa.pub > /tmp/docker-test/authorized_keys
- 创建工作目录
首先创建 /tmp/docker-test/sshd_ubuntu 目录,并在其中创建两个文件 Dockerfile 和 run.sh。
> mkdir -p /tmp/docker-test/sshd_ubuntu
> cd /tmp/docker-test/sshd_ubuntu
> touch Dockerfile run.sh
run.sh 内容如下:
#! /bin/bash
/usr/sbin/sshd -D
接着,编写 Dockerfile 中的内容,操作与基于 commit 创建的操作基本一致:
# 基础镜像
FROM ubuntu:18.04
# 提供作者信息
MAINTAINER docker_user(user@docker.com)
# 备份原来的源,更改ubuntu源为163源
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak
RUN echo "deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/sources.list
RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list
RUN apt-get update
# 安装ssh服务
RUN apt-get install -y openssh-server
RUN mkdir -p /var/run/sshd
RUN mkdir -p /root/.ssh
# 取消pam限制
RUN sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd
# 复制配置文件到相应位置,并赋予脚本可执行权限
ADD /tmp/docker-test/authorized_keys /root/.ssh/authorized_keys
ADD /tmp/docker-test/sshd_ubuntu/run.sh /tmp/run.sh
RUN chmod 755 /tmp/run.sh
# 开发端口
EXPOSE 22
# 设置自启动命令
CMD ["/tmp/run.sh"]
- 创建镜像
在 /tmp/docker-test/sshd_ubuntu 目录下,使用 docker build 命令创建镜像。需要注意在最后还有一个“.”,表示使用当前目录中的 Dockerfile:
> cd /tmp/docker-test/sshd_ubuntu
> docker build -t sshd:dockerfile .
> docker images # 可以看到生成的镜像
:::danger 这里执行构建时一直没成功,以后有时间再研究~。。。。 :::
- 运行容器
使用创建的镜像来启动容器,映射容器的22端口到本地的10122端口:
> docker run --name sshd-dockerfile -d -p 10022:22 sshd:dockerfile
> docker ps # 查看运行的容器
在宿主主机(10.0.2.15)或其他主机上,可以通过 SSH 访问 10022 端口来登录容器:
> ssh 10.0.2.15 -p 10022
总结
在 Docker 社区中,对于是否需要为 Docker 容器启用 SSH 服务一直有争论。
一方的观点是:Docker 的理念是一个容器只运行一个服务。因此,如果每个容器都运行一个额外的 SSH 服务,就违背了这个理念。而且认为根本没有从远程主机进入容器进行维护的必要。
另外一方的观点是:虽然使用 docker exec 命令可以从本地进入容器,但是如果要从其他远程主机进入依然没有更好的解决方案。
这两种说法各有道理,其实是在讨论不同的容器场景:作为应用容器,还是作为系统容器。应用容器行为围绕应用生命周期,较为简单,不需要人工的额外干预;而系统容器则需要支持管理员的登录操作,这个时候,对 SSH 服务的支持就变得十分必要了。
因此,在 Docker 推出更加高效、安全的方式对系统容器进行远程操作之前,容器的 SSH 服务还是比较重要的,而且它对资源的需求不高,同时安全性可以保障。
to be continue…