Dockerfile的语法及示例

前言

Dockerfile是用于构建Docker镜像的文本文件,其中包含一系列指令,用于描述镜像的构建步骤和配置信息。通过Dockerfile,可以让用户自动化地构建镜像,并确保在不同的环境中获得相同的镜像。

Dockerfile的语法包括以下几个关键指令:

  1. FROM:指定基础镜像,格式为FROM <image>,用于指定构建镜像所基于的基础镜像。
  2. MAINTAINER:指定镜像的作者和联系方式,格式为MAINTAINER <name>
  3. RUN:用于在镜像中执行命令,格式为RUN <command>,可以累积多个RUN指令以构建镜像。
  4. ADD和COPY:用于将文件或目录复制到镜像中,格式为ADD <src> <dest>COPY <src> <dest>
  5. CMD:指定容器启动时执行的默认命令,可以在Dockerfile中只有一个CMD指令,如果有多个CMD指令,只有最后一个生效。
  6. EXPOSE:声明容器在运行时需要监听的端口,格式为EXPOSE <port>
  7. ENV:设置环境变量,格式为ENV <key> <value>
  8. WORKDIR:指定在容器中执行命令的工作目录,格式为WORKDIR <path>
  9. ENTRYPOINT:配置容器启动时执行的命令,格式为ENTRYPOINT <command>
  10. VOLUME:声明容器数据卷,格式为VOLUME <path>

除了这些基本指令外,Dockerfile还支持其他一些指令,可以根据具体需求选择使用。

在编写Dockerfile时,建议遵循最佳实践,减少镜像大小、优化镜像构建速度,并保持Dockerfile的可读性和可维护性。

项目的根目录下添加Dockerfile文件

基本镜像

1
2
# Pull base image
FROM centos:7

作者信息

旧版本

1
MAINTAINER psvmc "psvmc@outlook.com"

新版本

1
2
# 使用 LABEL 指定维护者信息
LABEL maintainer="psvmc <psvmc@outlook.com>"

环境

1
2
3
4
5
# Set Charset
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

安装wget

1
2
# 安装 wget
RUN yum -y install wget

常见环境配置

YUM环境

阿里的

1
2
3
# YUM镜像
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum makecache

或者使用华为的

1
2
3
# YUM镜像
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.huaweicloud.com/repository/conf/CentOS-7-anon.repo
RUN yum makecache

注意

在华为云的服务器上用不了阿里云的镜像

安装Python2

1
2
3
# 安装Python
RUN yum install -y epel-release
RUN yum install -y python2

Python3环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Pull base image
FROM python:3.9.0

LABEL maintainer="psvmc <psvmc@outlook.com>"

# Set Charset
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8


# 创建 pip 配置目录
RUN mkdir -p /root/.pip

# 创建或修改 pip.conf 文件,指定清华镜像源
RUN echo "[global]" > /root/.pip/pip.conf && \
echo "index-url = https://mirrors.huaweicloud.com/repository/pypi/simple" >> /root/.pip/pip.conf

RUN pip install pipenv
RUN pip install cmake

安装FFMpeg

1
2
3
4
5
6
# 安装ffmpeg
RUN yum install epel-release -y
RUN yum update -y
RUN rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
RUN rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
RUN yum install ffmpeg ffmpeg-devel -y

安装C++编译环境

1
2
# 安装 gcc
RUN yum -y install gcc+ gcc-c++ automake autoconf libtool make

Node环境

安装NodeJS

1
2
3
4
5
6
RUN wget https://mirrors.huaweicloud.com/nodejs/v10.24.0/node-v10.24.0-linux-x64.tar.xz
RUN tar -xvf node-v10.24.0-linux-x64.tar.xz
RUN mv node-v10.24.0-linux-x64 /usr/local/nodejs10
RUN rm -rf node-v10.24.0-linux-x64.tar.xz
ENV NODE_HOME /usr/local/nodejs10
ENV PATH $PATH:$NODE_HOME/bin

NodeJS官方源地址

