LoginSignup
21

More than 5 years have passed since last update.

Spring Cloudで簡単なマイクロサービスを構築する

Last updated at Posted at 2018-06-18

◇目的

SpringCloudを使用して簡単なマイクロサービスを構築する。

◇ゴール

クライアントからリクエストするとDBから取得(SELECT)した値を返すサービスを作成する。

【ゴール】全体像

4.png

構成要素名 役割
APIGateway リバースプロキシの役割を担う。Zuulを使用。
DiscoveryService サービスの登録/検索/呼出の役割を担う。Eurekaを使用。
ConfigService 各サービスのプロパティをGitLabから取得し、返却する。Spring Cloud Configを使用。
GitLab 各サービスのプロパティを管理する。(ポート番号/DBのURL・ユーザ・パスワード等)
ProductService リクエストされたDB値をJSONで返却する。

【ゴール】補足

各サービスの構築・連携方法を話のメインにしたいため、HA構成にはしない。
※HA構成の場合、各サービスを冗長化し、前にLoadBalancerを立てるイメージ。

◇前提

◇完成したソース

こちら。
https://gitlab.com/tk_230to/spring-cloud-msa-sample

◇参考

Spring Cloudのリファレンスはこちら。
https://spring.io/docs/reference

◇概要

準備

  1. 【準備】PostgerSQLインストール&DB作成
  2. 【準備】GitLabリポジトリ作成

構築

  1. ConfigService作成
  2. DiscoveryService作成
  3. ProductService作成
  4. APIGateway作成

◇準備

1. 【準備】PostgerSQLインストール&DB作成

ProductServiceが接続するDBをローカルに用意する。
今回はPostgreSQLを使用する。

1.1 ダウンロード

ダウンロードリンクからPostgreSQLのバージョンとOSを選択してダウンロード。

1.2 インストール

ダウンロードしたインストーラを実行して↓以外はデフォルトでポチポチ。
・Password:「postgres」(好きなパスワードで)
・Locale:「Japanese, Japan」
・スタックビルダ:無し

1.3 テーブル作成

商品ID(item_id)/商品名(item_name)を持つ簡単な商品テーブルを作成。

1.3.1 作成する商品テーブル

No カラム名 NotNull PK
1 item_id integer
2 item_name character varying(255)

1.3.2 テーブル作成手順

(1)「スタート」→「pgadmin」で検索→「pgAdmin 4」を実行。
(2)「pgAdmin 4」画面の「Tools」→「Query Tool」
(3) ↓のSQL文を貼り付けて「F5」で実行。

create_table_item.sql
-- item_idのシーケンス作成
CREATE SEQUENCE item_id_seq;

-- テーブル作成
CREATE TABLE public.item
(
    item_id integer PRIMARY KEY DEFAULT nextval('item_id_seq'),
    item_name character varying(255) COLLATE pg_catalog."default" NOT NULL
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE public.item
    OWNER to postgres;

1.4 データ登録

(1) ↓のSQL文を貼り付けて「F5」で実行。

insert_item.sql
INSERT INTO item (item_name) VALUES ('商品1');

2. 【準備】GitLabリポジトリ作成

プロパティを管理するためのGitLabリポジトリを作成する。

2.1 GitLab.comの無料アカウントを作成

(1) GitLab.comを表示して、赤枠をポチポチ。
 

(2) 「Register」を選択してユーザー名等を入力して「Register」。
 

(3) 確認メールが届くので「Confirm your account」で確認。
(4) プライバシーポリシーを確認して問題なければ「Accept terms」

2.2 リポジトリ作成

GitLabアカウントが登録できたら、リポジトリを作成。
プロジェクト名は、プロパティファイルの管理が目的なので「conf」。
公開範囲はサンプルなので「Public」。

2.3 masterブランチ作成

何でも良いのでファイルを登録するとmasterブランチが作成される。
「Add Readme」で「README.md」を登録する。

◇構築

PostgreSQLとGitLabの準備が整ったので、サービスを作成する。

1. ConfigService作成

各サービスのプロパティはConfigServiceから取得するので、
ConfigServiceが完成していないと各サービスを動かせない。
そのため、最初にConfigServiceを作成する。

手順概要

手順 概要
1.1 プロジェクト作成 「Springスターター・プロジェクト」でプロジェクトの雛形を作成
1.2 Javaアプリケーション作成 @EnableConfigServer」にて、私はConfigServiceですよと宣言
1.3 build.gradleファイル作成 動作するSpringのバージョンを設定
1.4 プロパティファイル作成 GitLabのURIや起動ポート番号を設定
1.5 動作確認 実行してみる

1.1 プロジェクト作成

1.1.1 新規プロジェクト作成

STSを起動して、「ファイル」→「新規」→「Spring スターター・プロジェクト」。

1.1.2 プロジェクト名等を設定

プロジェクト名=「ConfigService」、型=「Gradle (Buildship 2.x)」。
 

1.1.3 依存関係を設定

依存関係に「Config Server」(「構成サーバ」)を選択して完了。
バージョンはここでは変更できないので「1.3 build.gradleファイル作成」にて後で変更。
 

1.2 Javaアプリケーション作成

src/main/javaのConfigServiceApplication.javaに「@EnableConfigServer」を付与。

ConfigServiceApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer // ←付与
public class ConfigServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServiceApplication.class, args);
    }
}

