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