Dockerfile 详解

繁星-赵老师 2024-10-02 10:07:02 阅读 62

文章目录

一、Dockerfile(制作镜像脚本化)1.1 什么是Dockerfile1.2 为什么要使用Dockerfile

二、Docker Build 工作原理三、Dockerfile 常用指令3.1 FROM3.2 MAINTAINER(新版即将废弃)3.3 RUN3.4 ADD3.5 COPY3.6 CMD3.7 ENTRYPOINT3.8 LABEL3.9 ENV3.10 EXPOSE3.11 VOLUME3.12 WORKDIR3.13 USER3.14 ARG3.15 ONBUILD

四、制作镜像

一、Dockerfile(制作镜像脚本化)

1.1 什么是Dockerfile

Dockerfile 是一个文本文件,包含一系列用于构建镜像的指令(Instructions)。每条指令都会构建一层镜像,指令的内容描述了该层镜像应如何构建。

Dockerfile 用于指导 docker image build 命令自动构建镜像它是一个纯文本文件

示例:

<code>docker build -f /path/Dockerfile

1.2 为什么要使用Dockerfile

问题:Docker Hub 官方提供了许多满足我们服务需求的镜像,为什么还需要自定义镜像?

核心作用:用户可以将自己的应用打包成镜像,从而让应用在容器中运行。还可以对官方镜像进行扩展,打包成适合生产环境的应用镜像

完整镜像的结构图:

在这里插入图片描述

Dockerfile的格式

包含两种类型的行:

以 # 开头的注释行以专用"指令(Instruction)"开头的指令行

Image Builder 按顺序执行各指令,从而完成镜像构建

在这里插入图片描述

二、Docker Build 工作原理

在这里插入图片描述

<code>docker build [选项] <上下文路径/URL/->

docker build 命令后的 . 表示当前目录,同时也指定了上下文路径。

上下文:

Docker 运行时分为 Docker 引擎(服务端守护进程)和客户端工具。Docker 引擎提供了一组 REST API,称为 Docker Remote API。客户端工具(如 docker 命令)通过这组 API 与 Docker 引擎交互,完成各种功能。

虽然表面上我们似乎在本机执行各种 Docker 功能,但实际上,一切都是通过远程调用在服务端(Docker 引擎)完成的。这种客户端/服务器设计使得操作远程服务器上的 Docker 引擎变得简单易行。

镜像构建过程中,不是所有定制都通过 RUN 指令完成。我们经常需要将本地文件复制进镜像,比如使用 COPY 或 ADD 指令。docker build 命令构建镜像时,实际上是在服务端(Docker 引擎)中进行的。那么,在这种客户端/服务端架构中,如何让服务端获得本地文件呢?

这就引入了上下文的概念。构建时,用户指定构建镜像的上下文路径,docker build 命令会将该路径下的所有内容打包并上传给 Docker 引擎。Docker 引擎收到并展开这个上下文包后,就能获得构建镜像所需的全部文件。

为什么有人误以为 . 是指定 Dockerfile 所在目录呢?这是因为默认情况下,如果不额外指定 Dockerfile,系统会将上下文目录下名为 Dockerfile 的文件作为 Dockerfile。

实际上,Dockerfile 的文件名不必是 “Dockerfile”,也不必位于上下文目录中。例如,可以用 -f …/Dockerfile 参数指定其他文件作为 Dockerfile。

不过,人们通常会沿用默认的文件名 Dockerfile,并将其放在镜像构建的上下文目录中。

三、Dockerfile 常用指令

官方 build 参考

在这里插入图片描述

3.1 FROM

指定基础镜像,必须为第一个命令

<code>格式:

FROM <image>

FROM <image>:<tag>

FROM <image>@<digest>

示例:

FROM mysql:5.6

注:

tag 或 digest 是可选的,如果不指定,将使用 latest 版本的基础镜像

3.2 MAINTAINER(新版即将废弃)

维护者信息

格式:

MAINTAINER <name>

示例:

MAINTAINER bertwu

MAINTAINER xxx@163.com

MAINTAINER bertwu <xxx@163.com>

3.3 RUN

构建镜像时执行的命令

