概要
Next.jsで作成したアプリを AWS EKS上にデプロイする方法を紹介します!
以前はGoで実装したAPIをk8s環境にデプロイする記事も書きました!
ローカルのk8sではなく、EKSにデプロイする記事もということで
今回はNext.jsにて試します!
前提条件
- node.jsの開発環境が整っていること
- Docker と Kubernetes(k8s)がインストールされていること
- AWS ECR(Elastic Container Registry)へのアクセス権限があること
また今回はHelm Chartを使用して、k8sリソース作成を
簡略化します!
Helmについては以下記事で入門編として解説してます!
1. Next.js プロジェクトを作成
Next.jsアプリを作成し、ウェルカムページを表示します!
今回はこの状態でEKSにデプロイしようと思います。
npx create-next-app@latest nextjs-app
cd nextjs-app
# 動作確認
npm run dev
2. Dockerfile の作成
次に、アプリケーションを Docker コンテナにパッケージングするための Dockerfile を作成します。
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm install
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
# 本番に必要なものだけコピー
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
EXPOSE 3000
CMD ["npm", "start"]
今回は実装少ないですが、ライブラリをインストールしたりすると重くなるので
マルチステージビルド等で工夫すると尚良いかと!
3. Docker イメージをビルド
次に、Docker イメージをビルドします。
$ docker build -t nextjs-app .
一応ローカルでも動作確認してみよう!
1. Docker イメージをビルド
docker build -t nextjs-app .
-t nextjs-app はタグ名の指定です(任意)
2. コンテナを起動
docker run -p 3000:3000 nextjs-app
-p 3000:3000 でローカルのポート3000にバインドします。
3. ブラウザでアクセス
http://localhost:3000
Next.js のトップページが表示されれば成功です ✅
4. AWS ECR に Docker イメージをプッシュ
AWS ECR を使用して、作成した Docker イメージをアップロードします。
ECR にリポジトリを作成
AWSマネジメントコンソールにログインし、ECRにリポジトリを作成しましょう。
名称は任意で大丈夫です!
作成したら、画面右上に「プッシュコマンドを表示」ボタンがあります。
これを押下すると、何とECRにPushするところまで方法を案内してくれます!
5. Kubernetes クラスタの準備
kubectl コマンドで Kubernetes クラスタに接続していることを確認します。
今回は、kind でクラスタを作成する方法を記載します。
$ kind create cluster
6. Helm を使ってデプロイ
helm を使って、Kubernetes 上に Next.jsアプリをデプロイします。
まずは、Helm チャートのテンプレートを作成し、values.yaml を編集します。
Helm Chartを作成する
$ helm create nextjs-chart
これで go-api/ ディレクトリができ、k8sリソースを作成するための
基本構成が入っています。
ディレクトリ構成例
nextjs-chart/
Chart.yaml # Chartの基本情報
values.yaml # デフォルトの変数
templates/ # K8sマニフェスト(Helmテンプレート)
deployment.yaml # デプロイメント定義
service.yaml # サービス定義
ingress.yaml # ingress
...
values.yaml
replicaCount: 1
image:
repository: {作成したECRのURI}
tag: {作成したECRのタグ}
service:
name: nextjs-chart
type: ClusterIP
port: 3000
readinessProbe:
httpGet:
path: /test
port: 3000
initialDelaySeconds: 3
periodSeconds: 10
ingress:
enabled: true # falseになるとIngress リソースが作成されないので注意!
className: "alb" # ingress.yamlのingressClassNameに該当
annotations: {}
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextjs-chart
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: nextjs-chart
template:
metadata:
labels:
app: nextjs-chart
spec:
containers:
- name: nextjs-chart
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 3000
livenessProbe:
httpGet:
path: {{ .Values.livenessProbe.httpGet.path }}
port: {{ .Values.livenessProbe.httpGet.port }}
readinessProbe:
httpGet:
path: {{ .Values.readinessProbe.httpGet.path }}
port: {{ .Values.readinessProbe.httpGet.port }}
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nextjs-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nextjs-chart
port:
number: 3000
7. ingressの説明
改めてingressの説明!
Kubernetes の Ingress リソースは、
クラスター外部からの HTTP/HTTPS トラフィックを
Service にルーティングするためのエントリポイントです!
特に複数のアプリケーション(Next.js✖️go)のように、ドメインを集約し、
パスベースで振り分ける場合に非常に有効です。
- 「/」とか「/api」みたいに
- ingressを介して、ルーティングするためにALB Ingress Controllerをインストールします(8番で手順を説明します)
8. ALB Ingress Controllerをインストール(初回のみ)
① [IAM OIDC provider の有効化](初回のみ)
eksctl utils associate-iam-oidc-provider --region ap-northeast-1 --cluster <CLUSTER_NAME> --approve
② IAM Policy の作成
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam_policy.json
③ Service Account 作成(--cluster はあなたのEKS名に)
eksctl create iamserviceaccount \
--cluster <CLUSTER_NAME> \
--namespace kube-system \
--name aws-load-balancer-controller \
--attach-policy-arn arn:aws:iam::<AWS_ACCOUNT_ID>:policy/AWSLoadBalancerControllerIAMPolicy \
--approve
④ Helm を使って Controller をインストール
helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm upgrade -i aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<CLUSTER_NAME> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--set region=ap-northeast-1 \
--set vpcId=<VPC_ID> \
--set image.repository=602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon/aws-load-balancer-controller
vpcId は aws eks describe-cluster --name で取得できます。
⑤ 確認!
kubectl get pods -n kube-system | grep aws-load
Pod が Running になればOKです!
9. Kubernetes にデプロイ
次に、Helm を使って Kubernetes クラスタにデプロイします。
#「nextjs-chart」は任意で変えて大丈夫です
$ helm install nextjs-chart ./nextjs-chart
# Ingress確認(ALBのDNSが表示されるまで少し待ちます)
kubectl get ingress
これで、Next.jsアプリが Kubernetes 上でデプロイされ、サービスが公開されます。
10. 動作確認
デプロイ後、以下のコマンドでリソースが正常にデプロイされているか確認します。
まずはPodが起動しているかをチェック。
動作確認
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nextjs-chart-cd454c75-jk6wv 1/1 Running 0 2s
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
app-nextjs alb chart-example.local 80 44s
nextjs-ingress alb * k8s-frontend-63afaf69ef-1598947954.ap-northeast-1.elb.amazonaws.com 80 44s
アクセス確認
- 表示されたALBのDNSにブラウザでアクセス(
http://<ALB-DNS>/
) - Next.jsトップページが表示されれば成功!
Next.jsのウェルカムページの表示が
確認できればOKです!
まとめ
今回は Next.jsアプリをEKSにデプロイする方法を紹介しました!
k8sを個人開発で使用するための入門として、お役に立てれば幸いです!