LoginSignup
4
3

More than 3 years have passed since last update.

Dockerイメージのマルチステージビルド

Last updated at Posted at 2019-08-23

はじめに

最近、Dockerの勉強を始めました。
今回は、Spring Bootの開発環境を整えていきます。せっかくなのでMavenも少し触っていきたい。
ゴールとしてはSpring Bootプロジェクトが実行できればいいかなって感じです。

環境

  • macOS Mojave ver10.14.5
  • Docker for Mac ver18.09.2

準備

Spring Bootプロジェクトを用意する

動かすものがないと仕方がないので、Spring Initializrで用意しました。
へー、こんなのがあるんだ。Spring Web Starterでいいのかな??
image.png
すると、こんな感じでダウンロードされます。
スクリーンショット 2019-08-22 19.19.03.png
pom.xmlを編集します。

pom.xml
<?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>

続いて「Hello World from Docker」と表示されるように、HelloApplication.javaも編集します。

hello/src/main/java/hello/hello/HelloApplication.java
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が動いて、targetディレクトリにjarファイルを書き出してくれるはずです。

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 (他にもファイルがあるが、省略)

これでjarファイルの生成ができました!
では、ここまでのことを踏まえてDockerfileを書いていきます。

本題

Dockerfileの記述

次のことがコンテナで行われるよう、マルチステージビルドを利用して書いていきます。
1. 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

では、ブラウザでlocalhost:8080を叩いてみます。
スクリーンショット 2019-08-23 11.56.33.png
やったー

最後に

Dockerfileがうまく書けないときは、とにかくコンテナを作成・起動してみて、そこまでの過程をDockerfileに落とし込んでいくというやり方がいいと思いました。

参考

Dockerで始めるSpring Boot
CodeBuildでDockerイメージのマルチステージビルド
Dockerfileを書いてみる
DockerfileのADDとCOPYの違いを結論から書く
よく使うMavenコマンド集

更新

Dockerfile

イメージが小さくなるように書く。
ローカルのファイルをコピーするだけならADDコマンドよりCOPYを使ったほうがいい。
できるだけ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ファイルだけなので、targetディレクトリを丸ごとコピーする必要はない。

COPY --from=builder /opt/java/target/ /opt/app/
COPY --from=builder /opt/java/target/hello-world-0.0.1.jar /opt/app/
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3