Docker 镜像制作 --2

思考:针对官方提供的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.2

FROM 接镜像的两种格式:
方式一: 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它后面跟的是其它指令,比如 RUNADD 等,而这些指令在当前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

介绍:dockerfile中ONBUILD指令的使用_supertor的博客-CSDN博客

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中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值