はじめに
趣味の開発でチームでSpringBootを使ってwebサービスを作ろうという話になった。javaはわかるがSpringBootの知識は0なのでdockerを使って試しにREST APIを作ってみた。
作成するにあたって、以下の記事を参考にしました。
開発環境は以下の通り
- OS: macOS High Sierra
- docker: 17.12.0-ce
- docker-compose version 1.18.0
今回の記事のソースはこちら
作るもの
- DBコンテナは既存のMySQLのimageを用いる
- APPコンテナはDockerFileを作成しファイルをマウントすることで、ビルドする度に新たにimageを作成する必要を無くす
- MyadminコンテナはMySQL簡易操作用
SpringBootの構築
SpringBootわけわからんおじさんなので、準備としてローカルでRestApiを作ります
DBの準備
mysqlのコンテナに必要なデータを入れて立ち上げとく。これをしないとテストも通らない為ビルドができない。
コンテナ起動時に必要なことは以下の通り
- 事前にsqlファイルを作り
/docker-entrypoint-initdb.d
にマウントすると起動時に実行してくれるのでマウントさせる。 - SpringBoot用のmysqlユーザ sbootを作成する
- localhostのポート3306にリンクさせる
これらを加味すると以下のようなコマンドになる
docker container run -v $(PWD)/sql:/docker-entrypoint-initdb.d -d -e MYSQL_DATABASE=mydb -e MYSQL_USER=sboot -e MYSQL_PASSWORD=sboot -e MYSQL_ROOT_PASSWORD=root-pass -p 3306:3306 -d mysql
長くはなるが、docker-composeを作るまでの我慢しよう。
build.gradleの作成
SpringBootはビルド、ライブラリ管理にgradleを使っているそうです。
SPRING INITIALIZRに必要事項を記入し雛形を落としましょう。
ディレクトリトップにあるbuild.gradleファイルを以下のように編集します。
buildscript {
ext {
springBootVersion = '1.5.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'boot-get-started'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-data-rest")
compile('mysql:mysql-connector-java:6.0.6')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependenciesのとこに必要なライブラリを記入すれば良いらしい便利。
testCompileのとこで多分テストもしてくれてるうれしい。
ここらへんもあとで詳しく学びたい。
gradlew clean build
でライブラリのインストールが完了します。
Entity,Repositoryの作成
DBにたいおうするEnttityとRepositoryをsrc/main/java/com/example
に作成する。
ここら辺は参考記事をコピっただけなのであまり理解はしていない。
今回は環境構築がメインなので割り切る。
application.ymlの作成
src/main/resources/application.yml
を作成する。
ここにDBの接続先を記入する。
アプリケーションをローカルで実行する場合と、コンテナ上で接続する場合とでは接続先が変わることに注意する。
spring:
profiles:
active: localhost
---
spring:
profiles: localhost
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mydb
username: sboot
password: sboot
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update
data:
rest:
base-path: /api
---
spring:
profiles: docker
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://dbserver/mydb
username: sboot
password: sboot
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update
data:
rest:
base-path: /api
localhost、dockerに対応するプロファイルを作りlocalhostをデフォルトにする。
プロファイルの切り替えはDockerFile内で行う(後述)
ビルド
mysqlコンテナを立てた状態でgradlew build
をして、BUILD SUCCESSFUL
が出ればOK。
ビルドがうまくいったので次はアプリケーションをコンテナ化し実行できるようにする。
DockerFile、Composeの作成
最初にアプリケーションのDockerFileを作成する。
# use alpine as base image
FROM ubuntu:16.04
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64
# recommended by spring boot
VOLUME /tmp
# create directory for application
RUN mkdir /app
WORKDIR /app
# jar target
ENV JAR_TARGET "boot-get-started-0.0.1-SNAPSHOT.jar"
# set entrypoint to execute spring boot application
ENTRYPOINT ["sh","-c","java -jar -Dspring.profiles.active=docker build/libs/${JAR_TARGET}"]
-
ENTRYPOINT
の-Dspring.profiles.active=docker
でapplication.yml
に記載したプロファイルに切り替える。 - 実行時にビルドしたファイルを
/app
にマウントする。 -
JAR_TARGET
に指定したファイルを実行する。(デフォルトでは"boot-get-started-0.0.1-SNAPSHOT.jar")
次にdb,app,phpmyadminコンテナを組み合わせたdocker-compose.ymlを記載する
version: '2'
services:
dbserver:
image: mysql
volumes:
- ./sql:/docker-entrypoint-initdb.d
- mysql-db:/var/lib/mysql
environment:
MYSQL_DATABASE: mydb
MYSQL_USER: sboot
MYSQL_PASSWORD: sboot
MYSQL_ROOT_PASSWORD: root
app:
build: .
image: watari/boot:0.1.0
depends_on:
- dbserver
ports:
- "8080:8080"
volumes:
- .:/app
environment:
JAR_TARGET: boot-get-started-0.0.1-SNAPSHOT.jar
myadmin:
image: phpmyadmin/phpmyadmin
depends_on:
- dbserver
environment:
PMA_ARBITRARY: 1
PMA_HOST: dbserver
PMA_USER: root
PMA_PASSWORD: root
ports:
- "1111:80"
volumes:
mysql-db:
driver: local
実行
docker-compose up
で実行できる。初回はDockerファイルからイメージを作成する必要があるので--build
オプションをつけると良い。
コンテナを立ち上げ実行ができたら curl
コマンドで確認する。
$ curl http://localhost:8080/api/users
{
"_embedded" : {
"users" : [ {
"firstName" : "Taro",
"lastName" : "Yamada",
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/users/1"
},
"user" : {
"href" : "http://localhost:8080/api/users/1"
}
}
}, {
"firstName" : "Hanako",
"lastName" : "Tanaka",
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/users/2"
},
"user" : {
"href" : "http://localhost:8080/api/users/2"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/users"
},
"profile" : {
"href" : "http://localhost:8080/api/profile/users"
}
}
}
おわりに
SpringBootの知識はないまんだがコンテナを使うことで簡単に環境構築することができた。
けど、buildをローカルでやってるのでなんだかなという感じ、buildもコンテナにやらせた方が良いのでは?とも考えている。
それと今はemacsベースで開発してるけど、今後eclipseなどの統合開発環境で開発するときにはうまく組み合わせる必要があるなってかんじです(ここらへんのノウハウもない)。
これをたたき台に試行錯誤していこうかなと思います。