SpringBoot App on the Container access MySQL DB with jib.

1. Technical Elements

  • Spring Boot
    • Spring Framework ベースのアプリケーションを手軽に作成することができるフレームワーク
  • Docker
    • コンテナ仮想化を用いた OS レベルの仮想環境の構築ツール
  • GoogleContainerTools/jib: 🏗
    • jib-gradle-plugin
    • Java アプリケーションを実行する Docker コンテナイメージを簡単に作成するためのツール
  • GCP(Google Cloud Platform)
    • Google が提供しているクラウドコンピューティングサービス
      • Google 検索や YouTube などでも同じインフラストラクチャーが利用されている。

2. Coding & Settings of Each Technical Element

2.1. SpringBoot

2.1.1. SpringBootApplication

1
2
3
4
5
6
@SpringBootApplication
public class SpringbootHelloworldApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringbootHelloworldApplication.class, args);
	}
}

2.1.2. RestController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@RestController
@Slf4j
public class RestController {

    @Autowired
    private SampleMapper sampleMapper;

    @GetMapping("/test")
    public void test(){
        log.info("helloworld");
    }

    @GetMapping("/db")
    public void db(){
        var sampleTableList = sampleMapper.selectAll();

        sampleTableList.forEach(sampleTable -> log.info("id = {}, name = {}", sampleTable.getId(), sampleTable.getName()));
    }
}

2.1.3. DTO

1
2
3
4
5
6
@Getter
@Setter
public class SampleTable {
    int id;
    String name;
}

2.1.4. Mapper

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Mapper
public interface SampleMapper {
    @Insert("INSERT INTO sample_table (id, name) VALUES (#{id}, #{name})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(SampleTable sampleTable);

    @Select("SELECT id, name FROM sample_table WHERE id = #{id}")
    SampleTable select(int id);

    @Select("SELECT id, name FROM sample_table")
    List<SampleTable> selectAll();
}

2.1.5. Application.properties

1
2
3
4
5
spring.datasource.url=jdbc:mysql://[IPアドレス]/[DB名]
spring.datasource.username=[username]
spring.datasource.password=[password]
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.initialization-mode=always

2.1.6. build.gradle

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
plugins {
	// spring
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

// 省略

dependencies {
	// lombok
	compileOnly 'org.projectlombok:lombok'
	testCompileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testAnnotationProcessor 'org.projectlombok:lombok'
	annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

	// Spring
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-logging'

	// DB
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.2'
	implementation 'mysql:mysql-connector-java:8.0.19'

	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

2.2. jib-gradle-plugin

2.2.1. build.gradle

1
2
3
4
plugins {
	// for docker image
	id "com.google.cloud.tools.jib" version "2.1.0"
}

3. Build and Run

3.1. Build

1
$ gradle jibDockerBuild --image=springio/gs-spring-boot-docker

3.2. Run

1
$ docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t springio/gs-spring-boot-docker

3.3. Conrainer Repository への push と pull

3.3.1. docker push

1
2
3
4
5
6
7
$ docker image ls
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
openjdk                          11                  8ae694851c0d        4 days ago          627MB
springio/gs-spring-boot-docker   latest              2c3be3672b39        50 years ago        218MB

$ docker tag  springio/gs-spring-boot-docker gcr.io/[GCPのプロジェクトID]/springio/gs-spring-boot-docker:tag1
$ docker push gcr.io/[GCPのプロジェクトID]/springio/gs-spring-boot-docker:tag1

3.3.2. docker pull & docker run

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
openjdk             11                  8ae694851c0d        4 days ago          627MB

$ docker pull gcr.io/[GCPのプロジェクトID]/springio/gs-spring-boot-docker@sha256:[ハッシュ値]
$ docker image ls
  REPOSITORY                                               TAG                 IMAGE ID            CREATED             SIZE
  openjdk                                                  11                  8ae694851c0d        4 days ago          627MB
  gcr.io/[GCPのプロジェクトID]/springio/gs-spring-boot-docker   <none>              2c3be3672b39        50 years ago        218MB

$ docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t 2c3be3672b39

4. Trouble

4.1. SpringBoot App から外部(DB 等)へのアクセスができない

docker run実行時の以下の警告は解決しないといけない。

1
WARNING: IPv4 forwarding is disabled. Networking will not work.

sudo sysctl -w net.ipv4.ip_forward=1を実行することで、IPV4のフォーワーディングができるようになる。

これを実施することで、コンテナ内から外部(DB 等)へのアクセスができるようになる。

4.2. GCR(Google Container Registry)に Docker Image を登録(push)できない

docker-credential-gcrコマンドによるリポジトリの認証が必要だった。

1
2
3
4
5
6
$ gcloud auth configure-docker
$ wget https://github.com/GoogleCloudPlatform/docker-credential-gcr/releases/download/v2.0.1/docker-credential-gcr_linux_amd64-2.0.1.tar.gz
$ tar -zxvf ./docker-credential-gcr_linux_amd64-2.0.1.tar.gz
$ mv ./docker-credential-gcr /usr/bin/
$ chmod +x /usr/bin/docker-credential-gcr
$ docker-credential-gcr configure-docker

5. Execution Result

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ docker run -p 8080:8080 -t springio/gs-spring-boot-docker
Picked up JAVA_TOOL_OPTIONS: -Djava.library.path=/jnr-native-side_release/0.0.1
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.2.RELEASE)
2020-04-07 08:24:47.061  INFO 1 --- [           main] c.e.s.SpringbootHelloworldApplication    : Starting SpringbootHelloworldApplication on 1375be00459c with PID 1 (/app/clas
ses started by root in /)
2020-04-07 08:24:47.072  INFO 1 --- [           main] c.e.s.SpringbootHelloworldApplication    : No active profile set, falling back to default profiles: default
2020-04-07 08:24:50.487  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-04-07 08:24:50.521  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-04-07 08:24:50.522  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
2020-04-07 08:24:50.765  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-04-07 08:24:50.765  INFO 1 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3551 ms
2020-04-07 08:24:52.650  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-07 08:24:53.353  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-04-07 08:24:53.367  INFO 1 --- [           main] c.e.s.SpringbootHelloworldApplication    : Started SpringbootHelloworldApplication in 7.334 seconds (JVM running for 8.212)
2020-04-07 08:24:57.947  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-07 08:24:57.947  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-04-07 08:24:57.964  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 17 ms
2020-04-07 08:24:58.061  INFO 1 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-04-07 08:24:59.210  INFO 1 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-04-07 08:24:59.320  INFO 1 --- [nio-8080-exec-1] c.e.springboothelloworld.RestController  : id = 1, name = user01
2020-04-07 08:24:59.320  INFO 1 --- [nio-8080-exec-1] c.e.springboothelloworld.RestController  : id = 2, name = user02
2020-04-07 08:24:59.320  INFO 1 --- [nio-8080-exec-1] c.e.springboothelloworld.RestController  : id = 3, name = user03

6. Reference URL