Blogaomu

WEBアプリケーション開発とその周辺のメモをゆるふわに書いていきます。

ALB で gRPC を利用する on EKS

先日、Application Load Balancer (ALB)が HTTP/2 および gRPC に対応するようになったという発表がありました。これをEKS上で稼働するアプリケーションにも適用できるかを試してみました。

ALB の HTTP/2 および gRPC 対応

EKS で ALB を利用するには?

想定構成

f:id:TAKAyuki_atkwsk:20201214103446p:plain

作成手順

$ eksctl utils associate-iam-oidc-provider \
  --region ap-northeast-1 \
  --cluster floral-mongoose-1607656608 \
  --approve
 []  eksctl version 0.32.0
 []  using region ap-northeast-1
 []  will create IAM Open ID Connect provider for cluster "floral-mongoose-1607656608" in "ap-northeast-1"
 []  created IAM Open ID Connect provider for cluster "floral-mongoose-1607656608" in "ap-northeast-1"
 
# AWS Load Balancer Controller 用 IAM Policy の作成
$ curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.1.0/docs/install/iam_policy.json
 
$ aws iam create-policy \
     --policy-name AWSLoadBalancerControllerIAMPolicy \
     --policy-document file://iam-policy.json
 {
     "Policy": {
         "PolicyName": "AWSLoadBalancerControllerIAMPolicy",
         "PolicyId": "ANPA3TVC4QV7DOBMICOZQ",
         "Arn": "arn:aws:iam::accoundid:policy/AWSLoadBalancerControllerIAMPolicy",
         "Path": "/",
         "DefaultVersionId": "v1",
         "AttachmentCount": 0,
         "PermissionsBoundaryUsageCount": 0,
         "IsAttachable": true,
         "CreateDate": "2020-12-11T03:40:45+00:00",
         "UpdateDate": "2020-12-11T03:40:45+00:00"
     }
 }

# 先ほど作成した IAM Policy にひもづける ServiceAccount を作成
$ eksctl create iamserviceaccount \
  --cluster=floral-mongoose-1607656608 \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --attach-policy-arn=arn:aws:iam::accountid:policy/AWSLoadBalancerControllerIAMPolicy \
  --approve
 []  eksctl version 0.32.0
 []  using region ap-northeast-1
 []  1 existing iamserviceaccount(s) (kube-system/aws-node) will be excluded
 []  1 iamserviceaccount (kube-system/aws-load-balancer-controller) was included (based on the include/exclude rules)
 []  1 iamserviceaccount (kube-system/aws-node) was excluded (based on the include/exclude rules)
 [!]  serviceaccounts that exists in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
 []  1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/aws-load-balancer-controller", create serviceaccount "kube-system/aws-load-balancer-controller" } }
 []  building iamserviceaccount stack "eksctl-floral-mongoose-1607656608-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
 []  deploying stack "eksctl-floral-mongoose-1607656608-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
 []  created serviceaccount "kube-system/aws-load-balancer-controller"
 
# Controller をクラスターにインストール
$ helm repo add eks https://aws.github.io/eks-charts
 "eks" has been added to your repositories
 
$ kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller//crds?ref=master"
 customresourcedefinition.apiextensions.k8s.io/targetgroupbindings.elbv2.k8s.aws created
 
# helm install eks/aws-load-balancer-controller だと上手くいかなかった...
# see https://github.com/aws/eks-charts/tree/master/stable/aws-load-balancer-controller
$ helm upgrade \
    -i aws-load-balancer-controller \
    eks/aws-load-balancer-controller \
    -n kube-system \
    --set clusterName=floral-mongoose-1607656608 \
    --set serviceAccount.create=false \
    --set serviceAccount.name=aws-load-balancer-controller
 Release "aws-load-balancer-controller" does not exist. Installing it now.
 NAME: aws-load-balancer-controller
 LAST DEPLOYED: Fri Dec 11 12:52:57 2020
 NAMESPACE: kube-system
 STATUS: deployed
 REVISION: 1
 TEST SUITE: None
 NOTES:
 AWS Load Balancer controller installed!
