EKSを利用してKubernetesでSpring MVCをデプロイ (NLB + Auto Scaling)

ここではEKSを利用して、NLB配下にAutoScalingで起動するアプリケーションを起動するときの例について取り上げます。既にマネジメントコンソールやeksctlコマンドを通してクラスターは起動状態であるものとします。

PodがWorkloadsリソースの最小単位となります。それに対してReplicaSetによりPodのレプリカが作成され、指定した数のPodを維持し続けるようにします。そして、Deploymentが複数のReplicaSetを管理することで、ローリングアップデートやロールバック等を実現します。

MySQLやRedisのユーザー名やパスワード情報ははKubernetesのSecretの機能を利用してWebアプリケーションに渡します。 KubernetesのSecretでは環境変数として渡す方法とVolumeとしてマウントする方法がありますが、ここではSpring MVCのアプリケーションに対して環境変数として渡す方法について取り上げます。

以下の3つに分けて説明を行います。EKS以外のプラットフォームを使用している場合は、1の手順やその他適宜置き換えてください。 

  1. EKSの設定

  2. Dockerイメージの準備

  3. Kubernetesの設定

EKSの設定

eksctlの準備

eksctlを最新バージョンにアップデート

$ brew upgrade eksctl && brew link --overwrite eksctl

eksctlをインストールしてない場合は以下の方法でインストール

$ brew tap weaveworks/tap
$ brew install weaveworks/tap/eksctl
$ eksctl version
0.18.0

(参照) eksctl の開始方法

VPCの準備

予め新規にVPCとプライベートサブネットを3つ作成し、プライベートサブネットのルーティングテーブルとして、0.0.0.0/0宛にNAT Gateway, VPC PeeringでRDS, ElastiCacheへのルーティングを設定します。 このプライベートサブネットはNLB配下のターゲットインスタンスを配置するためのものとなります。また、RDSやElastiCacheは異なるVPCにある既存のものを利用する前提となっています。

VPC Peeringを使用する場合は、作成するEKSクラスターのVPCを作成する際、CIDRの重複がないことなどVPC Peeringの制約に注意ください。

NLB用に各AZに計3つのパブリックサブネットを作成し、以下のタグを付与します。

  • kubernetes.io/cluster/mywebsite-cluster shared

  • kubernetes.io/role/elb 1

(参照) クラスター VPC に関する考慮事項

EKSクラスターの作成

以下のようにEKSクラスターを作成

作成に失敗すると、CloudFormationのスタックのロールバックに時間を要し、再度リクエストを投げられるようになるまで時間がかかります。 

クラスターは以下の方法で削除します。

スタックの状況はコマンドで確認できます。

以下のようにreadyの文字で作成完了していることを確認できます。

NLBはServiceのリソースを作成しましたが、以下のようにエンドポイントを確認できます。

対象のドメインとNLBのFQDNの関連付けについて、Route53を利用している場合はAliasレコード、それ以外のレジストラを利用している場合はCNAMEレコードに登録しておきます。

Dockerイメージの準備

DockerHubからTomcatのイメージを利用してDockerイメージを作成します。

conf/以下のTomcatの設定ファイルとしてserver.xmlを配置します。

server.xmlは以下の内容で記載します。

  • server.xml

Dockerfileを作成します。

  • Dockerfile

Spring MVCなどのように作成したwarファイルをDockerイメージを作成するディレクトリにコピーしてきます。

ローカルでテストする場合は以下のようにビルドしてWebサーバを稼働させておきます。

正常に稼働していることを確認できます。また、http://localhost でアクセスできることも確認します。

動作に問題がない場合、ECRにレポジトリを予め作成しておき、こちらにイメージをpushします。以下はECRのコンソール上でも実行例として表示されるものとなります。

Kubernetesの設定

以下の3つに分けて説明を行います。

  1. NLBの設定

  2. 機密情報の受け渡し設定

  3. コンテナ設定

NLBの設定

NLBを作成するため、service-nlb.yamlという名前で以下のようにマニフェストファイルを作成します。 ここではNLBのTLSリスナーを作成するために、事前に対象のドメインでSSL証明書をACMで発行済みであることを前提としています。

  • service-nlb.yaml

機密情報の受け渡し設定

EKSでは現状ECSのようにSecret Managerに対応しておらず、アプリケーション上からSDKを通してしか利用することができません。

[EKS] [request]: AWS Secrets Manager / SSM Parameter Store #168

そのため、Kubernetesで稼働するアプリケーションに機密情報を渡すために、KubernetesのSecretリソースを利用します。

KubernetesのSecretの機能では、YAMLファイルを作成して、kubectl applyコマンドを使用する方法と、kubectl create secret generic <Secretリソース名>で直接コマンドで直接作成する方法があります。

