スプリングブートマイクロサービスの12要素の方法論

1. 概要

このチュートリアルでは、https://12factor.net/ [12要素アプリの方法論]を理解します。
また、Spring Bootを使用してマイクロサービスを開発する方法も理解します。 その過程で、このようなマイクロサービスを開発するために12要素の方法論を適用する方法を見ていきます。

2. 十二因子方法論とは何ですか?

  • 12要素の方法論は、サービスとして実行するために開発されたアプリケーションを開発するための12のベストプラクティスのセットです*。 これは元々、2011年にクラウドプラットフォームにサービスとしてデプロイされたアプリケーション用にHerokuによって作成されました。 時間が経つにつれて、これはhttps://en.wikipedia.org/wiki/Software_as_a_service[software-as-a-service](SaaS)の開発に十分な汎用性があることが判明しました。

    それで、サービスとしてのソフトウェアとはどういう意味ですか? 従来、ソフトウェアソリューションを設計、開発、展開、および保守して、ビジネスソリューションからビジネス価値を引き出してきました。 しかし、必ずしも同じ結果を達成するためにこのプロセスに関与する必要はありません。 たとえば、適用税の計算は、多くのドメインで一般的な機能です。
    これで、このサービスを自分で構築して管理するか、*商用サービスの提供を申し込む*ことができます。 このような*サービスの提供は、私たちがサービスとしてのソフトウェア*として知っているものです。
    サービスとしてのソフトウェアは、それが開発されたアーキテクチャに制限を課しませんが、いくつかのベストプラクティスを採用すると非常に便利です。
    最新のクラウドプラットフォーム上でソフトウェアをモジュラー、ポータブル、およびスケーラブルに設計する場合、サービス提供に非常に適しています。 これは、12要素の方法論が役立つ場所です。 チュートリアルの後半でそれらの動作を確認します。

3. Spring Bootを使用したマイクロサービス

link:/spring-microservices-guide[Microservice]は、疎結合サービスとしてソフトウェアを開発するためのアーキテクチャスタイルです。 ここで重要な要件は、*サービスをビジネスドメインの境界に沿って編成することです*。 これは多くの場合、識別するのが最も難しい部分です。
さらに、ここのサービスはそのデータに対する唯一の権限を持ち、操作を他のサービスに公開します。 サービス間の通信は通常、HTTPなどの軽量プロトコルを介して行われます。 これにより、独立して展開可能でスケーラブルなサービスが実現します。
現在、マイクロサービスアーキテクチャとサービスとしてのソフトウェアは相互に依存していません。 しかし、*サービスとしてのソフトウェアを開発するとき、マイクロサービスアーキテクチャを活用することは非常に有益*であることを理解することは難しくありません。 モジュール性やスケーラビリティなど、前述の多くの目標を達成するのに役立ちます。
https://spring.io/projects/spring-boot[Spring Boot]は、Springに基づくアプリケーションフレームワークであり、エンタープライズアプリケーションの開発に関連する多くの定型文を取り除きます。 これは、マイクロサービスを開発するための非常に意見の多い、しかし柔軟なプラットフォームを提供します。 このチュートリアルでは、Spring Bootを活用して、12要素の方法論を使用してマイクロサービスを提供します。

4. 12因子方法論の適用

ここで、今説明したツールとプラクティスを使用して開発しようとする単純なアプリケーションを定義しましょう。 私たちは皆映画を見るのが大好きですが、すでに見た映画を追跡するのは難しいです。
今、誰が映画を始めて、後でそれを放棄したいですか? 必要なのは、私たちが見た映画を記録し、クエリする簡単なサービスです:
http://inprogress.baeldung.com/uploads/12-factpr-app.jpg []
これは、データストアとRESTエンドポイントを備えた非常にシンプルで標準的なマイクロサービスです。 永続性にもマップするモデルを定義する必要があります。
@Entity
public class Movie {
    @Id
    private Long id;
    private String title;
    private String year;
    private String rating;
    // getters and setters
}
idと他のいくつかの属性を持つJPAエンティティを定義しました。 RESTコントローラーがどのように見えるかを見てみましょう。
@RestController
public class MovieController {