RUN 用于在构建镜像时执行命令,有以下两种执行方式:

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-cache

3.4 ADD

将本地文件添加到容器中,tar 类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似 wget

格式:

ADD <src>... <dest>

ADD ["<src>",... "<dest>"] 用于支持包含空格的路径

示例:

ADD hom* /mydir/ # 添加所有以"hom"开头的文件

ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"

ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/

ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/

3.5 COPY

功能类似 ADD,但不会自动解压文件,也不能访问网络资源

3.6 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 用于指定镜像构建时要执行的命令。

3.7 ENTRYPOINT

配置容器,使其可执行化。配合 CMD 可省去"application",只使用参数。

格式:

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

ENTRYPOINT command param1 param2 (shell 内部命令)

示例:

FROM ubuntu

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

CMD ["/usr/local/tomcat"]

之后,docker run 传递的参数,都会先覆盖 CMD,然后由 CMD 传递给 ENTRYPOINT,实现灵活应用

注:ENTRYPOINT 与 CMD 非常类似,不同的是通过 docker run 执行的命令不会覆盖 ENTRYPOINT,

而 docker run 命令中指定的任何参数,都会被当做参数再次传递给 CMD。

Dockerfile 中只允许有一个 ENTRYPOINT 命令,多次指定时会覆盖前面的设置,

而只执行最后的 ENTRYPOINT 指令。

通常情况下,ENTRYPOINT 与 CMD 一起使用,ENTRYPOINT 写默认命令,当需要参数时使用 CMD 传参

3.8 LABEL

用于为镜像添加元数据

格式:

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

示例:

LABEL version="1.0" description="这是一个 Web 服务器" by="IT 笔录"code>

注:

使用 LABEL 指定元数据时,一条 LABEL 指定可以指定一或多条元数据,指定多条元数据时不同元数据

之间通过空格分隔。推荐将所有的元数据通过一条 LABEL 指令指定,以免生成过多的中间镜像

3.9 ENV

设置环境变量

格式:

ENV <key> <value> # <key> 之后的所有内容均会被视为其 <value> 的组成部分,因此,一次只能设置一个变量

ENV <key>=<value> ... # 可以设置多个变量,每个变量为一个 "<key>=<value>" 的键值对,如果 <key> 中包含空格,可以使用 \ 来进行转义,也可以通过 "" 来进行标示;另外,反斜线也可以用于续行

示例:

ENV myName John Doe

ENV myDog Rex The Dog

ENV myCat=fluffy

3.10 EXPOSE

指定与外界交互的端口

格式:

EXPOSE <port> [<port>...]

示例:

EXPOSE 80 443

EXPOSE 8080

EXPOSE 11211/tcp 11211/udp

注:EXPOSE 并不会让容器的端口访问到主机。要使其可访问,需要在 docker run 运行容器时通过 -p 来发布这些端口,或通过 -P 参数来发布 EXPOSE 导出的所有端口

如果没有暴露端口,后期也可以通过 -p 8080:80 方式映射端口,但不能通过 -P 形式映射

3.11 VOLUME

用于指定持久化目录(指定此目录可以被挂载出去)

格式:

VOLUME ["/path/to/dir"]

示例:

VOLUME ["/data"]

VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]

注:一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:

1. 卷可以在容器间共享和重用

2. 容器并不一定要和其它容器共享卷

3. 修改卷后会立即生效

4. 对卷的修改不会对镜像产生影响

5. 卷会一直存在,直到没有任何容器在使用它

3.12 WORKDIR

工作目录,类似于 cd 命令

格式:

WORKDIR /path/to/workdir

示例:

WORKDIR /a (这时工作目录为 /a)

WORKDIR b (这时工作目录为 /a/b)

WORKDIR c (这时工作目录为 /a/b/c)

注:

通过 WORKDIR 设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY

等命令都会在该目录下执行。在使用 docker run 运行容器时,可以通过 -w 参数覆盖构建时所设置的工作目录。

3.13 USER

指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用 USER 指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户

格式:

USER user

USER user:group

USER uid

USER uid:gid

USER user:gid

USER uid:group

示例:

USER www

注:

使用 USER 指定用户后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。

