😸

Dockerで起動できるReactアプリをEKSにデプロイしてみた

2022/04/16に公開

EKSに触れたことがなかったのでReactアプリをEKSにデプロイしてみました。
大まかな流れは以下のようになります。

  • VPC、サブネット準備
  • kubectlインストール
  • kubectxインストール
  • IAM作成
  • EKSクラスター作成
  • Config編集
  • ノード作成
  • docker image作成
  • docker imageをECRにpush
  • namespace作成
  • deployment作成
  • service作成

VPC、サブネット準備

まずはVPCを作成します。
サブネット等も一緒に作成したいので、「VPC・サブネットなど」の方にチェックを入れます。

名前タグのところにeks-testと入力し、自動生成にチェックを入れます。こうするとサブネット名とかがeks-testから始まる名前に勝手に設定されます。

AZ、パブリック・プライベートサブネットは2つずつにします。
NATゲートウェイは料金が高いのでなしでVPCエンドポイントもなしにします。
「DNS ホスト名を有効化」と「DNS 解決を有効化」の両方にチェックを入れて作成をクリック。

作成完了後、サブネットのページに移動しeksで検索します。

今回作成したサブネットが表示されるので、publicが名前に含まれるサブネットを編集し、「パブリック IPv4 アドレスの自動割り当てを有効化」にチェックを入れます。

kubectlインストール

Kubernetesを操作するためにkubectlをインストールします。
私はbrewでインストールしました

brew install kubectl

その後、kubectl version --short --client でバージョンが表示されたらOKです。

kubectxインストール

kubernetesの名前空間の切り替え等をするためにkubectxをインストールします。
こちらもbrewでインストールしました。

brew install kubectx

IAM作成

次に後から必要になってくるIAMを作成します。
まずはEKSクラスターにつけるロールから作成します。

IAMロールの画面に移動し、ロールを作成をクリック
信頼されたエンティティタイプはAWSのサービスにチェックを入れます。
ユースケースはEKSと入力してEKS - Clusterを選択して次へボタンをクリック。

ロール名にmyAmazonEKSClusterRoleを指定し「ロールを作成」をクリックして作成します

参考
↓のステップ1
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started-console.html

次にEKSのノードにつけるロールを作成します。
またIAMロールのページにアクセス、ロールを作成をクリック。
信頼されたエンティティタイプはAWSのサービスにチェックを入れ、ユースケースはEC2にチェックを入れます。

許可ポリシーとして以下の3つのポリシーをアタッチします

  • AmazonEKSWorkerNodePolicy
  • AmazonEC2ContainerRegistryReadOnly
  • AmazonEKS_CNI_Policy

入力欄に「eks」と入力すると1つ目と3つ目が表示されるのでチェックを入れます。

「フィルターをクリア」を押してから入力欄にEC2と入力すると、2つ目が表示されるのでチェックを入れます。

許可ポリシーの横に(選択済み 3/xxx)と表示されていればOKです。「次へ」をクリックしてください。
ロール名は「AmazonEKSNodeRole」として「ロールを作成」をクリック

参考
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-node-role.html

EKSクラスター作成

いよいよEKSクラスターを作成します。
AWS CLIで作成しました。コマンドは以下です。

aws eks create-cluster --region ap-northeast-1 --name eks-test-cluster --kubernetes-version 1.21 --role-arn myAmazonEKSClusterRoleのarn --resources-vpc-config subnetIds=subnet-xxxxx,subnet-xxxxx

上記コマンドを実行した後、AWSのマネジメントコンソールのEKSのページにアクセスすると、クラスター名「eks-test-cluster」のクラスターが表示され、ステータスが作成中になっていると思います。

しばらくする(約10分ほど)とステータスが「作成中」から「アクティブ」に変わります。アクティブになったら次のステップに進んでください。

参考
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-cluster.html

Config編集

