EKSクラスタ内で動作しているpodを外部公開するためのエンドポイントとしてALBを使う場合の構築手順をまとめておく。
ALB Ingress Controllerを使うことで、ingressをapplyしたときに自動でALBを構築してくれるのですごく便利だった。
また、ingressで任意のドメインを指定するとALBのhost-based routingに反映してくれるので、サブドメインを変えて複数のサイト公開も楽にできた。
加えて、ExternalDNSを使うと自分が管理しているドメインのレコード追加を自動でやってくれる。
SSL証明書をACMに用意しておくと、簡単にHTTPS化できたので、HTTPS対応についても最後にまとめておく。
アーキテクチャ
今回使うアプリケーションはDjangoとその前段にリバースプロキシとしてnginxを配置したシンプルなもの。EKSクラスタ内にはその他にALBにルール反映してくれるALB Inress ControllerとRoute 53にレコード反映してくれるExternalDNSのpodが起動している。SSL証明書発行にはACMを利用。

EKSクラスタ構築
公式サイトの方法を参考にクラスタ構築。
eksctl で構築するのが便利。
eksctl create cluster \
--name test-cluster \
--version 1.14 \
--region ap-northeast-1 \
--nodegroup-name standard-workers \
--node-type t3.medium \
--nodes 2 \
--nodes-min 1 \
--nodes-max 4 \
--managed(参考)EC2インスタンスのタイプによって付与可能なIPアドレス数が異なるため、podをたくさん起動する場合はworker nodeのインスタンスタイプに注意すること。
IPアドレス数の一覧はこちら
ALB Ingress Controllerのデプロイ
基本は公式サイトの手順通りに実施する。
EKSクラスタのサブネットにタグが付いていることを確認
- VPC 内のすべてのサブネット
kubernetes.io/cluster/:<cluster-name>shared
- VPC のパブリックサブネット
kubernetes.io/role/elb:1
- VPC 内のプライベートサブネット
kubernetes.io/role/internal-elb:1
IAM ポリシーを作成
IAMポリシーファイルをダウンロード
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/iam-policy.jsonIAMポリシーを作成
aws iam create-policy \
--policy-name ALBIngressControllerIAMPolicy \
--policy-document file://iam-policy.jsonEKSクラスタのワーカーノードの IAM ロール名を取得
kubectl -n kube-system describe configmap aws-auth出力結果の<アカウントID>と<ロール名>を控えておく。
Name: aws-auth
Namespace: kube-system
Labels: <none>
Annotations: <none>
Data
====
mapRoles:
----
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::<アカウントID>:role/<ロール名>
username: system:node:{{EC2PrivateDNSName}}
mapUsers:
----
[]
Events: <none>EKSクラスタのワーカーノードにIAMポリシーをアタッチ
aws iam attach-role-policy \
--policy-arn arn:aws:iam::<アカウントID>:policy/ALBIngressControllerIAMPolicy \
--role-name <ロール名>ALB Ingress Controller で使用するサービスアカウント、クラスターロール、クラスターロールバインディングを作成
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/rbac-role.yamlALB Ingress Controller をデプロイ
ここは公式サイトとは違う方法でデプロイする。
公式サイトではmanifestをデプロイした後に環境に合わせて編集しているが、今回は最初にデプロイ用manifestをダウンロードし、ファイルを編集した後にデプロイする。
ALB-Ingress-Controllerのmanifestをダウンロード
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/alb-ingress-controller.yamlManifestを編集する。以下のパラメータのコメントアウトを外し、書き換える。
spec:
containers:
- args:
- --cluster-name=test-cluster
- --aws-vpc-id=<VPC ID>
- --aws-region=ap-northeast-1(参考)VPC IDを確認するには以下のコマンドを実行する。
aws ec2 describe-vpcsデプロイ
kubectl apply -f alb-ingress-controller.yaml以下のコマンドを実行してエラーが表示されなければデプロイ成功
kubectl logs -n kube-system -f $(kubectl get po -n kube-system | egrep -o 'alb-ingress-controller[A-Za-z0-9-]+')ExternalDNSのデプロイ
ALBのエンドポイントを自分が管理しているRoute53にailiasとして反映させてくれる ExternalDNS というOSSがあるので使ってみる。
IAM ポリシーを作成
IAMポリシーファイルを作成。公式サイトのチュートリアルから流用
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
}IAMポリシーを作成
aws iam create-policy \
--policy-name ExternalDNSIAMPolicy \
--policy-document file://external-dns-iam-policy.jsonEKSクラスタのワーカーノードにIAMポリシーをアタッチ
aws iam attach-role-policy \
--policy-arn arn:aws:iam::<アカウントID>:policy/ExternalDNSIAMPolicy \
--role-name <ロール名>ExternalDNS をデプロイ
ExternalDNSのmanifestをダウンロード
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/external-dns.yaml Manifestを編集。example.comには自分で管理しているFQDNに変更すること。ダウンロードしたファイルではpolicyオプションがupsert-onlyになっているが、これはレコード追加だけすることを表す。今回はingressの内容に合わせて適宜レコード削除もしてほしいのでpolicyオプションは使わない。
args:
- --domain-filter=example.com
#- --policy=upsert-only # コメントアウトまたは削除デプロイ
kubectl apply -f external-dns.yaml確認
kubectl logs -f $(kubectl get po | egrep -o 'external-dns[A-Za-z0-9-]+')以下のように表示されればOK
time="2019-12-13T14:48:31Z" level=info msg="Created Kubernetes client https://10.100.0.1:443"app1のmanifestを作成
ここからようやくアプリケーションをデプロイすることができる。
まずはdeploymentとserviceとingressのmanifestを用意する。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app1-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: app1
spec:
containers:
- image: tetsis/simple-nginx-django-app
name: app1
ports:
- containerPort: 8080
env:
- name: APPLICATION_NAME
value: app1
- image: tetsis/simple-nginx-django-proxy
name: app1-proxy
ports:
- name: app1-port
containerPort: 80apiVersion: v1
kind: Service
metadata:
name: app1-service
spec:
ports:
- port: 80
targetPort: app1-port
protocol: TCP
type: NodePort
selector:
app: app1apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
labels:
app: ingress
spec:
rules:
- host: app1.example.com
http:
paths:
- path: /*
backend:
serviceName: app1-service
servicePort: 80example.comには自分が所有するドメインを指定する。
app1のデプロイ
kubectl apply -f app1-deployment.yaml
kubectl apply -f app1-service.yaml
kubectl apply -f ingress.yamlALB Ingress Controllerで作られたALBを確認
kubectl get ingressNAME HOSTS ADDRESS PORTS AGE
ingress app1.example.com d7f12bb1-default-ingress-e8c7-1478980459.ap-northeast-1.elb.amazonaws.com 80 38sRoute 53にレコードが作られたことを確認
コンソール画面もしくは以下のコマンドでAliasレコードが作成されていることを確認する。
aws route53 list-resource-record-sets --hosted-zone-id /hostedzone/<ホストゾーンID>ページにアクセスしてみる
ALBの起動とRoute 53のDNSレコード情報が反映されるまで少し待って、ブラウザで「http://app1.example.com」にアクセスし、以下のように表示されればOK。
(example.comは自分のドメインを指定)
This application is "app1".
サブドメイン分割でapp2を追加
さっきはapp1.example.comというドメインでアプリケーションをデプロイしたが、次はapp2.example.comドメインでアプリケーションを追加デプロする。
deploymentとserviceはapp1と同様にmanifestを作成する。
ingressについては 、app1とapp2で同じALBを使うので先程作成したmanifestに追記する。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app2-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: app2
spec:
containers:
- image: tetsis/simple-nginx-django-app
name: app2
ports:
- containerPort: 8080
env:
- name: APPLICATION_NAME
value: app2
- image: tetsis/simple-nginx-django-proxy
name: app2-proxy
ports:
- name: app2-port
containerPort: 80apiVersion: v1
kind: Service
metadata:
name: app2-service
spec:
ports:
- port: 80
targetPort: app2-port
protocol: TCP
type: NodePort
selector:
app: app2apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
labels:
app: ingress
spec:
rules:
- host: app1.example.com
http:
paths:
- path: /*
backend:
serviceName: app1-service
servicePort: 80
- host: app2.example.com
http:
paths:
- path: /*
backend:
serviceName: app2-service
servicePort: 80app2のデプロイ
kubectl apply -f app2-deployment.yaml
kubectl apply -f app2-service.yaml
kubectl apply -f ingress.yamlページにアクセスしてみる
ブラウザで「http://app2.example.com」にアクセスして以下の文字が表示されればOK。(もちろんドメインは環境に合わせること)
This application is "app2".
HTTPS化
公式ページを参考に、ingress.yamlの annotations 句に一行追加する。
尚、使用するドメインのSSL証明書は事前にACMで発行しておく。
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/listen-ports: '[{"HTTPS":443}]' # 追加
labels:
app: ingress
spec:
rules:
- host: app1.example.com
http:
paths:
- path: /*
backend:
serviceName: app1-service
servicePort: 80
- host: app2.example.com
http:
paths:
- path: /*
backend:
serviceName: app2-service
servicePort: 80忘れずにapplyする。
kubectl apply -f ingress.yamlブラウザで「https://app1.example.com」、 「https://app2.example.com」 にアクセスして、ページが表示されることを確認する。
リソースの削除
EKSクラスタは起動しておくだけでお金がかかるので、検証利用の場合は忘れずにクラスタを削除を実施する。
K8sリソースを削除
kubectl delete -f ingress.yaml
kubectl delete -f app1-service.yaml
kubectl delete -f app2-service.yaml
kubectl delete -f app1-deployment.yaml
kubectl delete -f app2-deployment.yamlIAMポリシーをデタッチ
aws iam detach-role-policy --policy-arn arn:aws:iam::<アカウントID>:policy/ExternalDNSIAMPolicy --role-name <ロール名>
aws iam detach-role-policy --policy-arn arn:aws:iam::<アカウントID>:policy/ALBIngressControllerIAMPolicy --role-name <ロール名>IAMポリシーを削除
aws iam delete-policy --policy-arn arn:aws:iam::<アカウントID>:policy/ExternalDNSIAMPolicy
aws iam delete-policy --policy-arn arn:aws:iam::<アカウントID>:policy/ALBIngressControllerIAMPolicyEKSクラスタを削除
eksctl delete cluster --region=ap-northeast-1 --name=test-cluster