ECSで運用しているサービスにEKSを導入し移行する - ECSからEKSへ移行
前回のEKS構築編に引き続き、ECSからEKSへの移行をどのようにしたか紹介します。今回は、ECSで動いているフロントエンドとバックエンドをEKSに移行します。構成図としては以下です。
EKSのIngressの設定でALBをたてます。ALBからNuxt.js(ポートは3333)でつくられたフロントエンドとGolang(ポートは3000)で作られたバックエンドにリクエストを振り分けます。
フロントエンドとバックエンドの設定
はじめにバックエンドのKubernetes用のファイルを作成します。replicasが1になっているとポッドが1つしか作られませんが、本番運用する際は障害に備えて最低でも3で運用してください。なお、Liveness ProbesとReadiness Probesは設定していないですが本番運用するときは設定したほうがいいので適宜設定してください。
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
ports:
- port: 3000
targetPort: 3000
protocol: TCP
name: backend
type: NodePort
selector:
app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: xxx.dkr.ecr.ap-northeast-1.amazonaws.com/backend:latest
ports:
- containerPort: 3000
フロントエンド用のファイルは以下のようになります。
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
ports:
- port: 3333
targetPort: 3333
protocol: TCP
name: frontend
type: NodePort
selector:
app: frontend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: xxx.dkr.ecr.ap-northeast-1.amazonaws.com/frontend:latest
ports:
- containerPort: 3333
フロントエンドとバックエンドをKubernetesに反映します。
kubectl apply -f backend.yaml
kubectl apply -f frontend.yaml
デプロイされたか確認します。
kubectl get pod
ALBの設定
Kubernetes内への外部からアクセスをコントロールするものをKubernetesではIngressといいます。Ingressを設定するとロードバランサが作られるのですが、今回はロードバランサとしてALBを採用します。
Ingressを設定する前に権限関係の解決に必要となるkube2iam
を設定します。
kube2iamの設定
kube2iamはKubernetesの設定ファイルのアノテーションにAWSのロールを記載することによりポッドがそのロールの権限を実行できるようになります。これを使わない場合AWSの鍵情報を権限が必要なすべてのKubernetes設定ファイルにかかなければならず面倒なのと秘匿情報を設定ファイルにかきたくないのでkube2iam
を使います。
kube2iam
の設定はREADMEを見ながらやるのがいいかなと思いますが手順を詳しくみていきます。
はじめにkube2iam
用のRBACロールをkubectl apply -f kube2iam-rbac.yaml
で反映します。
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube2iam
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kube2iam
rules:
- apiGroups: [""]
resources: ["namespaces","pods"]
verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kube2iam
subjects:
- kind: ServiceAccount
name: kube2iam
namespace: kube-system
roleRef:
kind: ClusterRole
name: kube2iam
apiGroup: rbac.authorization.k8s.io
AWSのコンソールでIAMのポリシーを作成します。以下をeks-kube2iam
という名前で作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
k8s-kube2iam
という名前でIAMのロールを作成します。ロールの使用するサービスはEC2を選びます。ロールの使用するポリシーはEC2で先程作ったeks-kube2iam
のポリシーをアタッチします。ロールの信頼関係の編集を選び以下でアップデートします。なおarn:aws:iam::xxx:role/worker-nodes-NodeInstanceRole-yyy
の部分はEKSのノードのロールを設定してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxx:role/worker-nodes-NodeInstanceRole-yyy"
},
"Action": "sts:AssumeRole"
}
]
}
kube2iam
のDaemonSetを作成しKubernetesにkubectl apply -f kube2iam.yaml
で反映します。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube2iam
namespace: kube-system
labels:
app: kube2iam
spec:
selector:
matchLabels:
name: kube2iam
template:
metadata:
labels:
name: kube2iam
spec:
serviceAccountName: kube2iam
hostNetwork: true
containers:
- image: jtblin/kube2iam:latest
imagePullPolicy: Always
name: kube2iam
args:
- "--app-port=8181"
- "--auto-discover-base-arn"
- "--iptables=true"
- "--host-ip=$(HOST_IP)"
- "--host-interface=eni+"
- "--verbose"
env:
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
ports:
- containerPort: 8181
hostPort: 8181
name: http
securityContext:
privileged: true
以下で確認してログにエラーが出てなければ大丈夫です。
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
...
kube2iam-kg5gz 1/1 Running 0 9m
...
$ kubectl logs -n kube-system kube2iam-kg5gz
alb-ingress-controllerの設定
alb-ingress-controllerはIngressの設定を読み取りALBを作ってくれます。
Ingress用のkube2iam
の設定をします。ここの手順をみるのがいいかなと思いますが順に説明します。
最初にeks-ingress-policy
という名前でiam-policy.jsonのIAMのポリシーを作成します。
次に、k8s-alb-controller
という名前でIAMのロールを作成します。ロールを使用するサービスはEC2を選びます。ロールの使用するポリシーは先程作ったeks-ingress-policy
のポリシーをアタッチします。ロールの信頼関係の編集を選び以下でアップデートします。なおarn:aws:iam::xxx:role/worker-nodes-NodeInstanceRole-yyy
の部分はEKSのノードのロールを設定してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxx:role/worker-nodes-NodeInstanceRole-yyy"
},
"Action": "sts:AssumeRole"
}
]
}
RBACの設定をします。以下をkubectl apply -f rbac-alb-ingress-controller.yaml
でKubernetesに反映します。
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app: alb-ingress-controller
name: alb-ingress-controller
rules:
- apiGroups:
- ""
- extensions
resources:
- configmaps
- endpoints
- events
- ingresses
- ingresses/status
- services
verbs:
- create
- get
- list
- update
- watch
- patch
- apiGroups:
- ""
- extensions
resources:
- nodes
- pods
- secrets
- services
- namespaces
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app: alb-ingress-controller
name: alb-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alb-ingress-controller
subjects:
- kind: ServiceAccount
name: alb-ingress
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: alb-ingress-controller
name: alb-ingress
namespace: kube-system
最後にalb-ingress-controllerのDeploymentをkubectl apply -f alb-ingress-controller.yaml
で反映します。xxxとなっているところは適宜かえてください。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: alb-ingress-controller
name: alb-ingress-controller
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: alb-ingress-controller
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
iam.amazonaws.com/role: arn:aws:iam::xxx:role/k8s-alb-controller
creationTimestamp: null
labels:
app: alb-ingress-controller
spec:
containers:
- args:
- --ingress-class=alb
- --cluster-name=xxx
- --aws-vpc-id=xxx
- --aws-region=ap-northeast-1
- --aws-api-debug
image: docker.io/amazon/aws-alb-ingress-controller:v1.1.0
imagePullPolicy: Always
name: server
resources: {}
terminationMessagePath: /dev/termination-log
dnsPolicy: ClusterFirst
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30
serviceAccountName: alb-ingress
serviceAccount: alb-ingress
kubectl get pod -n kube-system
でalb-ingress-controller
のポッドが動いているのを確認し、ログにエラーがでていなければ大丈夫です。
Ingressの設定
Ingressの設定し、kubectl apply -f ingress.yaml
で反映するとALBを自動でつくってくれます。xxxとなっているサブネットや証明書のARN、ホスト名など適宜かえてください。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/subnets: xxx, xxx, xxx
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:xxx:certificate/xxx
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
spec:
rules:
- host: frontend.example.com
http:
paths:
- path: /*
backend:
serviceName: frontend
servicePort: 3333
- host: backend.example.jp
http:
paths:
- path: /*
backend:
serviceName: backend
servicePort: 3000
backend:
serviceName: frontend
servicePort: 3333
各種ドメインでアクセスできるのが確認できたら完了です。適宜Route53などの設定をかえドメインの振り分けをEKS側にしてください。
開発環境でベーシック認証を設定している場合
すべてのパスにベーシック認証がかかっている場合ALBからのヘルスチェックが401となりヘルスチェックが失敗してALBが504 Gateway Time-out
をかえしてエラーになるのでベーシック認証がかかっているサービスに以下のようにアノテーションを追加します(/health
はヘルスチェック用のパスです)。
apiVersion: v1
kind: Service
metadata:
...
annotations:
alb.ingress.kubernetes.io/healthcheck-path: "/health"
alb.ingress.kubernetes.io/success-codes: 200,401
Ingress Annotationsにその他のアノテーションもあるのでもっとカスタマイズしたい場合は参考にするといいと思います。
まとめ
ECSで動いていたサービスをEKSに移行しました。Ingressの設定が少しやっかいですが、一度設定するとYAMLファイルでルーティングできるので非常に楽です。KubernetesにすることでYAMLを書くだけでサービスが展開できコードにものこっているので複数のサービスを運営するのも楽になるのでおすすめです。