「eks-test-cluster」をクリックするとクラスターの概要、ワークロード、設定が見れます。この時、画面上部に「現在のユーザーまたはロールには、この EKS cluster上の Kubernetes オブジェクトへのアクセス権がありません」と表示されていると思います。

これはクラスターを作成したIAMユーザーと、マネジメントコンソールにログインしているIAMユーザーが違うからです。kubernetesの権限とIAMの権限は違うらしく、アドミン権限を持つユーザーでログインしていてもこのメッセージが表示されます。

まずは下記コマンドを実行し、自分のコンピュータとクラスターを繋げます。

aws eks update-kubeconfig --region ap-northeast-1 --name eks-test-cluster

その後、 kubectl get svc を実行しNAMEとかTYPEとかが表示されればOKです。
しかしこれだけではマネジメントコンソールにログインしているユーザーが全ての情報を見れません。

まず設定マップをダウンロードします。

curl -o aws-auth-cm.yaml https://amazon-eks.s3.us-west-2.amazonaws.com/cloudformation/2020-10-29/aws-auth-cm.yaml

そしてダウンロードしたaws-auth-cm.yamlを下記のように編集します。

apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - rolearn: 先ほど作成したIAMロールAmazonEKSNodeRoleのarn
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes
  mapUsers: |
    - userarn: マネジメントコンソールにログインしているIAMユーザーのarn
      username: マネジメントコンソールにログインしているIAMユーザーの名前
      groups:
        - system:masters

最後に kubectl apply -f aws-auth-cm.yaml を実行して設定を適用します。
成功すると configmap/aws-auth created と表示されます。マネジメントコンソールでEKSクラスターを見ると「現在のユーザーまたはロールには、この EKS cluster上の Kubernetes オブジェクトへのアクセス権がありません」が表示されなくなっていると思います。

ノード作成

次にノードを作成します。ノードはマネジメントコンソールで作成します。
eks-test-clusterの設定タブを開き、さらにコンピューティングをクリックします。そしてノードグループを追加をクリックしてください。

名前は適当にeks-test-node-groupに、IAMロールは先ほど作成したAmazonEKSNodeRoleを選択します。

あとはデフォルトのままで次へをクリック。

インスタンスタイプはデフォルトではt3.mediumになっていますが、必要に応じて変更してください。私は1番小さいt3.microにしました。

ノードグループのスケーリング設定は全部2にしました。
ノードグループのネットワーク設定のサブネットは最初に作成したサブネットのパブリックの2つを指定。
最後に確認して作成。

ステータスが作成中からアクティブに変わればOKです。

docker image作成

Reactアプリのdocker imageを作っていきます。今回はnginxも使用しました。

Dockerifle
FROM node:14.2.0 as builder

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY ["package.json", "package-lock.json", "./"]
RUN npm install
COPY [".", "./"]
RUN npm run build

FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=builder ["/usr/src/app/build", "./"]
COPY ["nginx/default.conf", "/etc/nginx/conf.d"]
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
default.conf
server {
  listen 80;
  location / {
    root /usr/share/nginx/html;
    index index.html index.htm
    try_files $uri /index.html;
  }
}

下記コマンドでビルド

docker build -t eks-test .

ビルド完了後、docker run -p 3000:80 eks-test を実行し localhost:3000でアクセスできればOKです。

docker imageをECRにpush

先ほど作成したdocker imageをECRにpushします。
まずはAWSのマネジメントコンソールにログインし、ECRのリポジトリを作成します。
プライベートリポジトリの方で「リポジトリを作成」をクリックします。

プライベートにチェックを入れ、リポジトリ名はeks-test(docker imageの名前と同じ)にします。
そして「プッシュ時にスキャンを有効にする」にチェックを入れ、作成ボタンを押します。

リポジトリ一覧の中からeks-testをクリックすると次のような画面が現れるので、「プッシュコマンドの表示」をクリックします。

