Dockerfile简介

Dockerfile 可以用来快速构建定制镜像,Dockerfile是很简单文本,只需要编写一条条构建镜像所需的指令和说明即可。
既然是编写文本,就需要选择合适的目录建立Dockerfile文件,一般情况下是每个项目下面有不通版本,版本之后再创建一个空目录,然后创建文本:Dockerfile,最后编辑指定镜像指令与说明。

简单构建nginx

[root@centos7-11 docker_file]# pwd
/data/docker_file
[root@centos7-11 docker_file]# ls
Dockerfile
[root@centos7-11 docker_file]# cat Dockerfile 
FROM    nginx
RUN echo 'this is test' > /usr/share/nginx/html/index.html

构建镜像 ,可以看到构建了2层

[root@centos7-11 docker_file]# docker build -t   nginx:v111  /data/docker_file/
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> ae2feff98a0c
Step 2/2 : RUN  echo 'this is test' > /usr/share/nginx/html/index.html
 ---> Running in d5ce47eb676c
Removing intermediate container d5ce47eb676c
 ---> 2e2b4637f4fe
Successfully built 2e2b4637f4fe
[root@centos7-11 docker_file]# docker images
REPOSITORY                                                        TAG        IMAGE ID       CREATED          SIZE
nginx                                                             v111       2e2b4637f4fe   21 seconds ago   133MB

启动nginx:v111 ,端口映射到本机80端口

[root@centos7-11 docker_file]# docker run -itd -p 80:80  nginx:v111 
42b6da78310d96c80e5eac688e1f7f27d0676c507ae1d1870a7f5062d29f4760
[root@centos7-11 docker_file]# docker ps -l
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                NAMES
42b6da78310d   nginx:v111   "/docker-entrypoint.…"   37 seconds ago   Up 36 seconds   0.0.0.0:80->80/tcp   competent_rosalind

浏览器测试 ,输入ip得到如下内容,测试成功


image.png

镜像构建上下文(Context)

docker 的 C\S架构