# --validation-method は DNS も選べるが、今回は都合によりeメール認証を選んだ
# この ARN を後ほど使うのでコピーしておく
$ aws acm request-certificate --domain-name albgrpcsample.niboshino-tech.net --validation-method EMAIL
 {
     "CertificateArn": "arn:aws:acm:ap-northeast-1:accountid:certificate/f49ed98b-935e-4adc-ab82-b7f35c293f9c"
 }
  • manifest作成、適用
# helloworld.yml
apiVersion: v1
kind: Service
metadata:
  name: helloworld
spec:
  selector:
    app: helloworld
  ports:
    - port: 50051
      targetPort: 50051
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld
spec:
  selector:
    matchLabels:
      app: helloworld
  template:
    metadata:
      labels:
        app: helloworld
    spec:
      containers:
        - name: helloworld
          image: accountid.dkr.ecr.ap-northeast-1.amazonaws.com/albgrpcsample/helloworld:v0.0.1
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 50051
# routeguide.yml
apiVersion: v1
kind: Service
metadata:
  name: routeguide
spec:
  selector:
    app: routeguide
  ports:
    - port: 10000
      targetPort: 10000
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: routeguide
spec:
  selector:
    matchLabels:
      app: routeguide
  template:
    metadata:
      labels:
        app: routeguide
    spec:
      containers:
        - name: routeguide
          image: accountid.dkr.ecr.ap-northeast-1.amazonaws.com/albgrpcsample/route_guide:v0.0.1
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 10000
# alb-grpc-sample-ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: alb-grpc-sample
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/backend-protocol-version: GRPC
    # このアノテーションがあることでリスナープロトコルのデフォルトが HTTPS (443) になる
    # see https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/ingress/annotations/#listen-ports
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:accountid:certificate/f49ed98b-935e-4adc-ab82-b7f35c293f9c
spec:
  rules:
    - http:
        paths:
          - backend:
              serviceName: helloworld
              servicePort: 50051
            path: /helloworld.Greeter/*
          - backend:
              serviceName: routeguide
              servicePort: 10000
            path: /routeguide.RouteGuide/*
  • これらを適用したところ ALB が作成された

f:id:TAKAyuki_atkwsk:20201213102923p:plain f:id:TAKAyuki_atkwsk:20201213103015p:plain f:id:TAKAyuki_atkwsk:20201213103026p:plain f:id:TAKAyuki_atkwsk:20201213103003p:plain

  • 動作確認
    • ドメインの管理が Route53 以外で行われているので /etc/hosts を編集して確認した
    • 正常にレスポンスが返ってくることを確認できた
# /etc/hostsを書き換えるため、ALBのIPアドレスを取得
$ dig k8s-default-albgrpcs-5fb02487bb-383351884.ap-northeast-1.elb.amazonaws.com +short
 
 52.198.135.63
 18.182.181.161
 13.230.14.197
 
$ sudo vi /etc/hosts
 # 以下追加
 52.198.135.63 albgrpcsample.niboshino-tech.net
 
$ grpcurl -d '{"name": "foo"}' -proto helloworld/helloworld/helloworld.proto albgrpcsample.niboshino-tech.net:443 helloworld.Greeter/SayHello
 {
   "message": "Hello foo"
 }
 
$ grpcurl -d '{"latitude": 407838351, "longitude": -746143763}' -proto route_guide/routeguide/route_guide.proto albgrpcsample.niboshino-tech.net:443 routeguide.RouteGuide/GetFeature
 {
   "name": "Patriots Path, Mendham, NJ 07945, USA",
   "location": {
     "latitude": 407838351,
     "longitude": -746143763
   }
 }

まとめ

AWS Load Balancer Controller をインストールして Ingress に特定の annotation を追加したものを適用すると ALB が作成されることが分かりました。Ingress で指定したパスごとにターゲットグループが対応しているので理解しやすく感じました。EKS で gRPC を利用するシステムにおいてルーティングや負荷分散を担う要素として選択肢の一つになりそうです。