Dockerfile介绍

发布时间:2024-12-13 人气:151次

Dockerfile介绍

1、Dockerfile简介2、Dockerfile构建镜像步骤3、Dockerfile指令4、案例

1.1

什么是Dockerfile之前的文章我们介绍了Docker的基础知识,这篇文章我们介绍Docker比较重要的知识点——Dockerfile。Dockerfile是一个用于构建Docker镜像的文本文件,包含了一系列指令和配置,这些指令定义了如何从一个基础镜像开始,通过添加、修改文件、安装软件包、配置环境变量和设置启动命令等操作,最终构建出一个新的Docker镜像。


1.2

为什么需要自定义镜像?我们知道Docker Hub官方提供了许多满足我们服务需求的镜像,基本包含了所有场景,那为什么还需要自定义镜像呢?

因为官方镜像可能无法完全满足特定应用的需求,或者需要对现有镜像进行扩展和优化。比如一下场景就需要我们自定义镜像:

特定需求配置:官方镜像通常提供通用的基础环境,但每个项目可能都有其特定的配置需求,如环境变量、配置文件等。通过自定义镜像,可以在构建过程中添加这些特定的配置,确保应用在部署时能够无缝运行。

持续集成/持续部署(CI/CD)流程集成:在CI/CD流程中,可能需要将应用打包成镜像,并在测试或生产环境中运行。通过自定义镜像,可以确保在不同环境中都能获得一致的构建结果,从而简化部署流程。

优化性能和资源利用:自定义镜像可以根据应用程序的需求进行优化,包括调整系统配置、优化启动脚本等,从而提高性能和资源利用率。通过减少不必要的软件包和依赖项,自定义镜像可以减小镜像大小,加快下载和启动速度。

......


1.3

Dockerfile原理谈到Dockerfile原理,首页我们得搞清楚Docker镜像的原理。先思考一下下面几个问题:1. docker镜像的本质是什么?

2. docker中一个centos镜像大约200M左右,为什么一个centos系统的iso安装文件要好几个G?

3. docker中一个tomcat镜像大约500M左右,为什么一个tomcat安装包不足100M呢?

通过上面的三个问题,衍生出来了一些知识点。操作系统是由:进程调度子系统、进程通信子系统、内存管理子系统、设备管理子系统、文件管理子系统、网络通信子系统、作业控制子系统组成。Linux的文件管理子系统由bootfs和rootfs组成:

bootfs:包含bootloader(引导加载程序)和 kernel(内核)

rootfs:root文件系统,包含的就是典型 Linux 系统中的/dev、/proc、/bin、/etc等标准目录和文件

(PS: 不同的linux发行版,bootfs基本一样,而rootfs不同,如ubuntu,centos等)

Linux的文件管理子系统由bootfs和rootfs组成.png

上面的知识点后,现在来看下镜像的原理:

Docker镜像原理.png

Docker镜像是由特殊的文件系统叠加而成,最底端是 bootfs,并使用宿主机的bootfs;第二层是root文件系统rootfs,称为base image;然后再往上可以叠加其他的镜像文件。

统一文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。

一个镜像可以放在另一个镜像的上面。位于下面的镜像称为父镜像,最底部的镜像成为基础镜像。

当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器。

现在我们就能来解答这三个问题了:Q1:docker 镜像的本质是什么?

A1:是一个分层的文件系统。

Q2:docker中一个centos镜像大约200M左右,为什么一个centos系统的iso安装文件要好几个G?

A2:centos的iso文件包括bootfs和rootfs,而docker的centos镜像复用操作系统的bootfs。

Q3:docker中一个tomcat镜像大约500M左右,为什么一个tomcat安装包不足100M呢?

A3:docker中的镜像是分层的,tomcat虽然只有70多M,但是它需要依赖父镜像和基础镜像,所有整个对外暴露的tomcat镜像大约500M左右。

2.1

Dockerfile文件是怎么生成镜像的?创建Dockerfile文件:首先,你需要创建一个包含Dockerfile指令的文本文件,并将其命名为“Dockerfile”。这个文件中将包含构建镜像所需的所有指令,例如基于哪个基础镜像、需要安装哪些软件包、需要复制哪些文件到镜像中等。

准备上下文(Context):Dockerfile通常与一个上下文一起使用,上下文是指在使用Docker构建镜像时,Docker引擎会将当前目录及其子目录中的所有文件发送到Docker守护进程,作为构建环境的一个上下文。简单来说,Docker build上下文就是构建镜像时,Docker引擎用来生成镜像的所有文件和目录的集合。在运行docker build命令时,需要指定上下文路径。

