docker 学习(4)—— 通过 dockerfile 定制企业镜像

260 阅读10分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

8. 通过 dockerfile 定制企业镜像

8.1 dockerfile 的基本使用初体验(centos6.9_sshd)

  1. 创建存放 dockerfile 的目录

mkdir -p /opt/dockerfile

  1. 创建目录

cd /opt/dockerfile/

mkdir centos6.9_ssh

  1. 编写 Dockerfile。

cd /opt/dockerfile/centos6.9_ssh

vim 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\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

EXPOSE 80

CMD ["/usr/sbin/sshd","-D"]

  1. Dockerfile 指令介绍、语法介绍
  • FROM:基础镜像

  • 第一个非注释行必须是 FROM

  • FROM 语法:

  1. centos:6.9

  2. centos@2199b8eb8390(更安全)

  • RUN 指令:构建镜像过程中运行的命令

  • RUN 语法:

  1. 基于 bash 类的命令

  2. 和 shell 中的语法格式是一样的。可以使用 && 接多个命令。

  3. 而且在 Dockerfile 中我们建议在做 shell 命令时 尽量能写到一个行上就写到一个行上

  4. 上面的要求是基于 dockerfile 构建镜像的流程:

  5. 模仿了手工制作的流程,但是更加繁琐一些;

  6. dockerfile 中的每一行去执行时都会生成一个临时性的容器(中间容器)

  7. 基于 bash 类的命令仅限于 bash 支持的命令,在最前面会默认加 /bin/bash/bin/sh -c

  8. 会先运行一个 shell 进程,然后再去执行这些命令

  9. 其他命令(非 bash)

  10. 比如 mysql 命令:mysqld --initialize-insecure --user=mysql --bashdir=/usr/local/mysql --datadir=/data/mysql/data

  11. 使用 [] 将命令阔起来

  12. 示例:["mysqld","--initialize-insecure","--user=mysql","--bashdir=/usr/local/mysql","--datadir=/data/mysql/data"]

  13. 第一个位置是 命令本身

  14. 其他位置是 选项或者参数

  15. 使用逗号、引号区分

  16. 一般情况下,我们会将这种命令写在脚本中,调用脚本来实现。

  • RUN 可以写多个

  • EXPOSE 指令:向外暴露端口

  • 语法:

  • EXPOSE PORT

  • 可以暴露多个端口

  • CMD 指令:使用镜像启动容器时运行的命令

  • CMD 语法:

  • RUN 中非 bash 语法,例如:CMD ["/usr/sbin/sshd","-D"]

  • 标识 dockerfile 的结束。

  • 在使用镜像启动容器之后,执行的命令

  1. 使用 Dockerfile 构建镜像(会自动找到 Dockerfile 文件)

docker image build -t "wys_centos6.9-sshd:v1.0" ./


Step 2/6 : 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 -y

---> Running in 7cb22a8774c7

7cb22a8774c7 表示临时容器,临时容器可以登录。记得要使用 --rm,不要产生多余的临时容器,临时容器退出应该删掉。


centos6.9_ssh]# docker container run -it --rm c16c8f81cebf /bin/bash

  1. 查看镜像(none 表示临时镜像)

[root@VM-0-3-centos centos6.9_ssh]# docker image ls -a

REPOSITORY TAG IMAGE ID CREATED SIZE

wys_centos6.9-sshd v1.0 c16c8f81cebf 6 minutes ago 331 MB

<none> <none> f1a973938e62 6 minutes ago 331 MB

<none> <none> 6a8a8f3b17aa 6 minutes ago 331 MB

<none> <none> 73f93aa20247 6 minutes ago 331 MB

<none> <none> b917446275b6

  1. 使用镜像启动容器

docker container run -d wys_centos6.9-sshd:v1.0

  1. 查看镜像

[root@VM-0-3-centos centos6.9_ssh]# docker container ls -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

cb5b2b0e50e1 wys_centos6.9-sshd:v1.0 "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 22/tcp, 80/tcp practical_kare

  1. 查看容器地址

docker container inspect cb5b2b0e50e1

"IPAddress": "172.17.0.3"

  1. 测试连接,发现可以正常登录

ssh 172.17.0.3

8.2 制作 LAMP + BBS 镜像,介绍 COPY 和 ADD 命令

  1. 准备 discuz tar 类型压缩包。我们下载的是 .zip 格式的压缩包。