    @Autowired
    private MovieRepository movieRepository;
    @GetMapping("/movies")
    public List<Movie> retrieveAllStudents() {
        return movieRepository.findAll();
    }

    @GetMapping("/movies/{id}")
    public Movie retrieveStudent(@PathVariable Long id) {
        return movieRepository.findById(id).get();
    }

    @PostMapping("/movies")
    public Long createStudent(@RequestBody Movie movie) {
        return movieRepository.save(movie).getId();
    }
}
これは、当社のシンプルなサービスのベースをカバーしています。 以下のサブセクションで、12因子の方法論をどのように実装するかを説明しながら、アプリケーションの残りの部分を見ていきます。

4.1. コードベース

12要素アプリの最初のベストプラクティスは、バージョン管理システムで追跡することです。 https://git-scm.com/[Git]は、今日使用されている最も人気のあるバージョン管理システムであり、ほぼどこにでもあります。 原則では、*アプリは単一のコードリポジトリで追跡する必要があり、そのリポジトリを他のアプリと共有してはいけません*。
Spring Bootは、コマンドラインツールやhttps://start.spring.io/ [ウェブインターフェース]など、アプリケーションをブートストラップするための多くの便利な方法を提供します。 ブートストラップアプリケーションを生成したら、これをgitリポジトリに変換できます。
git init
このコマンドは、アプリケーションのルートから実行する必要があります。 この段階のアプリケーションには、生成されたファイルのバージョン管理を効果的に制限する.gitignoreファイルが既に含まれています。 したがって、すぐに最初のコミットを作成できます。
git add .
git commit -m "Adding the bootstrap of the application."
最後に、リモートを追加し、必要に応じてコミットをリモートにプッシュできます(これは厳密な要件ではありません)。
git remote add origin https://github.com/<username>/12-factor-app.git
git push -u origin master

4.2. 依存関係

次に、* twelve-factorアプリは、常にすべての依存関係を明示的に宣言する必要があります*。 依存関係宣言マニフェストを使用してこれを行う必要があります。 Javaには、MavenやGradleなどの依存関係管理ツールが複数あります。 これらの1つを使用して、この目標を達成できます。
したがって、この単純なアプリケーションは、REST APIを容易にし、データベースに接続するためのライブラリなど、いくつかの外部ライブラリに依存しています。 Mavenを使用して宣言的に定義する方法を見てみましょう。
Mavenでは、プロジェクトの依存関係を、通常https://maven.apache.org/guides/introduction/introduction-to-the-pom.html [プロジェクトオブジェクトモデル](POM)として知られるXMLファイルで記述する必要があります。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>
これは単純明快ですが、これらの依存関係には通常、他の推移的な依存関係があります。 これはある程度複雑になりますが、目標を達成するのに役立ちます。 現在、アプリケーションには、明示的に説明されていない直接的な依存関係はありません。

4.3. 構成

通常、アプリケーションには多くの構成があり、その一部はデプロイメント間で異なる場合がありますが、その他は同じままです。
この例では、永続的なデータベースがあります。 接続するデータベースのアドレスと資格情報が必要です。 これは、展開ごとに変わる可能性が最も高いです。
  • 12要素アプリは、展開ごとに異なるこのような構成をすべて外部化する必要があります*。 ここでの推奨事項は、このような構成に環境変数を使用することです。 これにより、構成とコードが明確に分離されます。

    Springは、このような構成を宣言して環境変数に添付できる構成ファイルを提供します。
spring.datasource.url=jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/movies
spring.datasource.username=${MYSQL_USER}
spring.datasource.password=${MYSQL_PASSWORD}
ここでは、構成としてデータベースURLと資格情報を定義し、環境変数から選択される実際の値をマップしました。
Windowsでは、アプリケーションを開始する前に環境変数を設定できます。
set MYSQL_HOST=localhost
set MYSQL_PORT=3306
set MYSQL_USER=movies
set MYSQL_PASSWORD=password
このプロセスを自動化するには、https://www.ansible.com/ [Ansible]やhttps://www.chef.io/[Chef]などの構成管理ツールを使用できます。

