跳转至

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