SpringBootマイクロサービスにおける12要素の方法論

1。概要

このチュートリアルでは、12要素のアプリの方法論を理解します。

また、SpringBootを使用してマイクロサービスを開発する方法についても理解します。その過程で、このようなマイクロサービスを開発するために12要素の方法論を適用する方法を見ていきます。

2. 12因子の方法論とは何ですか?

12要素の方法論は、サービスとして実行するために開発されたアプリケーションを開発するための12のベストプラクティスのセットです。これは元々、2011年に、クラウドプラットフォームにサービスとしてデプロイされたアプリケーション用にHerokuによって作成されました。時間の経過とともに、これはサービスとしてのソフトウェア(SaaS)開発に十分な汎用性を持つことが証明されました。

では、Software-as-a-Serviceとはどういう意味ですか?従来、私たちはソフトウェアソリューションを設計、開発、展開、および保守して、そこからビジネス価値を引き出してきました。しかし、必ずしも同じ結果を達成するために、このプロセスに従事する必要はありません。たとえば、適用される税金の計算は、多くのドメインで一般的な機能です。

現在、このサービスを自分で構築および管理するか、商用サービスの提供に加入するかを決定する場合があります。このようなサービスの提供は、Software-as-a-Serviceとして知られているものです。

Software-as-a-Serviceは、それが開発されたアーキテクチャに制限を課しませんが、いくつかのベストプラクティスを採用することは非常に便利です。

最新のクラウドプラットフォームでモジュール式、ポータブル、およびスケーラブルになるようにソフトウェアを設計する場合、それは当社のサービス提供に非常に適しています。これは、12要素の方法論が役立つところです。チュートリアルの後半でそれらの動作を確認します。

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

マイクロサービスは、ソフトウェアを疎結合サービスとして開発するためのアーキテクチャスタイルです。ここでの重要な要件は、サービスをビジネスドメインの境界を中心に編成する必要があることです。これは多くの場合、識別するのが最も難しい部分です。

さらに、ここでのサービスは、そのデータに対する唯一の権限を持ち、他のサービスに操作を公開します。サービス間の通信は通常、HTTPなどの軽量プロトコルを介して行われます。これにより、独立して展開可能でスケーラブルなサービスが実現します。

現在、マイクロサービスアーキテクチャとサービスとしてのソフトウェアは相互に依存していません。ただし、サービスとしてのソフトウェアを開発する場合、マイクロサービスアーキテクチャを活用することが非常に有益であることを理解するのは難しくありません。モジュール性やスケーラビリティなど、前に説明した多くの目標を達成するのに役立ちます。

Spring Bootは、Springに基づくアプリケーションフレームワークであり、エンタープライズアプリケーションの開発に関連する多くの定型文を取り除きます。これにより、マイクロサービスを開発するための非常に意見が高いが柔軟なプラットフォームが提供されます。このチュートリアルでは、Spring Bootを活用して、12要素の方法論を使用してマイクロサービスを提供します。

4.12ファクター手法の適用

ここで、今説明したツールとプラクティスを使用して開発しようとする単純なアプリケーションを定義しましょう。私たちは皆、映画を見るのが大好きですが、すでに見た映画を追跡するのは困難です。

さて、誰が映画を始めて、後でそれを放棄したいですか?必要なのは、視聴した映画を録画およびクエリするためのシンプルなサービスです。

これは、データストアと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 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要素アプリの最初のベストプラクティスは、バージョン管理システムで追跡することです。Gitは、今日使用されている最も人気のあるバージョン管理システムであり、ほぼユビキタスです。原則として、アプリは単一のコードリポジトリで追跡する必要があり、そのリポジトリを他のアプリと共有してはなりません

Spring Bootは、コマンドラインツールやWebインターフェイスなど、アプリケーションをブートストラップするための多くの便利な方法を提供します。ブートストラップアプリケーションを生成したら、これをgitリポジトリに変換できます。

git init

このコマンドは、アプリケーションのルートから実行する必要があります。この段階のアプリケーションには、生成されたファイルのバージョン管理を効果的に制限する.gitignoreファイルがすでに含まれています。したがって、すぐに最初のコミットを作成できます。

git add . git commit -m "Adding the bootstrap of the application."

最後に、必要に応じてリモートを追加し、コミットをリモートにプッシュできます(これは厳密な要件ではありません)。

git remote add origin //github.com//12-factor-app.git git push -u origin master

