只使用Docker+Maven实现全自动化流程部署服务;Docker创建ffmpeg环境;

Step1、Docker开启远程访问

Step1、修改配置

复制代码
# 编辑docker.service文件
sudo vi /etc/systemd/system/docker.service
# 或使用
sudo vi /usr/lib/systemd/system/docker.service

# 将 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock 修改为下面内容
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock

Step2、重载服务

复制代码
# 重新加载systemd配置
sudo systemctl daemon-reload
# 重启Docker服务
sudo systemctl restart docker
# 检查服务状态
sudo systemctl status docker
# 查看端口监听
sudo netstat -tlnp | grep 2375

Step3、测试是否修改完成

复制代码
# 本地测试
curl http://localhost:2375/version
# 远程测试
curl http://ip:2375/version

Step2、Docker制作Base基础镜像

仅构建JDK镜像

Step1、将本地jdk制作成镜像---新建Dockerfile

复制代码
# 多阶段构建 - 第一阶段:准备JDK 1
FROM ubuntu:24.04 AS builder

WORKDIR /opt
# 复制JDK目录到容器中
# 此处的COPY ./jdk1.8 /opt/jdk1.8 ,其中的"jdk1.8"只能是Dockerfile所在目录下面的jdk1.8,不能是宿主机其他地方的目录
# 如果是其他目录可以使用下面cp命令操作
### # 在构建上下文目录中创建jdk目录
### mkdir -p /apps/docker_build/jdk
### # 复制JDK到构建上下文
### cp -r /usr/lib/jvm/java-1.8.0-openjdk-amd64/* /apps/docker_build/jdk/
COPY ./jdk1.8 /opt/jdk1.8
# 第二阶段:创建最终镜像
FROM ubuntu:24.04

# 更新包列表并安装必要的依赖
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# 从第一阶段复制JDK
COPY --from=builder /opt/jdk1.8 /opt/java

# 设置环境变量
ENV JAVA_HOME=/opt/java
ENV PATH=$JAVA_HOME/bin:$PATH

# 验证Java安装
RUN java -version

# 设置默认命令
CMD ["java", "--version"]

Step2、执行Dockerfile脚本

复制代码
# docekr build -t 镜像名称:镜像版本 Dockerfile所在位置
docker build -t my-jdk1.8:latest . (有一个点)

Step3、查看是否打包好

复制代码
docker images;

Step4、运行容器测试

复制代码
docker run --rm my-jdk1.8:latest java -version

Step5、容器打包:.tar包。保存为tar文件

复制代码
docker save -o my-jdk-1.7.tar my-jdk1.8:latest

Step6、加载镜像文件

复制代码
docker load -i my-jdk-1.7.tar

基础实际效果

在已有镜像的基础上增加环境

假设我们现在通过Docker images查看到我们有一个my-jdk1.8的镜像,但是这个镜像中我们只有一个jdk环境,我们现在需要新增一个比如ffmpeg的环境依赖时,有两种方法,一种是修改原有Dockerfile一种是使用"my-jdk1.8"镜像为基础镜像新增后续环境即可。

方法一:使用my-jdk1.8为基础镜像

Step1、创建一个Dockerfile.ffmpeg的Dockerfile文件
复制代码
# 基于现有的JDK镜像
FROM my-jdk1.8:latest