そこで提示されたコマンドを実行するとECRにdocker imageがpushされます。
このようになっていればOKです。

そしてこのlatestをクリックするとイメージのURIが表示されるので控えておきます。

namespace作成

名前空間を作成します。
下記のコマンドを実行します

kubectl create namespace eks-test

namespace/eks-test created と表示されればOKです。
そして kubens eks-test を実行し、namespaceを選択します。

deployment作成

eks-test-deployment.yamlという名前のファイルを作成し、以下を貼り付けます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: eks-test
spec:
  selector:
    matchLabels:
      app: eks-test
  replicas: 1
  template:
    metadata:
      labels:
        app: eks-test
    spec:
      containers:
      - name: eks-test
        image: ECRのURL
        imagePullPolicy: Always
        ports:
        - containerPort: 80

kubectl apply -f eks-test-deployment.yaml -n eks-test を実行してデプロイします。

service作成

deploymentだけではまだwebアプリにアクセスできません。serviceを作成する必要があります。
eks-test-service-lb.yamlという名前のファイルを作成し、以下を記述します。

apiVersion: v1
kind: Service
metadata:
  name: eks-test
spec:
  type: LoadBalancer
  selector:
    app: eks-test
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

kubectl apply -f eks-test-service-lb.yaml -n eks-test を実行。
kubectl get service -n eks-test を実行。

そうするとEXTERNAL-IPが表示されるのでそれをコピーしてブラウザのURL欄に貼り付けます。
するとReactアプリが画面に表示されます。

後片付け

今回作成したリソースをそのままにしておくとお金が多くかかってしまうので削除しておきます。

namespace削除

まずは下記コマンドを実行し、namespaceごと削除します。

kubectl delete namespace eks-test

これでeks-test-service-lb.yamlで作成したロードバランサーが削除されます。

ECRリポジトリ削除

次にECRリポジトリを削除します。

aws ecr delete-repository --repository-name eks-test --force --region ap-northeast-1

ノードグループ削除

次はノードグループを削除します。
まずこのコマンドでクラスターにあるノードグループを確認します

aws eks list-nodegroups --cluster-name eks-test-cluster --region ap-northeast-1

本記事の手順に沿って作成していた場合は、eks-test-node-groupというノードグループが表示されると思います。そのノードグループを下記コマンドで削除します。

aws eks delete-nodegroup --nodegroup-name eks-test-node-group --cluster-name eks-test-cluster --region ap-northeast-1

ステータスが削除中になっていると思うのでしばらく待ちます。

10分ほどで削除されます。すると起動していた2台のEC2も消えているのが分かると思います。

EKSクラスター削除

最後にEKSクラスターを削除します。
下記コマンドを実行します。

aws eks delete-cluster --name eks-test-cluster --region ap-northeast-1

こちらもまたステータスが削除中になっていると思います。

こちらはすぐに削除されました。

これでお金がかかりそうなリソースは削除できたと思います。
あとのIAMやVPC等は残しておいても大丈夫ですが、不要なものを残しておきたくない場合は消しておきましょう。

終わりに

今回初めてEKSを触ってみましたが、ノードグループとかserviceとかdeploymentなどの知らない単語や抽象的な概念が多くて難しく感じました。またIAMの権限とは別でk8sでの権限があり、アドミン権限のIAMユーザーでログインしていても権限がなく表示されないなど今までに経験していなかったことに遭遇し少し戸惑いました。

最後に今回eksにReactアプリを上げるために参考にした記事等を共有して終わりにしたいと思います。

https://catalog.us-east-1.prod.workshops.aws/workshops/f5abb693-2d87-43b5-a439-77454f28e2e7/ja-JP/020-create-cluster
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started-console.html
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-cluster.html
https://qiita.com/sonots/items/f82912367693d717ff06
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-node-role.html
https://dev.classmethod.jp/articles/eks-support-provisioning-and-managing-worker-nodes/

Discussion