4.4. バッキングサービス

バッキングサービスは、アプリケーションが操作に依存するサービスです。 たとえば、データベースまたはメッセージブローカー。 * 12ファクターアプリでは、このようなすべてのバッキングサービスを添付リソースとして扱う必要があります。*これが効果的に意味するのは、互換性のあるバッキングサービスを交換するためにコードを変更する必要がないことです。 唯一の変更は構成にある必要があります。
このアプリケーションでは、永続性を提供するバッキングサービスとしてhttps://www.mysql.com/[MySQL]を使用しました。
link:/the-persistence-layer-with-spring-and-jpa[Spring JPA]は、コードを実際のデータベースプロバイダーにとらわれないものにします。 すべての標準操作を提供するリポジトリを定義するだけです。
@Repository
public interface MovieRepository extends JpaRepository<Movie, Long> {
}
ご覧のとおり、これはMySQLに直接依存していません。 SpringはクラスパスでMySQLドライバーを検出し、このインターフェイスのMySQL固有の実装を動的に提供します。 さらに、構成から他の詳細を直接引き出します。
したがって、MySQLからOracleに変更する必要がある場合は、依存関係のドライバーを置き換え、構成を置き換えるだけです。

4.5. ビルド、リリース、実行

12要素の方法論は、コードベースを実行中のアプリケーションに変換するプロセスを3つの異なる段階として厳密に分離します。
  • ビルドステージ:ここでコードベースを取得し、静的および
    動的チェックを行い、JARのような実行可能バンドルを生成します。 Mavenのようなツールを使用すると、これは非常に簡単です。

     mvn clean compile test package
  • リリース段階:これは、実行可能バンドルを取得する段階です
    これを適切な構成と組み合わせます。 ここでは、https://www.ansible.com/ [Ansible]のようなプロビジョニングツールでhttps://www.packer.io/[Packer]を使用してDockerイメージを作成できます。

     packer build application.json
  • 実行ステージ:最後に、これはアプリケーションを実行するステージです
    ターゲット実行環境。 Dockerをコンテナとして使用してアプリケーションをリリースする場合、アプリケーションの実行は非常に簡単です。

     docker run --name <container_id> -it <image_id>
最後に、これらの段階を必ずしも手動で実行する必要はありません。 これは、https://jenkins.io/ [Jenkins]が宣言パイプラインと非常に便利になる場所です。

4.6. プロセス

  • 12要素アプリは、ステートレスプロセスとして実行環境で実行されることが期待されています。つまり、リクエスト間で永続的な状態をローカルに保存することはできません。 それらは、1つ以上のステートフルバッキングサービスに格納する必要がある永続的なデータを生成する場合があります。

    この例の場合、複数のエンドポイントが公開されています。 これらのエンドポイントに対するリクエストは、それより前に行われたリクエストとは完全に独立しています。 たとえば、メモリ内のユーザーリクエストを追跡し、その情報を使用して将来のリクエストを処理すると、12要素アプリに違反します。
    したがって、12要素のアプリでは、スティッキーセッションのような制限はありません。 これにより、このようなアプリは非常にポータブルでスケーラブルになります。 自動スケーリングを提供するクラウド実行環境では、アプリケーションからの非常に望ましい動作です。

4.7. ポートバインディング