构建的时候,有指定一个路径,可能会认为是Dockerfile的路径,其实这样理解不完全正确,这里指定的是构建的上下文路径。
docker 是C\S 架构,分为 Docker 客户端 与 Docker 服务端(dockerd 守护进程)。我们这里实验是在同一台机器上,Docker 客户端默认通过 UNIX 套接字(/var/run/docker.sock)和服务端通信。
docker客户端的一些指令、操作都是通过docker服务端来完成的,docker客户端只是负责发送指令
Docker 的引擎提供了一组 REST API,被称为 Docker Remote API(https://docs.docker.com/develop/sdk/),而如 docker 命令这样的客户端工具,则是通过这组 API 与 Docker 引擎交互,从而完成各种功能。

构建的基本步骤

理解了 Docker 的架构就很容易理解 docker build 构建镜像的工作原理了。docker build 构建镜像的流程大概如下:

  1. 执行 docker build -t <imageName:imageTag> 上下文路径 ;
  2. Docker 客户端会将构建命令后面指定的路径(上下文路径)下的所有文件打包成一个 tar 包,发送给 Docker 服务端;
  3. Docker 服务端收到客户端发送的 tar 包,然后解压,根据 Dockerfile 里面的指令进行镜像的分层构建;

打包指定目录文件之后,docker构建就会查找指定上下文中查找文件名字为Dockerfile的文件构建镜像
Dockerfile 可以不在构建上下文路径下,此时需要构建时通过 -f 参数明确指定使用哪个构建文件,并且名称可以自己任意命名,例如docker build -f dockerfile.text -t xxxxxxxx
详情:https://docs.docker.com/engine/reference/commandline/build/
或者看下我之前看过的一篇通俗易懂的文章:https://blog.csdn.net/qianghaohao/article/details/87554255

Dockerfile构建参数简介

FROM指定基础镜像

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是基础镜像。后续的操作都是基于 nginx进行下去,所有这个是必备的一条命令,必须在Dockerfile的第一行。docker hub (https://hub.docker.com/search?q=&type=image&image_filter=official
)上有很多的基础镜像提供使用。
docker还提供一种虚拟的镜像scratch ,是空镜像,也就是说不需要基础镜像的一种定制方式,这个方式目前还没使用过,不过听说go开发很多会应用这个方式。

FROM scratch
....

RUN 执行命令

RUN:用于执行后面跟着的命令行命令。类似linux中的bash ,可以在后面跟可以执行的命令 。可以有shell类似方式,也可以使用exec方式
shell方式:RUN 需要执行的命令

FROM  ...
RUN   需要执行的命令

exec方式: RUN ["可执行文件","参数1","参数2"]
假设脚本makefile.sh 是创建文件的脚本,需要传入两个参数,参数1表示文件目录,参数2表示文件名称。

FROM ...
RUN  ["./makefile.sh","/data/test_dockerfile_v1","Dockerfile"]
#类似于:RUN  ./makefile.sh  /data/test_dockerfile_v1   Dockerfile

因为每一条定制指定都会多建立一层,不仅提高了执行步骤,还提升了执行时间,所以需要使用相同指令的行,可以使用连接符号(&&)合并使用一个指令即可,例如

FROM  ...
RUN  echo 'this is test' > /usr/share/nginx/html/index.html
RUN  yum install wget
RUN  wget -o  www.tar.gz   www.xxxx.com

转化为:

FROM  ...
RUN  echo 'this is test' > /usr/share/nginx/html/index.html
          && yum install wget
          && wget -o  www.tar.gz   www.xxxx.com

COPY 复制文件

从构建的目录中复制文件、目录到容器的指定目录中,而且可以指定容器中文件的属主属组,也有两种调用方式:

COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。

COPY data*.txt  /mydir/
COPY data?.txt /mydir/

/mydir/ 表示容器内的目标路径,不存在会创建

ADD 更高级的copy

ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。高级之处例如 <源路径> 是一个 URL,Docker 会尝试去下载这个链接的文件放到 <目标路径> 去。下载后的文件权限自动设置为 600,如果需要更改权限,可以使用RUN进行权限调整,如果下载的是个压缩包,需要解压缩,也可以使用 RUN 指令进行解压缩。如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且官方也不推荐使用。

CMD 容器启动命令

CMD 指令的格式和 RUN 相似,都是运行命令,但是运行命令的时间点不一样:

      CMD 在docker run 时运行。
      RUN 是在 docker build。

也像RUN是两种格式:

shell 格式:CMD <命令>
exec 格式:CMD ["可执行文件", "参数1", "参数2"...]

参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效,这个需要注意。

ENTRYPOINT

ENTRYPOINT 的作用和 CMD 一样,指定容器启动程序及参数。ENTRYPOINT 在运行时可以替代,不过需要通过 docker run 的参数 --entrypoint 来指定
指定 ENTRYPOINT 后,CMD 的含义就发生了改变,不是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,实际执行时,将变为:

<ENTRYPOINT> "<CMD>"

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
1、不传参运行

$ docker run  nginx:v11

容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf

2、传参运行

$ docker run  nginx:v11 -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf

ENV 设置环境变量

这个指令就是设置环境变量,在这个指令之后的指令都可以使用这里定义的环境变量

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

测试下

[root@centos7-11 docker_file]# cat Dockerfile 
FROM    nginx
RUN echo 'this is test' > /usr/share/nginx/html/index.html
ENV test    hubery_zhao
RUN echo $test
[root@centos7-11 docker_file]# docker build -t nginx:v1.1 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM nginx
 ---> ae2feff98a0c
Step 2/4 : RUN  echo 'this is test' > /usr/share/nginx/html/index.html
 ---> Using cache
 ---> 2e2b4637f4fe
Step 3/4 : ENV  test    hubery_zhao
 ---> Running in 35d1bceff89e
Removing intermediate container 35d1bceff89e
 ---> f60ab3ae6c4c
Step 4/4 : RUN  echo $test
 ---> Running in 675a8108c44d
hubery_zhao
Removing intermediate container 675a8108c44d
 ---> 965f20cdbb55
Successfully built 965f20cdbb55
Successfully tagged nginx:v1.1

ARG 构建参数

构建参数和 ENV 的效果一样,设置环境变量。不同的是,ARG设置的构建环境变量,在容器运行时不会存在这些环境变量,所以一些密码类的信息,都不要使用ARG了,这个在容器内部历史命令可以查看设置的值。

ARG <参数名>[=<默认值>]

VOLUME 定义匿名卷

在容器运行时,应该尽量保证容器存储层不发生写动作,数据库类需要保存动态数据的应用,应保存于卷(volume)中,这里为了防止用户运行容器是没有挂载卷的指令,在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。使用这个参数的好处在于可以避免容器随着数据增加而不断变大,也可以避免停止容器丢失数据。

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

也可以在docker run 的时候使用-v 修改挂载点

docker run -d -v mydata:/data xxxx

EXPOSE 暴露端口

声明运行时容器提供服务端口,这是一个声明,在运行时不会因为这个声明主动开启这个端口的服务。在 Dockerfile 中写入这样的声明的优点有:一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。(注意是使用随机端口时会自动映射到EXPOSE写入的端口,需要与docker run -p 宿主机端口:容器端口 区分开 )

EXPOSE <端口1> [<端口2>...]

WORKDIR 指定工作目录

用 WORKDIR 指定的工作目录,或者称为当前目录,在之后的各层构建没有指定目录就在这个目录中,没有这个目录 会自动创建。在没有改变目录的情况下,使用exec进入容器也是在这个目录中。

[root@centos7-11 docker_file]# cat Dockerfile 
FROM    nginx
RUN echo 'this is test' > /usr/share/nginx/html/index.html
ENV test    hubery_zhao
RUN echo $test
WORKDIR /data/tmp/test
[root@centos7-11 docker_file]# docker build  -t  nginx:v1.2  .
Sending build context to Docker daemon  2.048kB
Step 1/5 : FROM nginx
 ---> ae2feff98a0c
Step 2/5 : RUN  echo 'this is test' > /usr/share/nginx/html/index.html
 ---> Running in a9655a50e2a7
Removing intermediate container a9655a50e2a7
 ---> 7f8336a4cb6b
Step 3/5 : ENV  test    hubery_zhao
 ---> Running in 0d5fd2a7503d
Removing intermediate container 0d5fd2a7503d
 ---> 561ef92e8b69
Step 4/5 : RUN  echo $test
 ---> Running in c896a1eb6b08
hubery_zhao
Removing intermediate container c896a1eb6b08
 ---> 36541714b97c
Step 5/5 : WORKDIR  /data/tmp/test
 ---> Running in de629c1aecd3
Removing intermediate container de629c1aecd3
 ---> 87b1c453f141
Successfully built 87b1c453f141
Successfully tagged nginx:v1.2
[root@centos7-11 docker_file]# docker run -itd nginx:v1.2  /bin/bash
8fd3a25949a644f97ad08699f99bb83a2cd266c71ea7efcb89af6d303ae013ca
[root@centos7-11 docker_file]# docker exec  -it 8fd3a25949a644f97ad08699f99bb83a2cd266c71ea7efcb89af6d303ae013ca  /bin/bash
root@8fd3a25949a6:/data/tmp/test# exit

USER 指定当前用户

USER 指令和 WORKDIR 相似,都是改变环境状态并影响之后构建层,USER只是切换后续命令执行的用户,这个用户需要提前建立好,否则不能切换

USER <用户名>[:<用户组>]
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

HEALTHCHECK 健康检查

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽其健康检查指令
 HEALTHCHECK 支持下列选项:
    --interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
    --timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
    --retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。

指定某个程序或者指令来监控 docker 容器服务的运行状态,这是 Docker 1.12 引入的新指令。之前,docker引擎只能通过容器内主进程是否退出来判断容器是否状态异常,多数情况是可以这样使用的,但是如果程序死锁或者死循环情况下,程序不退出,容器已经无法提供服务。
HEALTHCHECK只可以出现一次,如果写了多个,只有最后一个生效。
例如web服务,希望使用健康检查web服务是否正常可以用curl来判断

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1
#这里是5秒检查一次,3秒超时,使用 curl -fs http://localhost/ || exit 1作为检查命令。

构建镜像

[root@centos7-11 docker_file]# docker build  -t nginx:v1.5 .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM nginx
 ---> ae2feff98a0c
Step 2/3 : RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
 ---> Using cache
 ---> 415fb1a62562
Step 3/3 : HEALTHCHECK --interval=5s --timeout=3s   CMD curl -fs http://localhost/ || exit 1
 ---> Using cache
 ---> 5fb706616ba3
Successfully built 5fb706616ba3
Successfully tagged nginx:v1.5

启动容器docker run -itd --name web -P nginx:v1.5
马上查看docker ps 可以看到health:starting

[root@centos7-11 docker_file]# docker ps
CONTAINER ID   IMAGE                                               COMMAND                  CREATED         STATUS                            PORTS                   NAMES
459b3370e94d   nginx:v1.5                                          "/docker-entrypoint.…"   4 seconds ago   Up 3 seconds (health: starting)   0.0.0.0:49157->80/tcp   web

稍等一会就可看到healthy

[root@centos7-11 docker_file]# docker ps
CONTAINER ID   IMAGE                                               COMMAND                  CREATED         STATUS                   PORTS                   NAMES
459b3370e94d   nginx:v1.5                                          "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds (healthy)   0.0.0.0:49157->80/tcp   web

如果检查连续失败重试次数,状态会变为unhealthy。检查命令输出回春在健康状态里,可以使用docker inspect来看

[root@centos7-11 docker_file]# docker inspect --format '{{json .State.Health}}' web | python -m json.tool
{
    "FailingStreak": 0,
    "Log": [
        {
            "End": "2021-01-07T20:09:58.675303046+08:00",
            "ExitCode": 0,
            "Output": "<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</title>\n<style>\n    body {\n        width: 35em;\n        margin: 0 auto;\n        font-family: Tahoma, Verdana, Arial, sans-serif;\n    }\n</style>\n</head>\n<body>\n<h1>Welcome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.</p>\n\n<p>For online documentation and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCommercial support is available at\n<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n<p><em>Thank you for using nginx.</em></p>\n</body>\n</html>\n",
            "Start": "2021-01-07T20:09:58.616761667+08:00"
        },

ONBUILD延迟构建

这个指令之后跟着的其他指令在当前镜像构建时不会被执行,只有以当前镜像作为基础镜像(FROM)去构建新镜像的时候才会被执行。

ONBUILD <其它指令>

LABEL 为镜像添加元数据

为镜像以键值对的形式添加一些元数据

LABEL <key>=<value> <key>=<value> <key>=<value> ...

添加标签测试

[root@centos7-11 docker_file]# cat Dockerfile 
FROM nginx
LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"
[root@centos7-11 docker_file]# docker build -t nginx:v1.6  .
[root@centos7-11 docker_file]# docker images
REPOSITORY                                                        TAG        IMAGE ID       CREATED              SIZE
nginx                                                             v1.6       d6d62f4cd9e0   About a minute ago   133MB
[root@centos7-11 docker_file]# docker image  inspect  --format=""   d6d62f4cd9e0
[
    {
...........................................
      "Comment": "",
        "Created": "2021-01-07T14:35:48.170668985Z",
        "Container": "86ba98ec7267cd66d3e0922109f6c974002d3071b659e86cad5e7fa5094ffff8",
        "ContainerConfig": {
...................................................
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>",
                "multi.label1": "value1",
                "multi.label2": "value2",
                "other": "value3"
            },
            "StopSignal": "SIGQUIT"
        },
        "DockerVersion": "20.10.1",
        "Author": "",
        ..................................


SHELL

该SHELL指令允许覆盖用于命令的shell形式的默认shell 。在Linux上默认shell是["/bin/sh", "-c"],在Windows上,默认shell是["cmd", "/S", "/C"]。该SHELL指令必须在Dockerfile中以JSON形式编写。可以指定 RUN ENTRYPOINT CMD 指令的 shell

SHELL ["executable", "parameters"]

参考文档:https://docs.docker.com/engine/reference/builder/

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

推荐阅读更多精彩内容