KubernetesをEKSで運用していくために、ALB Ingress Controllerについて調べた。日本語のドキュメントがなく苦労したので、調査メモを残しておくことにする。
「ALB Ingress Controller」とは
- ALB Ingress Controllerは、ALBを作る為のIngressリソースのコントローラである
- Ingressリソースを登録すると、コントローラーがALBを作成する処理を実行する
概要
公式サイトのDesignを元に解説する。
Ref:https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/controller/how-it-works/#design
alb-ingress-controller
が、Kubernetes API Server
からのingress events
を監視する。条件を満たしたら、AWSリソースの作成を始める。- ALBが
Ingressリソース
として作成される。(internet-facing/internalどちらのスキームでも大丈夫)annotations
を用いて、サブネットを指定することができる。 - ターゲットグループは、Kubernetesにおける
Service
ごとに作成される。 - リスナーは、Ingressの
annotations
で指定した全てのポート用に作成される。指定していない場合は、80/443が作成される。ACMについても、annotations
で指定する。 - リスナールールも、Ingressリソースで指定したように作成される。特定パスへのトラフィックは、正確にKubernetesにおける
Service
にルーティングされることが保証される。
Ingress Traffic
ALB Ingress Controllerは2つのtraffic modeをサポートしている(Instance mode
とIP mode
デフォルトはInstance mode
)
Instance mode
- ALB -> k8s node間の通信はNodePortサービスを経由する
- Ingressリソースから参照されるServiceリソースは、ALBから到達する為に
type:NodePort
である必要がある
IP mode
- ALB -> k8s node間は直接通信する
- CNI(Callicoみたいなやつ)は ENIのセカンダリIPを通じてPodに直接アクセス可能である事をサポートする必要がある
構築してみた
雰囲気はつかめた気がするので、実際に構築してみた。
Namespaceを作成する
$ kubectl create namespace alb-ingress-verification
namespace "alb-ingress-verification" created
ALB Ingress Controller Configuration
構築に必要なALB ingress Controllerの設定を定義した。
AWS API Access
- ALB Cngress Controllerが、API Serverに対してアクセスしたり、ALBリソースを作成できるようにする為に、IAMポリシーを付与する
- 公式サイトで提供されているIAMポリシーのサンプルはこちら
- 2019年9月にサポートされたPodに対してIAMロールを付与する機能を用いて、alb-ingress-controllerのPodに付与するのが適切ではあるが、今回は検証のため、Worker NodeのIAM Roleにポリシーを付与する。
- なお、AWSのリソースは基本的にTerraformを使って管理している。以下のようなtfを作成し、applyした。
# ingress alb
resource "aws_iam_policy" "infra_verify-ingress-alb-policy" {
name = "infra_verify-ingress-alb-policy"
path = "/"
description = "infra_verify-ingress-alb-policy"
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
・・・
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "infra_verify-cluster-node-alb-policy" {
policy_arn = aws_iam_policy.infra_verify-ingress-alb-policy.arn
role = aws_iam_role.infra_verify-cluster-node.name
}
Limiting ingress class
--ingress-class
というargs
を指定することで、コントローラのスコープをkubernetes.io/ingress.class
annotationにマッチしたingressesに狭めることができる- これは、同じクラスタ内で、複数のingress controllerを起動する時に役に立つ(詳細はこちら)
Limiting Namespaces
--watch-namespace
というargs
を指定することで、コントローラのスコープを一つのNamespaceに狭めることができる
- 指定された単一のNamespace外のIngress eventsを、コントローラは無視する
Resource Tags
--default-tags
というargs
を指定することで、ALBとターゲットグループに任意のタグが追加される- 今回は一旦不要なので、何もしない。
Subnet Auto Discovery
- ALB Ingress ControllerがSubnetをAutoDiscovery出来るように、タグを設定する
kubernetes.io/cluster/${cluster-name}
:shared
/owned
を追加kubernetes.io/role/alb-ingress
を追加(valueはnullでOK)kubernetes.io/role/elb
を追加(今回作成するのがinternet-facing
スキームのため。interanl
の場合はkubernetes.io/role/internal-elb
)
- 以下のとおり(事前に作成しておいた)Subnetのtfを修正し、Subnetにタグを付与する
tags = "${
map(
・・・
+ "kubernetes.io/cluster/${var.eks-cluster-name}", "shared",
+ "kubernetes.io/role/alb-ingress","",
+ "kubernetes.io/role/elb","",
)
}"
Setup ALB Ingress Controller
ALB Ingress Controllerを、Kubernetesにインストールする
- ALB ingress controller用のマニフェストをwgetしてくる
$ wget https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/alb-ingress-controller.yaml
--cluster-name=devCluster
の引数の値を、作成したClusterNameに修正する
- --cluster-name=infra_verify-cluster
- RBACマニフェストをwgetしてくる
$ wget https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/rbac-role.yaml
- 上記2点のリソースをapplyする
$ kubectl apply -f alb-ingress-controller.yaml
$ kubectl apply -f rbac-role.yaml
- 確認
$ kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o "alb-ingress[a-zA-Z0-9-]+")
実際にALBを作成してみる
Deploy the echoserver resources
- 公式サイトのwakthroughのechoserverを用意
- Namespace,Service,Deploymentリソースを作成する
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/echoservice/echoserver-namespace.yaml &&\
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/echoservice/echoserver-service.yaml &&\
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/echoservice/echoserver-deployment.yaml
- 作成されたリソースを確認する
$ kubectl get -n echoserver deploy,svc
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.extensions/echoserver 1 1 1 1 11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/echoserver NodePort 10.100.244.61 <none> 80:32206/TCP 7s
Deploy ingress for echoserver
- Ingressリソースの雛形マニフェストをwgetしてくる
wget https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/echoservice/echoserver-ingress.yaml
- annotationsにALBのオプションが書いてあるので、適宜修正
- Ingressリソースを適用する
kubectl apply -f echoserver-ingress.yaml
- ALBのDNS名を指定して、curlで正しいレスポンスが返ってくるか確認する。
$ curl --dump-header - 〜〜〜〜.ap-northeast-1.elb.amazonaws.com`
HTTP/1.1 200 OK
Date: Wed, 05 Jun 2019 04:52:09 GMT
Content-Type: text/plain
annotations
ALB Ingress Controllerが作成するALBの設定は、Ingressリソースのannotationsによって定義される。
必須項目と任意項目が存在する。全てのAnnotationsはalb.ingress.kubernetes.io/
Namespaceを使用する。
必須項目
alb.ingress.kubernetes.io/scheme
- schema
- ALBが
internal
かinternet-facing
であるべきかを定義する - 詳細はAWSの公式ドキュメントを参照
- ALBが
任意項目
alb.ingress.kubernetes.io/backend-protocol
alb.ingress.kubernetes.io/certificate-arn
alb.ingress.kubernetes.io/connection-idle-timeout
alb.ingress.kubernetes.io/healthcheck-interval-seconds
alb.ingress.kubernetes.io/healthcheck-path
alb.ingress.kubernetes.io/healthcheck-port
alb.ingress.kubernetes.io/healthcheck-protocol
alb.ingress.kubernetes.io/healthcheck-timeout-seconds
alb.ingress.kubernetes.io/healthy-threshold-count
alb.ingress.kubernetes.io/unhealthy-threshold-count
alb.ingress.kubernetes.io/listen-ports
alb.ingress.kubernetes.io/security-groups
alb.ingress.kubernetes.io/subnets
alb.ingress.kubernetes.io/successCodes
alb.ingress.kubernetes.io/tags
backend-protocol
- ALBがバックエンドサービスに接続する時に使うプロトコルを選択出来る。
- 省略された場合は
HTTP
が使用される
certificate-arn
- HTTPS及び利用する証明書を定義出来る。
- AWS Certificate Managerで作成した証明書のARNに基づいて定義する。
connection-idle-timeout
- アイドルタイムアウトを設定する
healthcheck-interval-seconds
- ターゲットに対するヘルスチェックの感覚を秒単位で設定する。
- デフォルトは15秒
healthcheck-path
- ヘルスチェックの為のターゲットのpathを設定する。
- デフォルトは
/
healthcheck-port
- ヘルスチェックをターゲットの実行する時に用いるポートを指定する。
- デフォルトは、各々のターゲットがロードバランサからトラフィックを受ける時のポートになる
healthcheck-protocol
- ヘルスチェックをターゲットの実行する時に用いるプロトコル指定する。
- デフォルトは
HTTP
healthcheck-timeout-seconds
- ヘルスチェックを失敗とみなす、ターゲットからレスポンスがない時間(秒単位)
healthcheck-healthy-threshold-count
- アンヘルシーなターゲットをヘルシーとみなすのに必要とされる連続したヘルスチェックの成功数
- デフォルトは2
healthcheck-unhealthy-threshold-count
- ターゲットを案ヘルシーだとみなす為に必要な連続したヘルスチェックの失敗回数
- デフォルトは2
listen-ports
- ALBが解放するポートを定義する。省略した場合HTTPでは
80
が、HTTPSでは443
が使用される。 [{"HTTP":8080,"HTTPS": 443}]
のようなフォーマットで記載する
security-groups
- ALBに適用するSecurity Groupを指定する
- これらは、セキュリティグループIDあるいは個々のセキュリティグループに紐付いたNameタグによって参照することができる
- このAnnnotationsが存在しない時、コントローラは以下のSGを作成する
- (ALB用)適切なポート(80,443)で0.0.0.0/0にアクセス出来る
- (インスタンス用)インスタンス用に、ソースがALBの為に作成されたSGで、全てのTCPトラフィックを許可する
subnets
- ALBインスタンスがデプロイされるサブネット
- 2つのサブネットを含む必要があり、異なるAZである必要がある
- これらは、サブネットIDあるいは個々のサブネットに紐付いたNameタグによって参照することができる
- もしサブネットがALBコントローラによって指定されていない場合は、資格のあるサブネットを検出しようと試みる
- この資格は以下の基準にマッチしたサブネットが相当する
kubernetes.io/cluster/$CLUSTER_NAME
の$CLUSTER_NAMEがingress controllerと同じ場所であること(値はshared
である必要がある)kubernetes.io/role/alb-ingress
で値が空のタグがあること- 上の2つのタグにマッチしたサブネットが発見されたあと、2あるいはそれ以上のAZである事をチェックし、そうでなければALBは作成されない もし2つのサブネットが同じAZをシェアしている場合は、2つのうち1つが使用される
successCodes
- ヘルスチェックを行った時に期待される
HTTP status code
を定義する - 省略された場合、
200
が使われる
tags
- ALB及びターゲットグループに指定するタグを定義する
所感
- マネジメントコンソールやTerraformを使わずALBを作成出来るのは便利
- Kubernetesの世界とAWSの世界が結合するので、そこをどう捉えるか
- AWSのリソースをマニフェストで管理することになる
- (k8s全てに共通しそうだけど)原因調査、デバッグの難しさを感じる(sshで入って、、みたいなのが出来ない)
- 日本語のDoc充実が早いか、わいの英語力向上が早いか、ファイッ