やること
docker で javaのフレームワークの動作環境を試してみる。
動作環境
- windows10
- vagrant2.1.1
- virtualbox5.2.14
- ubuntu-18.04
- Docker version 18.05.0-ce, build f150324
- docker-compose version 1.21.2, build a133471
ディレクトリ構造
project
+ bin # コマンド覚書用のシェルスクリプト
+ data # dockerの永続化用ディレクトリ
- docker
- gradle
- Dockerfile
- oracle
- 11.2.0.2
- Checksum.xe
- Dockerfile.xe
- checkDBStatus.sh
- rnOracle.sh
- setPasword.sh
- xe.rsp
- oracle-xe-11.2.0-1.0.x86_64.rpm.zip # Oracleからダウンロードしたもの。.gitignoreで無視
- buildDockerImage.sh
- spring
- Dockerfile
- .env # docker-composer.yml で使用する環境変数設定
- docker-compose.yml
- src
- hello # spring initializerで作成されたものをひながたに改変
- build.gradle
- settings.gradle
- lib
- ojdbc7.jar # Oracleからダウンロードしたもの。.gitignoreで無視
- src
- main
- java
- hello
- hello
- model
- Staff.java
- repository
- StaffRepository.java
- HelloApplication.java
- resouces
- application.yml
+ test
設定ファイル
ORACLE_PWD=MY_DB_PASSWORD
USER_PASS=MY_DB_USER_PASSWORD
version: '3'
services:
dbserver:
build:
context: ./oracle/11.2.0.2/
dockerfile: Dockerfile.xe
volumes:
- ../data/database:/u01/app/oracle/oradata
- ./oracle/startup:/docker-entrypoint-initdb.d/startup
ports:
- 1521:1521
- 8085:8080
env_file: .env
environment:
- TZ=`ls -la /etc/localtime | cut -d/ -f8-9`
shm_size: 1g
restart: unless-stopped
gradle:
build: ./gradle
user: gradle
volumes:
- ../src/hello:/app
- cache1:/home/gradle/.gradle
links:
- dbserver
environment:
- TZ=`ls -la /etc/localtime | cut -d/ -f8-9`
command: [echo, "no work"]
spring:
build: ./spring
ports:
- "8080:8080"
volumes:
- ../src/hello:/app
links:
- dbserver
environment:
- TZ=`ls -la /etc/localtime | cut -d/ -f8-9`
command: [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app/build/libs/hello-0.0.1-SNAPSHOT.jar"]
volumes:
cache1:
データベースの準備
DockerでOracleデータベース11g XEを構築を参考にデータベースを設定した。
oracle/docker-images の 11.2.0.2ディレクトリをコピー。
同じディレクトリにoracle-xe-11.2.0-1.0.x86_64.rpm.zipのlinux版を配置。
また、javaからDBにつなげるためのojdbc7ドライバーをダウンロードしておく。
githubからcloneするもの
- oracle/docker-imagesの OracleDatabase/SingleInstance/dockerfiles/11.2.0.2ディレクトリ
- docker/oracle/11.2.0.2に配置
Oracleからダウンロードするもの
- oracle-xe-11.2.0-1.0.x86_64.rpm.zip
- docker/oracle/11.2.0.2/oracle-xe-11.2.0-1.0.x86_64.rpm.zipに配置
- ojdbc7.jar
- src/hello/lib/ojdbc7.jar に配置
データベース起動
docker-compose up -d dbserver
sqlplusでの接続
データベースを立ち上げた状態でないと接続できない。
かならず、docker-compose up
した後に行うこと。
#!/bin/bash
bin_dir=$(cd $(dirname $0) && pwd)
container_name=dbserver
# 環境変数読み込み
. $bin_dir/../docker/.env
cd $bin_dir/../docker && docker-compose exec $container_name sqlplus sys/$ORACLE_PWD@localhost:1521/XE as sysdba
シェルを実行して接続を試みる。
vagrant@vagrant[master]:/vagrant/tutorial/lesson/spring$ ./bin/sqlplus.sh
立ち上がっていない状態でアクセスすると以下のようなエラーがでる。
7df144c6f135 docker_dbserver "/bin/sh -c 'exec $O…" 19 seconds ago Up 18 seconds (health: start
ing) 0.0.0.0:1521->1521/tcp, 0.0.0.0:8085->8080/tcp docker_dbserver_1
WARNING: The JAVA_OPTS variable is not set. Defaulting to a blank string.
SQL*Plus: Release 11.2.0.2.0 Production on Sun Jul 15 15:08:51 2018
Copyright (c) 1982, 2011, Oracle. All rights reserved.
ERROR:
ORA-12528: TNS:listener: all appropriate instances are blocking new connections
Enterを2回押して一旦終了させる。
Enter user-name:
ERROR:
ORA-12547: TNS:lost contact
Enter user-name:
ERROR:
ORA-12547: TNS:lost contact
SP2-0157: unable to CONNECT to ORACLE after 3 attempts, exiting SQL*Plus
もう一度sqlplusでの接続を試みる。
vagrant@vagrant[master]:/vagrant/tutorial/lesson/spring$ ./bin/sqlplus.sh
7df144c6f135 docker_dbserver "/bin/sh -c 'exec $O…" 25 seconds ago Up 23 seconds (health: start
ing) 0.0.0.0:1521->1521/tcp, 0.0.0.0:8085->8080/tcp docker_dbserver_1
WARNING: The JAVA_OPTS variable is not set. Defaulting to a blank string.
SQL*Plus: Release 11.2.0.2.0 Production on Sun Jul 15 15:08:55 2018
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL>
sqlplusの立ち上げ方が悪いのだろうか?
もしうまい方法知っているかたがいれば教えていただけると助かります。
ユーザの準備
sqlplusでつなぐことができたら、javaから接続するためのユーザの作成を行う。
今回は起動してみるテストだけで公開しないのですべての権限を持つユーザを作成。
CREATE TABLESPACE my_data DATAFILE '/u01/app/oracle/oradata/MY_DATA.dbf' SIZE 200M SEGMENT SPACE MANAGEMENT AUTO;
CREATE USER testuser IDENTIFIED BY "my_pass" DEFAULT TABLESPACE my_data TEMPORARY TABLESPACE temp;
GRANT DBA TO testuser ;
quit;
※ここで設定したmy_passはdocker/.env
のMY_DB_USER_PASSWORDのこと。
一旦ログアウトしたら、作成したユーザでの接続を試みる。
#!/bin/bash
bin_dir=$(cd $(dirname $0) && pwd)
container_name=dbserver
. $bin_dir/../docker/.env
cd $bin_dir/../docker && docker-compose exec $container_name sqlplus testuser/$USER_PASS@localhost:1521/XE
テスト用のテーブルの作成
create table STAFF (
EMP_ID number primary key,
STAFF_NAME varchar2(100)
);
insert into STAFF (EMP_ID, STAFF_NAME) values (1, 'Jasmine');
ビルドツールとソース
ビルドツールのdockerファイル
FROM gradle:4.8.1-jdk8
WORKDIR /app
ソースの準備
Dockerで始めるSpring Bootを参考に、Spring Initializerを使ってプロジェクトを作成。srcフォルダ以下に配置する。
今回はDBと接続したいため、DBに関する設定を追記。
設定ファイル
buildscript {
ext {
springBootVersion = '2.0.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'hello'
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 files('lib/ojdbc7.jar')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
spring:
datasource:
url: jdbc:oracle:thin:@//dbserver:1521/XE
username: testuser
password: pass
driverClassName: oracle.jdbc.driver.OracleDriver
testWhileIdle: true
validationQuery: SELECT 1
jpa:
showSql: true
hibernate:
ddlAuto: create-drop
naming:
implicitStrategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
physicalStrategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.Oracle10gDialect
プログラム
package hello.hello.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Column;
@Table(name="staff")
@Entity
public class Staff {
@Id
@Column(name="emp_id")
private long id;
@Column(name="staff_name")
private String name;
public void setId(long id){
this.id = id;
}
public long getId(){
return this.id;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
package hello.hello.repository;
import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
import hello.hello.model.Staff;
public interface StaffRepository extends CrudRepository<Staff, Long> {
Optional<Staff> findById(long id);
}
package hello.hello;
import java.util.Optional;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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;
import hello.hello.model.Staff;
import hello.hello.repository.StaffRepository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@SpringBootApplication
@RestController
public class HelloApplication {
@Autowired StaffRepository repository;
@PersistenceContext
private EntityManager entityManager;
@RequestMapping("/")
public String home() {
return "Hello World from Docker";
}
@RequestMapping("/staff")
public String staff() {
Optional<Staff> optional = repository.findById(1);
Staff staff = optional.orElseGet(() -> new Staff());
return "Hello " + staff.getName();
}
@RequestMapping("/query")
public String query() {
List<Staff> results = entityManager
.createNativeQuery("select * from staff where emp_id = :id ", Staff.class)
.setParameter("id",1)
.getResultList();
String name = "";
if(results.size() != 0){
name = results.get(0).getName();
}
return "Hello " + name;
}
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
ビルドの実行
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
container_name=gradle
cd $bin_dir/../docker && docker-compose run $container_name gradle clean build
起動
FROM openjdk:jdk-alpine
WORKDIR /app
ENV JAVA_OPTS=""
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
composeFile=${1:-"docker-compose.yml"}
cd $bin_dir/../docker && docker-compose -f $composeFile up $@
./bin/up.sh
で起動。
http://<仮想環境のIP>:8080/にブラウザでアクセスして表示を確認。
参考
DockerでOracleデータベース11g XEを構築
dockerでOracle DB 11gを動かす
Dockerで始めるSpring Boot
表領域
oracle spring sample
auto increment
SpringBootの開発環境をdockerでつくる
sample
Spring Data JPA でのクエリー実装方法まとめ
【JavaEE】今からでも間にあうJPA入門
初めてのJPA--シンプルで使いやすい、Java EEのデータ永続化機能の基本を学ぶ
Invalid number format for port number
Gradle使い方メモ
Dockerで- /etc/localtime:/etc/localtime:ro がMount Deniedを出すやつ
docker-compose
oracleでautoincrement