Spring Cloudでマイクロサービスを構成する（１）：イントロ編

久しぶりの投稿となりました。

しばらくSpring界隈から離れていましたが、ここ数年でいろいろなプロダクトの変遷があったようなので、
今回からSpring Cloudファミリーのプロダクトとdockerを使ったシンプルなマイクロサービス構成を紹介していきます。

### 概要

このシリーズでは図のような構成でサービスを立て、そこから少しずつテーマを設けて掘り下げていきたいと思います。
![services.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534936/c8ff2f2e-8ebb-d189-47ae-b11b95f6c87f.png)

* REST API Server
    * DBにアクセスしてJSONベースのやり取りをするREST APIを提供する。
    * 同じAPIを負荷分散のために複数インスタンス用意する。
* Service Discovery
    * APIのインスタンス情報（ホスト、ポート番号など）を保持し、クライアントにリストを提供する。
    * 冗長構成をとる。
* API Gateway
    * APIに対してリバースプロキシとなるサービス。
    * Service DiscoveryからSerivce Listを取得し、アルゴリズムに応じて負荷分散をしてAPIへアクセスする。
    * 認証関連、ルーティング（リクエストパスとサービスの関係解決）、フィルタリング、アクセス流量制御など、APIに持ち込みたくない共通の関心事を解決するモノ。

### 環境

以下が動く環境を前提とします。

* docker & docker-compose
* JDK11
* なんらかのエディタ、IDE

WindowsだとDocker Desktop for Windows & Ubuntu 20.04 on WSL2とか
MacだとDocker desktop for Mac とかで動くはずです。
ここではセットアップの手順は省きますので、他の記事を参考にセットアップしてください。

＜補足＞
私はDocker Desktop for Windows とWLS2の連携がいまいち調子が悪く、
以下の記事を参考に「Docker Desktop for Windows」をインストールせずにWSL2＆Ubuntu2.0の環境を使っています。

[Install Docker on Ubuntu 18.04 on WSL2](https://qiita.com/ymasaoka/items/83a39b9279ac2eb94b6b)


### docker-composeを利用してDBと管理Webツールをセットアップする

まずはAPIが使用するDB(PostgreSQL)とDB用の管理Webをセットアップします。
便利な世の中なので、docker-composeを使って、さくっとセットアップできちゃいます。

下記のフォルダ構成を作成し、docker-compose.yml と DB初期データ作成のSQLを配置します。

```text
spring-msa
 ├── docker-compose.yml
 └── db
     └── init
          ├── 01_create_table.sql
          └── 02_insert_data.sql
```

```text:docker-compose.yml
version: '3'

volumes:
  pgdata:

networks:
  default:

services:
  db:
    image: postgres
    container_name: db
    ports:
      - 5432:5432
    environment:
      - POSTGRES_DB=${DB_NAME:-db}
      - POSTGRES_USER=${DB_USER:-postgres}
      - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./db/init:/docker-entrypoint-initdb.d

  adminer:
    image: michalhosna/adminer
    container_name: adminer
    ports:
      - 8000:8080
    restart: always
    depends_on:
      - db
    environment:
      # specify service name of PostgreSQL to ADMINER_SERVER
      - ADMINER_SERVER=db
      - ADMINER_DRIVER=pgsql
      - ADMINER_DB=${DB_NAME:-db}
      - ADMINER_USERNAME=${DB_USER:-postgres}
      - ADMINER_PASSWORD=${DB_PASSWORD:-postgres}
      - ADMINER_NAME=ADMINER for PostgreSQL DB
## uncommnet to enable auto-login
#      - ADMINER_AUTOLOGIN=1
```

postgresは公式イメージを使っています。

dockerのVolume機能を使ってローカルのディレクトリ（今回はdb/init）を `/docker-entrypoint-initdb.d` ディレクトリにbindし、その中にprefixとして連番のついたSQLファイルを配置しておくと、DBの初回起動時に自動実行してくれます。（PostgreSQLの公式Dockerイメージの機能）
便利ですねー。

adminerはDBメンテツールでWeb上でPostgreSQLのデータを参照、編集ができる便利なやつです。
DBへの接続情報を自動設定（初期表示）してくれるように[カスタマイズされたイメージ](https://github.com/michalhosna/adminer-docker)がありましたので、使わせてもらいます。

※DB名やDBユーザ、パスワードはホスト側の環境変数で上書きできるようにしていますが、あまり気にしなくて良いでしょう


さて、DBをセットアップするためのSQLを用意しましょう。

ここでは`account`テーブルをcreateして3行の初期データをinsertします。

```sql:db/init/01_create_table.sql
CREATE TABLE account (
    id bigserial,
    uname VARCHAR(30),
    token  VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

```sql:db/init/02_insert_data.sql
INSERT INTO account (uname, token) VALUES ('sato', 'AAAA');
INSERT INTO account (uname, token) VALUES ('yamada', 'BBBB');
INSERT INTO account (uname, token) VALUES ('suzuki', 'CCCC');
```

さてここまできたらdocker-compose.ymlのあるディレクトリで以下を実行し、PostgreSQLとAdminerを起動します。

```console
（サービスを指定して起動する場合）
$ docker-compose up -d db adminer

（全サービスを一気に起動する場合）
$ docker-compose up -d
```

では、Webブラウザで http://localhost:8000 にアクセスしてみましょう。
Adminerのログイン画面が出るはずです。
ログインして、`accout` テーブルとデータが3行入っているのが確認できればOKです。

![adminer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534936/eb1b912e-6f07-567c-2c5c-9bb0085ae7e5.png)


確認が終わったら一応、コンテナを止めて破棄しておきましょう。

```console
（個別にサービスを指定してコンテナを停止する場合）
$ docker-compose stop db adminer
（起動中のすべてのコンテナを止めて、ネットワークを含めて破棄する場合）
$ docker-compose down
```

作ったDBの内容も一緒に破棄する場合は、Volumeも破棄する「-v」を付けます。

```console
$ docker-compose down -v
```


### 次回予告

今回はDBのセットアップだけでしたが、次回はDBをCRUD操作するREST APIをSpring Bootでさらっと作りたいと思います。

ではでは。