4.2。依存関係

次に、12因子アプリは、常にすべての依存関係を明示的に宣言する必要があります。これは、依存関係宣言マニフェストを使用して行う必要があります。Javaには、MavenやGradleなどの複数の依存関係管理ツールがあります。これらの1つを使用して、この目標を達成できます。

したがって、私たちの単純なアプリケーションは、REST APIを容易にし、データベースに接続するためのライブラリなど、いくつかの外部ライブラリに依存しています。Mavenを使用してそれらを宣言的に定義する方法を見てみましょう。

Mavenでは、プロジェクトの依存関係をXMLファイル(通常はプロジェクトオブジェクトモデル(POM)と呼ばれます)で記述する必要があります。

  org.springframework.boot spring-boot-starter-web   com.h2database h2 runtime  

これは単純明快に見えますが、これらの依存関係には通常、他の推移的な依存関係があります。これはある程度複雑になりますが、目標を達成するのに役立ちます。現在、アプリケーションには、明示的に記述されていない直接の依存関係はありません。

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

AnsibleやChefなどの構成管理ツールを使用して、このプロセスを自動化できます。

4.4。バッキングサービス

バッキングサービスは、アプリケーションが操作のために依存するサービスです。たとえば、データベースやメッセージブローカー。12ファクターのアプリは、このようなすべてのバッキングサービスを添付リソースとして扱う必要があります。これが効果的に意味するのは、互換性のあるバッキングサービスを交換するためにコードを変更する必要がないということです。唯一の変更は構成にあるべきです。

In our application, we've used MySQL as the backing service to provide persistence.

Spring JPA makes the code quite agnostic to the actual database provider. We only need to define a repository which provides all standard operations:

@Repository public interface MovieRepository extends JpaRepository { }

As we can see, this is not dependent on MySQL directly. Spring detects the MySQL driver on the classpath and provides a MySQL-specific implementation of this interface dynamically. Moreover, it pulls other details from configurations directly.

So, if we've to change from MySQL to Oracle, all we've to do is replace the driver in our dependencies and replace the configurations.

4.5. Build, Release and Run

The twelve-factor methodology strictly separates the process of converting codebase into a running application as three distinct stages:

  • Build Stage: This is where we take the codebase, perform static and dynamic checks, and then generate an executable bundle like a JAR. Using a tool like Maven, this is quite trivial:
 mvn clean compile test package
  • Release Stage: This is the stage where we take the executable bundle and combine this with the right configurations. Here, we can use Packer with a provisioner like Ansible to create Docker images:
 packer build application.json
  • Run Stage: Finally, this is the stage where we run the application in a target execution environment. If we use Docker as the container to release our application, running the application can be simple enough:
 docker run --name  -it 

Finally, we don't necessarily have to perform these stages manually. This is where Jenkins comes in as pretty handy with their declarative pipeline.

4.6. Processes

A twelve-factor app is expected to run in an execution environment as stateless processes. In other words, they can not store persistent state locally between requests. They may generate persistent data which is required to be stored in one or more stateful backing services.

In the case of our example, we've got multiple endpoints exposed. A request on any of these endpoints is entirely independent of any request made before it. For instance, if we keep track of user requests in-memory and use that information to serve future requests, it violates a twelve-factor app.

Hence, a twelve-factor app imposes no such restriction like sticky sessions. This makes such an app highly portable and scalable. In a cloud execution environment offering automated scaling, it's quite a desirable behavior from applications.

4.7. Port Binding

A traditional web application in Java is developed as a WAR or web archive. This is typically a collection of Servlets with dependencies, and it expects a conformant container runtime like Tomcat. A twelve-factor app, on the contrary, expects no such runtime dependency. It's completely self-contained and only requires an execution runtime like Java.

In our case, we've developed an application using Spring Boot. Spring Boot, apart from many other benefits, provides us with a default embedded application server. Hence, the JAR we generated earlier using Maven is fully capable of executing in any environment just by having a compatible Java runtime:

java -jar application.jar

Here, our simple application exposes its endpoints over an HTTP binding to a specific port like 8080. Upon starting the application as we did above, it should be possible to access the exported services like HTTP.

An application may export multiple services like FTP or WebSocket by binding to multiple ports.

4.8. Concurrency

Java offers Thread as a classical model to handle concurrency in an application. Threads are like lightweight processes and represent multiple paths of execution in a program. Threads are powerful but have limitations in terms of how much it can help an application scale.