1.3 build.gradleファイル作成

動作するバージョンに変更する。
・springBootVersion = '2.0.0.RELEASE'に変更
・springCloudVersion = 'Finchley.M8'に変更

build.gradle
buildscript {
    ext {
        springBootVersion = '2.0.0.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 = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
}


ext {
    springCloudVersion = 'Finchley.M8' // 変更
}

dependencies {
    compile('org.springframework.cloud:spring-cloud-config-server')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

1.4 プロパティファイル作成

1.4.1 bootstrap.yml作成

src/main/resourcesのapplication.propertiesをbootstrap.ymlにリネームして編集。
bootstarp.ymlはSpringBootで最優先に取得されるプロパティファイル。

bootstrap.yml
# サービス名
spring.application.name: ConfigService

# 使用するポート番号
server.port: 8888

# GitリポジトリURI (「2. 【準備】GitLabリポジトリ作成」で作成したGitLabのURIに変えてください)
spring.cloud.config.server.git.uri: https://gitlab.com/tk_230to/conf.git

1.5 動作確認

1.5.1 Gradleの依存関係を最新化

「ConfigService」を右クリック→「Gradle」→「Gradleプロジェクトのリフレッシュ」

1.5.2 サービス起動

「ConfigService」を右クリック→「実行」→「Spring Bootアプリケーション」

1.5.3 アクセスしてみる

http://localhost:8888/admin/env にアクセスしてみて、JSONレスポンスが返ってきたらOK。
綺麗に見たければDHC REST Client等を使う。

2. DiscoveryService作成

手順概要

手順 概要
2.1 プロジェクト作成 「Springスターター・プロジェクト」でプロジェクトの雛形を作成
2.2 Javaアプリケーション作成 @EnableEurekaServer」にて、私はEurekaですよと宣言
2.3 build.gradleファイル作成 動作するSpringのバージョンを設定
2.4 プロパティファイル作成 (1)ConfigServiceのURIと自サービス名を教える(bootstrap.yml)
(2)自身のプロパティをGitLabに登録(DiscoveryService.yml)
2.5 動作確認 実行してみる

2.1 プロジェクト作成

「1. ConfigService作成」と同様で、違うところは太字。
・プロジェクト名=「DiscoveryService」、型=「Gradle (Buildship 2.x)」。
・依存関係に「Eureka サーバー」「構成クライアント」を選択して完了。

2.2 Javaアプリケーション作成

src/main/javaのDiscoveryServiceApplication.javaに「@EnableEurekaServer」「@RefreshScope」を付与。

DiscoveryServiceApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer // ←追加
@RefreshScope // ←追加
public class DiscoveryServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(DiscoveryServiceApplication.class, args);
    }
}