镜像构建完成后,通过 docker run 运行容器时,可以通过 -u 参数来覆盖所指定的用户。

3.14 ARG

用于指定传递给构建运行时的变量(给 Dockerfile 传参),相当于构建镜像时可以在外部为里面传参

格式:

ARG <name>[=<default value>]

示例:

ARG site

ARG build_user=www

From centos:7

ARG parameter

VOLUME /usr/share/nginx

RUN yum -y install $parameter

EXPOSE 80 443

CMD nginx -g "daemon off;"

# 可以这样灵活传参

docker build --build-arg=parameter=net-tools -t nginx:01 .

3.15 ONBUILD

用于设置镜像触发器

格式:

ONBUILD [INSTRUCTION]

示例:

ONBUILD ADD . /app/src

ONBUILD RUN /usr/local/bin/python-build --dir /app/src

注:

ONBUILD 后面跟指令,当当前的镜像被用做其它镜像的基础镜像时,该镜像中的触发器将会被触发

四、制作镜像

如果有多个 RUN 指令,它们会自上而下依次执行,每次执行都会形成新的层。建议使用 && 将多个命令合并到一行中执行。如果有多个 CMD 指令,只有最后一个会生效。如果有多个 ENTRYPOINT 指令,只有最后一个会生效。如果 CMD 和 ENTRYPOINT 共存,只有 ENTRYPOINT 会执行,且最后的 CMD 会作为 ENTRYPOINT 的参数。

镜像制作分为两个阶段:

docker build 阶段:基于 Dockerfile 制作镜像(RUN 指令用于此阶段的命令执行)docker run 阶段:基于镜像运行容器(CMD 指令用于容器启动时需要运行的命令)docker build 阶段(基于现有镜像):当他人以你的镜像为基础制作新镜像时(ENTRYPOINT 或 ONBUILD 指令在此阶段执行)

以下示例中的注释已被移除

FROM openjdk:8-jre

WORKDIR /app

ADD demo-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8081

ENTRYPOINT ["java", "-jar"]

CMD ["app.jar"]

创建 Dockerfile 文件,粘贴如下内容:

FROM openjdk:8

WORKDIR /root

ADD springbootdemo3-0.0.1-SNAPSHOT.jar springboot.jar

EXPOSE 9999

ENTRYPOINT ["java", "-jar"]

CMD ["springboot.jar"]

将你的 jar 包复制到与 Dockerfile 文件同级目录下进入 Dockerfile 所在目录,执行命令:docker build . -t 自定义镜像名称使用命令启动容器:docker run --name yourboot -d -p 端口映射 自定义镜像名称测试是否可以访问,记得在阿里云上开放相应端口

使用 uname -a 命令查看当前操作系统发行版本

使用 apt search name 命令搜索软件包

自制一个 OpenJDK 8 镜像:

FROM ubuntu:18.04

RUN apt update -y && \

apt install -y openjdk-8-jre

根据 Dockerfile 构建镜像的命令:

docker build . -t 镜像名称

FROM openjdk:17-jdk-slim

COPY chatgpt-bootstrap/target/*.jar /app/app.jar

WORKDIR /app

ENV TZ=Asia/Shanghai

RUN echo > /etc/apt/sources.list && \

sed -i "1ideb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib" /etc/apt/sources.list && \

sed -i "2ideb-src https://mirrors.aliyun.com/debian/ bullseye main non-free contrib" /etc/apt/sources.list && \

sed -i "3ideb https://mirrors.aliyun.com/debian-security/ bullseye-security main" /etc/apt/sources.list && \

sed -i "4ideb-src https://mirrors.aliyun.com/debian-security/ bullseye-security main" /etc/apt/sources.list && \

sed -i "5ideb https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib" /etc/apt/sources.list && \

sed -i "6ideb-src https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib" /etc/apt/sources.list && \

sed -i "7ideb https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib" /etc/apt/sources.list && \

sed -i "8ideb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib" /etc/apt/sources.list && \

apt-get update -y && \

apt-get install -y fontconfig && \

ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

EXPOSE 3002

ENTRYPOINT ["sh","-c","java -jar -Xms150m -Xmx150m app.jar"]



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。