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 <Repository>[:<Tag>]
FROM <Repository>@<Digest>
MAINTAINER

用于让Dockerfile的作者提供个人的信息. Dockerfile并不限制MAINTAINER指令的位置,但是建议放在FROM指令之后. 在较新的docker版本中,已经被LABEL替代.

MAINTAINER "merle@example.com"
LABEL

让用户为镜像指定各种元数据 (键值对的格式) , 同docker run -l

LABEL <key>=<value> <key>=<value>
RUN

用于指定docker build过程中运行的程序, 可以是任何命令. 但是RUN指令后面所跟随的命令必须在FROM指定的基础镜像中存在.

RUN <command>
RUN ["executable", "param1", "param2"]
  • <command>通常是一个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 <src>... <dest>
COPY ["<src>",... "<dest>"]

注意

  • <src>必须是build上下文中的目录, 不能是其父目录中的文件.
  • 如果<src>是目录, 则其内部的文件或则子目录会被递归复制, 但<src>目录本身不会被复制.
  • 如果指定了多个<src>, 或者<src>中使用通配符, 则<dest>必须是一个目录, 且必须以 / 结尾.
  • 如果<dest>事先不存在, 它将会被自动创建, 包括其父目录路径.
ADD

ADD指令跟COPY类似, 不过它还支持使用tar文件和URL路径.

ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
  • 当拷贝的源文件是tar文件时, 会自动展开为一个目录并拷贝进新的镜像中; 然而通过URL获取到的tar文件不会自动展开.
  • 主机可以联网的情况下, docker build可以将网络上的某文件引用下载并打包到新的镜像中.
WORKDIR

用于指定工作目录, 可以指多个, 每个WORKDIR只影响他下面的指令, 直到遇见下一个WORKDIR为止. 效果同docker run -w, WORKDIR也可以调用通过ENV声明的变量.

WORKDIR 相对路径或者绝对路径

相对路径是相对于上一个WORKDIR指令的路径, 如果上面没有WORKDIR指令, 那就是当前Dockerfile文件的目录.

VOLUME

用于在镜像中创建一个挂载点目录. 是docker run -v简化版

VOLUME <mountpoint>
VOLUME ["<mountpoint>"]
EXPOSE

用于指定容器中待暴露的端口. 比如容器提供的是一个https服务且需要对外提供访问, 那就需要指定待暴露443端口, 然后在使用此镜像启动容器时搭配 -P 的参数才能将待暴露的状态转换为真正暴露的状态. 效果同docker run --expose. EXPOSE指令可以一次指定多个端口, 例如: EXPOSE 28443/udp 8443/tcp

# <protocol>用于指定协议类型,如果不指定,默认TCP协议
EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...]
ENV

用于为镜像定义所需的环境变量, 并可被ENV指令后面的其它指令所调用. 调用格式为$variable_name或者${variable_name}, 效果同docker run -e, 使用docker run启动容器的时候加上 -e 的参数为variable_name赋值, 可以覆盖Dockerfile中ENV指令指定的此variable_name的值. 但是不会影响到dockerfile中已经引用过此变量的文件名.

ENV <key> <value>
ENV <key>=<value> ...
  • 第一种格式一次只能定义一个变量, <key>之后所有内容都会被视为<value>的组成部分
  • 第二种格式一次可以定义多个变量, 每个变量为一个"="的键值对, 如果<value>中包含空格,可以用反斜线 进行转义, 也可以为<value>加引号, 另外参数过长时可用反斜线做续行.
  • 定义多个变量时, 建议使用第二种方式, 因为Dockerfile中每一行都是一个镜像层, 构建起来比较消耗资源.
ARG

ARG命令同EVN类似, 也是指定一个变量, 但不同的是, ENV指令配合-e参数可以在docker run过程中传参. 而使用ARG指令配合--build-arg参数可以在docker build过程中传参, 这方便了我们为不同场景构建不同镜像.

ARG <name>[=<default value>]
USER

用于指定docker build过程中任何RUN, CMD等指令的用户名或者UID. 默认情况下容器的运行用户为root. 指定的用户必须是已经存在的用户, 即UID需要是/etc/passwd中某用户的有效UID, 否则docker run命令将运行失败.

USER <user>[:<group>]
USER <UID>[:<GID>]
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的文字显示在屏幕上, 证明镜像构建成功.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容