2.3 build.gradleファイル作成

1.3と同様。

build.gradle
buildscript {
    ext {
        springBootVersion = '2.0.0.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 = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
}


ext {
    springCloudVersion = 'Finchley.M8' // 変更
}

dependencies {
    compile('org.springframework.cloud:spring-cloud-starter-config')
    compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-server')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

2.4 プロパティファイル作成

bootstrap.ymlとDiscoveryService.ymlの2種類を作成する。

種類 説明
bootstrap.yml ConfigServiceに関するプロパティを保持。それ以外のプロパティは↓に保持。
DiscoveryService.yml GitLabに外出しするプロパティ。ConfigServiceから取得される。

2.4.1 bootstrap.yml作成

src/main/resourcesのapplication.propertiesをbootstrap.ymlにリネームして編集。
ConfigServiceから「{サービス名}.yml」(DiscoveryService.yml) が取得されるようになる。
※正確には「{サービス名}-{プロファイル名}.yml」。
 プロファイル名は、product/development/default。
 今回はややこしくならないようプロファイル名は省略。

bootstrap.yml
# サービス名
spring.application.name: DiscoveryService

# ConfigServiceのURI
spring.cloud.config.uri: http://localhost:8888

2.4.2 DiscoveryService.yml作成

GitLabのリポジトリにDiscoveryService.ymlを作成。

DiscoveryService.yml
# 使用するポート番号(デフォルト8761だが分かりやすく明示)
server.port: 8761

# 自分自身をEurekaのレジストリに登録しない
eureka.client.registerWithEureka: false
eureka.client.fetchRegistry: false

2.5 動作確認

1.5と同様。ただし、ConfigServiceからプロパティを取得するので、
先にConfigServiceを起動してから、DiscoveryServiceを起動する順序。

(1) Gradleの依存関係を最新化
(2) ConfigService起動
(3) DiscoveryService起動
(4) アクセスしてみる
http://localhost:8761 にアクセスしてみて、Eurekaの画面が表示されたらOK。

3. ProductService作成

手順概要

手順 概要
3.1 プロジェクト作成 「Springスターター・プロジェクト」でプロジェクトの雛形を作成
3.2 Javaアプリケーション作成 @EnableEurekaClient」でEurekaクライアント宣言
3.3 Entityクラス作成 商品テーブルの情報を保持するクラスを作成
3.4 Repositoryクラス作成 商品テーブルのCRUDクラスを作成
3.5 build.gradleファイル作成 動作するSpringのバージョンを設定
3.6 プロパティファイル作成 (1)ConfigServiceのURIと自サービス名を教える(bootstrap.yml)
(2)自身のプロパティをGitLabに登録(ProductService.yml)
3.7 動作確認 実行してみる

3.1 プロジェクト作成

「1. ConfigService作成」と同様で、違うところは太字。
・プロジェクト名=「ProductService」、型=「Gradle (Buildship 2.x)」。
・依存関係に「Eureka ディスカバリー」「構成クライアント」「JPA」「Rest リポジトリー」「PostgreSQL」を選択して完了。

3.2 Javaアプリケーション作成

src/main/javaのProductServiceApplication.javaに「@EnableEurekaClient」「@RefreshScope」を付与。

ProductServiceApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient // ←追加
@RefreshScope // ←追加
public class ProductServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.class, args);
    }
}

3.3 Entityクラス作成

src/main/javaに商品テーブルのEntityクラスを作成。

Item.java
package com.example.demo;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="item")
public class Item implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="item_id")
    private Integer itemId;

    @Column(name="item_name")
    private String itemName;

    public Integer getItemId() {
        return itemId;
    }

    public void setItemId(Integer itemId) {
        this.itemId = itemId;
    }

    public String getItemName() {
        return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }
}

※lombokを使うとGETレスポンスに商品名が出力されなかったため、getter/setterを直接記述した。

3.4 Repositoryクラス作成

src/main/javaに商品テーブルのCRUDを操作するRepositoryクラスを作成。
「JpaRepository」を使用しているので、Rest URIのエンドポイントも作成される。

