Dockerfile构建镜像
一、前言
1. Dockerfile
是什么?
- 在 Docker 中,
Dockerfile
是一个纯文本文件,包含了一系列指令,用于定义如何构建一个 Docker镜像
。 Dockerfile
的文件名必须为 Dockerfile,没有扩展名。
2. 为什么要用Dockerfile
当我们编写好SpringBoot程序后,要把它运行到Docker容器中,那就得需要该项目的镜像,有镜像才能运行容器。而Dockerfile
就可以把Java程序构建成镜像。当然也不止是Java程序,Docker镜像库也包含MySQL、Redis等,所以我们也构建Vue项目、自定义的Redis等镜像。流程为:编写 Dockerfile 文件 -> docker build 命令构建镜像 -> docker run 以镜像运行容器实例。
二、Dockerfile格式
Dockerfile
一个名为Dockerfile
的纯文本文件(文件名必须为 Dockerfile,没有扩展名)- 每条指令都必须为大写字母,且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
下面假设一名Java程序员小王🐶,他写好了SpringBoot项目,然后想把该项目部署到Docker容器中,并能在主机访问容器中的项目接口。
FROM
FROM
是指定基础镜像,Dockerfile
的第一条指令就是FROM
。
你用Java写的SpringBoot项目,你要根据Java的版本是什么,来指定Java基础镜像。
如果你写的是Python项目,那就指定Python对应版本的基础镜像。
使用openjdk17轻量版本作为基础镜像(slim表示轻量镜像,去除了不必要的工具)
FROM openjdk:17-jdk-slim
使用openjdk8极简镜像
FROM openjdk:8-alpine
使用官方的 Python 3.9 作为基础镜像
FROM python:3.9-slim
程序员小王🐶使用Java8开发的,所以他的Dockerfile
文件内容可以如下:
# 使用openjdk8的slim轻量版
FROM openjdk:8-slim
MAINTAINER
MAINTAINER
指令用于标记镜像的作者信息,以便用户在使用镜像时能够找到相关的维护者信息。
MAINTAINER your_name <your_email@example.com>
程序员小王🐶 想把他自己的信息写上,这样别人用这个镜像时,都知道是他这个大佬开发的了😎。于是Dockerfile
内容如下:
# 使用openjdk8的slim轻量版
FROM openjdk:8-slim
# 镜像作者信息
MAINTAINER xiao wang <xiao.wang@example.com>
WORKDIR
WORKDIR
是设置工作目录,指定在创建容器后,终端默认登陆进来的目录,一个落脚点。
程序员小王🐶 设置容器内的工作目录为/app
,于是Dockerfile
内容如下:
# 使用openjdk8的slim轻量版
FROM openjdk:8-slim
# 镜像作者信息
MAINTAINER xiao wang <xiao.wang@example.com>
# 设置容器工作目录
WORKDIR /app
COPY
COPY
是将本机指定的文件或目录复制到镜像中,当通过该镜像生成容器
时,容器
中的目标路径就会有拷贝的内容。
COPY <源路径> <目标路径>
- <源路径>:指定要复制的文件或目录在构建上下文内的路径,可以是相对路径或绝对路径。
- <目标路径>:指定要将文件或目录复制到容器内的路径,必须是容器内的绝对路径。
程序员小王🐶把Dockerfile
文件和target目录放同一层,target目录下的my-spring-boot-app.jar
就是工程jar包,当容器运行后,要把my-spring-boot-app.jar
先拷贝并重命名到容器内/app/app.jar
。
# 使用openjdk8的slim轻量版
FROM openjdk:8-slim
# 镜像作者信息
MAINTAINER xiao wang <xiao.wang@example.com>
# 设置容器工作目录
WORKDIR /app
# 将jar包拷贝到容器的/app目录并重命名
COPY target/my-spring-boot-app.jar /app/app.jar
ADD
ADD 指令的作用是将源文件或目录复制到容器的文件系统中。它可以从 Docker 构建上下文(build context)中的本地文件系统中复制文件,也可以从远程 URL
下载文件并添加到容器中。看到这,感觉和COPY
比较类似,但是如果是压缩包,ADD
还可以解压,而且ADD
的源路径是支持远程的哦。
同样需求下,官方推荐使用 COPY。
ADD <源路径> <目标路径>
将远程文件拷贝到容器/app/目录下
ADD https://example.com/file.txt /app/
# 添加所有以"tes"开头的文件
ADD|COPY tes* /mydir/
# 添加 "test" 到 WORKDIR/mydir/
ADD|COPY test mydir/
# 添加 "test" 到 /opt/
ADD|COPY test /opt/
请注意以下几点:
- 如果 <目标路径> 是一个以 “/” 结尾的目录路径,那么源路径的基本名称将用作目标路径中的文件或目录名。
- 如果
<目标路径>
是一个不存在的目录,Docker 将自动创建该目录。 - 如果
<源路径>
是一个目录,Docker 将递归复制该目录及其内容。 - 如果
<源路径>
是一个文件或 URL,Docker 将复制该文件或从 URL 下载文件。 - 如果
<源路径>
是一个通配符表达式,Docker 将复制匹配该表达式的文件或目录
EXPOSE
EXPOSE
是声明容器运行时监听的端口,程序员小王🐶想暴露 Spring Boot 应用的端口为8088
,于是Dockerfile
内容如下:
# 使用openjdk8的slim轻量版
FROM openjdk:8-slim
# 镜像作者信息
MAINTAINER xiao wang <xiao.wang@example.com>
# 设置容器工作目录
WORKDIR /app
# 将jar包拷贝到容器的/app目录并重命名
COPY target/my-spring-boot-app.jar /app/app.jar
# 设置端口为8088
EXPOSE 8088
ENTRYPOINT
ENTRYPOINT
用于配置容器启动
时要执行的默认应用程序或命令。
ENTRYPOINT ["可执行文件", "参数1", "参数2", ...]
ENTRYPOINT command param1 param2 ...
ENTRYPOINT ["命令", "参数1 参数2", "参数3"]
程序员小王🐶想到执行app.jar的命令是java -jar app.jar
,于是他又在Dockerfile
中加了一行:
# 使用openjdk8的slim轻量版
FROM openjdk:8-slim
# 镜像作者信息
MAINTAINER xiao wang <xiao.wang@example.com>
# 设置容器工作目录
WORKDIR /app
ARG JAR_FILE=my-spring-boot-app.jar
# 将jar包拷贝到容器的/app目录并重命名
COPY target/${JAR_FILE} /app/app.jar
# 设置端口为8088
EXPOSE 8088
# 设置启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
RUN 和 CMD
RUN
: 执行命令并创建新的镜像层。当你需要在镜像构建过程中安装软件包或应用程序时,就会用到 RUN。每执行一次 RUN 就会在镜像上添加一个新的层。CMD
:设置容器启动后默认执行的命令及其参数。不过,CMD 指定的命令可以通过 docker run 命令行参数来覆盖。它主要用于为容器设定默认启动行为。如果 Dockerfile 中有多个 CMD 指令,只有最后一个生效。
RUN apt-get update && apt-get -y install redis-server
CMD格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
# 格式:
ENV <key> <value>
ENV <key>=<value>
# 示例:
ENV myName John
ENV myCat=tomcat
# 配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk-11
ENV PATH $JAVA_HOME/bin:$PATH
三、构建SpringBoot项目镜像
1. 创建SpringBoot项目
我们使用阿里云的SpringBoot创建地址:https://start.aliyun.com
创建一个最简单的SpringBoot项目,勾选有SpringMVC就可以。
在pom文件中,加上文件名为my-spring-boot-app
,并设置skip
为false(为了让jar包能启动)。
2. 使用Dockerfile构建镜像
打包后将target/my-spring-boot-app.jar
和Dockerfile
都传到服务器,执行构建镜像命令:
注意最后的点
docker build -t my-spring-boot-app .
查看镜像,看有没有多一个名为my-spring-boot-app的镜像
docker images
-t my-spring-boot-app:指定镜像的名称为 my-spring-boot-app
最后的点
.
表示当前目录是构建上下文,Docker 会查找当前目录下的 Dockerfile
3. 启动容器并测试接口
从镜像启动容器
docker run -d --name dockerfile_test_project -p 8088:8088 my-spring-boot-app
查看已经启动的容器,发现多了一个容器
docker ps
测试下容器中的接口,有返回说明访问容器内接口没有问题
curl http://127.0.0.1:8088/hello?name=lisi
4. 进入容器
进入容器
docker exec -it dockerfile_test_project /bin/bash
发现进入容器后默认目录就是配置的工作目录/app
。
参考文档:
https://www.cnblogs.com/miaocbin/p/15245836.html
https://blog.csdn.net/qq_47959003/article/details/142833781