使用Dockerfile创建镜像
Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。
1、基本结构
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。
一般而言,Dockerfile主体内容分为四部分:基础镜像镜像、维护者信息、镜像操作指令和容器启动时执行指令
2、指令说明
Dockerfile中指令的一般格式为:INSTRUCTION arguments,包括配置指令(配置镜像信息)和操作指令(具体执行操作)
分类 | 指令 | 说明 |
---|---|---|
配置指令 | ARG | 定义创建镜像过程中使用的变量 |
FROM | 指定所创建镜像的基础镜像 | |
LABEL | 为生成的镜像添加元数据标签信息 | |
EXPOSE | 声明镜像内服务监听的端口 | |
ENV | 指定环境变量 | |
ENTRYPOINT | 指定镜像的默认入口命令 | |
VOLUME | 创建一个数据卷挂载点 | |
USER | 指定运行容器时的用户名或UID | |
WORKDIR | 配置工作目录 | |
ONBUILD | 创建子镜像时指定自动执行的操作指令 | |
STOPSIGNAL | 指定退出的信号值 | |
HEALTHCHECK | 配置所启动容器如何进行健康检查 | |
SHELL | 指定默认shell类型 | |
操作指令 | RUN | 运行指定命令 |
CMD | 启动容器时指定默认执行的命令 | |
ADD | 添加内容到镜像 | |
COPY | 复制内容到镜像 |
2.1、配置指令介绍
ARG
定义创建镜像过程中使用的变量
格式:
ARG <name>[=<default value>]
在执行docker build时,可以通过-build-args[=]来为变量赋值。当镜像编译成功后,ARG指定的变量将不再存在(ENV指定的变量将在镜像中保留)
Docker内置了一些镜像创建变量,用户可以直接使用而无须声明,包括(不区分大小写)HTTP_PROXY、HTTPS_PROXY、FTP_PROXY、NO_PROXY。
FROM
指定所创建镜像的基础镜像
格式:
FROM <image> [AS <name>] 或 FROM <image>:<tag> [AS <name>] 或 FROM <image>@<digest> [AS <name>]
任何Dockerfile中第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM镜像(每个镜像一次)。
为了保证镜像精简,可以选用体积较小的镜像如Alpine或Debain作为基础镜像。
LABEL
LABEL指令可以为生成的镜像添加元数据标签信息。这些信息可以用来辅助过滤出特定镜像。
格式:
LABEL <key>=<value> <key>=<value> <key>=<value>...
EXPOSE
声明镜像内服务监听的端口。
格式:
EXPOSE <port> [<port>/<protocol>...]
eg:
EXPOSE 22 80 8443
注意:该指令只是起到声明作用,并不会自动完成端口映射。
如果要映射端口出来,在启动容器时可以使用-P参数(Docker主机会自动分配一个宿主机的临时端口)或-p HOST_PORT:CONTAINER_PORT参数(具体指定所映射的本地端口)
ENV
指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。
格式:
ENV <key> <value> 或 ENV <key>=<value>
eg:
ENV APP_VERSION=1.0.0 ENV APP_HOME=/usr/local/app ENV PATH $PATH:/usr/local/bin
指令指定的环境变量在运行时可以被覆盖掉,如docker run --env
注意:当一条ENV指令中同时为多个环境变量赋值且值也是从环境变量读取时,会为变量都赋值后再更新。
如下面的指令,最终结果为:key1=value1 key2=value2
ENV key1=value2 ENV key1=value1 key2=${keys1}
ENTRYPOINT
指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。
支持以下两种格式:
#exec调用执行 ENTRYPOINT ["executable","param1","param2"]、 #shell中执行 ENTRYPOINT command param1 param2
此时,CMD指令指定值将作为根命令的参数。
每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效。
在运行时,可以被--entrypoint参数覆盖掉,如:docker run --entrypoint(即覆盖Dockerfile文件中ENTRYPOINT指令)
VOLUME
创建一个数据挂载点
格式:
VOLUME ["/data"]
运行容器时可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保持的数据等。
USER
指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份。
格式:
USER daemon
当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在Dockerfile中创建所需要的用户,例如:
RUN groupadd -r postgres && useradd --no-log-init -r -g postgress postgres
如要临时获取管理员权限可以使用goru命令。
WORKDIR
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
格式:
WORKDIR /path/to/workdir
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
WORKDIR /a WORKDIR b WORKDIR c #最终路径为:/a/b/c
因此,为了避免出错,推荐WORKDIR指令中只使用绝对路径
ONBUILD
指定当基于所生成镜像创建子镜像时,自动执行的操作指令。
格式:
ONBUILD [INSTRUCYION]
例如,使用如下的Dockerfile创建父镜像ParentImage,指定ONBUILD指令:
#Dockerfile for ParentImage [...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
使用docker build命令创建子镜像ChildImage时(FROM ParentImage),会首先执行ParentImage中配置的ONBUILD指令:
#Dockerfile for ChildImage FROM ParentImage
等价于在ChildImage的Dockerfile中添加了如下指令:
[...] ADD . /app/src RUN /usr/local/bin/python-build --dir /app/src ...
由于ONBUILD指令是隐式执行的,推荐在使用它的镜像标签中进行标注,如:ruby:2.1-onbuild
ONBUILD指令在创建专门用于自动编译、检查等操作的基础镜像时,十分有用。
STOPSIGNAL
指定所创建镜像启动的容器接收退出的信号值
格式:
STOPSIGNAL signal
HEALTHCHECK
配置所启动容器如何进行健康检查(如何判断健康与否)。
格式有两种:
#根据所执行命令返回值是否为0来判断 HEALTHCHECK [OPTIONS] CMD command #禁止基础镜像中的健康检查 HEALTHCHECK NONE
OPTION支持如下参数:
- -interval=DURATION(default:30s):过多久检查一次
- -timeout=DURATION(default:30s):每次检查等待结果的超时
- -retries=N(default:3):如果失败了,重试几次才最终确定失败。
SHELL
指定其他命令使用shell时的默认shell类型
格式:
SHELL ["executable","parameters"]
默认值为["/bin/sh","-C"]
注意:对于windows系统,shell路径中使用了“\”作为分隔符,建议在Dockerfile开头添加”#escape=“来指定转义符。
2.2、操作指令介绍
RUN
运行指定命令
格式:
RUN <command> 或 RUN ["executable","param1","param2"]
注意:后者指令会被解析为JSON数组,因此必须使用双引号。前者默认将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行,不会启动shell环境。
指定使用其他终端类型可以通过exec方式实现,如:
RUN ["/bin/bsah","-c",“echo hello world"]
每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像层。当命令较长时,可用\来换行,如:
RUN apt-get update \ && apt-get install -y python3 libbz2-dev \ && rm -rf /var/cache/apt \ && rm -rf /var/lib/apt/list/*
CMD
CMD指令用来指定启动容器时默认执行的命令。
支持三种格式:
#推荐方式 CMD ["executable","param1","param2"] #在默认的shell中执行,提供给需要交互的应用 CMD command param1 param2 #提供给ENTRYPOINT的默认参数 CMD ["param1","param2"]
每个Dockerfile只能有一条CMD命令。如果指定了多条,只有最后一条会被执行。
如果用户启动容器时手动指定了运行的命令(作为run命令的参数),则会覆盖掉CMD指定的命令
ADD
添加内容到镜像
格式:
ADD <src> <dest> #该命令将复制指定的<src>路径下内容到容器中的<dest>路径下。
其中src可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL,还可以是一个tar文件(自动解压为目录);dest可以是镜像内绝对路径,或者相对于WORKDIR的相对路径。
COPY
复制内容到镜像
格式:
COPY <src> <dest>
复制本地主机的src(Dockerfile所在目录的相对路径、文件或目录)下内容到镜像中的dest。目标路径不存在时,会自动创建
COPY和ADD指令功能相似,当使用本地目录为源目录时,推荐使用COPY。
3、Dockerfile示例
FROM node MAINTAINER Taolei RUN git clone -q https://github.com/docker-in-practice/todo.git WORKDIR todo RUN npm install > /dev/null EXPOSE 8000 CMD ["npm","start"]
构建过程如下:
[root@aliyun docker]# pwd /home/docker #构建一个镜像 [root@aliyun docker]# docker build . Sending build context to Docker daemon 2.048kB Step 1/7 : FROM node latest: Pulling from library/node 0e29546d541c: Pull complete 9b829c73b52b: Pull complete cb5b7ae36172: Pull complete 6494e4811622: Pull complete 6f9f74896dfa: Pull complete f2930ff7fb60: Pull complete c1d26179dd86: Pull complete 1fa56dd41537: Pull complete 321141c774e9: Pull complete Digest: sha256:36aca218a5eb57cb23bc790a030591382c7664c15a384e2ddc2075761ac7e701 Status: Downloaded newer image for node:latest ---> a283f62cb84b Step 2/7 : MAINTAINER Taolei ---> Running in c367d3410334 Removing intermediate container c367d3410334 ---> e7567eaaf35c Step 3/7 : RUN git clone -q https://github.com/docker-in-practice/todo.git ---> Running in 9191275f23b1 Removing intermediate container 9191275f23b1 ---> 5d80658a509b Step 4/7 : WORKDIR todo ---> Running in f297028141cf Removing intermediate container f297028141cf ---> a81464358a14 Step 5/7 : RUN npm install > /dev/null ---> Running in 19d637151604 npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: 'minifyify@4.4.0', npm WARN EBADENGINE required: { node: '0.10.x' }, npm WARN EBADENGINE current: { node: 'v17.3.0', npm: '8.3.0' } npm WARN EBADENGINE } npm WARN deprecated graceful-fs@2.0.3: please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js npm WARN deprecated buffer-browserify@0.2.5: Package not maintained. Recent browserify uses https://github.com/feross/buffer npm WARN deprecated mkdirp@0.3.5: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) npm WARN deprecated mkdirp@0.3.5: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue npm WARN deprecated react-tools@0.11.2: react-tools is deprecated. For more information, visit https://fb.me/react-tools-deprecated npm notice npm notice New minor version of npm available! 8.3.0 -> 8.6.0 npm notice Changelog: <https://github.com/npm/cli/releases/tag/v8.6.0> npm notice Run `npm install -g npm@8.6.0` to update! npm notice Removing intermediate container 19d637151604 ---> d1b737e8b68f Step 6/7 : EXPOSE 8000 ---> Running in 27157638d7d6 Removing intermediate container 27157638d7d6 ---> 6fafd82e1672 Step 7/7 : CMD ["npm","start"] ---> Running in fe6d70c5ec05 Removing intermediate container fe6d70c5ec05 ---> eafa085c10fa Successfully built eafa085c10fa
步骤说明:
- docker会上传docker build指定目录下的文件和目录
- 每个构建步骤从1开始按顺序编号,并与命令一起输出
- 每个命令会导致一个新镜像被创建出来,其镜像ID在此输出
- 为节省空间,在继续前每个中间容器会被移除
- 构建的调试信息在此输出
- 此次构建的最终镜像ID,可用于打标签
打标签
#打标签前 [root@aliyun docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> eafa085c10fa 7 minutes ago 1.1GB busybox latest beae173ccac6 3 months ago 1.24MB node latest a283f62cb84b 3 months ago 993MB #打标签时 [root@aliyun docker]# docker tag eafa085c10fa todoapp #打标签后 [root@aliyun docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE todoapp latest eafa085c10fa 8 minutes ago 1.1GB busybox latest beae173ccac6 3 months ago 1.24MB node latest a283f62cb84b 3 months ago 993MB
4、Dockerfile创建镜像过程
编写完Dockerfile之后,可使用docker build命令来创建镜像。基本格式为:
docker build [OPTIONS] PATH | URL | -
创建过程:
该命令将读取指定路径下(包括子目录)的Dockerfile,并将该路径下所有数据作为上下文发送给docker服务端。docker服务端在校验Dockerfile格式通过后,逐条执行其中定义的指令,碰到RUN、ADD和COPY指令会生成一层新的镜像。最后如果创建镜像成功,会返回最终镜像的ID。
如果上下文过大,会导致发送大量数据给服务端,延缓创建过程。故而除非是生成镜像所必须的文件,不然不要放在上下文路径下。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)