运行docker build命令:使用docker build命令来读取Dockerfile并构建镜像。命令的基本格式为:

docker bulid -t <镜像名>:<标签> <上下文路径>执行命令后:

读取 Dockerfile:Docker CLI会读取指定上下文路径中的Dockerfile。

创建基础镜像层:根据Dockerfile中的FROM指令拉取指定的基础镜像。

逐条执行指令:按照从上到下的顺序逐条执行Dockerfile中的指令。每条指令都会在镜像中创建一个新的层,并对镜像进行修改。例如,RUN指令会在容器中执行命令,COPY和ADD指令会将文件或目录复制到镜像中。

提交新镜像层:每执行完一条指令后,Docker会提交一个新的镜像层。

缓存机制:为了提高构建速度,Docker会对每一层进行缓存。如果某一层没有变化,Docker将直接使用缓存的层,而不会重新构建。

生成镜像:所有指令执行完毕后,Docker会生成最终的镜像,并将其存储在本地。你可以通过 docker images命令查看生成的镜像。

3.1

Dockerfile指令大全
Dockerfile 指令
说明
FROM
指定基础镜像,用于后续的指令构建。
MAINTAINER
指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令)
LABEL
添加镜像的元数据,使用键值对的形式。
RUN
以FROM中定义的镜像为基础环境运行指定命令。生成结果将作为新镜像的一个镜像层,并可由后续指令所使用。
CMD
指定容器创建时的默认命令。(可以被覆盖)
ENTRYPOINT
设置容器创建时的主要命令。(不可被覆盖)
EXPOSE
声明容器运行时监听的特定网络端口。
ENV
在容器内部设置环境变量。以键值对格式,可被其后的指令所调用。
ADD
将文件、目录或远程URL复制到镜像中。
COPY
将文件或目录复制到镜像中。
VOLUME
为容器创建挂载点或声明卷。
WORKDIR
设置后续指令的工作目录。
USER
指定后续指令的用户上下文。
ARG
定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。
ONBUILD
当该镜像被用作另一个构建过程的基础时,添加触发器。
STOPSIGNAL
设置发送给容器以退出的系统调用信号。
HEALTHCHECK
定义周期性检查容器健康状态的命令。
SHELL
覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。

3.2核心指令介绍FROM:指定基础镜像,必须为第一个命令# 格式:

FROM <image>

FROM <image>:<tag>

FROM <image>@<digest>

# 示例:

FROM mysql:5.6

# 注:tag或digest是可选的,如果不指定,将使用latest版本的基础镜像LABEL:提供元数据,例如维护者信息、版本等。# 格式:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

# 示例:

LABEL maintainer="youremail@example.com"

# 注:使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据。之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。RUN:在镜像内运行命令,例如安装依赖、更新包等。每个RUN指令都会创建一个新的镜像层。# shell格式:等同于在终端操作的shell命令。

RUN <command>

# exec执行格式:

RUN ["executable", "param1", "param2"]

# 示例:

RUN ["executable", "param1", "param2"]

RUN apk update

RUN ["/etc/execfile", "arg1", "arg2"]

# 注:RUN指令创建的中间镜像会被缓存,并在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cacheCMD:指定容器启动时默认执行的命令,可以被docker run命令行参数覆盖。只能有一个CMD指令,如果有多个,只有最后一个生效。# 格式:

CMD ["executable","param1","param2"] (执行可执行文件,优先)

CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)

CMD command param1 param2 (执行shell内部命令)

# 示例:

CMD echo "This is a test." | wc -l

CMD ["/usr/bin/wc","--help"]

# 注:CMD不同于RUN,CMD用于指定容器启动时要执行的命令,而RUN用于指定镜像构建时要执行的命令。ENTRYPOINT:配置容器启动时的固定命令,通常与CMD配合使用。ENTRYPOINT不会被 docker run 命令行参数覆盖。# 格式:

ENTRYPOINT ["executable", "param1", "param2"] (可执行文件,优先)

ENTRYPOINT command param1 param2 (shell 内部命令)

# 示例:

FROM ubuntu

ENTRYPOINT ["ls", "/usr/local"]

CMD ["/usr/local/tomcat"]

# 注:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给CMD。Dockerfile中只允许有一个ENTRYPOINT命令,多次指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。通常情况下,ENTRYPOINT与CMD一起使用,ENTRYPOINT写默认命令,当需要参数时使用CMD传参。EXPOSE:声明容器将要监听的端口。# 格式:

EXPOSE <port> [<port>/<protocol>...]

# 示例:

EXPOSE 8080

