导读
本篇将按照我的尝试全过程依次排雷,这样也能够让各位看到更清晰的问题解决方案,但是照着做时需要避开明确标注了“不正确”的地方。
准备工作
无论是什么系统,首先下载安装Docker
准没错。如果你是Ubuntu
系统,那么这些就够了。如果你是Windows
系统,你可能还需要一个XShell
(提取码:88kv)用于远程连接。这里就以我使用的Ubuntu
系统为例记录流程。如果你是Windows
,你可以选择Docker for Windows
并用CMD(管理员)
执行同样的命令,也可以选择使用Windows
子系统。
第一次尝试
首先肯定是确保自己进入了超级管理员权限,并使用docker命令下载我们需要的CentOS
镜像。为什么是CentOS
?因为全都是Ubuntu
的话比较容易弄混,所以就用个其他的系统区分一下。
请求超管权限,输入密码认证之后进入超管权限。
sudo su
docker pull centos # 拉取镜像
docker run -itd centos /bin/bash # 创建容器运行镜像
docker exec -it 18 /bin/bash # 进入容器操作镜像
从这里之后便全是CentOS。
这里需要说明的是,run
命令中当我们使用-d
作为参数时,容器将支持后台运行。run
命令之后便会生成一个容器id,我的是:
18b400110fc8772d23016358e60b4b5ff00e3892d1ad7db4bbbc4b6d1bb13e45
这实在是太长了。于是我在确认了没有重复项之后缩减了长度,只写了18
,也就是exec
命令所示的那样。
然后我们开始搭建ssh
环境,因为需要使用ssh
工具进行连接。
yum install passwd openssl openssh-server openssh-clients initscripts vim -y # 安装软件
此处-y
代表确认安装。这个过程实在太长而且都是一样的输出就不截图了。你担心出错?放心好了。只要你不断网,这些输出必定每个人都是一样的。
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
运行sshd服务一共需要三种密钥,rsa
、ecdsa
、ed25519
。这三种都是数字签名的算法,能够保证服务器和客户端之间有能够认证身份的唯一指定令牌。在这里就不持续展开了,总之都是世界级的加密算法。
好了,准备工作差不多就到这里了,我们不如先存个档?
exit # 从CentOS中退出来,回到超管权限下的Ubuntu
docker commit -a "sakebow" -m "ssh complete" 18 centos_server/save:v1 # 保存镜像
既然我们已经保存了镜像,之前使用的18
容器就不再需要了,删除了吧。
docker stop 18 # 之前是保持后台运行,现在需要手动关闭容器
docker rm 18 # 删除容器
docker ps -a # 确认容器是否存在
好了,我们再次使用新的镜像跑一下。
友情提醒:从现在开始会出现错误情况,我将郑重标明
# 错误示范
docker run -itd 79 /bin/bash # 创建容器并运行镜像
docker exec -it da /bin/bash # 进入容器
这里的79
是新镜像的id,而da
是新容器的id。各位在这一步需要更换为自己的对应id。现在,我们已经进入了CentOS
系统中。
systemctl start sshd.service # 启动服务
然后,噩梦开始了。这是第一个错误:
[root@daa9499a8f9f /]# systemctl start sshd.service
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
就很奇怪。后来在baidu_38558076的“System has not been booted with systemd as init system”中找到了解决方案:/bin/bash
修改为/sbin/init
,这样才会注册主线程PID 1
。
第二次尝试
exit # 退出失败的容器
# 以下修改稿1 - 这说明他依然有问题
docker ps -a # 确认出错容器
docker stop da # 停掉后台的容器
docker rm da # 删除容器
docker run --privileged=true 94 /sbin/init # 使用不一样的方式创建镜像
docker exec -it 94 /bin/bash # 运行
截图之前没注意,参数还有顺序要求,闹了很多错误。我也就不回避这些,给大家排个雷。
run
命令一定是要--privileged=true
在镜像id之前。
再来试试:
systemctl start sshd.service # 启动服务
ps -e | grep sshd # 查看sshd服务运行情况
这次没有报错。你有些后怕?放心好了,Linux
的哲学就是:“没有报错就是没有错误!”相信自己,他不说你有错误你就是没错误。
我们试着用ssh
工具连接一下。另外开一个窗口,输入:
ssh root@192.168.1.111 # 这个192.168.1.111是我的IP地址
好像行不通。以下是错误信息。
sakebow@sakebow-Lenovo-V310-14IKB:~$ ssh root@192.168.1.111
ssh: connect to host 192.168.1.111 port 22: Connection refused
为什么?因为Docker
是运行在本机的,开的端口就是本机的端口,也就是默认监听22
端口。这个端口又是其他机器连接本机的关键,不允许被占用,所以直接被拒绝了。
那怎么搞嘛!换端口。
第三次尝试
# 这次是正确的
exit # 同样退出错误的容器
# 同样重开重进
docker ps -a
docker stop 94 e5 10
docker rm 94 e5 10
docker run -itd --privileged=true -p 1000:22 79 /sbin/init
docker exec -it be /bin/bash
systemctl start sshd # 同样在CentOS里面开启服务
没有错误提示。连接试试:
ssh root@192.168.1.111 -p 1000
出现了新的对话!
确定继续连接吗?确定的话CentOS
(服务器)中的指纹就会保存在Ubuntu
(客户机)中,方便下次连接。输入yes
录入指纹,也就是以后允许这台机器输入密码认证,这样其他任何机器输入的密码即使是正确的也不会核对;如果选择no
将会终止连接,虽然指纹依然在服务器CentOS
上,但是客户机Ubuntu
没有指纹,将不会核对密码。
密码正确后,进入服务器。
到这里全部完成。
总结正确的全过程
# Ubuntu
sudo su
docker pull centos # 此处获得mirror_id_1
docker run -itd ${mirror_id_1} /bin/bash # 此处填入你的mirror_id_1,执行后生成container_id_1
docker exec -it ${container_id_1} /bin/bash # 填入你获得的container_id_1
# CentOS
yum install passwd openssl openssh-server openssh-clients initscripts vim -y
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
systemctl start sshd.service # sshd.service可以简写为sshd
exit
# Ubuntu
docker commit -a "${custom_author}" -m "${custom_comments}" ${container_id_1} ${custom_mirror_name} # 输入自定义的作者信息、备注信息 和 container_id_1,并获得mirror_id_2
docker stop ${container_id_1} # 输入你的container_id_1
docker rm ${container_id_1} # 输入你的container_id_1
docker ps -a
docker run -itd --privileged=true -p ${custom_port}:22 ${mirror_id_2} /sbin/init # 此处填入你的自定义端口号custom_port,mirror_id_2
ssh root@${IP_HOST} -p ${port} # 此处填入你的IP_HOST和custom_port
是不是有点能理解了呢?