はじめに
今回は、これまでの回で学んだことを踏まえて、より複雑で実践的なアプリケーションをデプロイしてみましょう。
サンプルアプリケーションの概要
今回利用するサンプルアプリケーションは、技術ブログサイトをイメージして作成しました。4つのサービスに分かれており、それぞれ「Article」「AccessCount」「Rank」「WebSite」と呼びます。
アプリケーションのソースコードとデプロイ用のマニフェストはGitLab.comの以下のプロジェクトで公開されています。
https://gitlab.com/creationline/thinkit-kubernetes-sample1
- WebSiteサービス:エンドユーザ向けのWebサイトを提供。記事の一覧と各記事のページが閲覧でき、前日のアクセスランキングがサイドバーに表示される。
- Articleサービス:ブログ記事の一覧と取得、作成のAPIを提供。また、記事の取得APIは独自のヘッダーX-UIDにユーザ名を指定すると当該ユーザからのアクセスをAccessCountサービスに通知して保存する
- AccessCountサービス:記事へのアクセス数を記録、集計するAPIを提供。アクセス数は延べアクセス数とユニークユーザ数の両方を計算する
- Rankサービス:アクセス数順位の取得と更新APIを提供。また、設定された時刻に自発的にアクセス順位表を更新する
また、アプリケーションの詳細には立ち入りませんが、WebSiteはプログラミング言語にTypeScriptを、フレームワークにNuxtJSを利用し、Node.jsでホストされています。Article、AccessCount、Rankサービスはプログラミング言語にJavaを、フレームワークにSpring Frameworkを利用しています。
マニフェスト内容の確認
アプリケーションのマニフェストの内容を確認していきましょう。リポジトリには開発環境を想定したマニフェストとプロダクション環境を想定したマニフェストが含まれており、以下の場所に配置されています。
- 開発環境向け:deployments/develop/kubernetes/
- プロダクション環境向け:deployments/production/kubernetes/
それでは、プロダクション環境向けのマニフェストを見ていきます。ファイルを整理すると以下のようになっています(上記のマニフェスト配置場所のディレクトリからの相対パスで表記しています)。
- マニフェストの統合
- コンポーネント毎のマニフェストと関連ファイル
- Articleサービス
- deployment-article.yaml
- service-article.yaml
- ingress-article.yaml
- config/article/config.env.sample
- 設定のサンプルファイル。実際の設定はこのファイルをconfig.envにコピーして設定する
- AccessCountサービス
- deployment-accesscount.yaml
- service-accesscount.yaml
- ingress-accesscount.yaml
- config/accesscount/config.env.sample
- 設定のサンプルファイル。実際の設定はこのファイルをconfig.envにコピーして設定する
- Rankサービス
- deployment-rank.yaml
- service-rank.yaml
- ingress-rank.yaml
- config/rank/config.env.sample
- 設定のサンプルファイル。実際の設定はこのファイルをconfig.envにコピーして設定する
- WebSiteサービス
- deployment-website.yaml
- service-website.yaml
- ingress-website.yaml
以下、ファイルごとに見てみましょう。
マニフェストの統合
今回のように複数のアプリケーションを含む場合、1つのYAMLファイルにすべてのマニフェストを書くこともできますが、検索性の観点からも複数のファイルに分けることが多いでしょう。
複数のマニフェストをまとめてデプロイできるように管理するツールとして「kustomize」があります。独立したCLIツールとしても利用できますが、kubectlにも組み込まれています。今回のアプリケーションでもkustomizeを利用します。
今回はkustomizeの機能全体を解説しませんが、マニフェストのデプロイで利用している機能はその都度、解説します。
kustomizeはkustomization.yamlファイルの内容を元に具体的なマニフェストや関連するファイルを組み合わせ、最終的にkubernetesにデプロイする完全なマニフェストを作成します。
kustomization.yamlの内容をざっと見ていきます。ファイルの先頭にはkubernetesマニフェストと同様にapiVersion、kindフィールドがあります。これらの値はツールがサポートするバージョンに合わせます。
1 | apiVersion:kustomize.config.k8s.io/v1beta1 |
resourcesフィールドにはkubernetesマニフェストファイルが列挙されています。このフィールドで指定されたマニフェストが、ほかのフィールド(transformerとも呼ばれる)で指定された変更を加えてkustomizeの出力マニフェストになります。
02 | - deployment-article.yaml |
05 | - deployment-accesscount.yaml |
06 | - service-accesscount.yaml |
07 | - ingress-accesscount.yaml |
11 | - deployment-website.yaml |
この後にはimagesフィールドが続きますが、これらは関連するマニフェストと一緒に見ていくほうが分かりやすいので、該当箇所にて解説します。
3 | newName: registry.gitlab.com/thinkit-kubernetes-sample1/article |
5 | newName: registry.gitlab.com/thinkit-kubernetes-sample1/accesscount |
7 | newName: registry.gitlab.com/thinkit-kubernetes-sample1/rank |
9 | newName: registry.gitlab.com/thinkit-kubernetes-sample1/website |
Generatorにより生成されるSecret/ConfigMap
kustomization.yamlのsecretGenerator、configMapGeneratorフィールドは実際のマニフェストとは異なる設定ファイルなどから対応するSecretやConfigMapのマニフェストを生成するためのフィールドです。
SecretやConfigMapはアプリケーションの設定を保持するリソースであり、コンテナ外部から環境変数や設定ファイルとしてアプリケーションに読み込むことができます。どちらも大きな機能差はありませんが、Secretは機密情報が格納されることを想定して取り扱われます。例えば、コンテナで利用される際にSecretの内容が永続ストレージではなく一時ストレージに保存されるなどです。Secretの詳細なセキュリティ特性や管理者・利用者の責任となる事項については公式ドキュメントを参照してください。
kustomization.yamlでの設定内容を具体的に見ていきます。
4 | - config/article/config.env |
1つ目のsecretGeneratorフィールドの要素が1つのSecretマニフェストを生成します。ここで生成したSecretは後述するDeploymentの環境変数として設定され、アプリケーションが読み取ります。
envsフィールドで指定されているファイルそのものはリポジトリに含まれていません。実際にデプロイするにはconfig/article/config.env.sampleファイルをコピーしてconfig/article/config.env.sampleを作成し、内容を環境に合わせて設定してデプロイします。
config.envは、例えば以下のように設定します。
2 | DATABASE_USERNAME=username |
3 | DATABASE_PASSWORD=password |
DATABASE_URLはR2DBCのためのURLです。スキーマが異なりますが、おおよそJDBCの接続URLと同じで、以下の形式となっています。
DATABASE_USERNAME / DATABASE_PASSWORD はそのままPostgreSQLのユーザ名、パスワードです。上記の内容をconfig.envに設定すると、kustomizeの出力では以下のようなSecretが生成されます(見やすさのためにキーの順序を並べ替えています)。
04 | name: article-config-dk5g4h2289 |
08 | cjJkYmM6cG9zdGdyZXNxbDovL21hbmFnZWQucG9zdGdyZXNxbC5leGFtcGxlLmNvbTo1ND |
09 | MyL2FydGljbGU/c29tZW9wdGlvbj1zb21ldmFsdWU= |
10 | DATABASE_USERNAME: dXNlcm5hbWU= |
11 | DATABASE_PASSWORD: cGFzc3dvcmQ= |
config.envファイルで指定したキーと値のペアがdataフィールドに設定されています。Secretでは値は自動的にBase64でエンコードされるため、例えばdXNlcm5hbWU=は適切なツールでデコードするとusernameとなることが分かります。
例えば、以下のようにします。
1 | $ echo -n 'dXNlcm5hbWU=' | base64 -d |
また、マニフェストのnameフィールドがsecretGeneratorで指定したarticle-configではなく、-dk5g4h2289という接尾辞が付いています。kustomizeは、生成されたSecretを参照している箇所をほかのマニフェストから見つけて生成された名前に置き換えます。
この接尾辞はSecretを参照しているリソースでも変更を反映するために付与されています。例えばDeploymentがこのSecretを参照しているとき、Secretの内容が変更されるとSecretを参照する名前が変わることでDeploymentは新しいPodをデプロイし、変更されたSecretの内容がコンテナに反映されます。
article-configを例に解説しましたが、残りのaccesscount-configやrank-configも同様です。configMapGeneratorもほとんど同じです。
4 | - config/website/config.env |
website-configのみConfigMapを使っているのは、特に設定内容には機密情報を含まないためです。
config.envの設定例としては、以下のようになります。
上記の例でhttp://website.example.comとしている箇所は、第3回と同じくhttp://<ノードのIPアドレス>に変更します。ARTICLE_BASE_URL_FROM_SERVERとRANK_BASE_URL_FROM_SERVERの値はそのままで構いません。
上記の設定から、次のようなConfigMapのマニフェストが生成されます(先ほどと同様にキーの順序を並べ替えています)。
4 | name: website-config-k9f57c5df5 |
Secretの場合と異なり、ConfigMapではdataの設定値にBase64エンコードなどは行われません。また、名前はsecretGeneratorのときと同様に接尾辞が付いています。