Javaの従来のWebアプリケーションは、WARまたはWebアーカイブとして開発されます。 これは通常、依存関係を持つサーブレットのコレクションであり、Tomcatのような適合コンテナランタイムが必要です。 *それどころか、12要素のアプリはそのようなランタイム依存関係を期待していません。*完全に自己完結型であり、Javaのような実行ランタイムのみを必要とします。
今回のケースでは、Spring Bootを使用してアプリケーションを開発しました。 Spring Bootは、他の多くの利点とは別に、デフォルトの組み込みアプリケーションサーバーを提供します。 したがって、以前にMavenを使用して生成したJARは、互換性のあるJavaランタイムを使用するだけで、あらゆる環境で実行できます。
java -jar application.jar
ここで、単純なアプリケーションは8080などの特定のポートへのHTTPバインディングを介してエンドポイントを公開します。 上記のようにアプリケーションを起動すると、HTTPなどのエクスポートされたサービスにアクセスできるようになります。
アプリケーションは、複数のポートにバインドすることにより、FTPやlink:/websockets-spring[WebSocket]などの複数のサービスをエクスポートできます。

4.8. 並行性

Javaは、アプリケーションの同時実行性を処理するための古典的なモデルとして_Thread_を提供します。 スレッドは軽量プロセスに似ており、プログラム内の複数の実行パスを表します。 スレッドは強力ですが、アプリケーションのスケーリングにどれだけ役立つかという点で制限があります。
  • 12因子の方法論では、アプリがスケーリングのためにプロセスに依存することが示唆されています。*これが効果的に意味するのは、複数のプロセスにワークロードを分散するようにアプリケーションを設計することです。 ただし、個々のプロセスは、_Thread_などの並行性モデルを内部で自由に活用できます。

    Javaアプリケーションは、起動されると、基礎となるJVMにバインドされた単一のプロセスを取得します。 効果的に必要なのは、インテリジェントな負荷分散を使用して、アプリケーションの複数のインスタンスを起動する方法です。 link:/docker-java-api[Docker]コンテナとしてアプリケーションを既にパッケージ化しているため、https://www.baeldung.com/kubernetes [Kubernetes]はそのような選択肢ですオーケストレーション。

4.9. 使い捨て

アプリケーションプロセスは、意図的に、または予期しないイベントによってシャットダウンされる場合があります。 いずれの場合も、* 12ファクターアプリはそれを適切に処理することになっています*。 言い換えると、アプリケーションプロセスは、望ましくない副作用なしで完全に使い捨てである必要があります。 さらに、プロセスはすぐに開始する必要があります
たとえば、このアプリケーションでは、エンドポイントの1つは映画の新しいデータベースレコードを作成することです。 現在、このようなリクエストを処理するアプリケーションが予期せずクラッシュする可能性があります。 ただし、これはアプリケーションの状態に影響しないはずです。 クライアントが同じリクエストを再度送信する場合、レコードが重複することはありません。
要約すると、アプリケーションはべき等のサービスを公開する必要があります。 これは、クラウド展開向けのサービスのもう1つの非常に望ましい属性です。 これにより、他の考慮事項なしにいつでも新しいサービスを停止、移動、またはスピンできる柔軟性が得られます。

4.10。 開発/製品パリティ

ローカルマシンでアプリケーションを開発し、他のいくつかの環境でテストし、最終的に運用環境に展開するのが一般的です。 これらの環境が異なる場合がよくあります。 たとえば、開発チームはWindowsマシンで作業しますが、実稼働展開はLinuxマシンで行われます。
  • 12要素の方法論では、開発環境と運用環境のギャップをできるだけ小さく保つことが推奨されています。*これらのギャップは、長い開発サイクル、関与するさまざまなチーム、使用中のさまざまなテクノロジースタックに起因する可能性があります。

    現在、Spring BootやDockerなどのテクノロジーが、このギャップを自動的に大幅に埋めています。 コンテナ化されたアプリケーションは、どこで実行しても同じように動作することが期待されています。 データベースのような同じバッキングサービスも使用する必要があります。
    さらに、このギャップをさらに埋めるために、継続的な統合や配信などの適切なプロセスが必要です。

4.11。 Logs