# 安装FFmpeg
RUN apt-get update && apt-get install -y \
    ffmpeg \
    && rm -rf /var/lib/apt/lists/*

# 验证FFmpeg安装
RUN ffmpeg -version
Step2、构建新镜像
复制代码
# 如果新的Dockerfile文件名称也是Dockerfile,那么可以直接为"docker build -t my-jdk-ffmpeg(新镜像名称):1.0(新镜像版本) ."
docker build -t my-jdk-ffmpeg:1.0 -f Dockerfile.ffmpeg .(有一个·)
Step3、运行测试
复制代码
# 测试Java
docker run --rm my-jdk-ffmpeg:1.0 java -version

# 测试FFmpeg
docker run --rm my-jdk-ffmpeg:1.0 ffmpeg -version

# 交互模式运行
docker run -it --rm my-jdk-ffmpeg:1.0 bash

方法二:直接修改原始Dockerfile文件,重新构建

Step1、创建新的Dockerfile 使用多阶段构建镜像
复制代码
# 多阶段构建
FROM ubuntu:24.04 AS builder

WORKDIR /opt
# 复制JDK目录 --- 当前Dockerfile的目录下的jdk1.8
COPY ./jdk1.8 /opt/jdk1.8

# 第二阶段:基础环境
FROM ubuntu:24.04

# 设置时区和apt源(可选,加快下载速度)
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 安装基础依赖和FFmpeg
RUN apt-get update && apt-get install -y \
    ca-certificates \
    ffmpeg \
    libavcodec-extra \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 从第一阶段复制JDK
COPY --from=builder /opt/jdk1.8 /opt/java

# 设置环境变量
ENV JAVA_HOME=/opt/java
ENV PATH=$JAVA_HOME/bin:$PATH
ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

# 验证安装
RUN java -version && \
    ffmpeg -version

# 设置工作目录
WORKDIR /app

# 设置默认命令(可以根据需要修改)
CMD ["java", "--version"]
Step2、构建新的镜像
复制代码
docker build -t my-jdk-ffmpeg:1.0.0 .(有一个点)
Step3、运行测试
复制代码
# 测试Java
docker run --rm my-jdk-ffmpeg:1.0.0 java -version

# 测试FFmpeg
docker run --rm my-jdk-ffmpeg:1.0.0 ffmpeg -version

# 交互模式运行
docker run -it --rm my-jdk-ffmpeg:1.0.0 bash

Step3、正文-Docker+Maven插件自动打包

前提:要在第一步中打包jdk1.8本地镜像以后才能使用。

添加pom.xml配置文件依赖:

注意:我们在创建项目的时候一定要创建全小写名称,如果是多个单词中间可以使用"-"划分。如果是大写字母,系统要 报错。

有两种:

io.fabric8/docker-maven-plugin:可以实现自动docker run启动,但是配置麻烦

com.spotify/docker-maven-plugin:无法实现自动 docker run 启动,需要配合脚本或者手动 docker run命令才行

方法一:使用com.spotify/docker-maven-plugin

Step1、添加docker-maven插件

XML 复制代码
<!--dockerfile-maven-plugin用于docker打包-->
<plugins>
    <plugin>
        <groupId>com.spotify</groupId>
        <artifactId>docker-maven-plugin</artifactId>
        <version>1.2.2</version>  <!-- 因本插件停止更新,所以1.2.2是最新版本 -->
        <configuration>
            <imageName>qy/${project.artifactId}:${project.version}</imageName>
            <!-- 要上传到那个Docker服务器 -->
            <dockerHost>http://192.168.0.168:2375</dockerHost>
            <!-- 指定Dockerfile路径 -->
            <dockerDirectory>${project.basedir}</dockerDirectory>
            <!-- 构建参数 -->
            <buildArgs>
                <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
            </buildArgs>
        </configuration>
    </plugin>
</plugins>

Step2、创建Dockfile

XML 复制代码
FROM my-jdk1.8:latest  # Docker制作的Base基础镜像

# 创建日志目录
RUN mkdir -p /logs

# 复制jar包到容器,并重命名为 app.jar
ARG JAR_FILE=target/like-front-1.0.0.jar   
COPY ${JAR_FILE} /app.jar

# 设置环境变量
ENV SPRING_PROFILES_ACTIVE=test \
    JAVA_OPTS="-Xms512m -Xmx2048m"

# 设置启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app.jar -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE"]

Step3、执行Maven命令

XML 复制代码
mvn clean package -Dmaven.test.skip=true docker:removeImage docker:build

如果是在IDEA中,那么不需要mvn,如下:

最终效果:

方法二:使用io.fabric8/docker-maven-plugin

实现要求

  • 本地install时,实现自动执行"docker stop"、"docker rm"、"docker build"、"docker run"等命令。也就是可以实现将本地jar做成镜像,然后自动上传到docker服务器上,如果docker服务器上有对应的镜像会先停止然后删除相关的镜像以及容器,然后执行build命令再,执行启动命令,并对外暴露端口;

  • 本文通过maven-profile管理启动端口server.port以及启动环境spring.profiles.active;

  • 通过Dockerfile管理build配置;

数据流转

  1. 执行maven命令(mvn clean install -Ptest -Dmaven.test.skip=true),指定启动环境为test;

  2. 读取profiles里面的id为test的profile(从而获取对应的server.port、spring.profiles.active等配置信息);

  3. 触发在docker-maven-plugin插件里面的生命周期配置,也就是executions里面中phase为install的execution配置,本文配置的是在install环境下执行goal为"stop、remove、build、start"也就是在maven install时系统会自动并依次为我们执行 docker stop、docker remove、docker build、docker start命令;

  4. 在执行docker stop时会根据configuration/images/image里面的stopNamePattern名称进行停止;

  5. 执行remove时,根据configuration/images/image里面的removeNamePattern名称移除;

  6. 执行build时,根据configuration/images/build里面的配置进行加载;

    • 包括我们设置的args(也就是环境变量:我们通过在这里设置SPRING_PROFILES_ACTIVE、SERVER_PORT向Dockerfile/application.yml传递参数)

    • dockerFile(Dockerfile文件所在位置)

  7. 执行run 的时候我们可以在里面指定ports映射端口,相当于我们手动执行docker run时通过 -v xxx:xxx 来指定的端口;

详细配置以及步骤

Step1、io.fabric8/docker-maven-plugin插件配置
XML 复制代码
<build>
     <plugin>
         <groupId>io.fabric8</groupId>
         <artifactId>docker-maven-plugin</artifactId>
         <version>0.48.0</version>
         <configuration>
             <dockerHost>${docker.host}</dockerHost>
             <images>
                 <image>
                     <!-- 镜像名称(是镜像名称不是容器名称) -->
                     <name>${docker.image.prefix}/${project.artifactId}:${project.version}</name>
                     <alias>${docker.container.name}</alias>
                     <stopNamePattern>${docker.container.name}</stopNamePattern>
                     <removeNamePattern>${docker.container.name}</removeNamePattern>
                     <build>
                         <dockerFile>${project.basedir}/Dockerfile</dockerFile>
                         <args>
                              <!-- 
                                    在application.yml中可以通过如下方法获取:
                                    # 服务配置
                                        server:
                                          port: ${SERVER_PORT:8085}
                                        spring:
                                          profiles:
                                            active: ${SPRING_PROFILES_ACTIVE:dev}
                                        
                                    在Dockerfile中可以通过如下方法获取;
                                        ARG JAR_FILE
                                        ARG SPRING_PROFILES_ACTIVE
                                        ARG SERVER_PORT 
                              -->
                             <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                             <!-- 添加以下参数 -->
                             <SPRING_PROFILES_ACTIVE>${spring.profiles.active}</SPRING_PROFILES_ACTIVE>
                             <SERVER_PORT>${server.port}</SERVER_PORT>
                             <DOCKER_HOST_DIR>${docker.host.dir}</DOCKER_HOST_DIR>
                             <DOCKER_WORKDIR_DIR>${docker.workdir.dir}</DOCKER_WORKDIR_DIR>
                         </args>
                         <!-- 构建上下文目录 -->
                         <contextDir>${project.basedir}</contextDir>
                         <!-- 清理中间镜像 -->
                         <cleanup>true</cleanup>
                         <!-- 不使用缓存 -->
                         <noCache>false</noCache>
                         <!-- 优化:缓存依赖层 -->
                         <optimise>true</optimise>
                     </build>

                     <!-- <run>配置是在镜像构建完成后运行容器的配置 -->
                     <run>
                         <!-- 容器配置 -->
                         <!-- 名字类型-别名 -->
                         <namingStrategy>alias</namingStrategy>
                         <containerNamePattern>${docker.container.name}</containerNamePattern>
                         <!-- 端口映射:主机端口:容器端口,和使用Docker-cli通过 -v来使用一样 -->
                         <ports>
                             <port>${docker.host.port}:${server.port}</port>
                              <port>8888:8895</port>
                         </ports>
                         <!-- 将容器日志输出到宿主机文件 -->
                         <volumes>
                             <bind>
                                 <!-- 将宿主机目录挂载到容器内日志目录:
                                        注意:如果我们直接将宿主机 目录 挂载到容器里面的工作目录 ${docker.workdir.dir} 
                                        这样会导致报错"Error: Unable to access jarfile /app/app.jar" 这是因为这样挂载会将宿主机的目录覆盖"${docker.workdir.dir}"目录。
                                        所以必须挂载的是日志文件目录,或者其他目录 -->
                                 <volume>${docker.host.dir}/logs:${docker.workdir.dir}/logs</volume>
                             </bind>
                         </volumes>
                         <!-- 添加重启策略 -->
                         <restartPolicy>
                             <name>always</name>
                         </restartPolicy>
                     </run>
                 </image>
             </images>
         </configuration>
         <!-- Maven生命周期绑定 -->
         <executions>
 		<!-- 在 deploy(部署)阶段停止旧容器并启动新容器,也就是在 执行maven deploy 时自动为我们执行 docker stop、 docker remove、 docker build、 docker start命令;除此之外phase还可以选择 clean、build、install比如(mvn clean install -Ptest -Dmaven.test.skip=true)或者 mvn clean install -Ptest -Dmaven.test.skip=true 进行绑定,
当然也可以不配置execution绑定maven的生命周期,也可以使用命令的形式绑定,比如:
mvn clean deploy -Ptest -Dmaven.test.skip=true -Dmaven.deploy.skip=true docker:stop docker:remove docker:build docker:start
或者
mvn clean deploy -Ptest -Dmaven.test.skip=true docker:stop docker:remove docker:build docker:start
-->
             <execution>
                 <id>docker-run</id>
                 <phase>deploy</phase>
                 <goals>
                     <goal>stop</goal>
                     <goal>remove</goal>
                     <goal>build</goal>
                     <goal>start</goal>
                 </goals>
             </execution>
         </executions>
    </plugin>
    <!-- Maven Deploy Plugin - 跳过默认部署;
如果不加这个插件,那么就需要使用命令:mvn clean deploy -Ptest -Dmaven.test.skip=true -Dmaven.deploy.skip=true
不跳过的话,因为我们没有配置maven私服所以我们在使用mvn clean deploy 时可能报错:
             [ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:3.1.2:deploy (default-deploy) on project like-front: Deployment failed: repository element was not specified in the POM inside distributionManagement element or in -DaltDeploymentRepository=id::url parameter -> [Help 1] -->
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>3.1.4</version>
        <configuration>
            <skip>true</skip>  <!-- 跳过默认的deploy部署 -->
        </configuration>
    </plugin>
    
 <!-- 配置资源通配符匹配器:这个如果不配置,只能在application.yml中只能通过@...@带入,docker又无法通过@...@带入 -->
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.3.1</version>
        <configuration>
            <delimiters>
                <delimiter>${*}</delimiter>
            </delimiters>
            <useDefaultDelimiters>true</useDefaultDelimiters>
        </configuration>
    </plugin>
</build>
Step2、配置资源过滤器
XML 复制代码
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering> <!-- 启用资源过滤 -->
            <includes>
                <include>**/application*.yml</include> <!-- 过滤所有环境配置文件 -->
            </includes>
        </resource>
    </resources>
