GoのアプリをEKS(Fargate)にデプロイしてみた話
Goで作ったアプリケーションを、公式ドキュメントに沿ってEKS(Fargate)にデプロイしようとしたところ、少し詰まったので記録を残しておきます。
この記事では、アプリをデプロイしてインターネット経由でアクセス可能にするところまでの手順を紹介します。
参考にした公式ドキュメントは以下です。
クラスターの作成
アプリのデプロイ
Load Balancer Controllerのインストール
実際の手順
コンテナで動くアプリを構築する
Goのアプリケーションをコンテナで動かせるように構築しました。フレームワークはginを使っていて、GET /
で「Server Running!!」というメッセージを返却、POST /
でAmazon Rekognitionのテキスト抽出の結果を返却する機能を実装しています。後者の機能については、別途記事を書きます。
Dockerイメージはこちら
クラスターを作成する
以下コマンドでクラスターを作成します。
eksctl create cluster --name <CRUSTER_NAME> --region ap-northeast-1 --fargate
前提として、eksctlのインストールが必要です。
手順はこちら
自分の場合は、eksctlをかなり前にインストールしていたのでバージョンが古くなっており、クラスター作成時に以下エラーが出ました(最新は0.95.0なのに対し、0.35.0がインストールされていた)。
Resource handler returned message: "unsupported Kubernetes version
上にリンクを記載した手順でeksctlの最新版をインストールすることで解決しました。
名前空間を作成する
k8sクラスターの中がごちゃごちゃになるのはいやなので、アプリケーション用の名前空間を作成します。
kubectl create namespace eks-sample-app
Fargateプロファイルを変更する
Fargateにデプロイする場合、ここが重要です!
この手順を忘れた結果、Podがpendingの状態となり、起動できませんでした。
散々悩んだ結果、ドキュメントを改めて読んでみると、以下の記載が、、(前提じゃなくて、手順の中に組み込んで記載してくれていると嬉しかった)
どうやら、Fargateプロファイルなるものに対して、上記で作成した名前空間eks-sample-app
を含めてあげる必要があるようです。
コンソールから設定しました。
デフォルトのFargateプロファイルに名前空間を追加する方法がわからなかったので、新規に作成してデフォルトのものは削除しました。
デフォルトのプロファイルでは、default、kube-systemの名前空間のみが含まれていたので、そこにeks-sample-appを追加した形です。
マニフェストファイルを作る(Deployment)
公式ドキュメントを参考に、Deploymentのマニフェストファイルを作成します。
containersのimageの箇所は、自分で作ったコンテナイメージに変更しています。また、affinityやnodeSelectorの箇所は以下の例では記載していますが、記載しなくても動きました。
apiVersion: apps/v1
kind: Deployment
metadata:
name: eks-sample-deployment
namespace: eks-sample-app
labels:
app: rekognition-go
spec:
replicas: 1
selector:
matchLabels:
app: rekognition-go
template:
metadata:
labels:
app: rekognition-go
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- arm64
containers:
- name: rekognition-go
image: hisamitsu/rekognition-go:latest
ports:
- name: http
containerPort: 8080
imagePullPolicy: IfNotPresent
nodeSelector:
kubernetes.io/os: linux
以下コマンドで、デプロイします。
kubectl apply -f infra/k8s/eks-sample-deployment.yaml
Podが意図通り作成されていることを確認。
kubectl get pod -n eks-sample-app
結果(Runningになっていたら成功です)
NAME READY STATUS RESTARTS AGE
eks-sample-deployment-795d4bd6c4-rdjc5 1/1 Running 0 5h38m
マニフェストファイルを作る(Service)
続いて、Serviceのマニフェストファイルを作成します。
targetPortには、Pod側で待ち受けているポート(8080)を指定します。
apiVersion: v1
kind: Service
metadata:
name: eks-sample-service
namespace: eks-sample-app
labels:
app: rekognition-go
spec:
selector:
app: rekognition-go
ports:
- protocol: TCP
port: 80
targetPort: 8080
これも、デプロイします。
kubectl apply -f infra/k8s/eks-sample-service.yaml
デプロイしたアプリケーションにアクセス(できない、、、)
以上で、デプロイが完了したので、インターネット経由でアプリケーションにアクセスしてみましょう。公式ドキュメントでは、Podの中に入り込んで、そこからcurlコマンドを打っていますが、できればインターネット経由でアクセスしたいですよね。
以下2通りの方針を考えました。
- Serviceに
type: NodePort
を設定してクラスタ外からアクセスできるようにして、FargateのパブリックIPからアクセスする - Serviceに
type: LoadBalancer
を設定して、ロードバランサー経由でアクセスする
実は、Fargateの場合は両方とも実現できないんです(Fargateでない場合は、できた記憶がある)。というのも、Fargateには以下の制約があります。
- FargateにパブリックIPアドレスを割り当てることはできない → 1つ目の方針がNGな理由
- Podはプライベートサブネットに配置して、ロードバランサーなどを経由する必要があります。
- LoadBalancerのCLB/NLBは非対応 → 2つ目の方針がNGな理由
- k8sのServiceでLoadBalancerを設定すると、デフォルトではCLB(Classic Load Balancer)が作成されますが、Fargateではこれに対応していません。
以上の理由から、Ingress + ALBを経由した構成が必要となります。
以降、その手順を記載します。
ALB Controllerを作成する
ALB Ingressを使うためには、事前にALB Controllerを設定する必要があります。
以下の手順の「Amazon EKS クラスター、サービスアカウントポリシー、RBAC ポリシーの作成」、「Helm を使用して AWS Load Balancer Controller をインストール」を実行します(ここは何もアレンジしていないので、少し雑)。
マニフェストファイルを作る(Ingress)
あとは、ALB Ingressのマニフェストファイルを作って、デプロイするだけです。
注意点としては、Fargateの場合は、alb.ingress.kubernetes.io/target-type
をip
にする必要がある点です。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: eks-sample-ingress
namespace: eks-sample-app
labels:
app: rekognition-go
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
rules:
- http:
paths:
- path: "/*"
backend:
serviceName: eks-sample-service
servicePort: 80
デプロイします。
kubectl apply -f infra/k8s/eks-sample-ingress.yaml
デプロイしたアプリケーションにアクセス
デプロイが成功していれば、ALBができているはずなので、画面からDNS名を取得してアクセスします。ブラウザに以下が表示されていれば成功です。
さいごに
この記事では、アプリをデプロイしてインターネット経由でアクセス可能にするところまでの手順を紹介しました。
k8sのような、新しい技術に触れられるのは楽しいですが、ALBを作るだけでも事前設定(ALB Controllerの作成)が必要だったりして、本番で使うなら、ECSの方が楽で良いかなーというのが感想。
今回作成したGoのアプリのPOST(Amazon Rekognitionのテキスト抽出の結果を返却する機能)を叩くには、Rekognitionの権限を持つIAMロールをPodに付与する必要があるので、その内容については別記事で紹介したいと思います。
Discussion