SpringBootとPostgreSQLの開発環境をdocker-composeで用意する！上

# 背景
プロジェクトに参加して開発環境を整える作業ってだいたい似たようなことをしますよね。
特にSpringBoot + DB環境をローカル端末に整えるといったことはよくあることです。
そこで、Dockerを使ってテンプレート化できなかと考えて、共有するためにこの記事を書こかなと思います。
PostgreSQLをDBに選んだのは[Heroku](https://jp.heroku.com/)を意識したからで深い理由はありません。

# 概要
SpringBootとPostgreSQLの開発環境をdocker-composeで用意していく入門記事です。
この記事ではdocker-compose.ymlで開発環境を定義していき、
SpringBootアプリでDB接続の確認まで記事に書いていきます。

また、一つの記事にしてしまうと長いので、上下に分けて記事を書いていきます。（この記事は上です！）

- SpringBootとPostgreSQLの開発環境をdocker-composeで用意する！上
- [SpringBootとPostgreSQLの開発環境をdocker-composeで用意する！下](https://qiita.com/gosutesu/items/f45150cbde3f035c54dd)

こちらの章では以下を説明していきます。

- docker-compose.ymlを用意する。
- テーブルを用意する。

それでは早速始めていきましょう！

# 前提
この記事ではソフトウェアのインストールは省略した手順となります。
そのため、eclipseとdockerは事前にインストールしておいてください。

# ディレクトリ構成
それでは、まず始めに！
dockerで開発環境を作成していく時は、ディレクトリ構成を認識することが重要です。
下記では今回のディレクトリ構成を示しています。

```
current/
      ├ docker/
             ├ db/
                ├ data/
                ├ initdb/
      ├ SpringTestProject/
      ├ docker-compose.yml
```
大まかなファイルやディレクトリの意味を把握しておきましょう。

## ディレクトリ説明

| ディレクトリ・ファイル            | 概要                                        |
|:--------------------------|:-------------------------------------------|
| current                   | 今回の作業ディレクトリです。名前は何でもOK。          |
| current/docker/db/data    | データベースのデータを永続化するために使用します。     |
| current/docker/db/initdb  | データベースの初期化で使用するsqlを格納します。      |
| current/SpringTestProject | SpringBootプロジェクトです。                     |
| current/docker-compose.yml| dockerコンテナの定義を書いていきます。             |


# docker-compose.ymlを用意する。
今回の記事のメインどころと言っても過言ではないところです。

下記の図がdocker-compose.ymlで定義する今回のDockerコンテナの構成です。  
<img width="465" alt="スクリーンショット 2019-09-22 9.24.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325856/f82bfc6a-8242-e134-1718-808ec92604ee.png">

## docker-compose.yml
それでは、早速、docker-compose.ymlを用意します。
[SpringBoot公式](https://spring.io/guides/gs/spring-boot-docker/)の内容を参考にして、docker-compose.ymlに全てを定義していきます。
また、postgresの部分はDockerHubのドキュメントを参考にして作成していきます。

```docker-compose.yml
version: "3"
services:
  app:
    image: openjdk:11-slim
    ports:
      - "8080:8080"
    depends_on:
      - db
    volumes: 
      - "./SpringTestProject/build/libs/app.jar:/tmp/app.jar"
    entrypoint: "java -Djava.security.egd=file:/dev/./urandom -jar /tmp/app.jar"
  db:
    image: postgres:11.5
    environment:
      POSTGRES_USER: "root"
      POSTGRES_PASSWORD: "root"
      POSTGRES_DB: "test"
    ports:
      - "5432:5432"
    volumes:
      - "./docker/db/data:/var/lib/postgresql/data"
      - "./docker/db/initdb:/docker-entrypoint-initdb.d"

```
意外と短いですよね！それでは、各コンテナごとに少し詳しく見ていきましょう！

### app
openjdkの公式イメージを使ったSpringBootアプリを動作させるコンテナです。
アプリのjarをコンテナにマウントして、コンテナ起動時にjarを実行しています。

- *image*  
OpenJDK 11の公式イメージを使用しています。slimでlinuxをdebian-slimにしています。
現在はSpring公式でも使用していたalpineが人気ですが、個人的に苦手なのでdebian-slimにしました。
- *ports*  
SpringBootアプリでは特別な設定をしない限り、8080ポートでアプリが立ち上がります。
- *depends_on*
dbコンテナが立ち上がってからappコンテナが立ち上がるように設定しています。
SpringBootアプリからDB接続するためDBが先に立ち上がっている必要があります。

- *volumes*
コンテナ上でSpringBootアプリのjarを操作できるように設定しています。
- *entrypoint*
コンテナ起動時にSpringBootアプリが立ち上がるように設定しています。


### dbコンテナ
postgresqlを使用したDBコンテナです。データの永続化とデータベースの初期構築を実施しています。

- *image*
PostgreSQLの公式イメージを使用しています。

- *environment*
postgresで使用する環境変数を設定していきます。
 - POSTGRES_USER → rootユーザのユーザ名を設定しています。
 - POSTGRES_PASSWORD → rootユーザのパスワードを設定していきます。
 - POSTGRES_DB → 作成するデータベース名を設定します。

- *ports*
DBに接続するためのポートです。なぜ、5432ポートかというとpostgresイメージ内でそのポートが解放されているからです。
- *volumes*
１行目でデータの永続化を２行目でデータベース初期処理を設定しています。

 - データ永続化（１行目）  
 dockerコンテナを停止してもデータが消えないように設定しています。
 - データベース初期処理（２行目）  
 dockerコンテナ起動時にdocker-entrypoint-initdb.dに格納されているshellとsqlを一回だけ起動してくれます。

# テーブルを用意する。
今回のサンプルアプリで使用するテーブルとデータを用意していきます。
初期処理を通じてテーブルやデータを登録していきますので、マウントしていますinitdbフォルダ内に３のsqlを作成していきましょう。

```
current/
      ├ docker/
             ├ db/
                ├ initdb/
                       ├ 1-create-users.sql
                       ├ 2-insert-user.sql
                       ├ 3-user.sql

```
ファイルの先頭の数字で実行順序を制御しています。
それでは、各sqlの解説にうつっていきましょう！

## 1-create-users.sql
アプリで使用するusersテーブルを作成します。今回は、プライマリキーの他に名前のフィールドがあるシンプルな作りです。

```sql:1-create-users.sql
CREATE TABLE users (
  id SERIAL,
  name VARCHAR(255) NOT NULL, /** ユーザー名 */
  PRIMARY KEY (id)
);
```

## 2-insert-users.sql
usersテーブルに１レコードの初期データを投入します。

```sql:２-insert-users.sql
INSERT INTO users (
  name
) values ( 
  'test'
);
```
## 3-user.sql
アプリから使用するDBユーザを作成していきます。CRUD操作のみを許可しています。

```sql:3-user.sql
CREATE ROLE testuser WITH LOGIN PASSWORD 'testpass';
GRANT SELECT,UPDATE,INSERT,DELETE ON ALL TABLES IN SCHEMA public TO testuser;
```
publicはpostgresのデフォルトスキーマです。特にスキーマを指定しない場合、全てpublicスキーマにテーブルが作られます。

# まとめ
お疲れ様でした！開発環境の下地ができたって状態です！
これから後半の記事でサンプルとなるアプリを作っていきます。ここまででも慣れてないと大変ですよね。
しかし、後少しでbootアプリからDB接続できてきます。後半もちょっと長くなりますが頑張っていきましょう！

# 続き
[SpringBootとPostgreSQLの開発環境をdocker-composeで用意する！下](https://qiita.com/gosutesu/items/f45150cbde3f035c54dd)


# 参考記事
- [postgres docker official image](https://hub.docker.com/_/postgres)
- [spring boot with docker](https://spring.io/guides/gs/spring-boot-docker/)