YAMLファイルを通してSecretのリソースを利用する場合、環境変数のキーおよび値をBase64でエンコーディングしておく必要があります。

エンコーディングした値をSecretリソースのマニフェストファイルで指定します。secret-mywebsite.yamlというような名前でファイルを作成します。

  • secret-mywebsite.yaml

kubectl applyコマンドで適用します。

もしくは、YAMLファイルを使用せずに、kubectl create secret generic <Secretリソース名>で直接コマンドで行うこともできます。YAMLファイルを使用する際は、事前にBase64でエンコーディングする必要はありません。

Spring MVCの方でMySQLやRedisの設定で.propertiesファイルに設定を記載している場合、以下のように環境変数で取得した値を代入するように設定します。

  • db.properties

  • cache.properties

後述するようにPod設定部分に以下のように設定することでコンテナで稼働するアプリケーションに環境変数を渡します。env直下のnameで環境変数名、secretKeyRef直下のnameでSecretリソースのmetadata.nameで指定した名前、keyでSecretリソースのdata以下で指定したキーを指定します。

コンテナ設定

Deploymentを通して起動する方法がKubernetesで推奨されている方法となります。そのため、ここではDeploymentリソースにより、ReplicaSetを作成し、目的のPodを立ち上げるという3層構成でコンテナを立ち上げます。

deployment-mywebiste.yamlという名前でDeploymentリソースのマニフェストファイルを作成します。spec以下でReplicaSetリソースの定義を行います。ReplicaSetリソース以下のspec以下でPodの定義を行います。

Pod定義以下のenvで、先程KubernetesのSecretリソースで作成した環境変数の設定を行っています。

resourcesでリソース制限を行っています。デフォルトではCPUとメモリーの制限のみが可能ですが、Device Pluginによりその他GPUなどのリソースも制限可能になります。

  • deployment-mywebiste.yaml

kubectl applyコマンドで適用します。

以下のように作成したDeploymentリソースの詳細を確認できます。

kubectl describe deployment.apps/<Deployment name>コマンドで詳細を確認できます。 

起動したPodの詳細を確認できます。

作成したリソースの種類全体は以下のように確認できます。-Aオプションでnamespace全体を表示、-o wideオプションでより詳細に情報を表示します。

Error

[✖] AWS::EKS::Nodegroup/ManagedNodeGroup: CREATE_FAILED – "Nodegroup mywebsite-ng failed to stabilize: Internal Failure"

eksctl create clusterコマンドで上記のエラー。このCloudFormationからのエラーはサブネットのルーティングの設定が意図したものになっていなかった。 

ModuleNotFoundError: No module named 'pip._internal.cli.main'

pipコマンドで何打っても上記エラーになる。pipの再インストールで解消。

aws: error: argument operation: Invalid choice, valid choices are:

ECRで例示されたプッシュコマンドを打つと以下のエラー

AWS CLI 1.7.10およびv2で使用できる

  • https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html#cliv2-migration-ecr-get-login

The aws ecr get-login-password command is available in the AWS CLI version 1.17.10 and later, and the AWS CLI version 2.

v2をインストール

インストールが完了したことを確認

Installing the AWS CLI version 2 on macOS

Error syncing load balancer: failed to ensure load balancer: could not find any suitable subnets for creating the ELB

kubectl applyコマンドでNLB作成後、kubectl describe serviceコマンドでイベントを確認すると上記エラー

ドキュメントに従って、NLB用のパブリックサブネットを作成し、以下のタグを付与

  • kubernetes.io/cluster/mywebsite-cluster shared

  • kubernetes.io/role/elb 1

解消される

The connection to the server kubernetes.docker.internal:6443 was refused - did you specify the right host or port?

Docker for Macで稼働しているローカル環境のKubernetesのクラスターに対してkubectlコマンドを実行すると上記エラー。Kubernetesクラスターを起動して解消

E: Unable to locate package telnet

Dockerイメージからコンテナを稼働後、シェル環境にアクセスしてもtelnetをインストールできない。

apt-get updateコマンドを一度実行すれば良い

Request processing failed; nested exception is org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

Springの接続先を上のIPアドレスに置き換え

ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.11.6' (61)

  1. bind-addressによる制限を解除

/usr/local/etc/my.cnf

  1. 権限テーブルでリモートからのアクセスを許可

RDSだと以下のようになっているのでこちらの作業は不要

権限テーブルの設定ミスでログインできなくなった場合

以下のようなエラーでログインできなくなった場合

以下のコマンドを起動

--skip-grant-tablesオプションによる起動中は、以下のようなコマンドが使用できなくなる

以下の方法で回避して、権限テーブルを設定

(参照) How to get all privileges back to the root user in MySQL?

Last updated