Dockerfile中编译、打包、部署spring boot项目
1、Dockerfile
1.1、什么是Dockerfile
Dockerfile是自动构建docker镜像的配置文件,将镜像构建过程通过指令的方式定义在Dockerfile中。配合docker build命令行可以实现自动化的Docker镜像的构建。
1.2、Dockerfile语法解析
我们在学习一门语言或文档语法的时候,最快的学习方式就是看别人是怎么写的。这里这个“「别人」”是谁就很重要,跟着臭棋篓子下棋越下越臭。
所以学习Dockerfile语法,我们有必要找一个模范:大家可以去Dockerhub看一下那些开源软件官方提供的镜像,都可以找到对应的Dockerfile,看看别人是怎么写的。我们就以上文中的nginx:1.20.2版本docker镜像的Dockerfile( 官方提供的),我们来逐行解析它的语法及构建过程。本文中涉及的脚本都可以在github:docker-nginx官方渠道获取。
1.3、Dockerfile命令
FROM
一般我们构建镜像的都需要一个基础的linux操作系统的发行版镜像,并且在此基础上我们构建自己的镜像。
所以FROM指令的作用就是指定基础镜像,nginx这里使用的基础linux镜像是debian:bullseye-slim。其中debian:bullseye是debian的linux发行本操作系统的一个版本,版本名称叫做bullseye。slim通常是指这个镜像是该发行版本中的最小安装版本,因为我们构建完成的镜像是要在后续的持续集成过程中,以及仓库和docker服务器之间网络传播的,所以尽可能让镜像的构建结果size最小化。「基础镜像的选择要着重考虑size的大小,满足linux基本功能及你的程序运行的前提下越小越好」。
FROM debian:bullseye-slim
LABEL
LABEL用于给当前镜像添加一些描述、解释性信息,如:当前镜像的维护人及联系方式等信息。用键值对的方式自定义,一行可以定义多个。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
maintainer、description
也可以定义多行,如maintainer维护人信息,description镜像描述信息。如果描述信息一行写不下,可以用“\”换行。
LABEL maintainer="NGINX Docker Maintainers "
LABEL description="This is a Docker image \
for nginx 1.20.2. "
Dockerfile语法中有一个指令叫做MAINTAINER,用于描述该镜像的维护人信息,但是现在已经不建议使用了,统一使用LABEL。
ENV
ENV的作用是设置环境变量,该环境变量设置之后,可以在shell脚本中使用。
使用方法如:${NGINX_VERSION}。学过JAVA的同学想想你的JAVA_HOME环境变量怎么设置的以及怎么使用的?ENV是同样的道理。只不过放到docker这里语法发生了变化而已,语法格式:ENV 环境变量KEY 环境变量Value。
ENV NGINX_VERSION 1.20.2
ENV NJS_VERSION 0.7.0
ENV PKG_RELEASE 1~bullseye
RUN
RUN指令的作用就是执行linux的shell脚本,通过下图可以看到在shell脚本中可以使用通过ENV定义的环境变量。
对于nginx镜像而言,RUN指令的作用就是执行一系列shell命令行来(脚本)完成nginx的安装。所以说要想掌握RUN指令的重点不在于RUN指令本身,关键在于:
- 你会不会手动安装nginx?
- 你会不会linux的shell脚本语法?
- 你能不能把nginx的安装过程写成shell脚本?
如果上面三个问题的答案都是肯定的,用RUN指令即可执行shell脚本完成软件的安装。这也是Dockerfile编写内容的核心所在,linux shell并不是本文要为大家说明的内容。
COPY
COPY指令的作用是:将本地文件(执行镜像构建所在的服务器),拷贝到镜像文件中。
语法是:COPY <本地文件路径>:<镜像文件路径>,镜像文件路径也是容器运行时文件系统的路径。
COPY docker-entrypoint.sh /
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
COPY 30-tune-worker-processes.sh /docker-entrypoint.d
如果本地文件路径只有文件名,就是表示文件和Dockerfile在同一个目录下(相对路径语法)。即:下面的这些文件在同一个目录,这些文件在我上文给出的nginx官方Dockerfile连接中都可以看到。
注意:如果<本地文件路径>是目录,则只是拷贝目录内部文件到镜像中,而不是拷贝目录。
WORKDIR
另外可以使用WORKDIR 指令为 Dockerfile 中跟随它的任何 RUN、CMD、ENTRYPOINT、COPY、ADD 指令设置本地工作目录。
这样上文提到的相对路径,就是相对WORKDIR指定路径的相对路径。「但是通常情况下,不建议使用WORKDIR,因为很难保证执行构建的开发者工作主机的工作路径和Dockerfile编写者的工作路径都是一致。」
WORKDIR /root
EXPOSE
Docker 容器在运行时暴漏指定的网络端口,可用于容器端口映射,默认协议是 TCP。格式如下:
EXPOSE <端口号>
EXPOSE <端口号>/<协议>
将容器端口暴露出去后,可以与宿主机的端口建立映射关系,这样可以通过访问宿主机的端口来访问容器内部的服务。比如同时在 TCP、UDP 上暴露容器的80端口。
EXPOSE 80/tcp
EXPOSE 80/udp
STOPSIGNAL
这个指令笔者也并不常用,我查询了docker-nginx在github上的issues里面给出的答案是,之所以加上STOPSIGNAL信号的目的是:避免docker容器停止后,nginx服务不能正确终止造成僵尸进程的存在。
STOPSIGNAL SIGQUIT
CMD
CMD指令也是用来执行linux命令或脚本,这一点和RUN指令是一致的。二者的区别在于:
- RUN指令实在镜像构建的时候执行,即docker bulid时候执行。
- CMD指令是在执行docker run指令时被执行,也就是在创建容器时执行;
也正因为指令的执行期不同,RUN命名执行的写入操作被写入到镜像层。CMD指令执行结果包含写入操作,被写入到容器层。(可以参考我之前文章《镜像分层原理》学习理解)。
所以CMD和ENTRYPOINT 指令有点相似,都是在创建容器时运行。
需要注意的是:「一旦Dockerfile中包含ENTRYPOINT指令,CMD指令就作为ENTRYPOINT指定的脚本的参数存在」。
参考下文格式语法。
CMD包含三种格式:
- 第一种为ENTRYPOINT指定的脚本传参,上文中的ENTRYPOINT脚本最后一行的exec "$@"就是在执行CMD传递的命令及参数。来完成nginx服务的启动。**这种用法是各官方Dockerfile常用的做法(如:nginx、redis)**,就是在ENTRYPOINT指定的脚本中做一些配置准备工作,然后在ENTRYPOINT脚本的最后一行通过exec "$@"调用CMD命令进行容器服务的启动。
CMD ["nginx", "-g", "daemon off;"]
- 第二种 执行一个命令或shell脚本,可以传参,注意是双引号。与第一种格式语法是一样的,只是没有ENTRYPOINT指定脚本,所以不作为ENTRYPOINT指定脚本的参数存在。
CMD ["executable","param1","param2"]
- 第三种为普通的执行shell脚本的语法,如执行echo "This is a test." | wc -cshell命令行。笔者说:「在Dockerfile中这种方法不要用,没必要知道为什么」。
CMD echo "This is a test." | wc -c
ENTRYPOINT
一个Dockerfile中如果定义多个ENTRYPOINT,只有最后一条ENTRYPOINT生效,并且每次启动docker容器,都会执行ENTRYPOINT指定的脚本。
对于nginx:1.20.2而言,"/docker-entrypoint.sh"脚本中定义了nginx配置检查及nginx服务的启动指令。所以通常情况下「ENTRYPOINT指定的脚本通常都是镜像内核心服务的启动脚本」。
ENTRYPOINT ["/docker-entrypoint.sh"]
这个脚本中最后执行了nginx服务启动,需要配合CMD命令完成,参考下文的CMD命令。
1.4、docker操作
具体可以参考:3-docker基础操作命令 · linux运维 · 看云
1.生成镜像
# docker build -t springboot-docker .
# docker build -f ./Dockerfile -t springboot-docker .
# docker build -f ./Dockerfile -t springboot-docker:0.1 .
[root@ip-100 dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
springboot-docker 0.1 54dcc83613d7 About a minute ago 682MB
springboot-docker latest 54dcc83613d7 About a minute ago 682MB
# 注意:
# 1,命令是在 Dockerfile 所在目录执行;
# 2,一定不能忘了后面的. 此处的 springboot-docker 是实际生成的镜像名
- --tag -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
- -f :指定要使用的Dockerfile路径
参考: https://www.runoob.com/docker/docker-build-command.html
2.运行镜像
- -d : 表示容器在后台运行
- --name : 为容器起一个名字
- -p : 端口映射,格式为宿主机端口:容器端口,上文中含义是将容器中的端口80映射到宿主机的端口80,对外提供访问服务。
最后一个字段为镜像名称
# docker run --name springboot-docker01 -d -p 8080:8080 springboot-docker
[root@ip-100 dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
65bb62a54e55 springboot-docker "java -Djava.securit…" 33 seconds ago Up 31 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp springboot-docker01
宿主机浏览器: http://192.168.192.128:8080/getIpAndPort
3.查看启动日志
docker logs xxx
docker logs -f springboot-docker01
2、Dockerfile多阶段构建
2.1、使用Dockerfile的示例1
FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/appCOPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src srcRUN ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
2.2、使用Dockerfile的示例2
在项目根目录创建Dockerfile:
# 拉取编译环境
FROM maven:3.6.1 as builder#拷贝源码到固定的目录,注意前面有个 '.'
COPY . /project# 切换到源码目录
WORKDIR /project# 使用maven进行编译
RUN mvn clean package -Dmaven.test.skip=true# 拉取运行环境,这个镜像打包出的镜像比较小,如需要可换成oracle的jre
FROM fabric8/java-alpine-openjdk8-jre# 从编译好的镜像中将jar拷贝到运行时容器
COPY --from=builder /project/target/your-jar-name.jar /# 容器启动时执行的命令,这里可加jvm参数
ENTRYPOINT ["java","-jar","/mqtt-rule-engine.jar"]# 开放端口,根据自己的配置进行开放
EXPOSE 8080
2.3、使用Dockerfile的示例3
# First stage: complete build environment
FROM maven:3.5.0-jdk-8-alpine AS builder# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/# package jar
RUN mvn clean package# Second stage: minimal runtime environment
From openjdk:8-jre-alpine# copy jar from the first stage
COPY --from=builder target/my-app-1.0-SNAPSHOT.jar my-app-1.0-SNAPSHOT.jarEXPOSE 8080CMD ["java", "-jar", "my-app-1.0-SNAPSHOT.jar"]
FROM maven:3.6.3-openjdk-8 AS builder# AS builder 起别名RUN mkdir /build
# 创建临时文件ADD src /build/src
#将 src目录复制到临时目录ADD pom.xml /build
# 将 pom文件复制到临时目录RUN cd /build && mvn -B -ntp package
# 打包FROM adoptopenjdk/openjdk8:alpine-jre
# 获取jreCOPY --from=builder /build/target/ems-0.0.1-SNAPSHOT.jar /ems.jar
#从标记点 拷贝jar包 并改名CMD ["java", "-jar", "/ems.jar"]# 声明运行方式
在项目根目录执行下面命令
docker build -t name:tag .
3、插件打包
3.1、spring-boot-maven-plugin插件打包
SpringBoot自己内置了一个
Docker
镜像打包工具,在spring-boot-starter-parent
中,我们无需多余的设置。 优点:不需要写DockerFile
,Spring建议的安全、内存、性能等问题都不需要管。
3.2、jib-maven-plugin插件
来自
Docker
,也不需要写DockerFile
,Jib
可以直接推送到指定的Docker
仓库。
3.3、dockerfle-maven-plugin插件
需要写
DockerFile
也需要本地Docker
环境,但是恰恰是最好用的,最稳定的,最自由把控的。 优点:稳定,不受网络限制,DockerFile自己写,自由度很高,想怎么改怎么改,个人推荐这个。
插件打包,具体例子可参考:Java(SpringBoot)项目打包(构建)成Docker镜像的几种方式-腾讯云开发者社区-腾讯云
4、参考:
docker编译Dockerfile自动化部署springboot项目的jar包_dockerfile编译jar包_xixiyuguang的博客-CSDN博客
2021年 最新 多阶段构建dockerfile实现java源码编译打jar包并做成镜像-阿里云开发者社区
Java(SpringBoot)项目打包(构建)成Docker镜像的几种方式-腾讯云开发者社区-腾讯云
在docker中编译、打包、部署spring boot项目_docker 部署时编译_csdn_meng的博客-CSDN博客
相关文章:

Dockerfile中编译、打包、部署spring boot项目
1、Dockerfile 1.1、什么是Dockerfile Dockerfile是自动构建docker镜像的配置文件,将镜像构建过程通过指令的方式定义在Dockerfile中。配合docker build命令行可以实现自动化的Docker镜像的构建。 1.2、Dockerfile语法解析 我们在学习一门语言或文档语法的时候&am…...

微型计算机原理知识点总结(一)
目录 一.微型计算机 二.微型计算机系统 1.微型计算机硬件系统 冯诺依曼体系结构 总线 (1)微处理器(CPU) 运算器 控制器 内部寄存器 (2)存储器 1.基本概念 2.内存的操作 3.内存的分类 (3)I/O接口与输入/输出设备 2.微型计算机软件系统 (1)系统软件 操作系统 …...

【postgresql 基础入门】psql客户端的使用方法
psql 客户端使用 专栏内容: postgresql内核源码分析手写数据库toadb并发编程 开源贡献: toadb开源库 个人主页:我的主页 管理社区:开源数据库 座右铭:天行健,君子以自强不息;地势坤…...

QTcpSocket发送数据方法
文章目录 一、简介二、write(const char *, qint64)三、isValid() 一、简介 本文主要记录QTcpSocket的write(const char *, qint64)和isValid()。 二、write(const char *, qint64) 概念:在QTcpSocket中,使用write(char* data, int size)函数将指定长…...

select 语句执行顺序
sql 样例 select t_students.name as 姓名, sum(case when b.cname语文 then c.sc_val else 0 end) As 语文 ,sum(case when b.cname数学 then c.sc_val else 0 end) As 数学,sum(case when b.cname英语 then c.sc_val else 0 end) As 英语, From t_students a, t_corses b, t…...

PMD 检查java代码:避免将内部数组直接返回给调用者(MethodReturnsInternalArray)
https://docs.pmd-code.org/pmd-doc-6.55.0/pmd_rules_java_bestpractices.html#methodreturnsinternalarray 直接将内部数组暴露给调用者破坏了封装性,因为调用者可能在拥有内部数组的对象外部更改或者删除数组的元素。返回内部数组的拷贝会更加安全。 例如&…...

ActiveMQ配置初探
文章目录 配置wrapper相关配置wrapper是干什么用的MQ的运行内存修改【需修改】修改内容题外话 wrapper.log配置【需修改】引起的问题优化方式 activemq.xml相关配置官网介绍配置管理后台的认证授权【建议修改】配置broker【根据自己需求更改】配置允许jmx监控关闭消息通知持久化…...

【官方中文文档】Mybatis-Spring #示例代码
示例代码 提示 查看 JPetstore 6 demo 了解如何在完整的 Web 应用服务器上使用 Spring。 您可以在 MyBatis-Spring 的 代码仓库 中查看示例代码: 所有示例都能在 JUnit 5 下运行。 示例代码演示了事务服务从数据访问层获取域对象的典型设计。 FooService.java …...

python二级例题
请编写程序,生成随机密码。具体要求如下: (1)使用 rand…...

【java】【项目实战】[外卖九]项目优化(缓存)
目录 一、问题说明 二、环境搭建 2.1 Git管理代码 2.1.1 创建本地仓库 2.1.2 创建远程仓库 2.1.3 创建分支--》推送到远程仓库 2.2 maven坐标 2.3 配置文件application.yml 2.4 配置类RedisConfig 三、缓存短信验证码 3.1 实现思路 3.2 代码改造 3.2.1 UserContro…...

Scala集合常用函数与集合计算简单函数,高级计算函数Map和Reduce等
Scala集合常用函数与集合计算简单函数 1.Scala集合常用函数 基本属性和常用操作 1.常用函数: (1) 获取集合长度(2) 获取集合大小(3) 循环遍历(4) 迭代器(…...

You must install at least one postgresql-client-<version> package
使用主机上的映射端口来连接到 PostgreSQL 数据库。例如,使用以下命令连接到数据库: psql -h localhost -p 5432 -U postgres出现下面的问题: 分析: 如果您在运行 psql 命令时遇到错误消息 You must install at least one pos…...

爬虫源码---爬取自己想要看的小说
前言: 小说作为在自己空闲时间下的消遣工具,对我们打发空闲时间很有帮助,而我们在网站上面浏览小说时会被广告和其他一些东西影响我们的观看体验,而这时我们就可以利用爬虫将我们想要观看的小说下载下来,这样就不会担…...

【AGC】云数据库API9开发问题汇总
【问题描述】 云数据库HarmonyOS API9 SDK已经推出了一段时间了,下面为大家汇总一些在集成使用中遇到的问题和解决方案。 【问题分析】 1. 报错信息:数据库初始化失败:{“message”:“The object type list and permission …...

ASP.NET Core IOC容器
//IOC容器支持依赖注入{ServiceCollection serviceDescriptors new ServiceCollection();serviceDescriptors.AddTransient<IMicrophone, Microphone>();serviceDescriptors.AddTransient<IPower, Power>();serviceDescriptors.AddTransient<IHeadphone, Headp…...
入门力扣自学笔记277 C++ (题目编号:42)(动态规划)
42. 接雨水 题目: 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组…...

SwiftUI实现iPad多任务分屏
1. 概述 iPadOS引入了多任务分屏功能,使用户能够同时在一个屏幕上使用多个应用程序。这为用户提供了更高效的工作环境,可以在同一时间处理多个任务。 iPad多任务分屏有两种常见的模式:1/2分屏和Slide Over(滑动覆盖)…...

maven依赖,继承
依赖的范围 compile引入的依赖 对main目录下的代码有没有效,main目录下的代码能不能用compile引入的依赖中的类等 以test引入的依赖,在main中是否可以使用 provided(已提供),有了就不要带到服务器上,打包…...

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法
文章目录 仿gRPC功能实现像调用本地方法一样调用其他服务器方法 简介单体架构微服务架构RPCgPRC gRPC交互逻辑服务端逻辑客户端逻辑示例图 原生实现仿gRPC框架编写客户端方法编写服务端方法综合演示 仿 gRPC功能实现像调用本地方法一样调用其他服务器方法 简介 在介绍gRPC简介…...

分布式环境下的数据同步
一般而言elasticsearch负责搜索(查询),而sql数据负责记录(增删改),elasticsearch中的数据来自于sql数据库,因此sql数据发生改变时,elasticsearch也必须跟着改变,这个就是…...

无涯教程-Flutter - 数据库
SQLite" class"css-1occaib">SQLite数据库是基于事实和标准SQL的嵌入式数据库引擎,它是小型且经过时间考验的数据库引擎,sqflite软件包提供了许多函数,可以有效地与SQLite数据库一起使用,它提供了操作SQLite数据…...

算法笔记:平衡二叉树
1 介绍 平衡二叉树(AVL树)是一种特殊的二叉搜索树(BST),它自动确保树保持低高度,以便实现各种基本操作(如添加、删除和查找)的高效性能。 ——>时间都维持在了O(logN)它是一棵空…...

redis 通用命令
目录 通用命令是什么 SET & GET keys EXISTS DEL EXPIRE TTL redis 的过期策略 定时器策略 基于优先级队列定时器 基于时间轮的定时器 TYPE 通过 redis 客户端和 redis 服务器交互。 所以需要使用 redis 的命令,但是 redis 的命令非常多。 通用命令…...

Pycharm配置及使用Git教程
文章目录 1. 安装PyCharm2. 安装Git3. 在PyCharm中配置Git插件4. 连接远程Gtilab仓库5. Clone项目代码6. 将本地文件提交到远程仓库6.1 git add6.2 git commit6.3 git push6.4 git pull 平时习惯在windows下开发,但是我们又需要实时将远方仓库的代码clone到本地&…...

CSS transition 过渡
1 前言 水平居中、垂直居中是前端面试百问不厌的问题。 其实现方案也是多种多样,常叫人头昏眼花。 水平方向可以认为是内联方向,垂直方向认为是块级方向。 下面介绍一些常见的方法。 2 内联元素的水平垂直居中 首先,常见内联元素有&…...

Unity中Shader的UV扭曲效果的实现
文章目录 前言一、实现的思路1、在属性面板暴露一个 扭曲贴图的属性2、在片元结构体中,新增一个float2类型的变量,用于独立存储将用于扭曲的纹理的信息3、在顶点着色器中,根据需要使用TRANSFORM_TEX对Tilling 和 Offset 插值;以及…...

Automotive 添加一个特权APP
Automotive 添加一个特权APP platform: android-13.0.0_r32 一. 添加一个自定义空调的app为例 路径:packages/apps/Car/MyHvac app内容可以自己定义,目录结构如下: 1.1 Android.bp package {default_applicable_licenses: ["Andr…...

自定义TimeLine
自定义TimeLine 什么是TimeLineData(数据)Clip(片段)Track(轨道)Mixer(混合) 什么是TimeLine 在 Unity 中,TimeLine(时间轴)是一种用于创建和管理…...

如何使用SQL系列 之 如何在SQL中使用WHERE条件语句
引言 在结构化查询语言 (SQL)语句中,WHERE子句限制了给定操作会影响哪些行。它们通过定义特定的条件(称为搜索条件)来实现这一点,每一行都必须满足这些条件才能受到操作的影响。 本指南将介绍WHERE子句中使用的通用语法。它还将概述如何在单个WHERE子句…...

leetcode:1941. 检查是否所有字符出现次数相同(python3解法)
难度:简单 给你一个字符串 s ,如果 s 是一个 好 字符串,请你返回 true ,否则请返回 false 。 如果 s 中出现过的 所有 字符的出现次数 相同 ,那么我们称字符串 s 是 好 字符串。 示例 1: 输入:s…...