Docker--初识Dockerfile 📅 2026/7/6 5:07:24 Dockerfile是构建Docker镜像的脚本文件由一系列指令构成。通过docker build 命令构建镜像时Dockerfile 中的指令由上到下依次执行每条指令都会构建出一个镜像就是镜像的分层。因此指令越多层次就越多创建的镜像就越多效率就越低。所以在定义Dockerfile时能在一个指令完成的动作就不要分为两条。指令简介指令不区分大小写一般惯例是写为全大写指令后至少会携带一个参数注释以# 开头# FORM 指令用于指定基础镜像。且必须是第一条指令若省略了tag则默认为latest FORM image[:tag] # MAINTAINER 指令的参数填写的一般是维护者的姓名和邮箱。此指令官方不建议使用使用LABEL指令代替 MAINTAINER name #LABEL 指令以键值对的形式包含任意镜像的元数据信息用来代替MAINTAINER指令。通过docker inspect 可查看 LABEL 和MAINTAINER 的内容 LABEL keyvalue keyvalue keyvalue ...... # ENV指令指定环境变量这些环境变量后续可以被RUN指令使用容器运行后也可以在容器中获取这些环境变量 ENV key value ENV keyvalue keyvalue keyvalue ...... #WORKDIR指令容器打开后默认进入的目录一般在后续的RUN、CMD、ENTRYINT、ADD等指令中会引用该目录。 # 可以设置多个WORKDIR 指令后续WORKDIR指令若使用相对路径则会基于之前WORKDIR指令的路径。 # 使用docker run 运行容器时加-w 参数可以覆盖 上面设置的工作目录。 WORKDIR path # RUN COMMAND这里的COMMAND 时shell命令在docker build 过程中使用shell 运行指定的command RUN COMMAND # 在docker build 过程中会调用第一个参数“EXECUTABLE” 指定的程序运行并使用后面的 参数作为运行参数 RUN [EXECUTABLE,PARAM1,PARAM2...] # 在容器启动后即执行完docker run 后立即执行“EXECUTABLE”指定的可执行文件并将后面的参数作为运行参数 CMD [EXECUTABLE,PARAM1,PARAM2...] # command表示shell 命令在容器启动后立即运行指定的shell命令 CMD command param1 param2 ... #提供给ENTRYPOINT 的默认参数 CMD [PARAM1,[PARAM2],...] # 在容器启动过程中即执行完docker run 时会执行“EXECUTABLE”指定的可执行文件并将后面的参数作为运行参数 ENTRYPOINT [EXECUTABLE,PARAM1,PARAM2...] # command表示shell 命令在容器启动过程中会运行指定的shell命令 ENTRYPOINT command param1 param2 ... # EXPOSE port [port...] # ARG varname[default value] # 复制宿主机的文件src到容器中的指定目录dest # src可以是绝对路径也可以是相对路径相对路径是相对于docker build 命令所指定的路径的 # src可以是一个压缩文件复制到容器后自动解压 # src也可以是一个url。这时ADD指令相当于wget命令 # src 最好不要是目录不然会将目录中的所有内容复制到容器中 # dest 是一个绝对路径其最后的路径必须要加上斜杠不然会将最后的目录名称当作是文件名 ADD src dest ADD [src,dest] #路径中存在空格时使用双引号引起来 # 功能和ADD相同但是src不能是url若src是压缩未见复制到容器后不能自动解压 COPY # 指定当前镜像的子镜像进行构建时要执行的指令 ONBUILD [INSTRUCTION] # 在容器创建可以挂载的数据卷 VOLUME [dir1,dir2,...]指令用法构建自己的HelloWorld镜像scratch 镜像scratch 镜像是一个空镜像是所有镜像的Base Image。scratch 镜像只能在Dockerfile 中被继承不能pull拉取不能run没有tag并且他不会生成镜像中的文件系统层。scratch 是一个保留字用户不能作为自己镜像的名称。安装编译器# 由于要编写C语言。所以要安装C语言的编译器 yum install -y gcc gcc-c yum install -y glibc-static创建hello.c在宿主机创建一个hello.c 文件#includstdio.h int main() { printf(hello my docker world\n); return 0; }编译测试hello.cgcc --statuc -o hello hello.c ./hello创建Dockerfile在当前目录下新建Dockerfile vim Dockerfile 文件名就叫Dockerfile 内容如下FROM scratch ADD hello / CMD [/hello]构建镜像docker build -t hello-my-world .-t :指定要生成镜像的repositort和tag。若省略tag则默认latest最后的【.】是一个宿主机的URL路径。构建镜像时会从该路径中查找Dockerfile文件。此时执行docker images 可以看到自己创建的镜像。然后可以运行这个镜像了docker run hello-my-world为经常重新打标签当进行过出新版本了上个版本的镜像标签就不能是tag了。docker tag 命令 可以对镜像重打标签。重打标签实际是复制了一份镜像将新镜像指定新的tag。新镜像的IMageID和Digest 和原镜像的相同。docker tag hello-my-world hello-my-world:1.0CMD与ENTRYPOINT这两个指令都是用于指定容器启动时要执行的命令无论哪个指令每个Dockerfile中只能有一个CMD/ENTRYPOINT 指令多个指令只会执行最后一个。不同点如下CMD指定的是容器启动时默认的命令即docker run 若指定了要运行的命令则Dockerfile 中的CMD指定的命令时不会执行的。而ENTRYPOINT 指定的是容器启动时一定会执行的命令。CMD 例子创建Dockerfile在dfs目录中新建文件Dockerfile2,其内容如下FROM centos:7 CMD cal然后构建镜像docker build -f ./Dockerfile2 -t mycal .-f :指定构建时要使用的Dockerfile文件当文件名称不是默认的Dockerfile时才需要指定然后运行就会显示当前月份的日历docker run -it mycal此时若在docker run 时指定要执行的命令则Dockerfile中CMD 指定的命令就不执行了此时也无法为CMD指定的命令设置选项如果说Dockerfile 的内容如下CMD指令的另一种形式也是一样的效果FROM centos:7 CMD [/bin/bash,-c,cal]ENTRYPOINT例子1.创建Dockerfile名字为Dockerfile4其内容如下FROM centos:7 ENTRYPOINT cal然后构建并运行结果显示本月的日历如果docker run 时指定了执行命令ENTRYPOINT的指令依然会执行不会被覆盖此时即使在docker run中添加命令选项也是无效的。如果Dockerfile 的内容如下那么在docker run中添加命令选项 是有效的。FROM centos:7 ENTRYPOINT [cal]总结CMD指定命令启动命令docker run 中不能添加参数【arg】。因为Dockerfile 中的CMD可以被替代如果启动的镜像 后仍有内容对于docker daemon来说 会认为是一个命令如果有两个或两个以上后面才会认为是参数。ENTRYPOINT指令启动命令docker run 中可以添加参数【arg】。因为ENTRYPOINT 不能被替代如果启动的镜像 后仍有内容对于docker daemon来说其只能是【arg】。不过docker daemon 对于ENTRYPOINT 指定的【command】和【“EXECUTABLE”】的处理方式不同【command】指定的是shelldaemon会直接运行。而不会与docker run 后的【arg】拼接【“EXECUTABLE”】指定的命令daemon会先与docker run 后的【arg】拼接然后运行拼接后的结果。结论无论CMD还是ENTRYPOINT 使用[“EXECUTABLE”]的方式的通用性会更强。ADD与COPY指令创建一个Dockerfile其内容如下FROM centos:7 WORKDIR /opt ADD zookeeper.tar.gz /opt/add COPY zookeeper.tar.gz /opt/copy CMD /bin/bash构建并运行镜像后会发现ADD指令添加的是解压后的目录COPY指令添加的是未解压的。ARG指令该指令用于定义一个变量该变量会在镜像构建时使用而不是容器启动时。创建一个Dockerfile其内容如下FROM centos:7 ARG nameTOM RUN echo $nameRUN指令用于指定在docker build时要执行的内容使用ARG默认值构建docker build -t myargs:1.0 .构建时没给变量name赋予新值所以name还是TOM使用ARG指定值构建docker build -t myargs:1.0 --build-arg namejerry .构建时给变量name赋予新值所以namejerryONBUILD指令ONBUILD指令 只对当前镜像的子镜像进行构建时有效。比如下面实现的是父镜像中没有wget命令但是子镜像会增加。父镜像的DockerfileFROM centos:7 ENV WORKPATH /usr/local WORKDIR $WORKPATH ONBUILD RUN yum -y install wget CMD /bin/bash当前镜像及其子镜像的工作目录都是/usr/local.子镜像在进行docker build 时会运行RUN的安装命令。构建父镜像docker build -t parent:1.0子镜像的DockerfileFROM parent:1.0构建并运行子镜像后就可以使用wget指令了。构建新镜像的方式总结docker builddocker commitdocker import 注意docker load并没有构建出新镜像其与原镜像是同一个镜像docker composedocker hub 中完成Automated Builds将Springboot项目部署到Docker准备应用新建一个名称为hello-docker的简单SpringBoot项目。POM文件内容如下?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version4.0.6/version relativePath/ !-- lookup parent from repository -- /parent groupIdcom.ali/groupId artifactIdhello-docker/artifactId version0.0.1-SNAPSHOT/version namehello-docker/name descriptionhello-docker/description url/ licenses license/ /licenses developers developer/ /developers scm connection/ developerConnection/ tag/ url/ /scm properties java.version17/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /project其配置文件application.yml内容如下logging: pattern: console: level-%-5level - %msg%nController类如下package com.ali.hellodocker.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; RestController public class SomeController { GetMapping(/hello) public String hello() { System.out.println(hello); return Hello Docker!; } }然后打成jar包发布应用在宿主机上创建一个专门的目录用来存放jar包和Dockerfile 等内容。mkdir /root/hello-docker然后将jar包上传到这个目录创建DockerfileFROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/openjdk:17 MAINTAINER zhangsan zs163.com LABEL version1.0 descriptionmy own app COPY hello-docker-0.0.1-SNAPSHOT.jar hd.jar ENTRYPOINT [java,-jar,hd.jar] EXPOSE 9000然后构建并运行镜像docker build -t hello-docker:1.0 . docker run --name myhd -dp 9000:8080 hello-docker:1.0这时就可以通过ip:9000/hello访问了可以通过docker log命令查看输出日志