首页 Docker教程docker-dockerfile指令详细介绍

docker实战-dockerfile制作镜像

dockerfile实战-制作基础镜像的Base镜像

运维派隶属马哥教育旗下专业运维社区,是国内成立最早的IT运维技术社区,欢迎关注公众号:yunweipai
领取学习更多免费Linux云计算、Python、Docker、K8s教程关注公众号:马哥linux运维

Dockerfile 相关指令

dockerfile 文件中的常见指令:

ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR

FROM:指定基础镜像

定制镜像,需要先有一个基础镜像,在这个基础镜像上进行定制。FROM 就是指定基础镜像,此指令必需放在有效指令的第一行。怎么选择合适的镜像呢?对于不同的软件官方都提供了相关的docker镜像,比如:nginx、redis、mysql、httpd、tomcat等服务类的镜像,也有操作系统类,如:centos、ubuntu、debian等。建议使用官方镜像,比较安全。

格式:

FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

说明:
--platform 指定镜像的平台,比如:linux/amd64, linux/arm64, or windows/amd64
tag 和 digest是可选项,如果不指定,默认为latest

范例:

FROM scratch #所有镜像的起源镜像,相当于Object类
FROM ubuntu
FROM ubuntu:bionic
FROM debian:buster-slim

LABEL:指定镜像元数据

可以指定镜像元数据,如:镜像作者等

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

范例:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

范例:多标签写法

LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

docker inspect 命令可以查看LABEL

范例:

"Labels": {
    "com.example.vendor": "ACME Incorporated"
    "com.example.label-with-value": "foo",
    "version": "1.0",
    "description": "This text illustrates that label-values can span multiple lines.",
    "multi.label1": "value1",
    "multi.label2": "value2",
    "other": "value3"
},

MAINTAINER: 指定维护者信息

此指令已过时,用LABEL代替

MAINTAINER <name>

范例:

MAINTAINER wangxiaochun <root@wangxiaochun.com>
#用LABEL代替
LABEL maintainer="wangxiaochun <root@wangxiaochun.com>"

RUN:执行shell命令

RUN 指令是用来执行命令的。shell命令功能丰富,所以RUN 指令经常用来调用shell指令

注意:run可以写多个,每一个run指令都会建立一层,所以尽可能合并成一条指令

#shell 格式: 
RUN <命令> 

#exec 格式: 
RUN ["可执行文件", "参数1", "参数2"]

范例:

RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
RUN ["/bin/bash", "-c", "echo hello world"]
RUN yum -y install epel-release \
      && yum -y install nginx \
      && rm -rf /usr/share/nginx/html/*
      && echo "<h1> docker test nginx </h1>" > /usr/share/nginx/html/index.html

COPY:复制文本

复制本地主机的 (为 Dockerfile 所在目录的相对路径)到容器中的

COPY <src>... <dest>
COPY ["<src1>",... "<目标路径>"]

说明:

  • 可以是多个、以及使用通配符,通配符规则满足Go的filepath.Match 规则
  • 使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
  • 如果是目录,只复制目录内容,而非目录本身

范例:

COPY hom* /mydir/    COPY hom?.txt /mydir/

ADD:复制和解包文件

该命令可认为是增强版的COPY,不仅支持COPY,还支持解缩。可以将复制指定的 到容器中的 。 其中 可以是Dockerfile所在目录的一个相对路径;也可是一个 URL;还可是一个 tar 文件(自动解压)。

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] 

说明:

  • 如果src是目录,只复制目录中的内容,而非目录本身
  • 如果src是本地打包或压缩文件,如gzip, bzip2 ,xz ,将解包
  • 如果src是一个 URL ,下载后的文件权限自动设置为 600

范例:

ADD test relativeDir/          # adds "test" to WORKDIR/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /

CMD:容器启动命令

指定启动容器时默认执行的命令,即:如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT,那么就会使用执行CMD指定的默认的命令

每个 Dockerfile 只能有一条 CMD 命令。如指定了多条,只有最后一条被执行

如果用户启动容器时指定了运行的命令,如:docker run xxx /bin/bash,则/bin/bash 会覆盖 CMD 指定的命令

# 使用 exec 执行,推荐方式,第一个参数必须是命令的全路径
CMD ["executable","param1","param2"] 

# 在 /bin/sh 中执行,提供给需要交互的应用;
CMD command param1 param2 

# 提供给 ENTRYPOINT 的默认参数;
CMD ["param1","param2"] 

范例:

CMD ["nginx", "-g", "daemon off;"]

范例:

FROM ubuntu:18.04
RUN apt update \
&& apt -y install  curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s","https://ip.cn"]

[root@centos8 ubuntu]#podman  run  9b cat /etc/issue
Ubuntu 18.04.4 LTS \n \l

[root@centos8 ubuntu]#podman  run  9b
{"ip": "111.199.187.36", "country": "北京市", "city": "联通"}

#cat /etc/etc/issue覆盖了curl命令
[root@centos8 ubuntu]#podman  run  9b cat /etc/issue
Ubuntu 18.04.4 LTS \n \l

ENTRYPOINT:入口点

功能类似于CMD,配置容器启动后执行的命令及参数,并且不可被 docker run 提供的参数覆盖,而是追加

如果docker run命令有参数,那么参数全部都会作为ENTRYPOINT的参数。如果docker run后面没有额外参数,但是dockerfile中的CMD里有(即上面CMD的第三种用法),那么CMD的全部内容会作为ENTRYPOINT的参数

可以通过docker run –entrypoint 参数在运行时替换

使用CMD要在运行时重新写命令才能追加运行参数,ENTRYPOINT则可以运行时接受新参数

每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个生效

# 使用 exec 执行
ENTRYPOINT ["executable", "param1", "param2"]

# shell中执行
ENTRYPOINT command param1 param2

范例:

FROM ubuntu:18.04
RUN apt update \
&& apt -y install  curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s","https://ip.cn"]

[root@centos8 ubuntu]#podman run -it --rm f68e006 
{"ip": "111.199.187.36", "country": "北京市", "city": "联通"}

#追加-i参数
[root@centos8 ubuntu]#podman run -it --rm f68e006  -i
HTTP/2 200 
date: Sun, 23 Feb 2020 08:05:19 GMT
content-type: application/json; charset=UTF-8
set-cookie: __cfduid=d4a22496ea6f3b2861763354f8ca600711582445119; expires=Tue, 24-Mar-20 08:05:19 GMT; path=/; domain=.ip.cn; HttpOnly; SameSite=Lax
cf-cache-status: DYNAMIC
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
alt-svc: h3-25=":443"; ma=86400, h3-24=":443"; ma=86400, h3-23=":443"; ma=86400
server: cloudflare
cf-ray: 5697b1ac1862eb41-LAX

{"ip": "111.199.187.36", "country": "北京市", "city": "联通"}

ENV:设置环境变量

指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持

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

范例:

ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ARG:构建参数

指定变量

ARG <name>[=<default value>]

如果和ENV同名,ENV覆盖ARG变量

和ENV不同的是,容器运行时不会存在这些环境变量

可以用 docker build –build-arg <参数名>=<值> 来覆盖

范例:

FROM busybox
ARG user1=someuser
ARG buildno=1

FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS

VOLUME:挂载点

在容器中创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等,一般会将宿主机上的目录/var/lib/containers/storage/volumes/<id>/_data挂载至VOLUME 指令指定的容器目录。即使容器后期删除,此宿主机的目录仍会保留,从而实现容器数据的持久保存。

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

范例:在容器创建一个/data/ 的挂载点

VOLUME [ "/data","/data2" ]  

范例:

[root@centos8 ~]#cat /data/dockerfile/system/alpine/Dockerfile 
FROM alpine:3.11 
LABEL maintainer="wangxiaochun <root@wangxiaochun.com>"
COPY repositories /etc/apk/repositories 
VOLUME [ "/testdata" , "/testdata2" ]

[root@centos8 alpine]#podman run -it --rm 8ef61dd3959da3f sh
/ # df 
Filesystem           1K-blocks      Used Available Use% Mounted on
overlay              104806400   3656380 101150020   3% /
tmpfs                    65536         0     65536   0% /dev
/dev/sda2            104806400   3656380 101150020   3% /testdata2
/dev/sda2            104806400   3656380 101150020   3% /testdata
/ # cp /etc/issue  /testdata/f1.txt
/ # cp /etc/issue  /testdata2/f2.txt

[root@centos8 ~]#tree /var/lib/containers/storage/volumes/
/var/lib/containers/storage/volumes/
├── 725f0f67921bdbffbe0aaf9b015d663a6e3ddd24674990d492025dfcf878529b
│   └── _data
│       └── f1.txt
└── fbd13e5253deb375e0dea917df832d2322e96b04ab43bae061584dcdbe7e89f2
    └── _data
        └── f2.txt

4 directories, 2 files

EXPOSE:暴露端口

告诉 Docker 服务端容器暴露的端口号,供互联系统使用。

EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射

因此,在启动容器时需要通过 -P 或-p ,Docker 主机会分配一个端口转发到指定暴露的端口,才可以使用

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

WORKDIR:指定工作目录

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录,当容器运行后,进入容器内的默认目录

WORKDIR /path/to/workdir

范例:

#两次run不在一个环境内,可以使用WORKDIR
RUN cd /app
RUN echo "hello" > world.txt

可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则最终路径为 /a/b/c

ONBUILD:子镜像引用父镜像的指令

可以用来配置当创建当前镜像的子镜像时,会自动触发执行的指令。

ONBUILD [INSTRUCTION]。

例如,Dockerfile 使用如下的内容创建了镜像 image-A。

...
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src...

如果基于 image-A 创建新的镜像时,新的Dockerfile中使用 FROM image-A指定基础镜像时,会自动执行ONBUILD 指令内容,等价于在后面添加了两条指令。

FROM image-A

#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

使用 ONBUILD 指令的镜像,推荐在标签中注明,例如 ruby:1.9-onbuild

USER:指定当前用户

指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户

当服务不需要管理员权限时,可以通过该命令指定运行用户

这个用户必须是事先建立好的,否则无法切换

要临时获取管理员权限可以使用 gosu,而不推荐 sudo

USER <user>[:<group>] 
USER <UID>[:<GID>]

范例:

RUN groupadd -r mysql && useradd -r -g mysql mysql
USER mysql

HEALTHCHECK:健康检查

检查容器的健康性

HEALTHCHECK [选项] CMD <命令> #设置检查容器健康状况的命令
HEALTHCHECK NONE #如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 支持下列选项:
--interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
--timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
--retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3次。

范例

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

STOPSIGNAL:退出容器的信号

STOPSIGNAL指令设置将被发送到容器退出的系统调用信号。该信号可以是与内核syscall表中的位置匹配的有效无符号数字(例如9),也可以是SIGNAME格式的信号名称(例如SIGKILL)

STOPSIGNAL signal

.dockerignore文件

官方文档:https://docs.docker.com/engine/reference/builder/#dockerignore-file
与.gitignore文件类似,生成构建上下文时Docker客户端应忽略的文件和文件夹指定模式。

以下是完整的语法:
'*'      匹配任何非分隔符字符序列
'?'     匹配任何单个非分隔符
'['['^'] {character-range}']'
字符类(必须是非空的)
c匹配字符c  (c!='*','?','\\','[')
'\\'    表示  \

'**'    匹配任意数量的目录(包括零)例如,**/*.go将排除.go 在所有目录中找到的以该结尾的所有文件,包括构建上下文的根。
'!'    表示取反,可用于排除例外情况
以此字符开头的'#'行将被忽略:将其用于注释

范例:

#排除 test 目录下的所有文件
test/*
#排除 md 目录下的 xttblog.md 文件
md/xttblog.md
#排除 xttblog 目录下的所有 .md 的文件
xttblog/*.md
#排除以 xttblog 为前缀的文件和文件夹
xttblog?
#排除所有目录下的 .sql 文件夹
**/*.sql 

范例:

#除了README的md不排外,排除所有md文件,但不排除README-secret.md
*.md
!README*.md
README-secret.md

#除了所有README的md文件以外的md都排除
*.md
README-secret.md
!README*.md

Dockerfile文件指令总结

docker-dockerfile指令详细介绍插图

本文链接:https://www.yunweipai.com/34830.html

docker实战-dockerfile制作镜像

dockerfile实战-制作基础镜像的Base镜像

网友评论comments

发表回复

您的电子邮箱地址不会被公开。

暂无评论

Copyright © 2012-2022 YUNWEIPAI.COM - 运维派 京ICP备16064699号-6
扫二维码
扫二维码
返回顶部