The twelve-factor methodology suggests apps to rely on processes for scaling. What this effectively means is that applications should be designed to distribute workload across multiple processes. Individual processes are, however, free to leverage a concurrency model like Thread internally.

A Java application, when launched gets a single process which is bound to the underlying JVM. What we effectively need is a way to launch multiple instances of the application with intelligent load distribution between them. Since we've already packaged our application as a Docker container, Kubernetes is a natural choice for such orchestration.

4.9. Disposability

Application processes can be shut down on purpose or through an unexpected event. In either case, a twelve-factor app is supposed to handle it gracefully. In other words, an application process should be completely disposable without any unwanted side-effects. Moreover, processes should start quickly

For instance, in our application, one of the endpoints is to create a new database record for a movie. Now, an application handling such a request may crash unexpectedly. This should, however, not impact the state of the application. When a client sends the same request again, it shouldn't result in duplicate records.

In summary, the application should expose idempotent services. This is another very desirable attribute of a service destined for cloud deployments. This gives the flexibility to stop, move, or spin new services at any time without any other considerations.

4.10. Dev/Prod Parity

It's typical for applications to be developed on local machines, tested on some other environments and finally deployed to production. It's often the case where these environments are different. For instance, the development team works on Windows machines whereas production deployment happens on Linux machines.

The twelve-factor methodology suggests keeping the gap between development and production environment as minimal as possible. These gaps can result from long development cycles, different teams involved, or different technology stack in use.

Now, technology like Spring Boot and Docker automatically bridge this gap to a great extent. A containerized application is expected to behave the same, no matter where we run it. We must use the same backing services – like the database – as well.

Moreover, we should have the right processes like continuous integration and delivery to facilitate bridging this gap further.

4.11. Logs

Logs are essential data that an application generates during its lifetime. They provide invaluable insights into the working of the application. Typically an application can generate logs at multiple levels with varying details and output ii in multiple different formats.

A twelve-factor app, however, separates itself from log generation and its processing. For such an app, logs are nothing but a time-ordered stream of events. It merely writes these events to the standard output of the execution environment. The capture, storage, curation, and archival of such stream should be handled by the execution environment.

There are quite several tools available to us for this purpose. To begin with, we can use SLF4J to handle logging abstractly within our application. Moreover, we can use a tool like Fluentd to collect the stream of logs from applications and backing services.

This we can feed into Elasticsearch for storage and indexing. Finally, we can generate meaningful dashboards for visualization in Kibana.

4.12. Admin Processes

Often we need to perform some one-off tasks or routine procedure with our application state. For instance, fixing bad records. Now, there are various ways in which we can achieve this. Since we may not often require it, we can write a small script to run it separately from another environment.

Now, the twelve-factor methodology strongly suggests keeping such admin scripts together with the application codebase. In doing so, it should follow the same principles as we apply to the main application codebase. It's also advisable to use a built-in REPL tool of the execution environment to run such scripts on production servers.

In our example, how do we seed our application with the already watched movies so far? While we can use our sweet little endpoint, but that may seem to be impractical. What we need is a script to perform a one-time load. We can write a small Java function to read a list of movies from a file and save them in batch into the database.

Moreover, we can use Groovy integrated with Java runtime to start such processes.

5. Practical Applications

So, now we've seen all the factors suggested by the twelve-factor methodology. Developing an application to be a twelve-factor app certainly has its benefits, especially when we wish to deploy them as services on the cloud. But, like all other guidelines, framework, patterns, we must ask, is this a silver bullet?

Honestly, no single methodology in software design and development claim to be a silver bullet. The twelve-factor methodology is no exception. While some of these factors are quite intuitive, and most likely we're already doing them, others may not apply to us. It's essential to evaluate these factors in the backdrop of our objectives and then choose wisely.

It's important to note that all these factors are there to help us develop an application which is modular, independent, portable, scalable, and observable. Depending upon the application, we may be able to achieve them through other means better. It's also not necessary to adopt all the factors together, adopting even some of these may make us better than we were.

Finally, these factors are quite simple and elegant. They hold greater importance in an age where we demand our applications to have higher throughput and lower latency with virtually no downtime and failure. Adopting these factors gives us the right start from the beginning. Combined with microservice architecture and containerization of applications, they just seem to hit the right spot.

6. Conclusion

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