V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
qwerthhusn
V2EX  ›  程序员

分享一个 Spring Boot 工程打 Docker 镜像非常方便的 pom,你也 Docker 的距离就差一个好用的生成镜像的工具,求大佬点评改进!

  •  
  •   qwerthhusn · 2021-05-25 09:53:25 +08:00 · 2081 次点击
    这是一个创建于 1039 天前的主题,其中的信息可能已经有所发展或是发生改变。
    1. spring-boot-maven-plugin自带的生成镜像功能超级慢。因为他要访问 Github 里面的东西,自己的电脑还好,CI 就扛不住了,在墙内的同事也扛不住了,而且那套逻辑也比较复杂灵活,不好掰出来里面的东西,这个一票否决。

    2. 使用这种方式不需要每个工程一个Dockerfile,比如你想给所有项目的 Dockerfile 修改一些配置,此处修改一次,所有工程通吃。

    3. 这个一个 pom 工程,deploy 到私服上之后,下面的 Spring Boot 工程可以使用此 pom 作为 parent 代替 spring-boot-starter-parent 。如果你们已经有自定义的通用 pom,这个也可以被轻松整合进去。

    4. 利用了 Spring boot 2.3 引入的分层构建,每次重新构建镜像会复用上面的层,导致上传一次镜像到远程仓库之后,后面上传镜像都很快,从本来的要上传几十上百 M 缩减到现在的几 M 甚至 1M 不到(这个根据自己的工程体量)。Spring Boot 2.3 以下不可使用

    5. 保持清爽,不堆重复配置,按照约定大于配置原则,不像某些工程,一个 pom 光<build>都几百行,其实大部分内容都是从网上上拷的,起不到作用。这个 pom 指定了很少的只是必须的内容,你可以轻轻松松的把其揉进已存的 pom 里面去。

    6. 按照<profile>的 activation 机制自动识别 Spring Boot 工程,非 SpringBoot 工程也能正常把其作为 parent,而且会自动屏蔽掉镜像构建。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>spring-boot-docker-parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>pom</packaging>
    
        <properties>
            <!-- TIPS: 默认使用的是 11
            <maven.compiler.target>1.8</maven.compiler.target>
            <maven.compiler.source>1.8</maven.compiler.source>
            -->
            <maven.compiler.release>11</maven.compiler.release>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <version.spring-boot>2.4.5</version.spring-boot>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${version.spring-boot}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <!-- TIPS: 添加其他依赖声明!此 pom 声明依赖版本,下面的工程不指定版本 -->
                <dependency>
                    <groupId>org.apache.commons</groupId>
                    <artifactId>commons-collections4</artifactId>
                    <version>4.4</version>
                </dependency>
                <dependency>
                    <groupId>commons-io</groupId>
                    <artifactId>commons-io</artifactId>
                    <version>2.8.0</version>
                </dependency>
                <dependency>
                    <groupId>com.google.guava</groupId>
                    <artifactId>guava</artifactId>
                    <version>30.1.1-jre</version>
                </dependency>
                <dependency>
                    <groupId>com.google.code.findbugs</groupId>
                    <artifactId>annotations</artifactId>
                    <version>3.0.1u2</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>org.jetbrains</groupId>
                    <artifactId>annotations</artifactId>
                    <version>20.1.0</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>org.mapstruct</groupId>
                    <artifactId>mapstruct</artifactId>
                    <version>${version.mapstruct}</version>
                </dependency>
                <dependency>
                    <groupId>org.mapstruct</groupId>
                    <artifactId>mapstruct-processor</artifactId>
                    <version>${version.mapstruct}</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-source-plugin</artifactId>
                    <version>3.2.1</version>
                    <executions>
                        <execution>
                            <id>attach-sources</id>
                            <goals>
                                <goal>jar</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
            <pluginManagement>
                <plugins>
                    <!-- TIPS: 使用 JDK11,如果不指定 maven-compiler-plugin 版本的话,默认版本较低,会导致编译失败
                            如果使用 JDK8 或者以下,则此处声明可以删除,使用 Maven 默认指定的编译插件版本 -->
                    <plugin>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.8.1</version>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    
        <!-- TIPS -->
        <!-- 默认将构建镜像流程放到了 package 这个 phase,如果想放到 deploy 这个 phase,可自行修改 execution 下面的 phase
             mvn fr.jcgay.maven.plugins:buildplan-maven-plugin:list-phase
             此 Maven 插件(不需要在<plugin>指定,直接运行 Maven 命令即可)可以帮助查看每个 phase 执行了哪个插件的哪些任务 -->
    
        <profiles>
            <profile>
                <id>spring-boot-package</id>
                <activation>
                    <file>
                        <!-- TIPS: 根据项目 Spring Boot 工程的特征,执行 profile 激活方式
                             比如此处去判断这个文件存在不存在来决定是否启用此 profile -->
                        <exists>${basedir}/src/main/resources/config/application.properties</exists>
                    </file>
                </activation>
                <build>
                    <plugins>
                        <plugin>
                            <groupId>org.codehaus.gmaven</groupId>
                            <artifactId>groovy-maven-plugin</artifactId>
                            <version>2.1.1</version>
                            <executions>
                                <execution>
                                    <id>copy-Dockerfile</id>
                                    <phase>package</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                </execution>
                            </executions>
                            <configuration>
                                <!-- TIPS: 下面可以指定运行 JDK 版本号,示例使用的是 adoptopenjdk 11,JVM 启动参数 -->
    
                                <source><![CDATA[
                                    import java.nio.charset.StandardCharsets
    
                                    File dockerBuildDir = new File((File) basedir, "target/docker-build")
                                    dockerBuildDir.mkdirs()
    
                                    def dockerfile =
    """
    FROM adoptopenjdk:11.0.11_9-jdk-hotspot as builder
    WORKDIR /app/
    ARG JAR_FILE
    COPY \${JAR_FILE} app.jar
    RUN java -Djarmode=layertools -jar app.jar extract
    
    FROM adoptopenjdk:11.0.11_9-jdk-hotspot
    WORKDIR /app/
    COPY --from=builder /app/dependencies/ ./
    COPY --from=builder /app/spring-boot-loader/ ./
    COPY --from=builder /app/snapshot-dependencies/ ./
    COPY --from=builder /app/application/ ./
    ENTRYPOINT ["java", "-Dfile.encoding=utf-8", "-Duser.timezone=Asia/Shanghai", "-Xms4g", "-Xmx4g", "-XX:+HeapDumpOnOutOfMemoryError", "org.springframework.boot.loader.JarLauncher"]
    """
                                    fos = new FileOutputStream(new File(dockerBuildDir, "Dockerfile"))
                                    fos.write(dockerfile.getBytes(StandardCharsets.UTF_8))
                                    fos.close()
                                ]]></source>
                            </configuration>
                        </plugin>
                        <plugin>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-maven-plugin</artifactId>
                            <version>${version.spring-boot}</version>
                            <executions>
                                <execution>
                                    <id>spring-boot-package</id>
                                    <phase>package</phase>
                                    <goals>
                                        <goal>repackage</goal>
                                    </goals>
                                    <configuration>
                                        <mainClass>${start-class}</mainClass>
                                        <outputDirectory>${project.build.directory}/docker-build/</outputDirectory>
                                    </configuration>
                                </execution>
                            </executions>
                        </plugin>
                        <plugin>
                            <groupId>io.fabric8</groupId>
                            <artifactId>docker-maven-plugin</artifactId>
                            <version>0.34.1</version>
                            <executions>
                                <execution>
                                    <id>docker-build-push</id>
                                    <phase>package</phase>
                                    <goals>
                                        <goal>build</goal>
                                        <goal>push</goal>
                                    </goals>
                                </execution>
                            </executions>
                            <configuration>
                                <images>
                                    <image>
                                        <!-- TIPS:在 settings.xml 里面的<servers>下添加一个<server>指定镜像仓库的用户名和密码
                                             CI 环境也可以通过指定 Java 变量参数来指定用户名密码
                                                mvn -Ddocker.username=XXX -Ddocker.password=YYY clean package
                                            <server>
                                                <id>your.registry.domain</id>
                                                <username>用户名</username>
                                                <password>密码</password>
                                            </server>
                                        -->
    
                                        <!-- TIPS: 需要在工程下的<properties>下面指定一个 property,dockerImageGroupAndName
                                             例如 abc/def -->
                                        <name>your.registry.domain/${dockerImageGroupAndName}</name>
                                        <build>
                                            <contextDir>${project.build.directory}/docker-build/</contextDir>
                                            <tags>
                                                <tag>${project.version}</tag>
                                            </tags>
                                            <args>
                                                <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
                                            </args>
                                        </build>
                                    </image>
                                </images>
                            </configuration>
                        </plugin>
                    </plugins>
                </build>
            </profile>
        </profiles>
    
        <!-- TIPS: 如需发布到 Maven 仓库,则指定下面的发布仓库地址 -->
        <distributionManagement>
            <repository>
                <id>xxx-release-deploy</id>
                <url>https://XXX/repository/maven-releases/</url>
            </repository>
            <snapshotRepository>
                <id>xxx-snapshot-deploy</id>
                <url>https://XXX/repository/maven-snapshots/</url>
            </snapshotRepository>
        </distributionManagement>
    </project>
    
    6 条回复    2021-05-25 13:27:12 +08:00
    zzl22100048
        1
    zzl22100048  
       2021-05-25 10:41:54 +08:00   ❤️ 1
    为啥不用 jib ?
    qwerthhusn
        2
    qwerthhusn  
    OP
       2021-05-25 10:58:29 +08:00
    @zzl22100048 不知道啊,刚刚听说,所以标题上写的“请大佬点评改进”。我来看看,也许能直接把我这钻木取火的方式给毙掉
    90d0n
        3
    90d0n  
       2021-05-25 11:18:16 +08:00
    同 1 楼, 推荐 google 的 jib
    cslive
        4
    cslive  
       2021-05-25 11:46:11 +08:00
    白嫖 Travis CI
    zoharSoul
        5
    zoharSoul  
       2021-05-25 12:08:10 +08:00
    jib 了解一下
    whitelee8080
        6
    whitelee8080  
       2021-05-25 13:27:12 +08:00
    同推荐 jib
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2698 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:13 · PVG 23:13 · LAX 08:13 · JFK 11:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.