</build>
Step3、配置maven-profile管理器
XML 复制代码
<profiles>
        <!-- 开发环境 -->
        <profile>
            <id>dev</id>
            <activation>
                <!-- 是否默认选择 -->
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!-- 容器内IP -->
                <server.port>8087</server.port>
                <!-- 选择的环境 -->
                <spring.profiles.active>dev</spring.profiles.active>
                <!-- 工作目录 -->
                <docker.workdir.dir>/app</docker.workdir.dir>
                <!-- 宿主机目录 -->
                <docker.host.dir>/apps/front</docker.host.dir>
                <!-- docker服务器位置 -->
                <docker.host>http://192.168.0.168:2375</docker.host>
                <!-- 对外暴露的端口 -->
                <docker.host.port>8084</docker.host.port>
            </properties>
        </profile>
    </profiles>
Step4、配置application.yml
XML 复制代码
# 服务配置
server:
  port: ${SERVER_PORT:8085} # 大写说明是环境变量
spring:
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev} # 大写说明是环境变量
Step5、配置Dockerfile
XML 复制代码
# 使用官方基础镜像(推荐)
#FROM openjdk:8-jdk-alpine
# 使用您自己的基础镜像
FROM my-jdk-ffmpeg:1.0

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 复制jar包到容器
### 获取环境变量里面的值 JAR_FILE、SPRING_PROFILES_ACTIVE、SERVER_PORT也就是xml中configuration/images/image/build/args里面的数据
#ARG JAR_FILE=target/like-front-1.0.0.jar
ARG JAR_FILE=target/like-front-1.0.0.jar
ARG SPRING_PROFILES_ACTIVE=test
ARG SERVER_PORT=8085
ARG DOCKER_WORKDIR_DIR=/app