unzip -o -d /tmp/discuz /root/Discuz_X3.2_SC_UTF8.zip

cd /tmp/discuz/

tar zcvf discuz.tar.gz ./*

mv discuz.tar.gz /root/

  1. 创建 lamp 目录

mkdir -p /opt/dockerfile/lamp

cd /opt/dockerfile/lamp/

  1. 编写 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 discuz.tar.gz /var/www/html/

ADD https://mirrors.aliyun.com/centos-vault/6.9/os/x86_64/Packages/edac-utils-devel-0.9-16.el6.x86_64.rpm /tmp/

EXPOSE 22

EXPOSE 80

EXPOSE 3306

CMD ["/bin/bash", "/init.sh"]

  1. COPY 指令:将宿主机文件复制到容器中

  2. COPY 语法:

  3. ... :源可以有多个

  4. COPY 宿主机文件 容器地址

  5. 支持通配符

  6. 必须和 Dockerfile 同一级别。比如我们将初始化脚本和 discuz 压缩包复制过来,后面会用到:cp /opt/vol/html/init.sh ./cp /root/discuz.tar.gz ./

  7. 如果拷贝的是目录,只拷贝目录下的子文件和目录

  8. ADD 指令:复制(同 COPY,也是将文件拷贝到容器内部) + 自动解压 .tar* 压缩文件

  9. ADD 语法:

  10. ... :源可以有多个

  11. ADD 宿主机文件 容器地址

  12. ADD URL文件 容器地址

  13. 对于压缩文件会自动解压(.tar 类型):.tar.gz.tar.bz2.tar.xz.tar

  14. 如果容器地址目录不存在,会自动创建

  15. ADD 还可以传 URL 文件,但是不可以解压。比如 ADD https://mirrors.aliyun.com/centos-vault/6.9/os/x86_64/Packages/edac-utils-devel-0.9-16.el6.x86_64.rpm /tmp/

  16. 制作镜像


docker build -t "wys/centos69_sshd_lamp_bbs" ./

  1. 执行失败,查看错误信息。可以看到是连接数据库失败。

---> d3652e0f7ff8

Removing intermediate container 872b4485d50f

Step 4/11 : RUN mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"

---> Running in adefbb34d25d

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)

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

  1. 登录执行失败的上一步的容器,查看错误原因

docker container run -it --rm d3652e0f7ff8

/etc/init.d/mysqld start -- 正常启动

mysql -- 可以正常启动

/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;" -- 从出错的命令我们可以看到是 /bin/bash 不能执行 mysql 命令

  1. 解决方案一:把这几条命令放到脚本中,执行脚本

mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"

  1. 解决方案二:把这个命令放在 init.sh 脚本中。这个逻辑是正确的,授权命令只要在安装 discuz 之前做好了就可以了。

#!/bin/bash

/etc/init.d/mysqld start

/etc/init.d/httpd start

mysql -e "grant all on *.* to root@'%' identified by '123';grant all on *.* to discuz@'%' identified by '123';create database discuz charset utf8;"

/usr/sbin/sshd -D

  1. 重新编写 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

COPY init.sh /

ADD discuz.tar.gz /var/www/html/

ADD https://mirrors.aliyun.com/centos-vault/6.9/os/x86_64/Packages/edac-utils-devel-0.9-16.el6.x86_64.rpm /tmp/

EXPOSE 22

EXPOSE 80

EXPOSE 3306

CMD ["/bin/bash", "/init.sh"]

  1. 制作镜像

docker build -t "wys/centos69_sshd_lamp_bbs" ./

  1. 查看镜像

[root@VM-0-3-centos lamp]# docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE

wys/centos69_sshd_lamp_bbs latest 01e9ef53a65f 15 seconds ago 465 MB

  1. 启动容器

docker container run -d -p 80 -p 3306 -p 22 wys/centos69_sshd_lamp_bbs:latest

  1. 查看容器

[root@VM-0-3-centos lamp]# docker container ls -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

7619cf31cb08 wys/centos69_sshd_lamp_bbs:latest "/bin/bash /init.sh" 50 seconds ago Up 49 seconds 0.0.0.0:32773->22/tcp, 0.0.0.0:32772->80/tcp, 0.0.0.0:32771->3306/tcp elastic_mcclintock

  1. 测试访问,使用 80 对应的 32772 端口

http://82.156.85.205:32772/upload/install/

  1. 安装失败了,发现还是权限的问题,登录容器授权 777,刷新重新安装

docker container exec -it 7619cf31cb08 /bin/bash

chmod -R 777 /var/www/html/

  1. 检查 copy ADD 是否成功。能正常执行 copy add 肯定是正常的。再看一下 /tmp 目录下有没有对应文件就好了

ssh 172.17.0.4

[root@7619cf31cb08 ~]# cd /tmp/

[root@7619cf31cb08 tmp]# ll

total 56

-rw-r--r-- 5 root root 1991 Mar 28 2017 CentOS-Base.repo

-rw-r--r-- 5 root root 647 Mar 28 2017 CentOS-Debuginfo.repo

-rw-r--r-- 5 root root 630 Mar 28 2017 CentOS-Media.repo

-rw-r--r-- 5 root root 7989 Mar 28 2017 CentOS-Vault.repo

-rw-r--r-- 5 root root 289 Mar 28 2017 CentOS-fasttrack.repo

-rw------- 11 root root 19035 Apr 6 2017 anaconda-post.log

-rw------- 1 root root 8680 Jul 24 2015 edac-utils-devel-0.9-16.el6.x86_64.rpm

-rw------- 11 root root 0 Apr 6 2017 yum.log

8.3 VOLUME 指令介绍

VOLUME 指令的作用是在镜像中创建挂载点。

该指令与 -V 的区别是,通过 VOLUME 指令 创建的挂载点,无法指定主机上对应的目录,是自动生成的。

生成的挂载文件是在 /var/lib/docker/volumes/ 目录下,文件名随机生成。

我们来试验一下。

  1. 编写 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

COPY init.sh /

ADD discuz.tar.gz /var/www/html/

ADD https://mirrors.aliyun.com/centos-vault/6.9/os/x86_64/Packages/edac-utils-devel-0.9-16.el6.x86_64.rpm /tmp/

VOLUME ["/var/www/html","data/mysql/data"]

EXPOSE 22

EXPOSE 80

EXPOSE 3306

CMD ["/bin/bash", "/init.sh"]

  1. 制作镜像

docker build -t "wys/centos69_sshd_lamp_volume" ./

  1. 查看镜像

[root@VM-0-3-centos lamp]# docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE

wys/centos69_sshd_lamp_volume latest 40c5b1598239 6 seconds ago 465 MB

  1. 使用镜像启动容器

docker container run -d -p 80 -p 3306 -p 22 wys/centos69_sshd_lamp_volume:latest

  1. 查看容器

[root@VM-0-3-centos lamp]# docker container ls -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

7c2d98b62372 wys/centos69_sshd_lamp_volume:latest "/bin/bash /init.sh" 7 seconds ago Up 6 seconds 0.0.0.0:32776->22/tcp, 0.0.0.0:32775->80/tcp, 0.0.0.0:32774->3306/tcp priceless_meitner

adefbb34d25d d3652e0f7ff8 "/bin/sh -c 'mysql..." 3 hours ago Exited (1) 3 hours ago confident_hopper

  1. 测试连接

echo "" > ~/.ssh/known_hosts

ssh 172.17.0.2

  1. /var/lib/docker/volumes/ 目录查看挂载文件。

root@VM-0-3-centos ~]# cd /var/lib/docker/volumes/

[root@VM-0-3-centos volumes]# ll

总用量 32

drwxr-xr-x 3 root root 4096 33 21:45 015f35f12c910e38fa4064f39fad82730695f02ab3ba4941bfa44b59b9fac817

drwxr-xr-x 3 root root 4096 33 21:45 fae15a2b1fc8105b02634252eca97d3d81e79e37179e4f63fd721fd8bc8f6b4a

-rw------- 1 root root 32768 33 21:45 metadata.db

8.4 WORKDIR 指令介绍

WORKDIR 命令的作用是在 docker 中进入某个目录,相当于 cd

存在的缺点是,当我们使用 WORKDIR 进入某个目录后,后续的所有操作都在这个目录下,如果我们想进入其他目录,只能使用绝对路径。

平时我们可以使用 cd 代替

8.5 ENV 指令介绍

ENV 指令就是用来给一串指令定义别名的,类似变量。在 Dockerfile 中就可以使用这个变量了。

我们来试验一下。

  1. 编写 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

COPY init.sh /

ENV CODE_DIR="/var/www/html/"

ENV DATA_DIR="/data/mysql/data"

ADD discuz.tar.gz ${CODE_DIR}

ADD https://mirrors.aliyun.com/centos-vault/6.9/os/x86_64/Packages/edac-utils-devel-0.9-16.el6.x86_64.rpm /tmp/

VOLUME ["${CODE_DIR}","${DATA_DIR}"]

EXPOSE 22

EXPOSE 80

EXPOSE 3306

CMD ["/bin/bash", "/init.sh"]

  1. 制作镜像

docker build -t "wys/centos69_sshd_lamp_env" ./

  1. 查看镜像

[root@VM-0-3-centos lamp]# docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE

wys/centos69_sshd_lamp_env latest 111bd2d14042 7 seconds ago 465 MB

  1. 使用镜像启动容器

docker container run -d -p 80 -p 3306 -p 22 wys/centos69_sshd_lamp_env:latest

  1. 查看容器

[root@VM-0-3-centos lamp]# docker container ls -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

4f6fda3d493f wys/centos69_sshd_lamp_env:latest "/bin/bash /init.sh" 12 seconds ago Up 10 seconds 0.0.0.0:32779->22/tcp, 0.0.0.0:32778->80/tcp, 0.0.0.0:32777->3306/tcp agitated_knuth

adefbb34d25d d3652e0f7ff8 "/bin/sh -c 'mysql..." 5 hours ago Exited (1) 5 hours ago confident_hopper

  1. 测试连接

echo "" > ~/.ssh/known_hosts

ssh 172.17.0.2

  1. 进入容器查看文件是否存在

[root@4f6fda3d493f ~]# cd /var/www/html/

[root@4f6fda3d493f html]# ll

total 12

drwxr-xr-x 2 root root 4096 Mar 3 15:08 readme

drwxr-xr-x 12 root root 4096 Mar 3 15:08 upload

drwxr-xr-x 4 root root 4096 Mar 3 15:08 utility

8.6 ENTRYPOINT 指令介绍

ENTRYPOINT 指令同 CMD 类似,也是出现在 Dockerfile 最后面的指令。

作用:在构建容器时最后运行的命令。

CMD 区别:使用 CMD 时,如果容器启动最后跟着一条命令,CMD 中的命令就会被这一条命令所替换,ENTRYPOINT 则不会被替换。

ENTRYPOINT 可以防止在启动容器是,第一进程被手工输入的命令被替换掉,防止容器秒起秒关。

我们来试验一下:


docker container run -d -p 80 -p 3306 -p 22 wys/centos69_sshd_lamp_env:latest /bin/bash


CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

cd8734412370 wys/centos69_sshd_lamp_env:latest "/bin/bash" About a minute ago Exited (0) About a minute ago mystifying_fermi

我们再使用 ENTRYPOINT 指令看一下。

  1. 编写 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

COPY init.sh /

ENV CODE_DIR="/var/www/html/"

ENV DATA_DIR="/data/mysql/data"

ADD discuz.tar.gz ${CODE_DIR}

ADD https://mirrors.aliyun.com/centos-vault/6.9/os/x86_64/Packages/edac-utils-devel-0.9-16.el6.x86_64.rpm /tmp/

VOLUME ["${CODE_DIR}","${DATA_DIR}"]

EXPOSE 22

EXPOSE 80

EXPOSE 3306

# CMD ["/bin/bash", "/init.sh"]

ENTRYPOINT ["/bin/bash", "/init.sh"]

  1. 制作镜像

docker build -t "wys/centos69_sshd_lamp_entrypoint" ./

  1. 查看镜像

[root@VM-0-3-centos lamp]# docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE

wys/centos69_sshd_lamp_entrypoint latest 89b4cec375b8 13 seconds ago 465 MB

  1. 使用镜像启动容器

docker container run -d -p 80 -p 3306 -p 22 wys/centos69_sshd_lamp_entrypoint:latest /bin/bash

  1. 查看容器,发现仍在启动中

[root@VM-0-3-centos lamp]# docker container ls -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

40b0448358f7 wys/centos69_sshd_lamp_entrypoint:latest "/bin/bash /init.s..." 6 seconds ago Up 5 seconds 0.0.0.0:32791->22/tcp, 0.0.0.0:32790->80/tcp, 0.0.0.0:32789->3306/tcp vibrant_joliot