多阶段构建Docker镜像
首先
我最近開始學習Docker。
這次我要設置Spring Boot的開發環境。既然這樣,我也想稍微接觸一下Maven。
我的目標是能夠運行Spring Boot項目。
环境
-
- macOS Mojave ver10.14.5
- Docker for Mac ver18.09.2
做好準備。
准备一个Spring Boot项目

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>hello</groupId>
<artifactId>hello-world</artifactId><!-- ここ -->
<version>0.0.1</version><!-- ここ -->
<name>hello</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
接下来,我们需要编辑HelloApplication.java文件,使其显示”Hello World from Docker”。
package hello.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class HelloApplication {
@RequestMapping("/")
public String home() {
return "Hello World from Docker";
}
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
我暂时先尝试着进行构建。
最终,我们将把它转化为Dockerfile,但由于经验不足,我们不能一下子就写出来,所以我们先尝试用从Maven镜像创建的容器来构建项目。
通过使用”-v”选项,容器内部也可以访问hello目录及其子目录。
docker run --rm -it -v /Users/.../hello:/opt/java maven:3.6.1-jdk-8 /bin/bash
一旦容器启动后,我们会执行命令进行构建。
Maven会开始工作,将jar文件输出到target目录中。
root@2a00dc872367:# cd /opt/java
root@2a00dc872367:/opt/java# mvn install
(省略)
[INFO] BUILD SUCCESS
(省略)
root@2a00dc872367:/opt/java# ls target
hello-world-0.0.1.jar (他にもファイルがあるが、省略)
那么,根据以上内容,我们来编写Dockerfile。
这个问题
Dockerfile的描述
1. 使用多阶段构建(Multi-Stage Build)来实现在容器中进行以下操作:
– 构建 Spring Boot 项目(生成 jar 文件)
2. 将 jar 文件复制到可执行容器中
3. 执行
# 1.jarファイルの生成
FROM maven:3.6.1-jdk-8 as builder
RUN mkdir -p /opt/java/src
# 必要なソースを /opt/java へコピー
COPY ./hello/ /opt/java/
# mvn install によりtargetディレクトリにjarが生成される
RUN cd /opt/java && mvn install
FROM openjdk:8-jre-alpine
RUN mkdir -p /opt/app/
# 2.builderコンテナの中にあるjarファイルを /opt/app/ にコピー
COPY --from=builder /opt/java/target/hello-world-0.0.1.jar /opt/app/
# 8080ポートを開ける
EXPOSE 8080
# 3.アプリを実行
CMD ["java","-jar","/opt/app/hello-world-0.0.1.jar"]
创建和启动容器
在下面的容器中创建并启动容器。
docker build -t java_server .
docker run --rm -it -p 8080:8080 java_server:latest -d

最后
当你无法正确编写Dockerfile时,我认为一个好的方法是先创建和启动容器,然后将整个过程整理到Dockerfile中。
在中国,只需要一个选项,将以下内容用中文进行本地化改写如下:
参考 means “reference” in English.
使用Docker来开始Spring Boot
使用CodeBuild来进行Docker镜像的多阶段构建
尝试编写Dockerfile
总结Dockerfile中ADD和COPY的区别
常用的Maven命令集
更新 –
Dockerfile (中文:容器文件)
尽量写地图片更小。
如果只是复制本地文件,使用COPY命令比ADD命令更好。
尽量保持Dockerfile尽量短。
ADD ./hello/pom.xml /opt/java/
ADD ./hello/src /opt/java/src
COPY ./hello/ /opt/java/
用JDK的话,我一直不太确定,但如果只是执行的话,JRE就足够了。
FROM openjdk:jdk-alpine
FROM openjdk:8-jre-alpine
只需要jar文件才能启动,所以不需要完整复制目标目录。
COPY --from=builder /opt/java/target/ /opt/app/
COPY --from=builder /opt/java/target/hello-world-0.0.1.jar /opt/app/