springboot项目打包docker示例

博客原文:https://itdong.me/springboot-to-docker-image/

一般springboot项目会依赖mysql,redis等服务,所以我们写一个docker-compose来进行多个容器的统一管理

MySQL

首先说一下mysql,我们肯定是希望我们启动mysql时就会把数据库建好,相关的表建好,所以我们的操作是
在environment中
MYSQL_ROOT_PASSWORD是你数据库的root密码
MYSQL_DATABASE是mysql容器创建的时候自动建的数据库
而我们想要建表是通过挂载文件实现的,mysql容器启动的时候会读取/docker-entrypoint-initdb.d目录下的文件,所以我们将主机的某一个目录放上我们的sql文件,然后volumes中挂载
生产环境不要映射端口**

  mysql:  
    image: mysql:8.0  
    container_name: #你的容器名字
    environment:  
      MYSQL_ROOT_PASSWORD: # ROOT密码  
      MYSQL_DATABASE: # 你java程序种需要用的数据库名,将自动创建数据库  
    volumes:  
      -  /javaProject/sql:/docker-entrypoint-initdb.d:rw  # 将存有sql文件的目录挂载到容器  
      -  /javaProject/mysql_data:/var/lib/mysql:rw 
    ports:  
      - "601:3306"  # 生产环境不要映射端口

redis

然后是redis
这个相对简单一点,只需要记住
生产环境不要映射端口

  redis:  
    image: redis:latest  
    container_name: #你的容器名字  
    ports:  
      - "602:6379"  # 生产环境不要映射端口

springboot

将java打包至容器镜就有点复杂,有两种方式,一种是你本地打包成jar包,直接copy,另一种是上传源码,在制作镜像过程中进行maven打包,然后copy jar包
首先介绍第一种,这种需要你先ide中打包成jar包,然后再构建镜像

FROM openjdk:21-jre # 切换对应的java版本
  
# 设置工作目录  
WORKDIR /app  
  
# 复制打包后的 JAR 文件到运行镜像  
COPY /target/你项目的打包名字.jar /app/你项目的打包名字.jar  
  
# 创建上传目录  
RUN mkdir uploads  
  
# 暴露应用端口  
EXPOSE 8080  
  
# 启动应用  
ENTRYPOINT ["java", "-jar", "/app/你项目的打包名字.jar"]

第二种更方便,因为你可以少操作一步,但是如果你的代码里依赖了自己的一些库,这种在docker中构建maven时将无法构建,除非你将你本地maven仓库复制过去
首先需要新建一个Dockerfile文件,示例如下
这里需要更改的地方有,第二步切换对应的java版本,COPY jar包时需要改为你项目打包的名字

# 第一阶段:构建阶段  
FROM maven AS build  
  
# 设置工作目录  
WORKDIR /app  
  
# 复制 pom.xml 文件和源代码到容器中  
COPY pom.xml /app/  
COPY src /app/src/  
  
# 使用 Maven 构建项目  
RUN mvn clean package -DskipTests  
  
# 第二阶段:运行阶段  
FROM openjdk:21-jre AS runtime  # 切换对应的java版本
  
# 设置工作目录  
WORKDIR /app  
  
# 复制打包后的 JAR 文件到运行镜像  
COPY --from=build /app/target/你项目的打包名字.jar /app/你项目的打包名字.jar  
  
# 创建上传目录  
RUN mkdir uploads  
  
# 暴露应用端口  
EXPOSE 8080  
  
# 启动应用  
ENTRYPOINT ["java", "-jar", "/app/你项目的打包名字.jar"]

对应的dockerCompose文件是

app:  
  build:  
    context: .  
  container_name: # 容器名字
  environment:  
    SPRING_PROFILES_ACTIVE: prod  
    SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/你配置的数据库名?serverTimezone=Asia/Shanghai&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull  
    SPRING_DATASOURCE_USERNAME: root  
    SPRING_DATASOURCE_PASSWORD: # 上面指定的数据库密码  
    SPRING_REDIS_HOST: redis  
    SPRING_REDIS_PORT: 6379  
    SPRING_REDIS_DATABASE: 1  
  ports:  
    - "603:8081" # 这个端口看情况暴露
  volumes:  
    - /project/uploads:/app/uploads  # 这里是映射上传文件的目录
  depends_on:  
    - mysql  
    - redis  
  command: ["java", "-jar", "/app/你项目的打包名字.jar"]