# 设置工作目录
WORKDIR ${DOCKER_WORKDIR_DIR}

# 创建日志目录 /app/logs
RUN mkdir -p logs

# 复制JAR文件(保持在工作目录内) 完整路径:/app/app.jar
COPY ${JAR_FILE} app.jar

# 设置环境变量
#### 最打包后最终会使用这个的端口、环境以及java参数
#ENV SPRING_PROFILES_ACTIVE=test \
#    JAVA_OPTS="-Xms512m -Xmx2048m"
# SERVER_PORT=8080:相当于指定application.yml中的"server.port"为8080
ENV SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE} \
    SERVER_PORT=${SERVER_PORT} \
    JAVA_OPTS="-Xms512m -Xmx2048m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/dump.hprof" \
    TZ=Asia/Shanghai

# 设置日志环境变量(如果使用Spring Boot)
### 完整路径为:/app/logs/
ENV LOGGING_FILE_NAME=logs/like-front.log

# 对外暴露端口
EXPOSE ${SERVER_PORT}

# 设置启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=${SERVER_PORT} -jar app.jar " ]
Step6、配置Maven启动命令

如果是在IDEA中,就不需要配置mvn 。 之所以使用deploy,是因为我们在开发过程中可能会不断地 clean/install/package,如果绑定在这上面,那么后续我们所有的install..都会执行docker stop/docker build ...之类的命令,所以直接使用maven的deploy(部署)命令即可

