最近赶上项目快要上线, 一直没有时间更新博客, 今天终于有空可以更新了......
在前面的章节中, 我们介绍了Docker中的一些基本概念, 并且以Ubuntu系统为例, 演示了如何安装Docker, 并且分享了一些常用的Docker命令, 在章节中, 主要介绍一下如何定制化一个属于自己的Docker镜像.
Docker镜像创建的方式
Docker镜像创建方法有三种, 分别为基于已有镜像创建, 基于本地模板创建以及基于Dockerfile创建. 这篇文章主要介绍的是大家常用的Dockerfile来创建Docker镜像.
Dockerfile语法
- Dockerfile可分为四个部分:
(1) 基础镜像信息
(2) 维护者信息
(3) 镜像操作指令
(4) 容器启动时执行指令 - Dockerfile每行支持一条指令,每条指令可带多个参数,支持使用以#号开头的注释。
- Dockerfile文件名首字母必须大写;
- Dockerfile指令大小写不敏感, 但是为了和参数做区分, 一般指令使用大写字母;
- Dockerfile指令按照定义的顺序从上至下一次执行;
- Dockerfile的第一个非注释行必须是FROM指令, 用来指定当前镜像是基于哪个基础镜像构建的;
- Dockfile中需要调用的文件必须跟Dockerfile文件在同一目录或者在其子目录中, 父目录或者其他路径为无效.
Dockerfile指令
FROM
FROM指令必须为Dockerfile文件开篇的第一个非注释行, 用于指定构建镜像所使用的基础镜像, 后续的指令运行都要依靠此基础镜像所提供的的环境 ( 简单说就是假如Dockerfile中所引用的基础镜像里面没有mkdir命令, 那后续的指令是没法使用mkdir参数的 ). 实际使用中, 如果没有指定仓库, docker build会先从本机查找是否有此基础镜像, 如果没有会默认去Docker Hub Registry上拉取, 再找不到就会报错.
FROM [:]
FROM @
MAINTAINER
用于让Dockerfile的作者提供个人的信息. Dockerfile并不限制MAINTAINER指令的位置,但是建议放在FROM指令之后. 在较新的docker版本中,已经被LABEL替代.
MAINTAINER "[email protected]"
LABEL
让用户为镜像指定各种元数据 (键值对的格式) , 同docker run -l
LABEL = =
RUN
用于指定docker build过程中运行的程序, 可以是任何命令. 但是RUN指令后面所跟随的命令必须在FROM指定的基础镜像中存在.
RUN
RUN ["executable", "param1", "param2"]
通常是一个shell命令,系统默认会把后面的命令作为shell的子进程来运行,以"/bin/sh -c"来运行它,也就意味着此进程在容器中的PID一定不为1. - 第二种格式的参数是一个JSON格式的数组, 其中"executable"为要运行的命令, 后面的"paramN"为传递给命令的选项或参数. 此格式指定的命令不会以"/bin/sh -c"来发起, 也就是直接由内核创建, 因此不具备shell特性,类似于RUN [ "echo", "$HOME" ], 是无法识别 $ 的; 如果想要依赖shell特性, 可以替换命令为这样的格式[ "/bin/sh", "-c", "echo $HOME" ].
CMD
用于指定启动容器的默认要运行的程序, 也就是PID为1的进程命令, 且其运行结束后容器也会终止. 如果不指定, 默认是bash. 所以在Dockerfile中可以存在多个CMD指令, 但仅最后一个生效. 因为一个docker容器只能运行一个PID为1的进程. CMD指令指定的默认程序会被docker run命令行指定的参数所覆盖. 类似于RUN指令, 也可以运行任意命令或程序, 但是两者的运行时间点不同, RUN指令运行在docker build的过程中, 而CMD指令运行在基于新镜像启动容器 (docker run) 时.
CMD command param1 param2
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
- 前两种语法格式同RUN指令. 第一种用法对于CMD指令基本没有意义, 因为它运行的程序PID不为1.
- 第三种则需要结合ENTRYPOINT指令使用, CMD指令后面的命令作为ENTRYPOINT指令的默认参数. 如果docker run命令行结尾有参数指定, 那CMD后面的参数不生效.
ENTRYPOINT
类似CMD指令的功能, 用于为容器指定默认运行程序. 在Dockerfile中可以存在多个ENTRYPOINT指令, 但仅最后一个生效, 与CMD区别在于, 由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖, 而且这些命令行参数会被当做参数传递给ENTRYPOINT指令指定的程序. 不过, docker run的--entrypoint选项的参数可覆盖ENTRYPOINT指定的默认程序.
ENTRYPOINT command param1 param2
ENTRYPOINT ["executable", "param1", "param2"]
COPY
用于复制宿主机上的文件到目标镜像中.
COPY ...
COPY ["",... ""]
注意
必须是build上下文中的目录, 不能是其父目录中的文件. - 如果
是目录, 则其内部的文件或则子目录会被递归复制, 但 目录本身不会被复制. - 如果指定了多个
, 或者 中使用通配符, 则 必须是一个目录, 且必须以 / 结尾. - 如果
事先不存在, 它将会被自动创建, 包括其父目录路径.
ADD
ADD指令跟COPY类似, 不过它还支持使用tar文件和URL路径.
ADD ...
ADD ["",... ""]
- 当拷贝的源文件是tar文件时, 会自动展开为一个目录并拷贝进新的镜像中; 然而通过URL获取到的tar文件不会自动展开.
- 主机可以联网的情况下, docker build可以将网络上的某文件引用下载并打包到新的镜像中.
WORKDIR
用于指定工作目录, 可以指多个, 每个WORKDIR只影响他下面的指令, 直到遇见下一个WORKDIR为止. 效果同docker run -w, WORKDIR也可以调用通过ENV声明的变量.
WORKDIR 相对路径或者绝对路径
相对路径是相对于上一个WORKDIR指令的路径, 如果上面没有WORKDIR指令, 那就是当前Dockerfile文件的目录.
VOLUME
用于在镜像中创建一个挂载点目录. 是docker run -v简化版
VOLUME
VOLUME [""]
EXPOSE
用于指定容器中待暴露的端口. 比如容器提供的是一个https服务且需要对外提供访问, 那就需要指定待暴露443端口, 然后在使用此镜像启动容器时搭配 -P 的参数才能将待暴露的状态转换为真正暴露的状态. 效果同docker run --expose. EXPOSE指令可以一次指定多个端口, 例如: EXPOSE 28443/udp 8443/tcp
# 用于指定协议类型,如果不指定,默认TCP协议
EXPOSE [/] [[/] ...]
ENV
用于为镜像定义所需的环境变量, 并可被ENV指令后面的其它指令所调用. 调用格式为$variable_name或者${variable_name}, 效果同docker run -e, 使用docker run启动容器的时候加上 -e 的参数为variable_name赋值, 可以覆盖Dockerfile中ENV指令指定的此variable_name的值. 但是不会影响到dockerfile中已经引用过此变量的文件名.
ENV
ENV = ...
- 第一种格式一次只能定义一个变量,
之后所有内容都会被视为 的组成部分 - 第二种格式一次可以定义多个变量, 每个变量为一个"="的键值对, 如果
中包含空格,可以用反斜线 进行转义, 也可以为 加引号, 另外参数过长时可用反斜线做续行. - 定义多个变量时, 建议使用第二种方式, 因为Dockerfile中每一行都是一个镜像层, 构建起来比较消耗资源.
ARG
ARG命令同EVN类似, 也是指定一个变量, 但不同的是, ENV指令配合-e参数可以在docker run过程中传参. 而使用ARG指令配合--build-arg参数可以在docker build过程中传参, 这方便了我们为不同场景构建不同镜像.
ARG [=]
USER
用于指定docker build过程中任何RUN, CMD等指令的用户名或者UID. 默认情况下容器的运行用户为root. 指定的用户必须是已经存在的用户, 即UID需要是/etc/passwd中某用户的有效UID, 否则docker run命令将运行失败.
USER [:]
USER [:]
HEALTHCHECK
用于声明镜像的健康检查方式, 此指令的就是告诉docker如果检查容器是否正常工作.
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE
- HEALTHCHECK指令需要我们去定义一个判断容器是否正常指令CMD, OPTIONS是指定检查的频率
- --interval=DURATION(默认值:30s): 每隔多久检查一次,默认30s
- --timeout=DURATION(默认值:30s):超时时长,默认30s
- --start-period=DURATION(默认值:0s):启动健康检查的等待时间. 因为容器启动成功时. 进程不一定立马就启动成功,那过早开始检查就会返回不健康.
- --retries=N(默认值:3):失败尝试次数
- CMD健康检测命令发出时,返回值有三种情况
- 0:成功
- 1:不健康
- 2:保留,无实际意义。
- HEALTHCHECK NONE就是不做健康检查
SHELL
用来指定运行程序默认要使用的shell类型, 此指令一般不会使用
SHELL ["executable", "parameters"]
ONBUILD
用于在Dockerfile中定义一个触发器. ONBUILD后面指定的指令在docker build时是不会执行, 构建完的镜像在被另一个Dockerfile文件中FROM指令所引用的时才会触发执行.
ONBUILD [INSTRUCTION]
- 几乎任何指令都可以成为触发器指令, 但ONBUILD不能自我嵌套, 且不会触发FROM和MAINTAINER指令, 多数情况是使用RUN或者ADD.
另外在使用COPY指令时, 应该注意后续引用该镜像的Dockerfile的同级目录下是否有被拷贝的文件.
使用Dockerfile构建自己的镜像
创建镜像工作目录
mkdir -p ./httpd
cd ./httpd
编写Dockerfile文件
vim Dockerfile
# 指定基础镜像
FROM centos
# 维护者信息
MAINTAINER The demo project for docker
#安装httpd软件包
RUN yum -y update
RUN yum -y install httpd&&yum -y install net-tools
#开启80端口
EXPOSE 80
#复制网站首页文件至镜像中
ADD index.html /var/www/html/index.html
#复制该脚本至镜像中,并修改其权限
ADD run.sh /run.sh
RUN chmod 755 /run.sh
#当启动容器时执行的脚本文件
CMD ["/run.sh"]
创建运行脚本
vim run.sh
#!/bin/bash
#清空httpd缓存文件
rm -rf /run/httpd/*
#启动httpd服务
exec /usr/sbin/apachectl -D FOREGROUND
创建index.html文件
echo "Hello Docker!!!" > index.html
查看当前目录
root@ubuntu:/home/admin/docker/httpd# ll
total 20
drwxr-xr-x 2 root root 4096 Dec 8 22:40 ./
drwxr-xr-x 3 root root 4096 Dec 8 22:19 ../
-rw-r--r-- 1 root root 210 Dec 8 22:40 Dockerfile
-rw-r--r-- 1 root root 24 Dec 8 22:27 index.html
-rw-r--r-- 1 root root 73 Dec 8 22:27 run.sh
构建Docker镜像
docker build -t httpd:centos .
Sending build context to Docker daemon 4.096kB
Step 1/9 : FROM centos
---> 0f3e07c0138f
Step 2/9 : MAINTAINER The demo project for docker
---> Using cache
---> ea3b22982f6a
Step 3/9 : RUN yum -y update
---> Using cache
---> c06da0483e94
Step 4/9 : RUN yum -y install httpd
---> Running in ef1a95562223
Last metadata expiration check: 0:02:06 ago on Sun Dec 8 14:38:08 2019.
Dependencies resolved.
================================================================================
Package Arch Version Repository
Size
================================================================================
Installing:
httpd x86_64 2.4.37-12.module_el8.0.0+185+5908b0db AppStream 1.7 M
Installing dependencies:
apr x86_64 1.6.3-9.el8 AppStream 125 k
apr-util x86_64 1.6.1-6.el8 AppStream 105 k
centos-logos-httpd
noarch 80.5-2.el8 AppStream 24 k
httpd-filesystem noarch 2.4.37-12.module_el8.0.0+185+5908b0db AppStream 35 k
httpd-tools x86_64 2.4.37-12.module_el8.0.0+185+5908b0db AppStream 102 k
mod_http2 x86_64 1.11.3-3.module_el8.0.0+185+5908b0db AppStream 158 k
brotli x86_64 1.0.6-1.el8 BaseOS 323 k
mailcap noarch 2.1.48-3.el8 BaseOS 39 k
Installing weak dependencies:
apr-util-bdb x86_64 1.6.1-6.el8 AppStream 25 k
apr-util-openssl x86_64 1.6.1-6.el8 AppStream 27 k
Enabling module streams:
httpd 2.4
Transaction Summary
================================================================================
Install 11 Packages
Total download size: 2.6 M
Installed size: 7.6 M
Downloading Packages:
(1/11): apr-util-bdb-1.6.1-6.el8.x86_64.rpm 153 kB/s | 25 kB 00:00
(2/11): apr-util-openssl-1.6.1-6.el8.x86_64.rpm 500 kB/s | 27 kB 00:00
(3/11): centos-logos-httpd-80.5-2.el8.noarch.rp 452 kB/s | 24 kB 00:00
(4/11): apr-util-1.6.1-6.el8.x86_64.rpm 330 kB/s | 105 kB 00:00
(5/11): apr-1.6.3-9.el8.x86_64.rpm 340 kB/s | 125 kB 00:00
(6/11): httpd-filesystem-2.4.37-12.module_el8.0 359 kB/s | 35 kB 00:00
(7/11): httpd-tools-2.4.37-12.module_el8.0.0+18 1.0 MB/s | 102 kB 00:00
(8/11): mod_http2-1.11.3-3.module_el8.0.0+185+5 1.5 MB/s | 158 kB 00:00
(9/11): httpd-2.4.37-12.module_el8.0.0+185+5908 6.4 MB/s | 1.7 MB 00:00
(10/11): brotli-1.0.6-1.el8.x86_64.rpm 240 kB/s | 323 kB 00:01
(11/11): mailcap-2.1.48-3.el8.noarch.rpm 13 kB/s | 39 kB 00:03
--------------------------------------------------------------------------------
Total 474 kB/s | 2.6 MB 00:05
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : apr-1.6.3-9.el8.x86_64 1/11
Running scriptlet: apr-1.6.3-9.el8.x86_64 1/11
Installing : apr-util-bdb-1.6.1-6.el8.x86_64 2/11
Installing : apr-util-openssl-1.6.1-6.el8.x86_64 3/11
Installing : apr-util-1.6.1-6.el8.x86_64 4/11
Running scriptlet: apr-util-1.6.1-6.el8.x86_64 4/11
Installing : httpd-tools-2.4.37-12.module_el8.0.0+185+5908b0db. 5/11
Installing : mailcap-2.1.48-3.el8.noarch 6/11
Installing : brotli-1.0.6-1.el8.x86_64 7/11
Running scriptlet: httpd-filesystem-2.4.37-12.module_el8.0.0+185+5908 8/11
Installing : httpd-filesystem-2.4.37-12.module_el8.0.0+185+5908 8/11
Installing : centos-logos-httpd-80.5-2.el8.noarch 9/11
Installing : mod_http2-1.11.3-3.module_el8.0.0+185+5908b0db.x86 10/11
Installing : httpd-2.4.37-12.module_el8.0.0+185+5908b0db.x86_64 11/11
Running scriptlet: httpd-2.4.37-12.module_el8.0.0+185+5908b0db.x86_64 11/11
Verifying : apr-1.6.3-9.el8.x86_64 1/11
Verifying : apr-util-1.6.1-6.el8.x86_64 2/11
Verifying : apr-util-bdb-1.6.1-6.el8.x86_64 3/11
Verifying : apr-util-openssl-1.6.1-6.el8.x86_64 4/11
Verifying : centos-logos-httpd-80.5-2.el8.noarch 5/11
Verifying : httpd-2.4.37-12.module_el8.0.0+185+5908b0db.x86_64 6/11
Verifying : httpd-filesystem-2.4.37-12.module_el8.0.0+185+5908 7/11
Verifying : httpd-tools-2.4.37-12.module_el8.0.0+185+5908b0db. 8/11
Verifying : mod_http2-1.11.3-3.module_el8.0.0+185+5908b0db.x86 9/11
Verifying : brotli-1.0.6-1.el8.x86_64 10/11
Verifying : mailcap-2.1.48-3.el8.noarch 11/11
Installed:
httpd-2.4.37-12.module_el8.0.0+185+5908b0db.x86_64
apr-util-bdb-1.6.1-6.el8.x86_64
apr-util-openssl-1.6.1-6.el8.x86_64
apr-1.6.3-9.el8.x86_64
apr-util-1.6.1-6.el8.x86_64
centos-logos-httpd-80.5-2.el8.noarch
httpd-filesystem-2.4.37-12.module_el8.0.0+185+5908b0db.noarch
httpd-tools-2.4.37-12.module_el8.0.0+185+5908b0db.x86_64
mod_http2-1.11.3-3.module_el8.0.0+185+5908b0db.x86_64
brotli-1.0.6-1.el8.x86_64
mailcap-2.1.48-3.el8.noarch
Complete!
Removing intermediate container ef1a95562223
---> 6e80b729aa73
Step 5/9 : EXPOSE 80
---> Running in 022b5e81c48f
Removing intermediate container 022b5e81c48f
---> a7e2a0f8ca09
Step 6/9 : ADD index.html /var/www/html/index.html
---> a6450e5f3d5f
Step 7/9 : ADD run.sh /run.sh
---> 4255ab58097c
Step 8/9 : RUN chmod 750 /run.sh
---> Running in edcf0d326c35
Removing intermediate container edcf0d326c35
---> bce1514adab5
Step 9/9 : CMD ["/run.sh"]
---> Running in 72e9d0b3758d
Removing intermediate container 72e9d0b3758d
---> ba16efc6a7aa
Successfully built ba16efc6a7aa
Successfully tagged httpd:centos
"." 代表镜像的工作路径, 构建Docker Image时需要指定上下文环境.
运行构建的镜像
docker run -d -p 80:80 --name=httpd httpd:centos
查看运行中的容器
root@ubuntu:/home/admin/docker/apache# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0ef13088e62 httpd:centos "/run.sh" 13 seconds ago Up 11 seconds 0.0.0.0:80->80/tcp httpd
测试镜像
root@ubuntu:~# curl http://127.0.0.1:80
Hello Dockervim run.sh!
可以看到之前我们写入index.html的文字显示在屏幕上, 证明镜像构建成功.