总体的docker-compose文件是

services:  
  mysql:  
    image: mysql:8.0  
    container_name: #你的容器名字  
    environment:  
      MYSQL_ROOT_PASSWORD: # ROOT密码  
      MYSQL_DATABASE: # 你java程序种需要用的数据库名,将自动创建数据库  
    volumes:  
      -  /javaProject/sql:/docker-entrypoint-initdb.d:rw  # 将存有sql文件的目录挂载到容器
      -  /javaProject/mysql_data:/var/lib/mysql:rw 
    ports:  
      - "601:3306"  # 生产环境不要映射端口  
  
  redis:  
    image: redis:latest  
    container_name: #你的容器名字  
    ports:  
      - "602:6379"  # 生产环境不要映射端口  
  
  app:  
    build:  
      context: .  
    container_name: # 容器名字  
    environment:  
      SPRING_PROFILES_ACTIVE: prod  
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/CyberGenealogy?serverTimezone=Asia/Shanghai&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull  
      SPRING_DATASOURCE_USERNAME: root  
      SPRING_DATASOURCE_PASSWORD: # 上面指定的数据库密码  
      SPRING_REDIS_HOST: redis  
      SPRING_REDIS_PORT: 6379  
      SPRING_REDIS_DATABASE: 1  
    ports:  
      - "603:8081" # 这个端口看情况暴露  
    volumes:  
      - /project/uploads:/app/uploads  # 这里是映射上传文件的目录  
    depends_on:  
      - mysql  
      - redis  
    command: ["java", "-jar", "/app/你项目的打包名字.jar"]

idea中配置jar镜像每次重新构建

我们更新代码肯定希望镜像重新构建
在编辑配置中选择,始终构建镜像

9 个赞

感谢大佬分享

生产环境也能这么玩吗? mysqlredis这些中间件跟应用应该是分开的吧

感谢大佬的分享

RUN mvn clean package -DskipTests 这一步如果如果有本地库岂不是直接嗝屁,而且每次都要下载包还会影响打包效率,加一步复制本地镜像仓库的步骤会更好吧。

要怎么分呢?
之前实验室部署项目也是在一台服务器上安装mysql,redis,java,nginx,然后nohup java -jar

好的!!
忘记这茬了,感谢!

如果能做到只从本地拷贝,当前项目依赖的库是不是效率会更高?

你们实验室场景的访问频率是不是不高以及用户不是很多?这样的话你这个方案没问题。
生产环境的话一般应用服务跟中间件服务服务分开部署,避免互相影响。

我们所谓的生产环境只有一台大母鸡,部署新应用是新开一个Ubuntu的docker,在里面挨个装中间件,用户可能真的不多,小小本科生,不清楚nie

那正规的生产环境就不用docker嘛?
k8s嘛?

基本这个情况。可能到时候redis一台机器,mysql一台机器,n个应用一台,尽量避免互相影响。当然最上面还是一台配置贼高的物理机。


再往上拆分机房,在往上拆分区域中心,类似意思

我们小厂,开发人员个位数,还有一堆是在校生,用不上这么高规格
:pensive:

好奇佬友基本待遇 :nerd_face:

冲冲冲冲冲冲 都是打工人

感谢大佬分享

我?我才大三,
一点点劳务费(假期早八晚九30天,说是2500,但是还没到账

平时按8小时一天

1 个赞

大佬!我大三只会打游戏 :tieba_087:

每个人的环境不一样直接用docker的maven编只适用于所依赖的jar全能在公开仓库里的情况。如果有私有仓库还得重写maven的配置。太麻烦了没必要,如果实在要实现源码编译的话,直接在机器上搞一个编译环境,打包jar。然后直接用一个jre镜像把编好的jar挂进去运行,docker-compose里重写 command就行了。

那就是,不用在docker里面maven,在ide打包好,jar传到镜像就行