Dockerfile¶
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明
1 常用指令¶
# syntax=docker/dockerfile:1
FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py
FROM
: 指明基础镜像,每一个 dockeefile 文件都必须从FROM
开始COPY
: 从本地拷贝文件到指定的镜像中位置RUN
: 执行命令并创建新的镜像层,通常用于安装软件包CMD
: 设置容器启动后默认执行的命令,但会被docker run
命令后面的命令行参数替换
2 注释¶
dockerfile的注释同shell脚本,首行字母#表示注释
3 COPY 和 ADD¶
title: 语法格式
- `ADD [--chown=<user>:<group>] <src>... <dest>`
- `ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]`
- `--chown`用于修改文件的所属组,只能用在linux容器上
1. 当源文件是目录时,不是直接拷贝目录,而是<font color=#FF0211>将目录下的文件拷贝到容器里面</font>,所以我们需要避免拷贝过程污染目标目录
2. COPY也支持模糊匹配,如:`*`、`?`,规则参考[Go匹配规则](https://pkg.go.dev/path/filepath#Match)
- 当 COPY 多个文件时,容器内目录需要以/结尾
- 当 COPY 的源路径是文件时,目标路径不以/结尾,则解析目标路径是文件;以/结尾,则解析目标路径为目录;将源文件拷贝到目标目录中
- 当 COPY 的源路径是目录时,不管目标路径是否以/结尾,都会把目标路径当成目录;将 源目录下的文件拷贝到目标目录下
- 当源路径不存在时会自动创建
- 示例
COPY hom* /mydir/
COPY --chown=55:mygroup hom?.txt /mydir/
title: 拷贝多个文件,目标路径没有以/结尾错误提示
When using COPY with more than one source file, the destination must be a directory and end with a /
4 CMD 和 ENTRYPOINT¶
*注意*:
- CMD指令会被run最后的指令替换,CMD和ENTRYPOINT只能存在一个,如果有多个,最后一个才是有效的。
- shell脚本首行指定脚本解释器,如指定`#!/usr/bin/bash`,否则docker可能使脚本执行失败,导致容器启动失败
CMD
语法:CMD ["executable","param1","param2"]
(exec 格式)CMD command param1 param2
(shell 格式,默认会被解析为sh -c command param1 param2
)CMD ["param1","param2"]
(当有 ENTRYPOINT 时,只作为 ENTRYPOINT 参数,附加在 ENTRYPOINT 命令后面)ENTRYPOINT
语法:ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
- 示例 1:
FROM ubuntu
CMD ["/usr/bin/wc","--help"]
- 示例 2
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
5 EXPOSE¶
`EXPOSE` 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。
在 Dockerfile 中写入这样的声明有两个好处:
1. 一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
2. 另一个用处则是在运行时使用随机端口映射时,也就是 `docker run -P` 时,会自动随机映射 `EXPOSE` 的端口。
- 功能:声明需要公开的容器端口,通常在 run 选项中通过
-P
来将 EXPOSE 中定义的端口暴露出来 - 语法:
EXPOSE <port> [<port>/<protocol>...]
- 示例:
FROM ubuntu:20.04
EXPOSE 80/tcp
EXPOSE 80/udp
$ docker build -f my_ubuntu3 -t my_ubuntu:20.04 .
$ docker run -it -P --rm my_ubuntu3:20.04 /bin/bash
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
db02f8b2ecbe my_ubuntu:20.04 "/bin/bash" 5 seconds ago Up 2 seconds 0.0.0.0:49153->80/tcp, 0.0.0.0:49153->80/udp eloquent_tereshkova
6 ARG 和 ENV¶
- ENV 定义的环境变量可以被`docker run --env <key>=<value>`时修改
都是定义变量的作用,区别如下
- ARG
:
- 变量只限于 dockerfile 里面
- 当 ARG 出现在 FROM 前时,只能用于 FROM 指令中,FROM 之后的指令不会生效
- ARG 是唯一一个可以出现在 FROM 之前的指令
- ENV
: 定义的是环境变量,不仅在 dockerfile 中生效,也能作为镜像生成的容器的环境变量
- 示例 1:ARG 出现在 FROM 前
ARG VERSION=20.04
FROM ubuntu:$VERSION
ENV VERSION2=$VERSION
$ docker build -f my_ubuntu -t my_ubuntu:20.04 .
$ docker run -it my_ubuntu:20.04 /bin/bash
root@2b61dbdd9138:/# echo $VERSION2
root@2b61dbdd9138:/# echo $VERSION
- 输出分析:
- VRERION 为空说明 ARG 不能作用在容器中
- VERSION2 为空,说明 FROM 前的 ARG 不能在 FROM 后生效
- 示例 2:ARG 在 FROM 后
ARG VERSION1=20.04
FROM ubuntu:$VERSION1
ARG VERSION2=20.04
ARG VERSION1
ENV VERSION11=$VERSION1 VERSION22=$VERSION2
$ docker build -f my_ubuntu2 -t my_ubuntu:20.04 .
$ docker run -it --rm my_ubuntu:20.04 /bin/bash
root@9d17a34421e4:/# echo $VERSION11
20.04
root@9d17a34421e4:/# echo $VERSION22
20.04
- 输出分析:
- VERSION11=20.04 表示在 FROM 后的 ARG 生效
- VERSION22=20.04 表示如果要使用 FROM 之前的 ARG,可以在 FROM 后使用
ARG 变量
使生效
7 WORKDIR¶
- 功能:指定进入容器后的默认工作目录
- 语法:
WORKDIR /path/to/workdir
- 示例
FROM ubuntu:20.04
WORKDIR /home/root
$ docker run -it -P --rm my_ubuntu:20.04 /bin/bash
root@5070c2aa2879:/home/root# pwd
/home/root
8 USER¶
- 功能:用于指定后续如 RUN、CMD、ENTRYPOINT 等指令执行的用户(此用户必须已经存在,可以通过 RUN 命令创建用户)
- 语法:
USER <user>[:<group>]
USER <UID>[:<GID>]
- 示例: 创建用户和组,并切换用户
FROM ubuntu:20.04
RUN useradd -m user1 &&\
groupadd g1200 -g 1200
USER user1:g1200
$ docker run -it --rm my_ubuntu:20.04 /bin/bash
user1@d5e09cbda6b4:/$ id
uid=1000(user1) gid=1200(g1200) groups=1200(g1200)
9 VOLUME¶
- 功能:指定容器内挂载点(但不能指定本地挂载点,本地挂载点由 docker 自动生成,因此一般不使用,一般在 run 选项中 -v 挂载)
10 SHELL¶
- 语法:
SHELL ["executable", "parameters"]
- 功能:
SHELL
指令可以指定RUN
ENTRYPOINT
CMD
指令的 shell,Linux 中默认为["/bin/sh", "-c"]
,并影响所有后续指令 - 示例:第一条 RUN,会以
/bin/bash -c ls
执行,第一条 RUN 会以/bin/bash -cex ls
执行
SHELL ["/bin/sh", "-c"]
RUN ls
SHELL ["/bin/sh", "-cex"]
RUN ls
11 LABEL¶
- 语法:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
- 功能:给镜像添加元信息
- 示例
LABEL "com.example.vendor"="ACME Incorporated"
LABEL version="1.0"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
12 多行命令和减少镜像层¶
\
: 多行命令用\
区分(和 c 语法一样)&&
: 连续多条RUN
指令通过&&
来连接(和 shell 语法一样)- 示例
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz