思考:针对官方提供的docker镜像,比如centos6.9,制作此镜为容器后,容器内部缺少很多的组件,最基础的ssh都没有,所以需要针对基础镜像做二次做封装。
7. 基于容器的镜像制作
7.1 简单的镜像制作
测试准备:
ftp:Centos6.iso、容器image:centos:6.9、物理机IP:10.4.7.7
搭建ftp环境:
1、 上传系统镜像进行到虚拟机
cd /mnt
rz CentOS-6.9-x86_64-bin-DVD1.iso
2、配置yum仓库
mkdir -p /var/ftp/centos6.9
3、镜像挂在到一个目录上去
[root@docker mnt]# mount -o loop /mnt/CentOS-6.9-x86_64-bin-DVD1.iso /var/ftp/centos6.9/
4、验证
windows机器访问: ftp://10.4.7.7/centos6.9/
7.1.1 启动基础镜像容器
[root@docekr mnt]# docker run -itd --name="test_centos6.9" centos:6.9
0e6ab25d3f196ccb09a1839ffba7ec31de49efe1855c93c09b6b5dcc783ffce4
[root@docekr mnt]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e6ab25d3f19 centos:6.9 "/bin/bash" 15 seconds ago Up 14 seconds test_centos6.9
[root@docekr mnt]# docker container inspect test_centos6.9 |grep "IPAddress"
"IPAddress": "172.17.0.2",
[root@docekr ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.080 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.117 ms
2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.080/0.098/0.117/0.021 ms
[root@docekr ~]# telnet 172.17.0.2 22 宿主机telnet docker test_centos6.9 不通,没有ssh服务
Trying 172.17.0.2...
telnet: connect to address 172.17.0.2: Connection refused
7.1.2 docker中安装软件包ssh
正常下载yum包,应该同步阿里云、清华等制作到本地,需要epel源(centos6.9/Packages/CentOS-Base.repo) ,但是在生产环境中,一般都是内网不能访问外网,如何让docker下载ssh,使用本地yum仓库 。并且本地yum仓库能升下载速度 。
首先确保centos6.9 挂在了ftp上
[root@localhost rc.d]# lftp 10.4.7.7
bash: lftp: command not found...
安装lftp软件: yum -y install lftp
[root@localhost rc.d]# lftp 10.4.7.7
lftp 10.4.7.7:~> ls
drwxr-xr-x 8 0 0 2048 May 03 2018 centos6.9
drwxr-xr-x 2 0 0 6 Apr 01 04:55 pub
docker 0 的网卡IP为172.17.0.1,所以访问lftp://172.17.0.1 如果也是有挂载内容,说明容器也是能访问这个ftp,这样容器就能在ftp://172.17.0.1/centos/6.9/Packages/中就可以找到ssh包.
[root@localhost rc.d]# lftp 172.17.0.1
lftp 172.17.0.2:~> lftp 172.17.0.1
lftp 172.17.0.1:~> ls
drwxr-xr-x 8 0 0 2048 May 03 2018 centos6.9
drwxr-xr-x 2 0 0 6 Apr 01 04:55 pub
容器内部更新本地ftp的yum仓库,并安装ssh
进入容器
[root@docekr mnt]# docker exec -it test_centos6.9 bash
[root@0e6ab25d3f19 /]#
1、先把/yum.repos.d/*的文件都挪走
[root@0e6ab25d3f19 /]# mv /etc/yum.repos.d/*.repo /tmp
2、更新yum源
[root@0e6ab25d3f19 /]# cat >/etc/yum.repos.d/ftp_6.9.repo <<EOF
[ftp]
name=ftpbase
baseurl=ftp://172.17.0.1/centos6.9
enabled=1
gpgcheck=0
EOF
或者
[root@0e6ab25d3f19 /]# echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/centos6.9\ngpgcheck=0">/etc/yum.repos.d/ftp_6.9.repo
3、加载yum源
[root@0e6ab25d3f19 /]# yum clean all
[root@0e6ab25d3f19 /]# yum makecache fast
4、安装ssh
[root@0e6ab25d3f19 /]# yum install openssh-server -y
配置ssh
目前我们测试的是centos6.9容器+ssh,在文章后篇会演示centos7容器+ssh。而安装centos6.9容器+ssh,初始化ssh是不一样。
1、正常启动sshd,使用sshd挂载到前台。(ssh第一次启动时,需要生成秘钥,生成pam验证配置文件)
[root@0e6ab25d3f19 /]# /etc/init.d/sshd start
Generating SSH2 RSA host key: [ OK ]
Generating SSH1 RSA host key: [ OK ]
Generating SSH2 DSA host key: [ OK ]
Starting sshd: [ OK ]
2、验证ssh是否正常,宿主机通过ssh 172.17.0.2 发现可以连接,但是需要密码,容器ssh 设置root密码
[root@0e6ab25d3f19 ]# /etc/init.d/sshd stop 把sshd停止,如果是/usr/sbin/sshd -D & 启动就杀死进程pid
[root@0e6ab25d3f19 ]# echo "123456" | passwd --stdin root
[root@0e6ab25d3f19 ]# /etc/init.d/sshd start
3、宿主机ssh 172.17.0.2是无问题。
存在的问题:
1、除了宿主机能连上,外部机器不好使,所以需要暴露端口,针对22端口
2、目前容器是通过run -itd启动的,在退出exit容器后,ssh依旧是可以运行的。
如果是docker container exec -it oldguo_centos /bin/bash,交互式的启动,ctrl p q 退出,ssh依旧是可以运行。如果把ssh启动的脚本/etc/init.d/sshd start 写在/etc/rc.local中,启动docker后不会自动ssh服务
7.1.3 基于容器镜像的制作
不管是在线还是不在线的容器,都可以制作镜像, 基于容器制作镜像
1、把带有ssh的test_centos6.9容器,制作成镜像
[root@docekr ftp]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e6ab25d3f19 centos:6.9 "/bin/bash" 4 hours ago Up 4 hours test_centos6.9
[root@docekr ftp]# docker commit test_centos6.9 jerry/test_centos6.9:v1
sha256:b6be31af9b8d2f90e1905a2d2596f6dd7ac0b266bccd3dbc8086ffa168d0625f
[root@docekr ftp]# docker image ls |grep "jerry/test_centos6"
REPOSITORY TAG IMAGE ID CREATED SIZE
jerry/test_centos6.9 v1 b6be31af9b8d 7 seconds ago 258MB
参数:
-a :提交的镜像作者;
-c :使用Dockerfile指令来创建镜像;
-m :提交时的说明文字;
-p :在commit时,将容器暂停。
实例,将容器a404c6c174a2 保存为新的镜像,并添加提交人信息和说明信息。
docker commit -a "runoob.com" -m "my apache" a404c6c174a2 mymysql:v1
7.1.4 基于新镜像启动容器
失败案例:启动容器,不自启动ssh
我们启动容器的时候,如果不指定第一启动的进程,会自动分配主进程(父进程)/bin/sh -c。(如Linux系统第一个启动的主进程是init,init作为父进程,在init下的分支启动其他的子进程,有init后才能执行其他的事情。)
容器制作成镜像后,只保存多层的文件系统,里面的进程是无法保存,所以这个时候如果启动刚刚生成的镜像,容器是不会启动ssh,因为没有告知启动ssh。所以默认分配主进程(父进程)/bin/sh -c
[root@docekr ftp]# docker image ls |grep "jerry/test_centos6.9"
REPOSITORY TAG IMAGE ID CREATED SIZE
jerry/test_centos6.9 v1 b6be31af9b8d 7 seconds ago 258MB
[root@docekr ftp]# docker run -it --name=sshd_1 b6be31af9b8d
[root@20fcab524fd7 /]# ps -ef |grep ssh
root 16 1 0 16:16 pts/0 00:00
正常配置:启动容器命令中,指定启动容器后,在启动ssh服务
[root@docekr ftp]# docker container run -d --name="sshd_3" b6be31af9b8d /usr/sbin/sshd -D
[1] 17870
[root@docekr ftp]# b166a67fd9c712bfcf6fbe0ff2d1917b6522246c3720815079c713dafeb278cd
[1]+ Done docker container run -d --name="sshd_3" b6be31af9b8d /usr/sbin/sshd -D
[root@docekr ftp]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b166a67fd9c7 b6be31af9b8d "/usr/sbin/sshd -D" 13 seconds ago Up 13 seconds sshd_3
注:如果使用docker container run -d --name="sshd_3" b6be31af9b8d /etc/init.d/ssh start 不可以,这个进程是后台的,执行后立马结束,不是夯主,而/usr/sbin/sshd -D是
实现windows xshell 链接容器
[root@docker ~]# docker container run -d --name=sshd_4 -p 2222:22 b6be31af9b8d /usr/sbin/sshd -D
7.1.5 centos:7.5.1804_sshd
centos 6 跟7 的区别是: centos 6是通过init.d/sshd 进行初始化, centos 7 用systemd,不在使用init.d 导致不能用init.d/sshd初始化
1、docker container run -it --name="ceshi" -p 22222:22 centos:7
2、配置yum源,安装openssh
mv /etc/yum.repos.d/*.repo /tmp
echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/centos7.5\ngpgcheck=0">/etc/yum.repos.d/ftp.repo
yum makecache fast && yum install openssh-server -y
3、初始化sshd
mkdir /var/run/sshd
echo 'UseDNS no' >> /etc/ssh/sshd_config
sed -i -e '/pam_loginuid.so/d' /etc/pam.d/sshd
echo 'root:123456' | chpasswd
/usr/bin/ssh-keygen -A # 如果不执行,启动后会报错,提示Could not load host key: /etc/ssh/ssh_host*_rabies
4、镜像制作
docker commit ceshi ceshi_centos7:v1
5、测试:
[root@docker ~]# docker container run -d --name=sshd_2222 -p 222:22 ceshi_centos7:v1 /usr/sbin/sshd -D
注意:如果想用systemd执行systemctl start sshd 会报错(Failed to get D-Bus connection: Operation not permitted),因为Docker的设计理念是在容器里面不运行后台服务,容器本身就是宿主机上的一个独立的主进程,也可以间接的理解为就是容器里运行服务的应用进程。一个容器的生命周期是围绕这个主进程存在的,所以正确的使用容器方法是将里面的服务运行在前台。
再说到systemd,这个套件已经成为主流Linux发行版(比如CentOS7、Ubuntu14+)默认的服务管理,取代了传统的SystemV风格服务管理。systemd维护系统服务程序,它需要特权去会访问Linux内核。而容器并不是一个完整的操作系统,只有一个文件系统,而且默认启动只是普通用户这样的权限访问Linux内核,也就是没有特权,所以自然就用不了,因此,请遵守容器设计原则,一个容器里运行一个前台服务。
如果就想使用systemd,解决方案是创建容器使用--privileged=true(特权模式运行容器)
# docker run -d -name test_centos7 --privileged=true centos:6 /usr/sbin/init
进入容器:
# docker exec -it test_centos7 /bin/bash
7.2 构建企业网站定制镜像 (Centos6.9_SSHD_LAMP_BBS)
7.2.1 启动基础镜像容器
[root@docker ~]# docker container rm -f `docker ps -a -q` 清空所有容器
[root@docker ~]# mkdir -p /opt/vol/mysql /opt/vol/html 共享卷
[root@docker ~]# docker run -it --name="centos_bbs" -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/var/www/html centos:6.9
7.2.2 优化yum源并安装软件
[root@5f6165a7a55a /]# mv /etc/yum.repos.d/*.repo /tmp
[root@5f6165a7a55a /]# echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/centos6.9\ngpgcheck=0">/etc/yum.repos.d/ftp_6.9.repo
[root@5f6165a7a55a /]# yum clean all
[root@5f6165a7a55a /]# yum makecache fast && yum install openssh-server htppd mysql mysql-server php php-mysql -y
7.2.3 软件初始化
sshd 初始化
[root@5f6165a7a55a ~]# echo "123456" | passwd root --stdin root
[root@5f6165a7a55a ~]# /etc/init.d/sshd start
mysqld 初始化
[root@5f6165a7a55a ~]# /etc/init.d/mysqld start
mysql> grant all on *.* to root@'%' identified by '123';
mysql> grant all on *.* to discuz@'%' identified by '123';
mysql> create database discuz charset utf8;
apache初始化
[root@5f6165a7a55a ~]# /etc/init.d/httpd start
测试在外部机器
[root@localhost ~]# curl 172.17.0.2
7.2.4 制作LAMP第一版基础镜像
[root@docker mysql]# docker commit centos_bbs jerry/centos_lamp:v1
7.2.5 端口暴露、数据落盘制作容器
数据卷挂在/opt/vol/mysql /opt/vol/html,即使容器挂掉,数据一样在
[root@docker ~]# docker run -it --name="centos_bbs_v3" -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/var/www/html -p 8080:80 jerry/centos_lamp:v1
[root@f22496ebafaf /]# /etc/init.d/mysqld start
[root@f22496ebafaf /]# /etc/init.d/httpd start
7.2.6 测试php功能
[root@docker ~]# vim /var/www/html/index.php
<?php
phpinfo();
?>
7.2.7 安装bbs论坛
上传bbs代码到宿主机/opt/vol/html并解压
安装。
7.2.8 制作 LAMP+bbs 镜像
[root@docker ~]# docker commit centos_bbs_v3 centos6.9_sshd_lamp_bbs:v1
如何让程序ssh,php apache,mysql 启动容器就起来,把启动命令写成一个脚本然后 "hang" 前台,不能用-it 这样进程就给替换掉了
7.2.9 创建启动脚本
[root@docker html]# cd /opt/vol/html 这样容器已启动,就自动在容器
[root@docker html]# cd /opt/vol/html
[root@docker html]# vi init.sh
#!/bin/bash
/etc/init.d/mysqld start
/etc/init.d/httpd start
/usr/sbin/sshd -D # 在脚本最后命令"hang"在那,就说明脚本一直在执行
[root@docker html]# chmod 777 init.sh
7.2.10 启动容器,映射端口,挂载数据卷,自动启动多服务
注意:不能用-it 这样init.d中得到进程就会被/bin/sh -c替换掉了。之前测试过 run -it 容器名
/etc/init.d/sshd start 启动程序直接运行后退出
而 run -it 容器名 /usr/sbin/sshd -D 或者 /var/www/html/init.sh后。会夯住命令卡主。
最后的命令:
[root@localhost html]# docker container run -it --name="yun_lamp_bbs1" -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/var/www/html -p 33333:22 -p 9999:80 -p 33061:3306 centos6.9_sshd_lamp_bbs:v1 /var/www/html/init.sh
Starting mysqld: [ OK ]
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4 for ServerName
[ OK ]
思考:
可否简化,比较麻烦,中间生成一些没有用的容器,所有步骤做成文件,到时候build一下就行。称之为dockerfile
注意:
例如封装好的nginx ,通过 run -d 就可以在后台运行(docker run -d --name="oldguo_nginx" nginx:1.14)因为,封装好的nginx ,启动第一条命令为"nginx -g 'daemon of…"
[root@localhost ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e9afb82f9b6 nginx:1.14 "nginx -g 'daemon of…" 3 minutes ago Up 3 minutes 80/tcp oldguo_nginx
而封装好的centos任意版本 ,通过 run -d -p -v 不可以在后台运行(docker container run -d --name="oldguoyun_lamp_bbs" -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/var/www/html -p 22222:22 -p 8888:80 -p 33060:3306 ac8888ea3e21 )因为,封装好的centos任意版本 ,启动第一条命令为 "/bin/sh -c" ,启动后就退出了
[root@localhost ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
092072e19114 centos:6.9 "/bin/bash" About a minute ago Exited (0) About a minute ago oldguoyun_lamp_bbs
但是:可以通过添加 -D /脚本形式,进行“hang” /usr/sbin/sshd -D /var/www/html/init.sh
[root@localhost ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6f38ae172fc0 centos:6.9 "/var/www/html/init.…" 4 seconds ago Exited (127) 2 seconds ago oldguoyun_lamp_bbs
8. 通过Dockerfile定制企业镜像
8.1 使用Dockerfile制作上述(centos6.9_sshd)
8.1.1 建立Dockerfile
[root@docker ~]# mkdir -p /opt/dockerfile/centos6.9_sshd;cd /opt/dockerfile/centos6.9_sshd # 自己配置Dockerfile位置
[root@docker centos6.9_sshd]# vim Dockerfile # 早期必须大写Dockerfile,现版本可以写dockerfile或者Dockerfile,其他的都不行
# Centos6.9-SSHDv1.0
FROM centos:6.9
RUN mv /etc/yum.repos.d/*.repo /tmp && echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/Centos6.9/Packages\ngpgcheck=0">/etc/yum.repos.d/ftp.repo && yum makecache fast && yum install openssh-server -y
RUN /etc/init.d/sshd start && /etc/init.d/sshd stop && echo "123456" | passwd root --stdin
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]
1、# Centos6.9-SSHDv1.0 注释
2、FROM centos:6.9
语法规定,dockerfile 第一条非注释的信息一定是FROM,FROM 后面接的是镜像,可以接本地的镜像,比如FROM centos:6.9 ,拉取的就是本地的镜像。也可以FROM 网络中的镜像,比如harbor中的镜像,比如FROM 192.168.78.5/jerry/hello-world:v1.2FROM 接镜像的两种格式:
方式一: FROM REPOSITORY:TAG (比如 FROM centos:6.9) 好处是看着简便好记。缺点是,如果黑客侵入你电脑,可能把非法程序的容器该成centos:6.9 镜像名字
方式二: FROM REPOSITORY@IMAGE@ID (比如 FROM centos:2199b8eb8390),优点:IMAGE ID是唯一的,即便其他容器改成centos:6.9镜像名字,但是IMAGE ID是不一致的,官网的上下的镜像IMAGE ID都是唯一的,也可以很好的看出此镜像是不是官方的
root@localhost ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
centos 6.9 2199b8eb8390 17 months ago 195MB
3、RUN:运行命令(容器启动后,你要想在容器中运行什么命令)
方式一:直接接命令
(比如RUN mv /etc/yum.repos.d/*.repo /tmp) ,建议最好使用 && 接多个命令(比如RUN mv /etc/yum.repos.d/*.repo /tmp && echo -e "[ftp]\nname=ftp && yum makecache fast)使用&&的好处:由于dockerfile原理是执行一个命令就开启一个临时容器。从一开始FROM 开启一个临时容器,RUN 命令开启一个临时容器,如果用&&命令1 && 命令2 &&等等只开启一个临时容器,如果临时容器开启多,会对docekrfile制作镜像的时间会长,但不会导致容器变大。
注:临时容器是基于上一个容器执行的最后一条命令开启的,比如FROM 镜像 ,RUN 命令1 ,USER root,RUN 命令2,ADD id_rsa /root/.ssh/id_rsa,RUN 命令3,过程是,FROM 使用镜像启动一个容器,遇到了RUN 命令1 执行,然后执行了用户切换USER root,遇到了RUN 命令2,把之前已经操作的RUN 命令1 ,USER root的容器执行类似docker commit的操作提交一个新的镜像层,docker再基于刚提交的镜像运行一个新容器,做为又一个临时容器,以此类推,执行RUN 命令2,把本地的ADD id_rsa 文件拷贝到容器/root/.ssh/id_rsa,然后遇到了RUN 命令3,把之前已经操作的RUN 命令1 ,USER root,RUN 命令2,ADD id_rsa /root/.ssh/id_rsa的容器执行类似docker commit的操作提交一个新的镜像层,docker再基于刚提交的镜像运行一个新容器做为又一个临时容器,执行RUN 命令3
使用RUN的好处:假如dockerfile中,写入了 RUN 命令1,RUN 命令2,等等,由于每执行一次RUN就会开启一次临时容器, 当容器由于内部命令执行错误导致的制作失败了,通过查看在那一步制作过程,执行什么命令出了问题,找到此处的上一层制作中产生的临时容器的 ID,进入这个容器,手动执行报错的命令,就知道到底是什么问题。(比如,执行dockerfile后,在RUN 命令3的时候出错,可以通过docker exec -it RUN 命令2 开启的临时容器的 ID /bin/bash ,进入容器后,我们知道这个容器已经继承了RUN 命令1、RUN 命令2 ,所以此容器中已经执行了RUN 命令3,就知道报错是什么)
思考:RUN 是通过在开启bash shell执行后面命令 RUN == /bin/sh -c "命令",所以,RUN 只是识别的是内部命令。但是非内部命令如何操作方式二:非内部命令执行
如 mysql 二进制启动( mysqld --basedir=/usr/local/mysql/ --datadir=/data/mysql/ --user=mysql --initialize)
mysqld(是内部命令,存在于/usr/sbin/mysqld),而后面的参数-initialize(非内部命令),这个非内部命令在RUN 不识别
docekrfile解决方案:["内部命令","非内部命令","非内部命令","内部命令".....],需要用"" 引用,例如 ["mysqld","--basedir=/usr/local/mysql/", "--datadir=/data/mysql/", "--user=mysql" ,"--initialize"]
方式一方式二:对于方式一,启动临时容器后,启动/bin/bash后调用执行命令
方式二:启动临时容器后,第一命令就是["mysqld","--basedir=/usr/local/mysql/", "--datadir=/data/mysql/", "--user=mysql" ,"--initialize"]
4、EXPOSE 端口:暴露端口启动
可以多端口,但只是暴露容器的端口给宿主机,并不是端口映射
EXPOSE 22
EXPOSE 80
5、CMD ["/usr/sbin/sshd","-D"]解释:
CMD :是结束的意思,结束dockerfiel并制作成一个镜像。
[命令] :CMD 后面的大括号[ ]中的内容,代表启动这个镜像为容器,容器启动的第一命令是什么。这个操作就等通于:制作镜像启动这个镜像容器,并在最后加上/usr/sbin/sshd -D
( 例如 docker container run -it --name="" -p centos:6.9 /usr/sbin/sshd -D)
这就是为什么官网下载的gninx 镜像的时候,启动nginx后,后面没有加入任何启动的命令,nginx 就自动夯的后台
8.1.2 建立容器:
[root@docker ~]# cd /opt/dockerfile/centos6.9_sshd
[root@docker centos6.9_sshd ]# docker image build -t "jerry/centos_ssh" ./ # ./ 会自动找Dockerfile -t 起名字 “ ” 名字不能大写
制作过程内容解释: Step 1/5 : FROM centos:6.9 ---> 2199b8eb8390 # 此处的ID(2199b8eb8390)是,centos:6.9 的镜像ID Step 2/5 : RUN mv /etc/yum.repos.d/*.repo /tmp && echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/Centos6.9/Packages\ngpgcheck=0">/etc/yum.repos.d/ftp.repo && yum makecache fast && yum install openssh-server -y ---> Running in 2ee7b8302f6a # Running in 后接的到是From 镜像产生的容器(ID 2ee7b8302f6a),不是镜像ID Complete! Removing intermediate container 2ee7b8302f6a # Removing... container 这句话意思是删除上述(2ee7b8302f6a)的容器 ---> 744c067b5d1c # 遇到RUN 之前,生成一个新的镜像,此条是镜像ID(744c067b5d1c) Step 3/5 : RUN /etc/init.d/sshd start && /etc/init.d/sshd stop && echo "123456" | passwd root --stdin ---> Running in 6858836130ac # 运行上述生成的(744c067b5d1c)镜像,并启动成一个临时容器,容器ID(为6858836130ac ) Generating SSH2 RSA host key: [ OK ] Generating SSH1 RSA host key: [ OK ] Generating SSH2 DSA host key: [ OK ] Starting sshd: [ OK ] Stopping sshd: [ OK ] Changing password for user root. passwd: all authentication tokens updated successfully. Removing intermediate container 6858836130ac # Removing... container 删除上述(6858836130ac)的容器 ---> 6996f4330bc0 # 遇到EXPOSE 之前,生成一个新的镜像,此条是镜像ID( 6996f4330bc0) Step 4/5 : EXPOSE 22 ---> Running in eb8b089f20b6 # Running in 后接的到是针对(6996f4330bc0)镜像产生的新的临时容器(ID eb8b089f20b6),不是镜像ID Removing intermediate container eb8b089f20b6 # Removing... container 删除上述(eb8b089f20b6)临时的容器 ---> 20b66ac69d5d # 遇到CMD 之前,生成一个新的镜像,此条是镜像ID(20b66ac69d5d) Step 5/5 : CMD ["/usr/sbin/sshd","-D"] ---> Running in dd20f5ce9250 # Running in 后接的到是针对(20b66ac69d5d)镜像产生的新的临时容器(ID dd20f5ce9250),不是镜像ID Removing intermediate container dd20f5ce9250 # Removing... container 删除上述(dd20f5ce925)的临时容器 ---> dc83eb42c2a8 # dockerfile结束,生成一个新的镜像,此条是镜像ID( dc83eb42c2a8) Successfully built dc83eb42c2a8 Successfully tagged oldguo/centos_ssh:latest
注意:在制作dockerfile过程中,如果在那个环节报错了,进入此环节的上一层环节,指的是上一层生成的镜像,而不是临时容器,因为容器在遇到报错或者dockerfile制作完成后,会自动消亡。
进入临时容器:比如在Step 5/5 : CMD ["/usr/sbin/sshd","-D"]报错了
推荐使用:
[root@localhost centos6.9_sshd]# docker run -it --rm 20b66ac69d5d /bin/bash
解释:--rm,退出后就销毁容器,别产生无用的容器在后台
[root@localhost centos6.9_sshd]# docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
jerry/centos_ssh latest dc83eb42c2a8 20 minutes ago 295MB
<none> <none> 6996f4330bc0 20 minutes ago 295MB 临时容器
<none> <none> 20b66ac69d5d 20 minutes ago 295MB 临时容器
<none> <none> 744c067b5d1c 20 minutes ago 295MB 临时容器
通过dockerfile中最后一条(是镜像ID( dc83eb42c2a8)),说明这个容器已经具备Dokerfile中所有功能(包括最后一条 CMD ["/usr/sbin/sshd","-D"],也就是/usr/sbin/sshd -D),所以启动此镜像,不用在加上/usr/sbin/sshd -D
启动[root@localhost ~]# docker run -d--name='old2' jerry/centos_ssh
[root@localhost ~]#docker container inspect old2
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.5",
"IPPrefixLen": 16,
"IPv6Gateway": "",
[root@localhost ~]# ssh 172.17.0.5
8.2 dockerfile 其他指令
8.2.1、 dockerfile 构建Lamp基础环境镜像
[root@docker dockerfile]# mkdir -p /opt/dockerfile/lamp;cd /opt/dockerfile/lamp/
[root@docker lamp]# vim dockerfile
# Centos6.9_sshd_LAMP
FROM centos:6.9
RUN mv /etc/yum.repos.d/*.repo /tmp && echo -e " [ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/centos6.9\ngpgcheck=0">/etc/yum.repos.d/ftp
.repo && yum makecache fast && yum install openssh-server htppd mysql mysql-server php php-mysql -y
RUN /etc/init.d/sshd start && echo "123456" | passwd root --stdin && /etc/init.d/mysqld start && /etc/init.d/httpd start
RUN mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"
COPY init.sh /
ADD bbs.tar.gz /var/www/html/
ADD https://mirrors.aliyun.com/centos/7.6.1810/os/x86_64/Packages/centos-bookmarks-7-1.el7.noarch.rpm /tmp
EXPOSE 22
EXPOSE 80
EXPOSE 3306
CMD ["/bin/bash","/init.sh"]
1、COPY 拷贝命令:
从dockerfile所在目录,拷贝目标文件到容器的制定目录下。方法:COPY <src>... <dest> (COPY 宿主机目录下的文件 容器内目录位置)
可以支持通配符,如果拷贝的是目录,只拷贝目录下的子文件子目录,而并非拷贝的此文件夹。案例1:拷贝宿主机/root/jerry/目录下的文件到容器的/tmp/jerry目录下(如果容器没有/tmp/jerry会自动创建) COPY /root/jerry/* /tmp/oldguo
案例2:把/root/jerry/init.sh文件拷贝到容器 / COPY /root/jerry/init.sh /
2、ADD 拷贝命令:
方法:
ADD <src>... <dest> 指定宿主机文件拷贝到容器内部
ADD url <dest> 可以指定源文件为URL地址,url中的文件拷贝到容器内部比COPY命令多的功能是,可以自动解压宿主机的(.tar.bz2 tar.xz *.tar *.tar.gz 只要是关于*.tar*,能够xf解压的)的软件包,到容器的目标目录下
案例1:(ADD <src>... <dest> )宿主机/root/jerry/index.tar.gz 文件拷贝到容器 /var/www/html
如果容器目录没有对应的位置,自动创建
ADD index.tar.gz /var/www/html # 会自动把index.tar.gz解压到容器的var/www/html 中案例2:(ADD url <dest> )通过url 上传
网络下载,然后传到容器。必须是可以下载的文件路径,如https://mirrors.aliyun.com/centos/7.6.1810/os/x86_64/Packages/centos-bookmarks-7-1.el7.noarch.rpm /tmp 并传到/tmp 下。这里注意url形式下载的文件即使是tar 也不会解压。
ADD https://mirrors.aliyun.com/centos/7.6.1810/os/x86_64/Packages/centos-bookmarks-7-1.el7.noarch.rpm /tmp
CMD ["/bin/bash","/init.sh"] 启动容器,第一个命令是启动一个/bin/bash,然后执行根目录下/init.sh脚本
[root@docker dockerfile]# cd /opt/dockerfile/lamp/
[root@docker dockerfile]# docker image bulid -t "cehsilnmp" ./
执行过程中报错
-->5856d693464d
ified by '123';create database discuz charset utf8;"
---> Running in 354715277e29
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
The command '/bin/sh -c mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"' returned a non-zero code: 1
报错显示:不能连接数据库,连接上一个容器5856d693464d
[root@docker dockerfile]# docker run -it --rm 5856d693464d /bin/bash
手动执行一下命令,查看报错日志
ERROR:/bin/sh -c mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"'
日志中提示 mysql -e 不能在bin/bash 执行,因为mysql 后有参数又有单引号,bash不识别,分号是你的还是我的,所以可以使用脚本。可以先容器中测试,脚本是不是无问题
cd /
vi mysql.sh
mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"
chmod 755 mysql.sh
通过/bin/sh -c /mysql.sh 无问题,所以需要 dockerfile 重新构建Lamp基础环境镜像修改:
[root@docker dockerfile]# cd /opt/dockerfile/lamp/
[root@docker dockerfile]# vi mysql.sh
mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%'
identified by '123';create database discuz charset utf8;"
[root@docker dockerfile]# chmod 755 mysql.sh
[root@docker dockerfile]# vim dockerfile # 修改dockerfile,注释之前的mysql,增加执行mysql.sh
## RUN mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"
COPY mysql.sh /
RUN /mysql.sh
或者mysql语句写在init.sh
[root@docker dockerfile]# cd /opt/dockerfile/lamp/
[root@docker dockerfile]# vim dockerfile 修改dockerfile , 注释之前的mysql
## RUN mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"
[root@docker html]#vi init.sh
#!/bin/bash
/etc/init.d/mysqld start
mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"
/etc/init.d/httpd start
/usr/sbin/sshd -D
由于在RUN mysql -e "grant all on *.* to .... 之前的操作已经构建了,所以重新在构建dockerfile,之前的构建不会删除,直接调用,虽然依然会显示,但是速度会很快。
[root@localhost lamp]# docker build -t "20200829lamp" ./
Sending build context to Docker daemon 11.78kB
Step 1/10 : FROM centos:6.9
---> 2199b8eb8390
Step 2/10 : RUN mv /etc/yum.repos.d/*.repo /tmp && echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/centos6.9\ngpgcheck=0">/etc/yum.repos.d/ftp.repo && yum makecache fast && yum install openssh-server htppd mysql mysql-server php php-mysql -y
---> Using cache
---> 4c5775976d97
Step 3/10 : RUN /etc/init.d/sshd start && echo "123456" | passwd root --stdin && /etc/init.d/mysqld start && /etc/init.d/httpd start
---> Using cache
---> 5856d693464d
Step 4/10 : COPY init.sh /
---> 1d993b1ced6d
Step 5/10 : COPY jerry/* /mnt/jerry/
---> c7aacd754090
Step 6/10 : ADD index.tar.gz /var/www/html
---> dba38f21ab55
Step 7/10 : EXPOSE 22
---> Running in f87ed34e5760
Removing intermediate container f87ed34e5760
---> 3e2d13b165f1
Step 8/10 : EXPOSE 80
---> Running in 02d0cfe23d0f
Removing intermediate container 02d0cfe23d0f
---> 72f5a5a66bbe
Step 9/10 : EXPOSE 3306
---> Running in bedf85c47b56
Removing intermediate container bedf85c47b56
---> d803edf66d4a
Step 10/10 : CMD ["/bin/bash","/init.sh"]
.............
启动容器:
[root@docker dockerfile]# container run -d --name="ceshi" 64c5ae628a8e
注意:虽然制作容器的时候,EXPOSE 22暴露端口 , 只是暴露容器的端口,给宿主机连接,并不是端口映射。
[root@localhost lamp]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8396539f250a 64c5ae628a8e "/bin/bash /init.sh" 3 minutes ago Up 3 minutes 22/tcp, 80/tcp, 3306/tcp
所以,如果是端口映射,启动容器还得需要加载端口映射
[root@localhost lamp]# docker container run -d -p 80 -p 3306 -p 22 --name="ceshi1" 64c5ae628a8e
[root@localhost lamp]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c2ab43d9465 64c5ae628a8e "/bin/bash /init.sh" 3 seconds ago Up 2 seconds 0.0.0.0:32770->22/tcp, 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->3306/tcp ceshi1
[root@localhost lamp]# mysql -uroot -p123 -h 192.168.78.4 -P32768
8.2.2 Dockerfile 常用指令
1、VOLUME :自动挂载卷
方法:VOLUME ["/var/www/html","/data/mysql/data"]
2、WORKDIR :相当于cd 命令,他是容器一个专用cd切换目录的命令。
与 RUN cd 的区别:
RUN cd 正常情况下,cd 跟 WORKDIR一样就是切换目录,但是在遇到下一个RUN 或者
EXPOSE 等等后会启动一个新的容器,默认Linux 系统的初始目录是home目录,所以在遇到下一个RUN之前,目录不会切换,但是启动一个新的容器,恢复默认home目录。而WORKDIR不会,除非你再次使用了WORKDIR切换目录,否则不管是不是启动新的临时容器,都依旧在你切换的目录
3、ENV 设定变量
构建dockerfile时候声明的变量,因为有时候要安装私有的程序,如安装java的需要掉用jdk环境变量 、用二进制安装mysql 会调用全路径等等,需要提前声明
ENV CODEDIR /var/www/html/ # 执行echo $CODEDIR 得到/var/www/html/
ENV DATADIR /data/mysql/data # 执行echo $DATADIR 得到/data/mysql/data
ADD bbs.tar.gz ${CODEDIR} # 设置环境变量
VOLUME ["${CODEDIR}","${DATADIR}"]
4、USER 命令
你要操作某个命令需要用什么身份执行,就是切换用户 USER root
5、ONBUILD
为他人做嫁衣裳,格式:ONBUILD <其它指令>。
ONBUILD
它后面跟的是其它指令,比如RUN
,ADD
等,而这些指令在当前dockerfile镜像构建时并不会被执行,当dockerfile制作成镜像后,再次以这个镜像作为基础,去构建下一级镜像的时候才会被执行。例如:
此时,构建dockerfile时候,并未执行ONBUILD 后的命令[root@localhost ]# vi ockerfile FROM centos:7 CMD /bin/bash ONBUILD RUN echo "---------- parent image's ONBUILD ----------" [root@localhost ]# docker image build -t "jerry/centos_test" ./ [root@docekr ~]# docker image build -t "jerry/centos_test" ./ Sending build context to Docker daemon 291.9MB Step 1/3 : FROM centos:7 ---> eeb6ee3f44bd Step 2/3 : CMD /bin/bash ---> Running in 82f4f76e07c3 Removing intermediate container 82f4f76e07c3 ---> 1b4fc39fef0f Step 3/3 : ONBUILD RUN echo "---------- parent image's ONBUILD ----------" ---> Running in 7d78e8b7a511 Removing intermediate container 7d78e8b7a511 ---> 6380876b385e Successfully built 6380876b385e Successfully tagged jerry/centos_test:latest
现在另外写一个Dockerfile文件,执行后,上一个镜像中的ONBUILD 后的命令执行了
[root@localhost ]# vi ockerfile FROM jerry/centos_test:latest #继承刚才构建的镜像 CMD /bin/bash [root@localhost ]# docker image build -t "jerry/centos_test2" ./ Sending build context to Docker daemon 291.9MB Step 1/2 : FROM jerry/centos_test:latest # Executing 1 build trigger ---> Running in f08f8b39454c ---------- parent image's ONBUILD ---------- Removing intermediate container f08f8b39454c ---> 7d9282136f06 Step 2/2 : CMD /bin/bash ---> Running in 2cb3b5a60b8a Removing intermediate container 2cb3b5a60b8a ---> 2481859604ba Successfully built 2481859604ba Successfully tagged jerry/centos_test2:latest [root@docekr ~]#
问题:基于第二次镜像在制作容器,发现不执行ONBUILD 后的命令。
[root@localhost ]# vi ockerfile FROM jerry/centos_test2:latest #继承刚才构建的镜像 CMD /bin/bash [root@docekr ~]# docker image build -t "jerry/centos_test3" ./ Sending build context to Docker daemon 291.9MB Step 1/2 : FROM jerry/centos_test2:latest ---> 2481859604ba Step 2/2 : CMD /bin/bash ---> Running in 57a4ce1e96b3 Removing intermediate container 57a4ce1e96b3 ---> 68141cff572c Successfully built 68141cff572c Successfully tagged jerry/centos_test3:latest
6、ENTRYPOINT
相当于类似cmd 命令
区别:使用CMD构建的镜像,在运行此镜像的时候,如果指定一个命令作为第一命令运行,就,就会替代镜像配置中的CMD里面的命令,作为第一容器执行命令。而ENTRYPOINT不会被替代。例子:使用CMD构建的镜像,在指定一个/bin/bash作为第一命令运行后,/bin/bash替换掉了CMD中的usr/sbin/sshd -D,导致容器直接启动后停止,没有夯住。而如果构建dockerfile的时候用NTRYPOINT,就不会被替代掉
[root@docekr ~]# vi dockerfile FROM centos:7 RUN mv /etc/yum.repos.d/*.repo /tmp && echo -e "[ftp]\nname=ftp\nbaseurl=ftp://172.17.0.1/centos7\ngpgcheck=0">/etc/yum.repos.d/ftp7.repo && yum makecache fast && yum install openssh-server -y RUN mkdir /var/run/sshd && echo 'UseDNS no' >> /etc/ssh/sshd_config && sed -i -e '/pam_loginuid.so/d' /etc/pam.d/sshd && echo 'root:123456' | chpasswd && /usr/bin/ssh-keygen -A CMD ["/usr/sbin/sshd","-D"] [root@docekr ~]# docker image build -t "jerry/centos7_test1" ./ [root@docekr ~]# docker run -d jerry/centos7_test1:latest 1d8dcb1962888c6320d54c037f7048e2d8f030202be46826c4904b68004a5cfd [root@docekr ~]# docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1d8dcb196288 jerry/centos7_test1:latest "/usr/sbin/sshd -D" 3 seconds ago Up 2 seconds agitated_yonath [root@docekr ~]# docker run -d jerry/centos7_test1:latest /bin/bash d72d92c44c7ca6bc5aea364627806dbb565e957a387f7a99c651c33e0f4d4fb8 [root@docekr ~]# docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d72d92c44c7c jerry/centos7_test1:latest "/bin/bash" 21 seconds ago Exited (0) 20 seconds ago crazy_bhabha 1d8dcb196288 jerry/centos7_test1:latest "/usr/sbin/sshd -D" 47 seconds ago Up 46 seconds agitated_yonath
如果ENTRYPOINT 后接参数,这个参数会怎么样?
dockerfile 构建镜像,最后执行命令是ENTRYPOINT构建,容器运行此镜像时候,附加命令
(docker run -d jerry/centos7_test1:latest /bin/bash),此命令会被当成脚本中的参数使用。比如ENTRYPOINT ["/usr/sbin/sshd","-D"],在运行容器的时候,附加命令 /bin/bash,最后容器执行结果:usr/sbin/sshd -D /bin/bash
小细节:dokerfile构建镜像的时候,如果报错,修改dokerfile为正确后,在built,执行的很快
ssh小细节:删除172.17.0.2的容器,重新构建新的容器后,占用了172.17.0.2。这个时候如果以前连接过172.17.0.2的机器,再次连接就会报错,如下
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:rgwr/eGdu7SU6nzvOliXDN4kn58ku/3UnRisCibyg5Y.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending RSA key in /root/.ssh/known_hosts:2
RSA host key for 172.17.0.2 has changed and you have requested strict checking.
Host key verification failed.
意思就是,已经有了这个连接172.17.0.2的信息,但是当前连接的信息与之前的信息不服,所以需要删除以前的记录,才能正常连接,在/root/.ssh/known_hosts中