ログは、アプリケーションがその存続期間中に生成する重要なデータです。 アプリケーションの動作に関する貴重な洞察を提供します。 通常、アプリケーションは、さまざまな詳細を含む複数のレベルでログを生成し、複数の異なる形式で出力することができます。
ただし、12要素のアプリは、ログ生成とその処理から分離されます。 *このようなアプリの場合、ログはイベントの時系列ストリームに過ぎません。*これらのイベントは、実行環境の標準出力に単に書き込まれます。 このようなストリームのキャプチャ、ストレージ、キュレーション、およびアーカイブは、実行環境で処理する必要があります。
この目的で使用できるツールはかなりあります。 まず、https://www.baeldung.com/slf4j-with-log4j2-logback [SLF4J]を使用して、アプリケーション内でロギングを抽象的に処理できます。 さらに、https://www.fluentd.org/ [Fluentd]などのツールを使用して、アプリケーションおよびバッキングサービスからログのストリームを収集できます。
これは、ストレージとインデックス作成のためにhttps://www.elastic.co/[Elasticsearch]にフィードできます。 最後に、https://www.elastic.co/products/kibana [Kibana]で視覚化のための意味のあるダッシュボードを生成できます。

4.12。 管理プロセス

多くの場合、アプリケーションの状態でいくつかの一時タスクまたはルーチン手順を実行する必要があります。 たとえば、不良レコードの修正。 現在、これを実現する方法はさまざまです。 あまり必要としないことが多いため、別の環境とは別に実行する小さなスクリプトを作成できます。
現在、* 12要素の方法論では、このような管理スクリプトをアプリケーションのコードベースと一緒に保持することを強くお勧めしています*。 その際、メインアプリケーションのコードベースに適用するのと同じ原則に従う必要があります。 また、実行環境の組み込みREPLツールを使用して、運用サーバーでこのようなスクリプトを実行することをお勧めします。
この例では、アプリケーションをこれまでに見た映画でどのようにシードしますか? 甘い小さなエンドポイントを使用できますが、それは実用的ではないように思えるかもしれません。 必要なのは、1回限りのロードを実行するスクリプトです。 ファイルから映画のリストを読み取り、それらをバッチでデータベースに保存する小さなJava関数を作成できます。
さらに、https://www.baeldung.com/groovy-java-applications [Javaと統合されたGroovy]ランタイムを使用して、このようなプロセスを開始できます。

5. 実用的なアプリケーション

それで、12因子の方法論によって提案されたすべての要因を見てきました。 アプリケーションを* 12ファクターアプリに開発することには、確かに利点があります。特に、クラウド上のサービスとしてそれらを展開したい場合*。 しかし、他のすべてのガイドライン、フレームワーク、パターンと同様に、これは特効薬ですか?
正直なところ、ソフトウェアの設計と開発における単一の方法論が特効薬であると主張することはありません。 12要素の方法論も例外ではありません。 *これらの要因のいくつかは非常に直感的*であり、おそらく私たちはすでにそれらを行っていますが、*その他は私たちに当てはまらない可能性があります*。 これらの要因を目標の背景で評価し、賢明に選択することが不可欠です。
これらのすべての要因は、*モジュール化された、独立した、ポータブルで、スケーラブルで、観察可能なアプリケーションの開発に役立つことに注意することが重要です。 アプリケーションによっては、他の方法でより良く達成できる場合があります。 また、すべての要因を一緒に採用する必要はありません。これらのいくつかを採用することで、私たちは以前よりも良くなるかもしれません。
最後に、これらの要素は非常にシンプルでエレガントです。 これらは、ダウンタイムや障害が事実上なく、より高いスループットとより低いレイテンシーをアプリケーションに要求する時代に、より重要になります。 *これらの要素を採用することで、最初から適切なスタートが切れます。*マイクロサービスアーキテクチャとアプリケーションのコンテナ化と組み合わせると、適切な場所にあるように見えます。

6. 結論

このチュートリアルでは、12要素の方法論の概念について説明しました。 Spring Bootでマイクロサービスアーキテクチャを活用して効果的に配信する方法について説明しました。 さらに、各要素を詳細に調査し、それらをアプリケーションに適用する方法を調べました。 また、これらの個々の要因を効果的に効果的に適用するためのいくつかのツールも検討しました。