EXPOSE 11211/tcp 11211/udp

# 注:EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过 -p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。如果没有暴露端口,后期也可以通过-p 8080:80方式映射端口,但不能通过-P形式映射。ENV:设置环境变量,可以在后续的RUN和CMD中使用。# 格式:

ENV <key> <value> 或 ENV <key>=<value> ...

# 示例:

ENV MY_VAR=my_valueADD:从构建上下文复制文件或URL到镜像中,如果复制的是压缩包,还会自动解压,可访问网络资源。# 格式:

ADD <src>... <dest>

# 示例:ADD ./myfile.txt /app/COPY:与ADD类似,但主要用于复制文件或目录到镜像中,不会解压压缩包,不可以访问网络资源。# 格式:

COPY <src>... <dest>

# 示例:

COPY ./myfile.txt /app/VOLUME:定义一个或多个挂载点,用于存储数据。# 格式:

VOLUME ["/data"]

# 示例:

VOLUME ["/data1", "/data2"]

# 注:一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统。WORKDIR:设置工作目录,对RUN、CMD、ENTRYPOINT、COPY和ADD指令有效。# 格式:

WORKDIR /path/to/workdir

# 示例:

WORKDIR /app

# 注:通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。USER:设置运行容器时的用户。# 格式:

USER <username>

# 示例:

USER myuser

# 注:使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。ARG:定义构建镜像过程中需要使用的变量。这些变量在构建时可以通过--build-arg参数来赋值。# 格式:

ARG <name>[=<default value>]

# 示例:

ARG IMAGE_VERSION=latestONBUILD:定义当镜像被用作其他镜像的基础镜像时的构建指令。# 格式:

ONBUILD <INSTRUCTION>

# 示例:

ONBUILD RUN apt-get update

# 注: ONBUILD后面跟指令,当当前的镜像被用做其它镜像的基础镜像时,该镜像中的触发器将会被触发。STOPSIGNAL:设置发送给容器以退出的信号。# 格式:

STOPSIGNAL <signal>

# 示例:

# 使用默认的SIGTERM信号

STOPSIGNAL SIGTERM 

# 使用信号编号15,它等同于SIGTERM

STOPSIGNAL 15

# 注:当容器被请求停止时,Docker会发送SIGTERM信号给容器内的主进程。HEALTHCHECK:定义周期性检查容器健康状态的命令。# 格式:

HEALTHCHECK [OPTIONS] CMD <command>

# 示例:

HEALTHCHECK --interval=30s --timeout=10s --retries=3 CMD curl --fail http://localhost/ || exit 1

# 注:这个例子中,Docker会每隔30秒运行一次curl --fail http://localhost/ 命令来检查容器的健康状态。如果命令失败(即返回非零退出状态),则会在接下来的两次尝试中继续运行该命令,如果三次都失败,则认为容器不健康。SHELL:覆盖Docker默认的shell,用于RUN、CMD和ENTRYPOINT指令。# 格式:

SHELL ["<executable>", "<param1>", "<param2>", ...]

# 示例:

SHELL ["/bin/bash", "-c"]

# 注:这个例子中,后续的RUN、CMD和ENTRYPOINT指令将使用/bin/bash -c来执行命令,而不是默认的 /bin/sh -c

4.1Dockerfile应用CI/CD 流程中的Dockerfile应用以下是一个Python基于flask框架的web项目的Dockerfile示例:# 选择轻量级的Python 3.8镜像

FROM python:3.8-slim

# 标记维护者信息

LABEL maintainer="th-0707"

# 设置工作目录为/app

WORKDIR /app

# 复制依赖文件到容器

COPY requirements.txt /app

# 安装Python依赖

RUN pip install -r requirements.txt

# 复制项目文件到容器

COPY . /app

# 设置Flask应用的文件

ENV FLASK_APP=app.py

# 允许Flask应用在所有网络接口上运行

ENV FLASK_RUN_HOST=0.0.0.0

# 暴露5000端口

EXPOSE 5000

# 容器启动时运行Flask应用

CMD ["flask", "run"]假如当前项目的文件目录如下所示:my_flask_app/

├── app.py

├── requirements.txt

└── Dockerfile构建镜像:cd my_flask_app

docker build -t my_flask_app .运行容器:docker run -p 5000:5000 my_flask_app


选择订阅-通过 Docker 订阅在协作、安全性和支持之间找到完美的平衡!
在线客服
联系方式

热线电话

18221674630

上班时间

周一到周五

公司电话

18221674630

二维码
线
获取免费体验资格

提交后,我们将在3个小时内与您联系