Dockerfile Introduction
Go 项目创建 Dockerfile
Dockerfile 的主要结构#
FROM#
FROM 为你要定制的镜像选择基础镜像
| Docker | |
|---|---|
ARG是唯一可能在FROM之前出现的指令- 单个
Dockerfile中可以出现多次FROM命令,用来创建多个镜像,或使用一个构建阶段作为另一个构建阶段的依赖项 - 可以选择通过添加
AS name到FROM指令来为新的构建阶段命名。该名称可在后续FROM和COPY --from=<name>说明中用于引用此阶段构建的镜像。 - 该
tag或digest值是可选的。如果您省略其中任何一个,构建器默认使用一个latest标签。如果找不到该tag值,构建器将返回错误。
--platform可以指定构建的目标平台,可以指定linux/amd64, linux/arm64, windows/amd64, 默认使用当前平台(--platform=$BUILDPLATFORM)
RUN#
RUN 用于执行后面跟着的命令行格式,有 shell 和 exec 两种格式,
- shell: 使用 Linux平台的
/bin/sh -c或 windows平台的cmd /S /S执行命令
- exec
| Docker | |
|---|---|
Dockerfile 的指令每执行一次都会在 docker 上新建一层。过多无意义的层,会造成镜像膨胀过大。所以可以将部分指令进行简化,合并到同一层,
| Bash | |
|---|---|
EXPOSE#
| Docker | |
|---|---|
EXPOSE指令通知 Docker , 容器在运行时侦听指定的网络端口。可以指定端口是监听TCP还是UDP,如果不指定协议,默认为TCP。
该EXPOSE指令实际上并未暴露端口。它充当构建镜像的人和运行容器的人之间的一种文档,关于打算暴露哪些端口。要在运行容器时实际暴露端口,请在docker run中使用-p标志 来暴露和映射一个或多个端口,或者使用-P标志来发布所有暴露的端口并将它们映射到高阶端口。EXPOSE默认使用TCP,也能手动指定UDP。
无论EXPOSE设置的如何,在运行时都可以用-p覆盖它们。
| Bash | |
|---|---|
docker network 命令支持创建用于容器间通信的网络,而无需公开或发布特定端口,因为接到该网络的容器可以通过任何端口相互通信。
ENV#
| Docker | |
|---|---|
ENV设置环境变量,用在后续构建阶段的环境中,也用在许多变量内联替换中。
使用ENV设置的环境变量,将在容器运行时始终存在。使用命令docker inspect可以查看环境变量的值,也可以使用docker run --env <key>=<value>修改运行时的环境变量。
如果仅在构建阶段使用到这个变量,而不是在最终的镜像中,可以在单个命令中设置该值,而非设置成环境变量。
| Docker | |
|---|---|
CMD#
一个Dockerfile只能指定一个CMD指令,若是有多个CMD指令,只有最后一个是生效的。CMD指令的目的是为了给“执行容器”一个默认的执行程序。
CMD 指令有三种形式:
CMD ["executable","param1","param2"](exec 形式,这是首选形式)CMD ["param1","param2"](作为 ENTRYPOINT 的默认参数)CMD command param1 param2(shell 形式)
ENTRYPOINT#
ENTRYPOINT有两种形式:
优先选用EXEC形式:
| Docker | |
|---|---|
shell形式:
| Docker | |
|---|---|
ENTRYPOINT允许你将容器配置成是“可执行”的。
docker run <image>的命令行参数将会附加到exec形式的ENTRYPOINT后面,同时也会覆盖所有CMD指令参数。例如,docker run <image> -d中的-d参数将会附加到entry point 后面。使用docker run --entrypoint标志可以覆盖ENTRYPOINT指令。
shell形式的ENTRYPOINT将会阻止CMD或docker run命令行参数。但是这种形式的ENTRYPOINT有个缺点,它会使用命令/bin/sh -c启动,并且不通过信号量机制。这意味着这个进程的PID不是1(sh 的PID才是1),并且收不到Unix的信号量,所以收不到docker stop <container>发送来的信号。
若有多个ENTRYPOINT指令,只有最后一个是有效的。
Exec形式的ENTRYPOINT示例
使用exec形式的ENTRYPOINT设置固定的参数,使用CMD指令设置可更改的参数的默认值。
默认执行docker run <image>执行的是top -b -c,而docker run <image> -H执行的是top -b -H.(CMD指令指定的参数被覆盖了)
Shell形式的ENTRYPOINT示例
shell形式的ENTRYPOINT指令将会在/bin/sh -c中执行。这种形式运行的程序将会忽略CMD和docker run指定的所有参数。
为了保证收到docker stop的信号,命令可以以exec开头:
以exec开头的shell形式的ENTRYPOINT指令,PID仍然是1.
CMD和ENTRYPOINT交互
指令CMD和ENTRYPOINT都指定了容器运行的命令,下面是两者交互的规则:
- Dockerfile中至少有一个
CMD或ENTRYPOINT指令 - 将容器作为一个执行体的时候应该定义
ENTRYPOINT指令 CMD指令应该定义ENTRYPOINT指令的默认参数,或者执行容器的临时命令- 当容器运行使用了其他参数,
CMD指令将被覆盖
如果CMD是在基础镜像中定义的,ENTRYPOINT将会重置CMD。在这种情况下,CMD必须在当前镜像中重新定义一个新值。
影响镜像大小的原因#
- 选择的基础镜像的大小会影响定制镜像的大小
这里有一些适用于 Linux 生产环境的基础镜像,
| 镜像名称 | 大小 | 使用场景 |
|---|---|---|
| busybox | 1.15MB | 临时测试用,超级简化版嵌入式Linux系统 |
| alpine | 4.41MB | 主要用于测试,也可用于生产环境,面向安全的、轻量级的Linux系统 |
| centos | 200MB | 主要用于生产环境,支持CentOS/Red Hat,常用于追求稳定性的企业应用 |
| ubuntu | 81.1MB | 主要用于生产环境,常用于人工智能计算和企业应用 |
| debian | 101MB | 主要用于生产环境 |
如果你不想使用任何镜像作为基础镜像或不需要基础镜像,可以使用 scratch 作为基础镜像,这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言开发的应用很多会使用这种方式来制作镜像。
- Dockerfile 的指令每执行一次都会在 docker 上新建一层。过多无意义的层,会造成镜像膨胀过大。
Dockerfile 使用说明 - 知乎 (zhihu.com) go项目创建Dockerfile,构建docker镜像 - 水木神舟10 - 博客园 (cnblogs.com)
创建日期: September 24, 2023