ItemRepository.java
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ItemRepository extends JpaRepository<Item, Integer> {
}

3.5 build.gradleファイル作成

1.3と同様。

build.gradle
buildscript {
    ext {
        springBootVersion = '2.0.0.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 = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
}


ext {
    springCloudVersion = 'Finchley.M8' // 変更
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-data-rest')
    compile('org.springframework.cloud:spring-cloud-starter-config')
    compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
    runtime('org.postgresql:postgresql')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

3.6 プロパティファイル作成

2.4と同様。bootstrap.ymlとProductService.ymlの2種類を作成する。

3.6.1 bootstrap.yml作成

src/main/resourcesのapplication.propertiesをbootstrap.ymlにリネームして編集。

bootstrap.yml
# サービス名
spring.application.name: ProductService

# ConfigServiceのURI
spring.cloud.config.uri: http://localhost:8888

3.6.2 ProductService.yml作成

GitLabのリポジトリにProductService.ymlを作成。

ProductService.yml
# 使用するポート番号
server:
  port: 8081

# DB接続情報
spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://localhost:5432/postgres
    username: postgres
    password: postgres

# Eurekaの情報
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

3.7 動作確認

2.5と同様。ConfigService→DiscoveryService→ProductServiceの順番で起動する。
http://localhost:8081/items/1 にアクセスしてみて、"商品1"が返却されたらOK。

4. API Gateway作成

手順概要

手順 概要
4.1 プロジェクト作成 「Springスターター・プロジェクト」でプロジェクトの雛形を作成
4.2 Javaアプリケーション作成 @EnableZuulProxy」にて、Zuul Proxyを有効化
4.3 build.gradleファイル作成 動作するSpringのバージョンを設定
4.4 プロパティファイル作成 (1)ConfigServiceのURIと自サービス名を教える(bootstrap.yml)
(2)自身のプロパティをGitLabに登録(APIGateway.yml)
4.5 動作確認 実行してみる

4.1 プロジェクト作成

「1. ConfigService作成」と同様で、違うところは太字。
・プロジェクト名=「APIGateway」、型=「Gradle (Buildship 2.x)」。
・依存関係に「Eureka ディスカバリー」「構成クライアント」「Zuul」を選択して完了。

4.2 Javaアプリケーション作成

src/main/javaのAPIGatewayApplication.javaに「@EnableZuulProxy」「@EnableEurekaClient」「@RefreshScope」を付与。

APIGatewayApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableEurekaClient // ←追加
@RefreshScope // ←追加
@EnableZuulProxy // ←追加
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

4.3 build.gradleファイル作成

1.3と同様。

build.gradle
buildscript {
    ext {
        springBootVersion = '2.0.0.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 = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
}


ext {
    springCloudVersion = 'Finchley.M8' // 変更
}

dependencies {
    compile('org.springframework.cloud:spring-cloud-starter-config')
    compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
    compile('org.springframework.cloud:spring-cloud-starter-netflix-zuul')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

4.4 プロパティファイル作成

2.4と同様。bootstrap.ymlとAPIGateway.ymlの2種類を作成する。

4.4.1 bootstrap.yml作成

src/main/resourcesのapplication.propertiesをbootstrap.ymlにリネームして編集。

bootstrap.yml
# サービス名
spring.application.name: APIGateway

# ConfigServiceのURI
spring.cloud.config.uri: http://localhost:8888

4.4.2 APIGateway.yml作成

GitLabのリポジトリにAPIGateway.ymlを作成。

APIGateway.yml
# 使用するポート番号
server:
  port: 8000

# Eurekaの情報
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

# ProductServiceのルート情報
zuul:
  routes:
    users:
      path: /items/**
      serviceId: ProductService
      stripPrefix: false

4.5 動作確認

2.5と同様。ConfigService→DiscoveryService→ProductService→APIGatewayの順番で起動する。
http://localhost:8000/items/1 にアクセスしてみて、"商品1"が返却されたらOK。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21