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

  1. alb-ingress-controllerが、Kubernetes API Serverからのingress eventsを監視する。条件を満たしたら、AWSリソースの作成を始める。
  2. ALBがIngressリソースとして作成される。(internet-facing/internalどちらのスキームでも大丈夫)annotationsを用いて、サブネットを指定することができる。
  3. ターゲットグループは、KubernetesにおけるServiceごとに作成される。
  4. リスナーは、Ingressのannotationsで指定した全てのポート用に作成される。指定していない場合は、80/443が作成される。ACMについても、annotationsで指定する。
  5. リスナールールも、Ingressリソースで指定したように作成される。特定パスへのトラフィックは、正確にKubernetesにおけるServiceにルーティングされることが保証される。

Ingress Traffic

ALB Ingress Controllerは2つのtraffic modeをサポートしている(Instance modeIP 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.classannotationにマッチした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

任意項目

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充実が早いか、わいの英語力向上が早いか、ファイッ