1
RUN wget https://nodejs.org/dist/v10.24.0/node-v10.24.0-linux-x64.tar.xz

设置NPM镜像

淘宝的

1
2
3
4
5
6
7
# NPM镜像
RUN npm config set registry https://registry.npmmirror.com/
RUN npm config set disturl https://npm.taobao.org/mirrors/node/
RUN npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
RUN npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
RUN npm config set python_mirror https://npm.taobao.org/mirrors/python/
RUN npm cache clean -f

华为的

1
2
3
4
# NPM镜像
RUN npm config set registry https://repo.huaweicloud.com/repository/npm/
RUN npm config set disturl https://repo.huaweicloud.com/nodejs
RUN npm cache clean -f

安装 node-gyp

1
2
# 安装 node-gyp
RUN npm install -g node-gyp@6.1.0

注意:

node-gyp 需要在系统中安装 C++ 编译器和 Python 环境。

项目配置

创建文件夹

1
RUN mkdir /data

进入文件夹

1
RUN cd /data

添加文件到容器内

1
ADD startup.sh /data/school_live_record/startup.sh

添加文件夹到容器内

1
ADD record /data/school_live_record/record

添加执行权限

1
RUN chmod +x /data/school_live_record/startup.sh

移动文件

1
RUN mv ./Agora_Recording_SDK_for_Linux_FULL/* /data/school_live_record/record/src/sdk/

删除文件

1
RUN rm -rf zxvf Agora_Recording_SDK_for_Linux_v3.0.5_20210106-1609927649_793.tar.gz

指定启动目录和程序

WORKDIR /data/school_live_record/
设置工作目录为/data/school_live_record/,这样后续的COPYRUNCMD指令都会在这个目录下执行。

配置

1
2
WORKDIR /data/school_live_record/
ENTRYPOINT ["./startup.sh"]

这两个指令在 Dockerfile 中扮演着不同的角色:

WORKDIR:

该指令用于设置容器中的工作目录。

在例子中,WORKDIR /data/school_live_record/ 会将容器的工作目录设置为 /data/school_live_record/,这意味着在后续的命令中,相对路径都会基于这个工作目录进行解析。

ENTRYPOINT:

该指令用于配置容器启动时执行的默认命令。

在例子中,ENTRYPOINT ./startup.sh 指定了容器启动时需要执行的脚本或命令,这个命令会成为容器的主要进程。

如果你在运行容器时提供了其他命令,它们会被作为参数传递给 ENTRYPOINT 指定的命令。

因此,这两个指令结合起来的作用是,在容器启动时,首先将工作目录设置为指定的目录,然后执行 startup.sh 脚本作为容器的主要进程。

方式1

1
2
3
# Define default command.
WORKDIR /opt/zapp/
ENTRYPOINT ["pipenv", "run", "python", "main.py"]

方式2

1
2
3
# Define default command.
WORKDIR /opt/zapp/
ENTRYPOINT ["sh", "./run.sh"]

run.sh

1
2
#!/bin/bash
pipenv run python main.py

文件复制

只复制当前目录下的文件,不包括子目录和子目录中的文件。

1
COPY ./* /opt/z-card-recognize/

复制当前目录下的所有内容,包括子目录和子目录中的文件

1
COPY . /opt/z-card-recognize/

通过使用.dockerignore文件,你可以控制复制中忽略的文件和目录。

比如.dockerignore

1
2
*.log
*.tmp

COPY 和 ADD 的区别

在Dockerfile中,ADDCOPY是两个用于将文件和目录从宿主机复制到Docker镜像中的指令。尽管它们看起来很相似,但在使用和功能上有一些显著的区别。

COPY 指令

COPY是最常用的指令之一,它将文件或目录从宿主机的路径复制到Docker镜像中的指定路径。

语法

1
COPY <源路径> <目标路径>
  • <源路径>:宿主机上的文件或目录的路径。
  • <目标路径>:镜像中的目标路径。

特点

  • COPY只支持基本的文件和目录复制功能。
  • COPY不会自动解压文件。
  • COPY更适合复制本地文件和目录到镜像中。

示例

1
2
COPY app.py /app/
COPY src/ /app/src/

ADD 指令

ADD指令的功能比COPY更强大,但同时也更复杂。

它不仅可以复制文件和目录,还可以处理远程URL和自动解压tar文件。

语法

1
ADD <源路径> <目标路径>
  • <源路径>:可以是宿主机上的文件或目录的路径,也可以是一个URL(远程文件)。
  • <目标路径>:镜像中的目标路径。

特点

ADD可以处理远程URL和自动解压tar文件。

  • 如果<源路径>是一个URL,ADD会下载文件并将内容放置在<目标路径>
  • 如果<源路径>是一个本地的tar文件(支持gzip、bzip2、xz格式),ADD会自动将其解压到<目标路径>

ADD的复杂性使得它不如COPY透明,建议在不需要远程URL或自动解压功能时使用COPY

示例

1
2
ADD https://example.com/file.tar.gz /tmp/
ADD app.tar.gz /app/

总结

使用COPY

  • 当你只需要简单地将本地文件或目录复制到镜像中时,使用COPY
  • COPY是更明确的指令,有助于保持Dockerfile的清晰和易读。

使用ADD

  • 当你需要从远程URL下载文件或自动解压tar文件时,使用ADD
  • 建议仅在需要ADD的特殊功能时使用,因为它可能会引入不必要的复杂性。

在大多数情况下,COPY是更好的选择,因为它更简单、更透明,并且更容易预测其行为。

整体示例

NodeJS项目

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
LABEL maintainer="psvmc <psvmc@outlook.com>"

# Pull base image
FROM centos:7

# Set Charset
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 安装 wget
RUN yum -y install wget

# YUM镜像
RUN wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum makecache

# 安装ffmpeg
RUN yum install epel-release -y
RUN yum update -y
RUN rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
RUN rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
RUN yum install ffmpeg ffmpeg-devel -y

# 安装Python
RUN yum install -y epel-release
RUN yum install -y python2

# 安装 gcc
RUN yum -y install gcc+ gcc-c++ automake autoconf libtool make

# 安装 nodejs
RUN wget https://mirrors.huaweicloud.com/nodejs/v10.24.0/node-v10.24.0-linux-x64.tar.xz
RUN tar -xvf node-v10.24.0-linux-x64.tar.xz
RUN mv node-v10.24.0-linux-x64 /usr/local/nodejs10
RUN rm -rf node-v10.24.0-linux-x64.tar.xz
ENV NODE_HOME /usr/local/nodejs10
ENV PATH $PATH:$NODE_HOME/bin

# NPM镜像
RUN npm config set registry https://registry.npmmirror.com/
RUN npm config set disturl https://npm.taobao.org/mirrors/node/
RUN npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
RUN npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
RUN npm config set python_mirror https://npm.taobao.org/mirrors/python/
RUN npm cache clean -f

# 安装 node-gyp
RUN npm install -g node-gyp@6.1.0

# 项目配置
RUN mkdir /data
RUN mkdir /data/school_live_record
RUN cd /data
ADD startup.sh /data/school_live_record/startup.sh
RUN chmod +x /data/school_live_record/startup.sh
ADD record /data/school_live_record/record
ADD server /data/school_live_record/server
RUN wget https://download.agora.io/ardsdk/release/Agora_Recording_SDK_for_Linux_v3.0.5_20210106-1609927649_793.tar.gz
RUN tar zxvf Agora_Recording_SDK_for_Linux_v3.0.5_20210106-1609927649_793.tar.gz
RUN mkdir /data/school_live_record/record/src/sdk/
RUN mv ./Agora_Recording_SDK_for_Linux_FULL/* /data/school_live_record/record/src/sdk/
RUN rm -rf zxvf Agora_Recording_SDK_for_Linux_v3.0.5_20210106-1609927649_793.tar.gz
RUN cd /data/school_live_record/record && chmod +x /data/school_live_record/record/build_debug.sh && /data/school_live_record/record/build_debug.sh
RUN cd /data/school_live_record/server && mkdir -p /data/school_live_record/server/output/liverecord && npm install

# Expose ports.
EXPOSE 7000

# Define default command.
WORKDIR /data/school_live_record/
ENTRYPOINT ./startup.sh

如果build_debug.sh构建的时候进度不动,可以把

1
RUN cd /data/school_live_record/record && chmod +x /data/school_live_record/record/build_debug.sh && /data/school_live_record/record/build_debug.sh

替换为

1
ADD agorasdk.node /data/school_live_record/record/agorasdk.node

把别的服务器上容器内的agorasdk.node放在Dockerfile同级

Python项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Pull base image
FROM python:3.9.0

LABEL maintainer="psvmc <psvmc@outlook.com>"

# Set Charset
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# Python
RUN mkdir -p /root/.pip
RUN echo "[global]" > /root/.pip/pip.conf && \
echo "index-url = https://mirrors.huaweicloud.com/repository/pypi/simple" >> /root/.pip/pip.conf
RUN pip install pipenv
RUN pip install cmake

# Project
RUN mkdir /opt/face-recognition/
ADD ./* /opt/face-recognition/
ADD ./web /opt/face-recognition/web
RUN chmod 755 /opt/face-recognition/main.py
RUN chmod 755 /opt/face-recognition/startup.sh
RUN cd /opt/face-recognition/ && pipenv install --skip-lock

# Expose ports.
EXPOSE 8000

# Define default command.
WORKDIR /opt/face-recognition/
ENTRYPOINT ["/opt/face-recognition/startup.sh"]

构建运行

构建

1
docker build -t psvmc/z-card-recognize .

如果构建一直失败可以禁用缓存

1
docker build --no-cache -t psvmc/z-card-recognize .

运行

1
docker run -d -p 8000:8000 --name z-card-recognize --restart=always psvmc/z-card-recognize

查看启动日志

1
docker logs z-card-recognize

删除

1
2
docker stop z-card-recognize
docker rm z-card-recognize

删除中间镜像

在 Docker 中,有时候会存在一些没有标签的镜像(即 REPOSITORYTAG 都是 <none> 的镜像),这些镜像通常是构建过程中产生的中间镜像或者是没有正确打标签的镜像。

删除这些镜像可以帮助清理 Docker 环境并减少磁盘空间占用。

查看所有镜像

首先,使用以下命令查看所有镜像:

1
docker images -a

您会看到类似以下的输出:

1
2
3
REPOSITORY          TAG       IMAGE ID        CREATED         SIZE
<none> <none> abcdef123456 2 weeks ago 500MB
myrepo/myimage latest 123456abcdef 1 week ago 400MB

删除所有 <none> 镜像

您可以使用以下命令删除所有 REPOSITORYTAG 都是 <none> 的镜像:

方法 1:使用 docker rmi

1
docker rmi $(docker images -f "dangling=true" -q)

解释:

  • docker images -f "dangling=true":过滤出所有没有标签的镜像(即 dangling 镜像)。
  • -q:只显示镜像的 ID。
  • docker rmi:删除指定 ID 的镜像。

方法 2:使用 docker image prune

1
docker image prune -f

解释:

  • docker image prune:删除未使用的镜像。
  • -f--force:强制执行,不需要确认。

注意事项

  • docker image prune -f 会删除所有未被容器使用的 dangling 镜像,因此请确保没有其他容器在使用这些镜像。
  • 如果您只想删除特定镜像,可以使用镜像的 ID 直接删除:
1
docker rmi <IMAGE_ID>

其他清理操作

如果您需要清理更多未使用的 Docker 资源(如容器、网络、卷等),可以使用以下命令:

清理所有未使用的容器、网络、卷和镜像

1
docker system prune -f

清理未使用的卷

1
docker volume prune -f

通过这些步骤,您可以有效地清理 Docker 环境中的 <none> 镜像和未使用的资源,释放磁盘空间。