XML 复制代码
# 在execution/phase中绑定对应的生命周期
# 使用deploy命令:execution/phase=deploy
# ### 如果没有指定 maven-deploy-plugin 插件的默认部署行为 需要配置 -Dmaven.deploy.skip=true
mvn clean deploy -Ptest -Dmaven.test.skip=true -Dmaven.deploy.skip=true
# ### 如果有开启 即maven-deploy-plugin/skip=true,只需要如下即可:
mvn clean deploy -Ptest -Dmaven.test.skip=true
# -----
# 使用install命令:execution/phase=install
mvn clean install -Ptest -Dmaven.test.skip=true
# ------------------------------------------------------------------------------------------------------------
# 在mvn命令中指定,无需配置execution/phase=deploy
# 使用mvn deploy命令
# ### 如果没有指定 maven-deploy-plugin 插件的默认部署行为 需要配置 -Dmaven.deploy.skip=true
mvn clean deploy -Ptest -Dmaven.test.skip=true -Dmaven.deploy.skip=true docker:stop docker:remove docker:build docker:start
# ### 如果有开启 即maven-deploy-plugin/skip=true,只需要如下即可:
mvn clean deploy -Ptest -Dmaven.test.skip=true docker:stop docker:remove docker:build docker:start
# -----
# 使用mvn install命令
mvn clean install -Ptest -Dmaven.test.skip=true docker:stop docker:remove docker:build docker:start
相关推荐
roman_日积跬步-终至千里8 小时前
【运维-架构】Starrocks生产级运维脚本设计与实现
运维
梦里不知身是客118 小时前
explain分析SQL语句分析sql语句的优劣
java·数据库·sql
学习3人组8 小时前
docker运行报错启动守护进程
linux·运维·centos
你想考研啊8 小时前
k8s使用kubectl报错
java·docker·kubernetes
nvvas8 小时前
JAVA 关于SpringBoot4新版本阅览
java·spring boot
白宇横流学长8 小时前
基于SpringBoot实现的大创管理系统
java·spring boot·后端
武子康8 小时前
大数据-187 Logstash Filter 插件实战:grok 解析控制台与 Nginx 日志(7.3.0 配置可复用)
大数据·后端·logstash
不爱学英文的码字机器8 小时前
【征文计划】Rokid AR眼镜在工业维修领域的应用实践:智能装配指导系统开发全流程
后端·ar·restful
Dylan的码园8 小时前
栈与stack
java·数据结构·链表