はじめに
最近、Dockerの勉強を始めました。
今回は、Spring Bootの開発環境を整えていきます。せっかくなのでMavenも少し触っていきたい。
ゴールとしてはSpring Bootプロジェクトが実行できればいいかなって感じです。
環境
- macOS Mojave ver10.14.5
- Docker for Mac ver18.09.2
準備
Spring Bootプロジェクトを用意する
動かすものがないと仕方がないので、Spring Initializrで用意しました。
へー、こんなのがあるんだ。Spring Web Starterでいいのかな??
すると、こんな感じでダウンロードされます。
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も編集します。
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
を叩いてみます。
やったー
最後に
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/