この投稿は、 2023 年 3 月の Microservices の概念を実践するのに役立つ 4 つのチュートリアルの 1 つです。 マイクロサービスの提供を開始する:
すべてのアプリには構成が必要ですが、マイクロサービスを構成する際の考慮事項は、モノリシック アプリの場合と同じではない可能性があります。両方のタイプのアプリに適用できるガイダンスについては、 12 要素アプリの要素 3 (環境に構成を保存する) を参照できますが、そのガイダンスはマイクロサービス アプリに適用できます。 特に、サービス構成を定義する方法、サービスに構成を提供する方法、およびサービスに依存する可能性のある他のサービスの構成値としてサービスを利用できるようにする方法を適応させることができます。
マイクロサービスに Factor 3 を適応させる方法 (具体的には、構成ファイル、データベース、サービス検出のベスト プラクティス) の概念を理解するには、弊社のブログの「マイクロサービス アプリを構成するためのベスト プラクティス」をお読みください。 この投稿は、その知識を実践するための素晴らしい方法です。
注記: このチュートリアルの目的は、マイクロサービスを本番環境にデプロイする正しい方法を示すことではなく、いくつかのコア概念を説明することです。 実際の「マイクロサービス」アーキテクチャを使用していますが、いくつか重要な注意点があります。
このチュートリアルでは、Factor 3 の概念がマイクロサービス アプリにどのように適用されるかを説明します。 4 つのチャレンジでは、一般的なマイクロサービス構成パターンをいくつか検討し、それらのパターンを使用してサービスをデプロイおよび構成します。
チャレンジ 1とチャレンジ 2では、マイクロサービス アプリの構成をどこに配置するかに関する最初のパターンを探ります。一般的な場所は 3 つあります。
このチュートリアルでは、次の 4 つのテクノロジを使用します。
チュートリアルの概要については、このビデオをご覧ください。 手順はこの投稿と完全に一致しているわけではありませんが、概念を理解するのに役立ちます。
独自の環境でチュートリアルを完了するには、次のものが必要です。
bash
の基本的な知識 (ただし、すべてのコードとコマンドが提供され、説明されているため、限られた知識でも成功できます)Node.js 19.x 以降
curl
(ほとんどのシステムに既にインストールされています)ホーム ディレクトリにmicroservices-marchディレクトリを作成し、このチュートリアルの GitHub リポジトリをそこにクローンします。 (別のディレクトリ名を使用して、それに応じて手順を変更することもできます。)
注記: チュートリアル全体を通して、コマンドをターミナルにコピーして貼り付けやすくするために、Linux コマンドラインのプロンプトは省略されています。 チルダ ( ~
) はホームディレクトリを表します。
mkdir ~/microservices-marchcd ~/microservices-march
git clone https://github.com/microservices-march/platform.git --branch mm23-twelve-factor-start
git clone https://github.com/microservices-march/messenger.git --branch mm23-twelve-factor-start
プラットフォームリポジトリに変更し、Docker Compose を起動します。
cd platformdocker compose up -d --build
これにより、後続のチャレンジで使用される RabbitMQ と Consul の両方が起動します。
-d
フラグは、コンテナが起動したら Docker Compose にコンテナからデタッチするように指示します (そうでない場合、コンテナはターミナルに接続されたままになります)。--build
フラグは、起動時にすべてのイメージを再構築するように Docker Compose に指示します。 これにより、実行中のイメージは、ファイルへの潜在的な変更を通じて最新の状態に保たれます。メッセンジャーリポジトリに変更し、Docker Compose を起動します。
cd ../messengerdocker compose up -d --build
これにより、メッセンジャーサービス用の PostgreSQL データベースが起動します。このチュートリアルの残りの部分では、これをmessenger-databaseと呼びます。
このチャレンジでは、チュートリアルで取り上げる 3 つの場所のうち最初の場所であるアプリケーション レベルで構成を設定します。 (課題 2 では、 2 番目と 3 番目の場所、デプロイメント スクリプト、および外部ソースについて説明します。)
Twelve-Factor App では、アプリケーション レベルの構成は明確に除外されます。これは、このような構成は、異なるデプロイメント環境 (Twelve-Factor App ではdeploysと呼びます) 間で変更する必要がないためです。 ただし、完全性を期すために 3 つのタイプすべてを取り上げます。サービスを開発、構築、展開する際に各カテゴリを処理する方法は異なります。
メッセンジャーサービスは Node.js で記述されており、エントリポイントはメッセンジャーリポジトリのapp/index.mjsにあります。 ファイルのこの行:
app.use(express.json());
アプリケーションレベルの構成の例です。 Express フレームワークを構成して、 application/json
タイプのリクエスト本体を JavaScript オブジェクトに逆シリアル化します。
このロジックはアプリケーション コードと密接に結合されており、Twelve-Factor App が「構成」とみなすものではありません。 しかし、ソフトウェアではすべては状況次第ですよね?
次の 2 つのセクションでは、この行を変更して、アプリケーション レベルの構成の 2 つの例を実装します。
この例では、メッセンジャーサービスが受け入れるリクエスト本文の最大サイズを設定します。 このサイズ制限は、Express API ドキュメントで説明されているように、 express.json関数のlimit
引数によって設定されます。 ここでは、上で説明した Express フレームワークの JSON ミドルウェアの構成に制限
引数を追加します。
好みのテキスト エディターでapp/index.mjsを開き、次のコードを置き換えます。
app.use(express.json())
と:
app.use(express.json({ limit: "20b" }));
アプリ ターミナル (セットアップで使用したターミナル) で、アプリディレクトリに移動し、メッセンジャーサービスを開始します。
cd app
npm install
node index.mjs
messenger_service listening on port 4000
2 番目の別のターミナル セッション (後続の命令ではクライアント ターミナルと呼ばれます) を開始し、メッセンジャーサービスにPOST
要求を送信します。 エラー メッセージは、リクエスト本文が手順 1 で設定された20 バイトの制限を下回っていたためリクエストが正常に処理されたが、JSON ペイロードの内容が正しくないことを示しています。
curl -d '{ "text": "hello" }' -H "Content-Type: application/json" -X POST http://localhost:4000/conversations...
{ "error": "Conversation must have 2 unique users" }
少し長めのメッセージ本文を送信します (これもクライアント端末で)。 出力はステップ 3 よりもはるかに多く、今回はリクエスト本文が 20 バイトを超えていることを示すエラー メッセージも含まれます。
curl -d '{ "text": "hello, world" }' -H "Content-Type: application/json" -X POST http://localhost:4000/conversations...
\”PayloadTooLargeError: request entity too large"
この例では、単一のファイルで構成「スキーマ」全体を定義できるライブラリであるconvict
を使用します。 また、12 要素アプリの要素 3 からの 2 つのガイドラインも示しています。
JSON_BODY_LIMIT
) を使用して最大本文サイズが設定されるようにアプリを変更します。この例では、チャレンジ 2で活用する「配管」も設定します。チャレンジ 2 で作成するメッセンジャーデプロイメント スクリプトは、デプロイメント スクリプトで指定された構成の例として、ここでアプリ コードに挿入するJSON_BODY_LIMIT
環境変数を設定します。
convict
構成ファイルapp/config/config.mjsを開き、 amqpport
キーの後に次のキーを新しいキーとして追加します。
jsonBodyLimit: { doc: `The max size (with unit included) that will be parsed by the
JSON middleware. Unit parsing is done by the
https://www.npmjs.com/package/bytes library.
ex: "100kb"`,
format: String,
default: null,
env: "JSON_BODY_LIMIT",
},
以下の手順 3 でコマンド ラインで最大本文サイズを設定するためにJSON_BODY_LIMIT
環境変数を使用すると、 convict
ライブラリによってその環境変数の解析が行われます。
文字列
)jsonBodyLimit
キーを使用してアクセスできるようにしますapp/index.mjsで以下を置き換えます:
app.use(express.json({ limit: "20b" }));
と
app.use(express.json({ limit: config.get("jsonBodyLimit") }));
アプリターミナル (例 1の手順 2 でメッセンジャーサービスを開始した場所) で、 Ctrl + c を
押してサービスを停止します。 次に、 JSON_BODY_LIMIT
環境変数を使用して最大本文サイズを 27 バイトに設定し、再度起動します。
^cJSON_BODY_LIMIT=27b node index.mjs
これは、ユースケースに適した場合に構成方法を変更する例です。つまり、Twelve-Factor App で推奨されているように、アプリ コードに値 (この場合はサイズ制限) をハードコーディングするのではなく、環境変数を使用して設定するように切り替えました。
前述のように、チャレンジ 2では、コマンド ラインで設定するのではなく、メッセンジャーサービスのデプロイメント スクリプトを使用して環境変数を設定する場合、 JSON_BODY_LIMIT
環境変数の使用が構成の 2 番目の場所の例になります。
クライアント端末で、例 1の手順 4のcurl
コマンドを繰り返します (リクエスト本文を大きくします)。 サイズ制限を 27 バイトに増やしたため、リクエスト本文は制限を超えなくなり、リクエストは処理されたが JSON ペイロードの内容が正しくないことを示すエラー メッセージが表示されます。
curl -d '{ "text": "hello, world" }' -H "Content-Type: application/json" -X POST http://localhost:4000/conversations{ "error": "Conversation must have 2 unique users" }
必要に応じてクライアント端末を閉じることができます。 チュートリアルの残りの部分では、すべてのコマンドをアプリのターミナルで発行します。
アプリ ターミナルで、 Ctrl + c を
押してメッセンジャーサービスを停止します (上記の手順 3 でこのターミナルでサービスを停止して再起動しました)。
^c
メッセンジャーデータベースを停止します。 プラットフォームリポジトリで定義されたインフラストラクチャ要素によってネットワークがまだ使用されているため、表示されるエラー メッセージは無視しても問題ありません。 メッセンジャーリポジトリのルートでこのコマンドを実行します。
docker compose down
...failed to remove network mm_2023....
一見すると、これは「ソース管理に構成をチェックインしない」と言っているように解釈されるかもしれません。 このチャレンジでは、このルールに違反しているように見えるかもしれませんが、実際にはルールを尊重しながら、マイクロサービス環境にとって重要な貴重なプロセス改善を提供する、マイクロサービス環境の共通パターンを実装します。
このチャレンジでは、マイクロサービスに構成を提供するインフラストラクチャ アズ コードとデプロイメント マニフェストの機能を模倣するデプロイメント スクリプトを作成し、外部の構成ソースを使用するようにスクリプトを変更し、シークレットを設定してから、スクリプトを実行してサービスとそのインフラストラクチャをデプロイします。
メッセンジャーリポジトリに新しく作成されたインフラストラクチャディレクトリにデプロイメント スクリプトを作成します。 インフラストラクチャ(またはその名前のバリエーション) と呼ばれるディレクトリは、最新のマイクロサービス アーキテクチャで一般的なパターンであり、次のようなものを保存するために使用されます。
このパターンの利点は次のとおりです。
前述したように、このチュートリアルの目的は実際のシステムの設定方法を示すことではなく、このチャレンジで展開するスクリプトは実際の運用システムに似たものではありません。 むしろ、マイクロサービス関連のインフラストラクチャのデプロイメントを扱う際に、ツール固有の構成によって解決されるいくつかのコア概念と問題を示し、スクリプトを可能な限り最小限の特定のツールに抽象化します。
アプリ ターミナルで、メッセンジャーリポジトリのルートにインフラストラクチャディレクトリを作成し、メッセンジャーサービスとmessenger-databaseのデプロイメント スクリプトを格納するファイルを作成します。 環境によっては、 chmod
コマンドの前にsudo
を付ける必要がある場合があります。
mkdir infrastructurecd infrastructure
touch messenger-deploy.sh
chmod +x messenger-deploy.sh
touch messenger-db-deploy.sh
chmod +x messenger-db-deploy.sh
好みのテキスト エディターで、 messenger-deploy.shを開き、次のコードを追加して、メッセンジャーサービスの初期デプロイメント スクリプトを作成します。
#!/bin/bashset -e
JSON_BODY_LIMIT=20b
docker run \
--rm \
-e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \
messenger
このスクリプトは現時点では完成していませんが、いくつかの概念を示しています。
docker
run
コマンドの-e
フラグを使用して、実行時にコンテナに環境変数を挿入します。この方法で環境変数の値を設定するのは冗長に思えるかもしれませんが、このデプロイメント スクリプトがどれほど複雑になっても、スクリプトの一番上をざっと見て、構成データがどのようにデプロイメントに提供されているかを理解できることを意味します。
さらに、実際のデプロイメント スクリプトではdocker
run
コマンドが明示的に呼び出されない場合もありますが、このサンプル スクリプトは、Kubernetes マニフェストのようなもので解決されるコアの問題を伝えることを目的としています。 Kubernetes のようなコンテナ オーケストレーション システムを使用する場合、デプロイメントによってコンテナが起動され、Kubernetes 構成ファイルから派生したアプリケーション構成がそのコンテナで使用できるようになります。 したがって、このサンプル デプロイメント ファイルは、Kubernetes マニフェストなどのフレームワーク固有のデプロイメント ファイルと同じ役割を果たすデプロイメント スクリプトの最小バージョンと考えることができます。
実際の開発環境では、このファイルをソース管理にチェックインし、コードレビューを行う場合があります。 これにより、チームの他のメンバーに設定についてコメントする機会が与えられ、誤った値の設定によって予期しない動作が発生するインシデントを回避するのに役立ちます。 たとえば、このスクリーンショットでは、チーム メンバーが、受信 JSON リクエスト本文の 20 バイトの制限 ( JSON_BODY_LIMIT
で設定) は低すぎることを正しく指摘しています。
チャレンジのこの部分では、マイクロサービスの構成の 3 番目の場所、つまり、デプロイ時にクエリされる外部ソースを設定します。 値を動的に登録し、デプロイメント時に外部ソースから取得することは、値をハードコーディングするよりもはるかに優れた方法です。ハードコーディングすると、常に更新する必要があり、障害が発生することがあります。 詳細については、弊社のブログの「マイクロサービス アプリを構成するためのベスト プラクティス」をご覧ください。
この時点で、メッセンジャーサービスに必要な補助サービスを提供するために、2 つのインフラストラクチャ コンポーネントがバックグラウンドで実行されています。
app/config/config.mjsのメッセンジャーサービスのconvict
スキーマは、これらの外部構成に対応する必要な環境変数を定義します。 このセクションでは、変数の値を一般にアクセス可能な場所に設定して構成を提供するこれら 2 つのコンポーネントを設定し、メッセンジャーサービスがデプロイ時に変数を照会できるようにします。
RabbitMQ とメッセンジャー データベースに必要な接続情報は、デプロイされたすべてのサービスがアクセスできる共通の場所であるConsul キー/値 (KV) ストアに登録されます。 Consul KV ストアは、このタイプのデータを保存する標準的な場所ではありませんが、このチュートリアルではわかりやすくするためにこれを使用します。
前のセクションの手順 2 で作成した、 infrastructure/messenger-deploy.shの内容を次の内容に置き換えます。
#!/bin/bashset -e
# This configuration requires a new commit to change
NODE_ENV=production
PORT=4000
JSON_BODY_LIMIT=100kb
# Postgres database configuration by pulling information from
# the system
POSTGRES_USER=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-application-user?raw=true)
PGPORT=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-port?raw=true)
PGHOST=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-host?raw=true)
# RabbitMQ configuration by pulling from the system
AMQPHOST=$(curl -X GET http://localhost:8500/v1/kv/amqp-host?raw=true)
AMQPPORT=$(curl -X GET http://localhost:8500/v1/kv/amqp-port?raw=true)
docker run \
--rm \
-e NODE_ENV="${NODE_ENV}" \
-e PORT="${PORT}" \
-e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \
-e PGUSER="${POSTGRES_USER}" \
-e PGPORT="${PGPORT}" \
-e PGHOST="${PGHOST}" \
-e AMQPPORT="${AMQPPORT}" \
-e AMQPHOST="${AMQPHOST}" \
messenger
このスクリプトは、次の 2 種類の構成の例を示しています。
NODE_ENV
) とポート ( PORT
) を設定し、 JSON_BODY_LIMIT を
20 バイトよりも現実的な値である 100 KB に変更します。POSTGRES_USER
、 PGPORT
、 PGHOST
、 AMQPHOST
、およびAMQPPORT
環境変数の値を取得します。 次の 2 つの手順で、Consul KV ストアの環境変数の値を設定します。messenger-db-deploy.shを開き、以下を追加して、 messenger-databaseの初期デプロイメント スクリプトを作成します。
#!/bin/bashset -e
PORT=5432
POSTGRES_USER=postgres
docker run \
-d \
--rm \
--name messenger-db \
-v db-data:/var/lib/postgresql/data/pgdata \
-e POSTGRES_USER="${POSTGRES_USER}" \
-e POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \
-e PGPORT="${PORT}" \
-e PGDATA=/var/lib/postgresql/data/pgdata \
--network mm_2023 \
postgres:15.1
# Register details about the database with Consul
curl -X PUT http://localhost:8500/v1/kv/messenger-db-port \
-H "Content-Type: application/json" \
-d "${PORT}"
curl -X PUT http://localhost:8500/v1/kv/messenger-db-host \
-H "Content-Type: application/json" \
-d 'messenger-db' # This matches the "--name" flag above
# (the hostname)
curl -X PUT http://localhost:8500/v1/kv/messenger-db-application-user \
-H "Content-Type: application/json" \
-d "${POSTGRES_USER}"
このスクリプトは、デプロイメント時にメッセンジャーサービスによって照会できる構成を定義するだけでなく、 「初期デプロイメント スクリプトの作成」のメッセンジャーサービスの初期スクリプトと同じ 2 つの概念を示しています。
-e
フラグを使用して Docker を実行し、実行時にコンテナに環境変数を挿入します。 また、実行中のコンテナの名前がmessenger-dbに設定され、これはセットアップの手順 2 でプラットフォームサービスを起動したときに作成した Docker ネットワーク内のデータベースのホスト名になります。実際の展開では、通常、プラットフォーム チーム (または同様のチーム) が、メッセンジャーリポジトリのメッセンジャー データベースの場合と同様に、プラットフォームリポジトリ内の RabbitMQ などのサービスの展開とメンテナンスを処理します。 次に、プラットフォーム チームは、そのインフラストラクチャの場所が、それに依存するサービスによって検出可能であることを確認します。 チュートリアルの目的上、RabbitMQ の値を自分で設定します。
curl -X PUT --silent --output /dev/null --show-error --fail \ -H "Content-Type: application/json" \
-d "rabbitmq" \
http://localhost:8500/v1/kv/amqp-host
curl -X PUT --silent --output /dev/null --show-error --fail \
-H "Content-Type: application/json" \
-d "5672" \
http://localhost:8500/v1/kv/amqp-port
(RabbitMQ 変数の定義にamqp
が使用されるのはなぜかと疑問に思うかもしれません。それは、 AMQPが RabbitMQ で使用されるプロトコルだからです。)
メッセンジャーサービスのデプロイメント スクリプトで欠落している (重要な) データは 1 つだけです。それは、メッセンジャー データベースのパスワードです。
注記: シークレットの管理はこのチュートリアルの焦点ではないため、簡単にするためにシークレットはデプロイメント ファイルで定義されます。 実際の環境(開発、テスト、本番)では絶対にこれを行わないでください。大きなセキュリティ リスクが生じます。
適切なシークレット管理について詳しくは、「Microservices March 2023」のユニット 2「Microservices Secrets Management 101」をご覧ください。 (ネタバレ: 秘密管理ツールは秘密を保存するための唯一の真に安全な方法です)。
メッセンジャー データベースのパスワード シークレットを Consul KV ストアに保存するには、 infrastructure/messenger-db-deploy.shの内容を次のように置き換えます。
#!/bin/bashset -e
PORT=5432
POSTGRES_USER=postgres
# NOTE: Never do this in a real-world deployment. Store passwords
# only in an encrypted secrets store.
POSTGRES_PASSWORD=postgres
docker run \
--rm \
--name messenger-db-primary \
-d \
-v db-data:/var/lib/postgresql/data/pgdata \
-e POSTGRES_USER="${POSTGRES_USER}" \
-e POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \
-e PGPORT="${PORT}" \
-e PGDATA=/var/lib/postgresql/data/pgdata \
--network mm_2023 \
postgres:15.1
echo "Register key messenger-db-port\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-port \
-H "Content-Type: application/json" \
-d "${PORT}"
echo "Register key messenger-db-host\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-host \
-H "Content-Type: application/json" \
-d 'messenger-db-primary' # This matches the "--name" flag above
# which for our setup means the hostname
echo "Register key messenger-db-application-user\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-application-user \
-H "Content-Type: application/json" \
-d "${POSTGRES_USER}"
echo "Register key messenger-db-password-never-do-this\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-password-never-do-this \
-H "Content-Type: application/json" \
-d "${POSTGRES_PASSWORD}"
printf "\nDone registering postgres details with Consul\n"
Consul KV ストアからmessenger-databaseパスワード シークレットを取得するには、 infrastructure/messenger-deploy.shの内容を次のように置き換えます。
#!/bin/bashset -e
# This configuration requires a new commit to change
NODE_ENV=production
PORT=4000
JSON_BODY_LIMIT=100kb
# Postgres database configuration by pulling information from
# the system
POSTGRES_USER=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-application-user?raw=true)
PGPORT=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-port?raw=true)
PGHOST=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-host?raw=true)
# NOTE: Never do this in a real-world deployment. Store passwords
# only in an encrypted secrets store.
PGPASSWORD=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-password-never-do-this?raw=true)
# RabbitMQ configuration by pulling from the system
AMQPHOST=$(curl -X GET http://localhost:8500/v1/kv/amqp-host?raw=true)
AMQPPORT=$(curl -X GET http://localhost:8500/v1/kv/amqp-port?raw=true)
docker run \
--rm \
-d \
-e NODE_ENV="${NODE_ENV}" \
-e PORT="${PORT}" \
-e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \
-e PGUSER="${POSTGRES_USER}" \
-e PGPORT="${PGPORT}" \
-e PGHOST="${PGHOST}" \
-e PGPASSWORD="${PGPASSWORD}" \
-e AMQPPORT="${AMQPPORT}" \
-e AMQPHOST="${AMQPHOST}" \
--network mm_2023 \
messenger
メッセンジャーリポジトリのアプリディレクトリに変更し、メッセンジャーサービスの Docker イメージをビルドします。
cd ../appdocker build -t messenger .
プラットフォームサービスに属するコンテナーのみが実行されていることを確認します。
docker ps --format '{{.Names}}'consul-server
consul-client
rabbitmq
メッセンジャーリポジトリのルートに変更し、メッセンジャー データベースとメッセンジャーサービスをデプロイします。
cd .../infrastructure/messenger-db-deploy.sh
./infrastructure/messenger-deploy.sh
messenger-db-deploy.shスクリプトは、 messenger-databaseを起動し、適切な情報をシステム (この場合は Consul KV ストア) に登録します。
次に、 messenger-deploy.shスクリプトがアプリケーションを起動し、 messenger-db-deploy.shによって登録された構成をシステム (この場合も、Consul KV ストア) から取得します。
ヒント: コンテナの起動に失敗した場合は、デプロイメント スクリプト内のdocker
run
コマンドの 2 番目のパラメータ ( -d
\
行) を削除し、スクリプトを再度実行します。 その後、コンテナはフォアグラウンドで起動し、そのログがターミナルに表示され、問題が特定される可能性があります。 問題を解決したら、実際のコンテナがバックグラウンドで実行されるように-d
\
行を復元します。
デプロイメントが成功したことを確認するために、アプリケーションに簡単なヘルスチェック リクエストを送信します。
curl localhost:4000/healthcurl: (7) Failed to connect to localhost port 4000 after 11 ms: Connection refused
あっ、失敗! 結局のところ、まだ重要な構成が 1 つ欠けており、メッセンジャーサービスがシステム全体に公開されていません。 mm_2023ネットワーク内では正常に動作していますが、そのネットワークにアクセスできるのは Docker 内からのみです。
次のチャレンジで新しいイメージを作成する準備として、実行中のコンテナを停止します。
docker rm $(docker stop $(docker ps -a -q --filter ancestor=messenger --format="{{.ID}}"))
実稼働環境では、通常、サービスを直接公開することはありません。 代わりに、一般的なマイクロサービス パターンに従い、メイン サービスの前にリバース プロキシ サービスを配置します。
このチャレンジでは、サービス検出 (新しいサービス情報の登録と、他のサービスがアクセスしたときにその情報を動的に更新する) を設定することで、メッセンジャーサービスを外部に公開します。 これを行うには、次のテクノロジを使用します。
サービス検出の詳細については、ブログの「マイクロサービス アプリを構成するためのベスト プラクティス」の「サービスを構成として利用できるようにする」を参照してください。
メッセンジャーリポジトリのapp/consul/index.mjsファイルには、起動時にメッセンジャーサービスを Consul に登録し、正常なシャットダウン時に登録を解除するために必要なすべてのコードが含まれています。 これは、新しくデプロイされたサービスを Consul のサービス レジストリに登録する、 register
という 1 つの関数を公開します。
好みのテキスト エディターでapp/index.mjsを開き、他のインポート
ステートメントの後に次のスニペットを追加して、 app/consul/index.mjsからregister
関数をインポートします。
import { register as registerConsul } from "./consul/index.mjs";
次に、スクリプトの末尾にあるSERVER
START
セクションを次のように変更し、アプリケーションの起動後にregisterConsul()
を呼び出すようにします。
/* ================= SERVER START
================== */
app.listen(port, async () => {
console.log(`messenger_service listening on port ${port}`);
registerConsul();
});
export default app;
app/config/config.mjsのconvict
スキーマを開き、例 2の手順 1 で追加したjsonBodyLimit
キーの後に次の構成値を追加します。
consulServiceName: { doc: "The name by which the service is registered in Consul. If not specified, the service is not registered",
format: "*",
default: null,
env: "CONSUL_SERVICE_NAME",
},
consulHost: {
doc: "The host where the Consul client runs",
format: String,
default: "consul-client",
env: "CONSUL_HOST",
},
consulPort: {
doc: "The port for the Consul client",
format: "port",
default: 8500,
env: "CONSUL_PORT",
},
これにより、新しいサービスが登録される名前が設定され、Consul クライアントのホスト名とポートが定義されます。 次のステップでは、メッセンジャーサービスのデプロイメント スクリプトを変更して、この新しい Consul 接続とサービス登録情報を含めます。
Infrastructure/messenger-deploy.shを開き、その内容を次の内容に置き換えて、前の手順で設定した Consul 接続とサービス登録情報をメッセンジャーサービス構成に含めます。
#!/bin/bashset -e
# This configuration requires a new commit to change
NODE_ENV=production
PORT=4000
JSON_BODY_LIMIT=100kb
CONSUL_SERVICE_NAME="messenger"
# Consul host and port are included in each host since we
# cannot query Consul until we know them
CONSUL_HOST="${CONSUL_HOST}"
CONSUL_PORT="${CONSUL_PORT}"
# Postgres database configuration by pulling information from
# the system
POSTGRES_USER=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-application-user?raw=true")
PGPORT=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-port?raw=true")
PGHOST=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-host?raw=true")
# NOTE: Never do this in a real-world deployment. Store passwords
# only in an encrypted secrets store.
PGPASSWORD=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-password-never-do-this?raw=true")
# RabbitMQ configuration by pulling from the system
AMQPHOST=$(curl -X GET "http://localhost:8500/v1/kv/amqp-host?raw=true")
AMQPPORT=$(curl -X GET "http://localhost:8500/v1/kv/amqp-port?raw=true")
docker run \
--rm \
-d \
-e NODE_ENV="${NODE_ENV}" \
-e PORT="${PORT}" \
-e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \
-e PGUSER="${POSTGRES_USER}" \
-e PGPORT="${PGPORT}" \
-e PGHOST="${PGHOST}" \
-e PGPASSWORD="${PGPASSWORD}" \
-e AMQPPORT="${AMQPPORT}" \
-e AMQPHOST="${AMQPHOST}" \
-e CONSUL_HOST="${CONSUL_HOST}" \
-e CONSUL_PORT="${CONSUL_PORT}" \
-e CONSUL_SERVICE_NAME="${CONSUL_SERVICE_NAME}" \
--network mm_2023 \
messenger
注目すべき主な点は次のとおりです。
CONSUL_SERVICE_NAME
環境変数は、メッセンジャーサービス インスタンスが Consul に登録されるときに使用する名前を指定します。CONSUL_HOST
およびCONSUL_PORT
環境変数は、デプロイメント スクリプトが実行される場所で実行される Consul クライアント用です。注記: 実際の展開では、これはチーム間で合意する必要がある構成の例です。サービスはこの接続情報なしで Consul を照会できないため、Consul を担当するチームはすべての環境でCONSUL_HOST
およびCONSUL_PORT
環境変数を提供する必要があります。
アプリ ターミナルで、アプリディレクトリに移動し、メッセンジャーサービスの実行中のインスタンスを停止し、Docker イメージを再構築して新しいサービス登録コードを組み込みます。
cd appdocker rm $(docker stop $(docker ps -a -q --filter ancestor=messenger --format="{{.ID}}"))
docker build -t messenger .
ブラウザでhttp://localhost:8500に移動して、Consul UI の動作を確認します (ただし、まだ何も面白いことは起きていません)。
メッセンジャーリポジトリのルートで、デプロイメント スクリプトを実行して、メッセンジャーサービスのインスタンスを起動します。
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infrastructure/messenger-deploy.sh
ブラウザの Consul UI で、ヘッダー バーの[サービス] をクリックして、単一のメッセンジャーサービスが実行されていることを確認します。
メッセンジャーサービスのインスタンスをさらに起動するには、デプロイメント スクリプトをさらに数回実行します。 Consul UI で実行されていることを確認します。
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infrastructure/messenger-deploy.sh
次のステップでは、NGINX Open Source をリバース プロキシおよびロード バランサーとして追加し、着信トラフィックを実行中のすべてのメッセンジャーインスタンスにルーティングします。
アプリのターミナルで、ディレクトリをメッセンジャーリポジトリのルートに変更し、 load-balancerというディレクトリと 3 つのファイルを作成します。
mkdir load-balancercd load-balancer
touch nginx.ctmpl
touch consul-template-config.hcl
touch Dockerfile
Dockerfile は、 NGINX と Consul テンプレートが実行されるコンテナを定義します。 Consul テンプレートは、他の 2 つのファイルを使用して、サービス レジストリでメッセンジャーサービスが変更されたとき (サービス インスタンスが起動または停止したとき) に、NGINX アップストリームを動的に更新します。
手順 1 で作成したnginx.ctmplファイルを開き、次の NGINX 構成スニペットを追加します。これは、Consul テンプレートが NGINX アップストリーム グループを動的に更新するために使用します。
upstream messenger_service { {{- range service "messenger" }}
server {{ .Address }}:{{ .Port }};
{{- end }}
}
server {
listen 8085;
server_name localhost;
location / {
proxy_pass http://messenger_service;
add_header Upstream-Host $upstream_addr;
}
}
このスニペットは、Consul に登録されている各メッセンジャーサービス インスタンスの IP アドレスとポート番号を NGINX messenger_serviceアップストリーム グループに追加します。 NGINX は、受信リクエストを動的に定義されたアップストリーム サービス インスタンスのセットにプロキシします。
手順 1 で作成したconsul-template-config.hclファイルを開き、次の構成を追加します。
consul { address = "consul-client:8500"
retry {
enabled = true
attempts = 12
backoff = "250ms"
}
}
template {
source = "/usr/templates/nginx.ctmpl"
destination = "/etc/nginx/conf.d/default.conf"
perms = 0600
command = "if [ -e /var/run/nginx.pid ]; then nginx -s reload; else nginx; fi"
}
Consul テンプレートのこの構成は、ソース
テンプレート (前の手順で作成された NGINX 構成スニペット) を再レンダリングし、指定された宛先
に配置し、最後に指定されたコマンド
(NGINX に構成を再読み込みするように指示する) を実行するように指示します。
実際には、これは、Consul でサービス インスタンスが登録、更新、または登録解除されるたびに、新しいdefault.confファイルが作成されることを意味します。 その後、NGINX はダウンタイムなしで構成を再読み込みし、トラフィックを送信できる最新かつ正常なサーバー セット (メッセンジャーサービス インスタンス) を NGINX が確保できるようにします。
手順 1 で作成したDockerfileファイルを開き、次の内容を追加して、NGINX サービスを構築します。 (このチュートリアルではDockerfile を理解する必要はありませんが、便宜上、コードはインラインで文書化されています。)
FROM nginx:1.23.1
ARG CONSUL_TEMPLATE_VERSION=0.30.0
# Set an environment variable for the location of the Consul
# cluster. By default, it tries to resolve to consul-client:8500
# which is the behavior if Consul is running as a container in the
# same host and linked to this NGINX container (with the alias
# consul, of course). But this environment variable can also be
# overridden as the container starts if we want to resolve to
# another address.
ENV CONSUL_URL consul-client:8500
# Download the specified version of Consul template
ADD https://releases.hashicorp.com/consul-template/${CONSUL_TEMPLATE_VERSION}/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip /tmp
RUN apt-get update \
&& apt-get install -y --no-install-recommends dumb-init unzip \
&& unzip /tmp/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip -d /usr/local/bin \
&& rm -rf /tmp/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip
COPY consul-template-config.hcl ./consul-template-config.hcl
COPY nginx.ctmpl /usr/templates/nginx.ctmpl
EXPOSE 8085
STOPSIGNAL SIGQUIT
CMD ["dumb-init", "consul-template", "-config=consul-template-config.hcl"]
Docker イメージをビルドします。
docker build -t messenger-lb .
メッセンジャーディレクトリのルートに移動し、NGINX サービスのデプロイメント ファイルとしてmessenger-load-balancer-deploy.shという名前のファイルを作成します (チュートリアル全体でデプロイした他のサービスの場合と同様)。 環境によっては、 chmod
コマンドの前にsudo
を付ける必要がある場合があります。
cd ..
touch infrastructure/messenger-load-balancer-deploy.sh
chmod +x infrastructure/messenger-load-balancer-deploy.sh
messenger-load-balancer-deploy.shを開き、次の内容を追加します。
#!/bin/bashset -e
# Consul host and port are included in each host since we
# cannot query Consul until we know them
CONSUL_HOST="${CONSUL_HOST}"
CONSUL_PORT="${CONSUL_PORT}"
docker run \
--rm \
-d \
--name messenger-lb \
-e CONSUL_URL="${CONSUL_HOST}:${CONSUL_PORT}" \
-p 8085:8085 \
--network mm_2023 \
messenger-lb
すべての準備が整ったので、NGINX サービスをデプロイします。
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infrastructure/messenger-load-balancer-deploy.sh
外部からメッセンジャーサービスにアクセスできるかどうかを確認します。
curl -X GET http://localhost:8085/health
OK
それは動作します! NGINX は、作成されたメッセンジャーサービスのすべてのインスタンス間で負荷分散を実行します。 これは、 X-Forwarded-For
ヘッダーに、前のセクションのステップ 8の Consul UI と同じメッセンジャーサービスの IP アドレスが表示されているためわかります。
大規模なアプリケーションでは、多くの場合、データの変更などの 1 回限りのタスクを実行するために使用できる小さなワーカー プロセスを備えた「ジョブ ランナー」が使用されます (例として、 SidekiqやCeleryがあります)。 これらのツールでは、多くの場合、 RedisやRabbitMQなどの追加のサポート インフラストラクチャが必要になります。 この場合、メッセンジャーサービス自体を「ジョブ ランナー」として使用して、1 回限りのタスクを実行します。 これは、すでに非常に小さく、データベースやそれが依存するインフラストラクチャの他の部分と完全に対話でき、トラフィックを処理するアプリケーションとはまったく別に実行されているため、理にかなっています。
これを行うと、3 つの利点があります。
このチャレンジでは、いくつかのデータベース構成値を変更し、メッセンジャーデータベースを新しい値を使用するように移行してパフォーマンスをテストすることで、アーティファクトを変更して新しい役割を果たす方法を探ります。
実際の運用環境では、「アプリケーション ユーザー」と「移行ユーザー」という、異なる権限を持つ 2 つの異なるユーザーを作成する場合があります。 簡単にするために、この例では、デフォルト ユーザーをアプリケーション ユーザーとして使用し、スーパーユーザー権限を持つ移行ユーザーを作成します。 実際の状況では、各ユーザーの役割に基づいて、どの特定の最小限の権限が必要かを決定するために、より多くの時間を費やす価値があります。
アプリターミナルで、スーパーユーザー権限を持つ新しい PostgreSQL ユーザーを作成します。
echo "CREATE USER messenger_migrator WITH SUPERUSER PASSWORD 'migrator_password';" | docker exec -i messenger-db-primary psql -U postgres
データベース デプロイメント スクリプト ( infrastructure/messenger-db-deploy.sh ) を開き、その内容を置き換えて新しいユーザーの資格情報を追加します。
注記: もう一度繰り返しますが、実際のデプロイメントでは、データベース資格情報などのシークレットをデプロイメント スクリプト内やシークレット管理ツール以外の場所に置かないでください。 詳細については、ユニット 2 を参照してください。 マイクロサービスの秘密管理 101マイクロサービス 2023 年 3 月。
#!/bin/bash
set -e
PORT=5432
POSTGRES_USER=postgres
# NOTE: Never do this in a real-world deployment. Store passwords
# only in an encrypted secrets store.
# Because we’re focusing on other concepts in this tutorial, we
# set the password this way here for convenience.
POSTGRES_PASSWORD=postgres
# Migration user
POSTGRES_MIGRATOR_USER=messenger_migrator
# NOTE: As above, never do this in a real deployment.
POSTGRES_MIGRATOR_PASSWORD=migrator_password
docker run \
--rm \
--name messenger-db-primary \
-d \
-v db-data:/var/lib/postgresql/data/pgdata \
-e POSTGRES_USER="${POSTGRES_USER}" \
-e POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \
-e PGPORT="${PORT}" \
-e PGDATA=/var/lib/postgresql/data/pgdata \
--network mm_2023 \
postgres:15.1
echo "Register key messenger-db-port\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-port \
-H "Content-Type: application/json" \
-d "${PORT}"
echo "Register key messenger-db-host\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-host \
-H "Content-Type: application/json" \
-d 'messenger-db-primary' # This matches the "--name" flag above
# which for our setup means the hostname
echo "Register key messenger-db-application-user\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-application-user \
-H "Content-Type: application/json" \
-d "${POSTGRES_USER}"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-password-never-do-this \
-H "Content-Type: application/json" \
-d "${POSTGRES_PASSWORD}"
echo "Register key messenger-db-application-user\n"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-migrator-user \
-H "Content-Type: application/json" \
-d "${POSTGRES_MIGRATOR_USER}"
curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-migrator-password-never-do-this \
-H "Content-Type: application/json" \
-d "${POSTGRES_MIGRATOR_PASSWORD}"
printf "\nDone registering postgres details with Consul\n"
この変更は、データベースのデプロイ後に Consul で設定されるユーザー セットに移行ユーザーを追加するだけです。
インフラストラクチャディレクトリに、 messenger-db-migrator-deploy.shという新しいファイルを作成します (ここでも、 chmod
コマンドの前にsudo
を付ける必要があります)。
touch infrastructure/messenger-db-migrator-deploy.shchmod +x infrastructure/messenger-db-migrator-deploy.sh
messenger-db-migrator-deploy.shを開き、以下を追加します。
#!/bin/bashset -e
# This configuration requires a new commit to change
NODE_ENV=production
PORT=4000
JSON_BODY_LIMIT=100kb
CONSUL_SERVICE_NAME="messenger-migrator"
# Consul host and port are included in each host since we
# cannot query Consul until we know them
CONSUL_HOST="${CONSUL_HOST}"
CONSUL_PORT="${CONSUL_PORT}"
# Get the migrator user name and password
POSTGRES_USER=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-migrator-user?raw=true")
PGPORT=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-port?raw=true")
PGHOST=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-host?raw=true)
# NOTE: Never do this in a real-world deployment. Store passwords
# only in an encrypted secrets store.
PGPASSWORD=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-migrator-password-never-do-this?raw=true")
# RabbitMQ configuration by pulling from the system
AMQPHOST=$(curl -X GET "http://localhost:8500/v1/kv/amqp-host?raw=true")
AMQPPORT=$(curl -X GET "http://localhost:8500/v1/kv/amqp-port?raw=true")
docker run \--rm \
-d \
--name messenger-migrator \
-e NODE_ENV="${NODE_ENV}" \
-e PORT="${PORT}" \
-e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \
-e PGUSER="${POSTGRES_USER}" \
-e PGPORT="${PGPORT}" \
-e PGHOST="${PGHOST}" \
-e PGPASSWORD="${PGPASSWORD}" \
-e AMQPPORT="${AMQPPORT}" \
-e AMQPHOST="${AMQPHOST}" \
-e CONSUL_HOST="${CONSUL_HOST}" \
-e CONSUL_PORT="${CONSUL_PORT}" \
-e CONSUL_SERVICE_NAME="${CONSUL_SERVICE_NAME}" \
--network mm_2023 \
messenger
このスクリプトは、 Consul のセットアップの手順 3で作成した、最終的な形式のInfrastructure/messenger-deploy.shスクリプトと非常によく似ています。 主な違いは、 CONSUL_SERVICE_NAME
がmessenger
ではなくmessenger-migrator
であり、 PGUSER が
上記の手順 1 で作成した「migrator」スーパーユーザーに対応していることです。
CONSUL_SERVICE_NAME
がmessenger-migrator
であることが重要です。 messenger
に設定されている場合、NGINX は自動的にこのサービスをローテーションに入れて API 呼び出しを受信しますが、トラフィックを処理することは意図されていません。
このスクリプトは、移行の役割を持つ短命インスタンスをデプロイします。 これにより、移行に関する問題がメインのメッセンジャーサービス インスタンスによるトラフィックの処理に影響することがなくなります。
PostgreSQL データベースを再デプロイします。 このチュートリアルではbash
スクリプトを使用しているため、データベース サービスを停止して再起動する必要があります。 実稼働アプリケーションでは、通常、変更された要素のみを追加するために、インフラストラクチャ アズ コードスクリプトを実行します。
docker stop messenger-db-primaryCONSUL_HOST=consul-client CONSUL_PORT=8500 ./infrastructure/messenger-db-deploy.sh
PostgreSQL データベース移行サービスをデプロイします。
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infrastructure/messenger-db-migrator-deploy.sh
インスタンスが期待どおりに実行されていることを確認します。
docker ps --format "{{.Names}}"
...
messenger-migrator
また、Consul UI で、データベース移行サービスがmessenger-migratorとして Consul に正しく登録されていることを確認することもできます (この場合も、トラフィックを処理しないため、 messenger名では登録されません)。
さて、最後のステップとして、データベース移行スクリプトを実行します。 これらのスクリプトは実際のデータベース移行スクリプトとは似ていませんが、 messenger-migratorサービスを使用してデータベース固有のスクリプトを実行します。 データベースの移行が完了したら、 messenger-migratorサービスを停止します。
docker exec -i -e PGDATABASE=postgres -e CREATE_DB_NAME=messenger messenger-migrator node scripts/create-db.mjsdocker exec -i messenger-migrator node scripts/create-schema.mjs
docker exec -i messenger-migrator node scripts/create-seed-data.mjs
docker stop messenger-migrator
メッセンジャーデータベースを最終形式に移行したので、メッセンジャーサービスの動作を確認できるようになりました。 これを行うには、NGINX サービスに対していくつかの基本的なcurl
クエリを実行します ( NGINX のセットアップで NGINX をシステムのエントリ ポイントとして構成しました)。
次のコマンドの一部は、 jq
ライブラリを使用して JSON 出力をフォーマットします。 必要に応じてインストールすることも、必要に応じてコマンド ラインから省略することもできます。
会話を作成する:
curl -d '{"participant_ids": [1, 2]}' -H "Content-Type: application/json" -X POST 'http://localhost:8085/conversations'{
"conversation": { "id": "1", "inserted_at": "YYYY-MM-DDT06:41:59.000Z" }
}
ID 1 のユーザーから会話にメッセージを送信します。
curl -d '{"content": "This is the first message"}' -H "User-Id: 1" -H "Content-Type: application/json" -X POST 'http://localhost:8085/conversations/1/messages' | jq{
"message": {
"id": "1",
"content": "This is the first message",
"index": 1,
"user_id": 1,
"username": "James Blanderphone",
"conversation_id": 1,
"inserted_at": "YYYY-MM-DDT06:42:15.000Z"
}
}
別のユーザー(ID 2)からのメッセージで返信します。
curl -d '{"content": "This is the second message"}' -H "User-Id: 2" -H "Content-Type: application/json" -X POST 'http://localhost:8085/conversations/1/messages' | jq{
"message": {
"id": "2",
"content": "This is the second message",
"index": 2,
"user_id": 2,
"username": "Normalavian Ropetoter",
"conversation_id": 1,
"inserted_at": "YYYY-MM-DDT06:42:25.000Z"
}
}
メッセージを取得します:
curl -X GET 'http://localhost:8085/conversations/1/messages' | jq{
"messages": [
{
"id": "1",
"content": "This is the first message",
"user_id": "1",
"channel_id": "1",
"index": "1",
"inserted_at": "YYYY-MM-DDT06:42:15.000Z",
"username": "James Blanderphone"
},
{
"id": "2",
"content": "This is the second message",
"user_id": "2",
"channel_id": "1",
"index": "2",
"inserted_at": "YYYY-MM-DDT06:42:25.000Z",
"username": "Normalavian Ropetoter"
}
]
}
このチュートリアルでは、多数のコンテナーとイメージを作成しました。 保持したくない Docker コンテナとイメージを削除するには、次のコマンドを使用します。
実行中の Docker コンテナを削除するには:
docker rm $(docker stop $(docker ps -a -q --filter ancestor=messenger --format="{{.ID}}"))docker rm $(docker stop messenger-db-primary)
docker rm $(docker stop messenger-lb)
プラットフォームサービスを削除するには:
# From the platform repositorydocker compose down
チュートリアル全体で使用したすべての Docker イメージを削除するには:
docker rmi messengerdocker rmi messenger-lb
docker rmi postgres:15.1
docker rmi hashicorp/consul:1.14.4
docker rmi rabbitmq:3.11.4-management-alpine
「簡単な設定なのに、こんなに手間がかかりそう」と思われるかもしれませんが、その通りです。 マイクロサービスに重点を置いたアーキテクチャに移行するには、サービスをどのように構造化し、構成するかについて細心の注意を払う必要があります。 あらゆる複雑さにもかかわらず、着実な進歩を遂げました。
マイクロサービスに関する学習を継続するには、「Microservices March 2023」をご覧ください。 ユニット 2「マイクロサービス シークレット管理 101」では、マイクロサービス環境でのシークレット管理について、詳細かつユーザーフレンドリーな概要を説明します。
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 q。"