つい最近Amazon EKSを使用してwebアプリをデプロイしたのでその時に学んだこと、詰まったところを記録として残します。
目次
awsの公式ドキュメントによると、EKSは下記のように説明されています。
Amazon Elastic Kubernetes Service (Amazon EKS) は、独自の Kubernetes コントロールプレーンまたはノードをインストール、操作、および維持することなく、AWS で Kubernetes を実行するために使用できるマネージドサービスです。
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/what-is-eks.html
この言葉が全てなのですが、簡単に言い換えると、AWS上でkubernetesを用いたインフラ構築をする際に便利な機能が詰まったAWSリソースということです。
EKSを触る前の私のレベルですが、「VPCって何それ美味しいの?」「dockerなんて触ったことがない」というくらいインフラの知識皆無の状態でした。
そんな私がEKSを最初から触るなんてハードルが高すぎたので、まずはUdemyで教材を2つほど購入してdockerとkubenetesの基本を学びました。
参考までにその時に購入したUdemyの動画教材のリンクを下記に置いておきます。
今回はチームで開発したサンプルアプリケーションをEKSを用いたインフラ基盤の上にデプロイしたので、(予算の都合上)完全に本番を意識した構成にはできませんでしたが、最終的なインフラ構成全体像は下記のようになっています。
EKSを使ってアプリケーションを動かす手段は2つあります。
- EC2インスタンスを立ててその中にpodを立ててアプリケーションを動かす方法
- AWS Fargateのプロファイルを作成しアプリケーションを動かす方法
上の図はEC2インスタンスを立てて動かした場合の図ですが、AWS Fargateを使った構成の方が楽だった印象です。
今回はこの2つの手段でアプリケーションを動かしたのですが、EC2を使った構成に関してはAWS CDKを使ってAWSリソースを作成する際に権限周りで詰まることが多かったのでAWS Fargateでの構成に移行しました。
EKSはpodの状態を監視し、最適な状態に保つ司令塔のような役割を持つ「EKSクラスター」と、アプリケーションをデプロイするインスタンスやプロファイルのことを指す「ノードグループ」があります。
AZは2つに分けてEKSのノードグループを作成する領域はプライベートサブネットにしました。
ここで注意したいのはいくら予算がなくてもAZを1つだけしか指定しなかったり、NATゲートウェイとプライベートサブネットを繋いでいない場合、EKSクラスターとノードグループ作成時エラーになってしまうところです。
EKSは基本的に大規模のシステムで運用されることを前提として作られているものなので、ここらへんはしょうがないですね。
EKS内部では最初に通信を受ける部分としてALBを採用しました。
kubenetes用のALBを導入するには、AWS Load Balancer Controller インストールが必要です。
ALB Controllerのインストールが完了したら下記のようにpodが立ち上がります。
NAME READY UP-TO-DATE AVAILABLE AGE
aws-load-balancer-controller 2/2 2 2 84s
ALBの詳細や詳しい導入手順は公式ドキュメントにまとまっているので詳しくはそちらをご覧ください。
ALB Controllerが準備できたら、kubenetesのingressリソースを利用できるようになるのでそちらもマニフェストファイルを適用して作成します。
ALBからの通信をkubenetesのingressリソースで受け取ります。ingressを作成したらpodが立ち上がることはなく、一つのkubenetesのリソースという扱いになります。
ALBではアプリケーションの負荷分散を実現し、ネットワークトラフィックを負荷分散するにはALBから流された通信をリバースプロキシするkubenetesリソースのserviceで実現します。
複数存在するフロントエンド用のpodへはこのserviceを使って通信の振り分けを実現しています。
そして、フロントエンドからバックエンドへの通信もこのserviceを使っています。
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: *
name: *
spec:
selector:
matchLabels:
app.kubernetes.io/name: backend-app
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: backend-app
spec:
containers:
- image: **
imagePullPolicy: Always
name: backend-app
ports:
- name: http
containerPort: port番号
// RDSを利用していたので環境変数として渡す
env:
- name: DATABASE_URL
value: {DATABASE_URL}
---
apiVersion: v1
kind: Service
metadata:
namespace: *
name: backend-service
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
selector:
app.kubernetes.io/name: backend-app
---
# フロントエンド
---
apiVersion: v1
kind: Namespace
metadata:
name: *
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: *
name: frontend-deployment
spec:
selector:
matchLabels:
app.kubernetes.io/name: frontend-app
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: frontend-app
spec:
containers:
# ここのimageを変える
- image: {imageURL}
imagePullPolicy: Always
name: frontend-app
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: *
name: *
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: frontend-app
EKSを導入する中で詰まった部分と、その解決法を記述していきます。
EKS周りを導入する際のエラーでは公式のトラブルシューティングで大体解決しました。
kubenetesリソースが作成されないなどのエラーの場合、そのpodの詳細情報を見れば大体のエラー原因が書いてあります。
私は序盤にクラスターとノードが結合できないエラーに悩まされましたが、ランブックを使って原因を突き止め対応していくことで解決しました。
原因としては、ノードに下記のようなタグが付与されていないことでした。
kubernetes.io/cluster/my-cluster:owned
マニフェストをapply、deleteと繰り返していく中で発生したエラーです。
これも公式の方法がありましたのでその通りに対応しました。
NATゲートウェイがプライベートサブネット内にあったため、docker Hubへの通信が行えず、イメージをpullしている中でtimeoutしていたようです。
NATゲートウェイをパブリックサブネットに作成し直すことで正常にpullできました。
t3.microを使っていたため、1インスタンスに4つしかpodを立てることができないことが原因でした。
4つ以上のpodを立てたい場合にはインスタンスタイプをグレードアップするか、インスタンス台数を増やす必要があります。
私はt3.smallにインスタンスタイプを変更することで正常にpodが立ち上がりました。
aws-load-balancer-controllerのマニフェストファイルをapplyしている中で起こったエラーです。
podの中でimageがpullできない状態でapplyしていたので、うまくyamlファイルが読み込まれていないようでした。
それによって必要なリソースがpodにデプロイされず、存在しないファイルをマウントしようとしていたことが原因でした。
imageがpullできない原因を解消し、podを立ち上げ直すことでエラーは解消されました。
今回初めてインフラを触ると同時にEKSを使ってアプリをデプロイするところまで経験しました。
その中で、異常系を意識した構成やログなどの可測性を意識することができなかったので次回触る機会があれば、動けばいいインフラの構成ではなく、本番を意識したインフラ構築をしてみたいです。