Docker 学习笔记 (3) : Docker 镜像定制

最近赶上项目快要上线, 一直没有时间更新博客, 今天终于有空可以更新了......
在前面的章节中, 我们介绍了Docker中的一些基本概念, 并且以Ubuntu系统为例, 演示了如何安装Docker, 并且分享了一些常用的Docker命令, 在章节中, 主要介绍一下如何定制化一个属于自己的Docker镜像.

Docker镜像创建的方式

Docker镜像创建方法有三种, 分别为基于已有镜像创建, 基于本地模板创建以及基于Dockerfile创建. 这篇文章主要介绍的是大家常用的Dockerfile来创建Docker镜像.

Dockerfile语法

  1. Dockerfile可分为四个部分:
    (1) 基础镜像信息
    (2) 维护者信息
    (3) 镜像操作指令
    (4) 容器启动时执行指令
  2. Dockerfile每行支持一条指令,每条指令可带多个参数,支持使用以#号开头的注释。
  3. Dockerfile文件名首字母必须大写;
  4. Dockerfile指令大小写不敏感, 但是为了和参数做区分, 一般指令使用大写字母;
  5. Dockerfile指令按照定义的顺序从上至下一次执行;
  6. Dockerfile的第一个非注释行必须是FROM指令, 用来指定当前镜像是基于哪个基础镜像构建的;
  7. 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的文字显示在屏幕上, 证明镜像构建成功.

你可能感兴趣的:(Docker 学习笔记 (3) : Docker 镜像定制)