亚马逊AWS官方博客

在AWS EKS上发布容器服务(下)

本文将介绍在AWS Load Balancer Controller(V2)中发布的其他几项重要功能:通过在上篇中创建好的EKS集群中实验通过使用Network Load Balancer (NLB) + IP模式实现南北向HTTP(S)流量的导入,以及演示通过引入Target Group Bingding CRD来实现将EKS中的服务灵活地绑定到已有Target Group上的新功能。

操作步骤

使用Network Load Balancer(NLB) + IP模式实现南北向流量的导入

除了上篇中介绍的使用Application Load Balancer的基于七层的HTTP流量导入,我们很多时候也会有基于四层TCP流量的导入需求,在EKS平台我们可以使用NLB来实现这个需求。下面的实验分别演示使用NLB的几种方法。

部署示例服务nginx,并通过Classic Load Balancer(CLB)发布

运行下列命令生成样例程序nginx的K8S部署和服务,注意通过设置type: LoadBalancer将服务通过AWS负载均衡器(默认类型为CLB)发布到互联网

cat <<EoF > ~/environment/nginx.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: "nginx"
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
EoF
kubectl apply -f ~/environment/nginx.yaml

通过Kubectl命令查看新生成的ningx服务,运行下列命令可以看到除了默认的kubernetes服务之外新增加了一个nginx服务,这个服务的EXTERNAL-IP指向一个负载均衡器的域名

kubectl get svc

在EC2服务控制台查看Load Balancer,输入上一条命令生成的EXTERNAL-IP的值作为过滤条件就可以查验刚刚生成的nginx服务对应的CLB,验证列表中负载均衡器的Type为classic

通过Network Load Balancer(实例模式)发布

接下来,我们运行下列命令生成nginx-nlb-instance服务,其中绝大部分设置都和CLB实验中的服务相同,不同之处就是这里通过设置annotations的service.beta.kubernetes.io/aws-load-balancer-type: nlb将负载均衡器的类型更改为Network Load Balancer (NLB)

cat <<EoF > ~/environment/nginx-nlb-instance.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: "nginx-nlb-instance"
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
EoF
kubectl apply -f ~/environment/nginx-nlb-instance.yaml

类似的,查看更改生成的nginx-nlb-instance服务

kubectl get svc nginx-nlb-instance

在EC2服务控制台查看Load Balancer,输入上一条命令生成的EXTERNAL-IP的值作为过滤条件就可以查验刚刚生成的nginx-nlb-instance服务对应的NLB,验证列表中的Type为network

 

待该NLB的状态从provisioning变为active后,选中该NLB后点击Listeners选项页查看该NLB对应的Listener,查看默认行为中的转发目标:Target Group的值(类似k8s-default-nginxnlb-xxxxx),点击该Target Group跳转到Target Group页面,选择Targets选项页,可以看到已经注册到该Target Group中的两个Targets为EC2 Instance类型,即在EKS集群中创建好的两台EC2主机节点

 

图1 – NLB Target Group中Targets为EC2 Instance类型

通过Network Load Balancer(IP模式)发布

接下来,我们运行下列命令生成nginx-nlb-ip服务,并通过设置annotations的service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip 将负载均衡器的类型更改为NLB + IP模式

cat <<EoF > ~/environment/nginx-nlb-ip.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: "nginx-nlb-ip"
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
EoF
kubectl apply -f ~/environment/nginx-nlb-ip.yaml

运行下列命令查看更改生成的nginx-nlb-ip服务

kubectl get svc nginx-nlb-ip

类似的,根据nginx-nlb-ip服务的EXTERNAL-IP值在EC2的负载均衡器页面查看对应该服务的NLB。可以看到和上述nginx-nlb-instance服务所不同的是,service.beta.kubernetes.io/aws-load-balancer-type 设置为nlp-ip后NLB将Target类型有EC2 Instance类型变更为IP地址类型(192.168.x.x),如下图所示

 

图2 – NLB Target Group中Targets为IP.类型

通过运行下列系列命令查看nginx Pod的IP地址,可知上述IP地址列表中列出的IP正是Nginx Pod所使用的IP

kubectl get pod -o wide

Target Group Binding

TargetGroupBinding是在AWS Load Balancer Controller中引入的一种K8S的CRD(Custom Resource Definition),目的是用来将K8S中的服务绑定到已有的ALB或NLB的 Target Group上从而进行更加灵活的服务发布,实现南北向流量导入。有了TargetGroupBinding的支持,可以使你能够使用EKS集群之外的Load Balanacer和Target Group。

通过以下命令查验安装AWS Load Balancer Controller过程中同时安装的TargetGroupBinding的CRD

kubectl get crd targetgroupbindings.elbv2.k8s.aws

运行下面的命令创建nginx-tgb-svc服务

cat <<EoF > ~/environment/nginx-tgb-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: "nginx-tgb-svc"
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
EoF
kubectl apply -f ~/environment/nginx-tgb-svc.yaml

运行下列命令在EKS集群所在的VPC中创建一个名称为my-ip-targets的Target Group

export VPC_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=eksctl-eksworkshop-albc* | jq -r '.Vpcs[].VpcId')
aws elbv2 create-target-group --name my-ip-targets --protocol TCP --port 8080 --target-type ip --vpc-id $VPC_ID
export TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --name my-ip-targets --query 'TargetGroups[0].TargetGroupArn')

 

接下来我们将这个Target Group绑定到服务nginx-nlb-ip对应的NLB上面(便于演示),运行下列命令

kubectl get svc nginx-nlb-ip

在EC2服务的Load Balancer子项的Load Balancer列表中输入上面命令生成的EXTERNAL-IP作为过滤条件查看服务nginx-nlb-ip对应的NLB实例,同时将此NLB的ARN复制替换到下列命令

export LOAD_BALANCER_ARN=<Replace with Above NLB ARN >

在nginx-nlb-ip对应的NLB实例上创建新的Listener并绑定刚刚创建好的Target Group

aws elbv2 create-listener --load-balancer-arn $LOAD_BALANCER_ARN --protocol TCP --port 8080 --default-actions

Type=forward,TargetGroupArn=$TARGET_GROUP_ARN 

可以看到nginx-nlb-ip对应的NLB实例上新增加了一个Listener TCP:8080并与新建的Target Group:my-ip-targets成功关联

图3 – NLB 监听器中新绑定的Target Group

运行下列命令可以列出目前AWS Load Balancer Controller针对服务nginx-nlb-ip和nginx-tgb-svc创建的两个Target Group Binding

kubectl get targetgroupbindings

接下来运行下列命令创建一个名称为my-tgb-1的Target Group Binding,将Target Group:my-ip-targets的流量分发到服务nginx-tgb-svc上

cat <<EoF > ~/environment/tgb.yaml.template
---
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
  name: my-tgb-1
spec:
  serviceRef:
    name: nginx-tgb-svc # route traffic to the awesome-service
    port: 8080
  targetGroupARN: $TARGET_GROUP_ARN
EoF
envsubst < ~/environment/tgb.yaml.template > ~/environment/tgb.yaml
kubectl apply -f ~/environment/tgb.yaml

重新运行下列命令查看新创建的Target Group Binding:my-tgb-1

kubectl get targetgroupbindings

运行下列命令可以验证刚刚创建的Target Group Binding:my-tgb-1成功将流量从nginx-nlb-ip服务对应的NLB的8080端口的Listener成功的转发到了服务nginx-tgb-svc上,两条curl命令的输出的内容相同且都包含Welcome to nginx!

export loadbalancer=$(kubectl get svc nginx-nlb-ip -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')
curl $loadbalancer
curl $loadbalancer:8080

删除上文中创建的K8S对象

按照与上述创建各种资源相反的顺序删除创建的各种K8S对象

kubectl delete -f ~/environment/tgb.yaml
kubectl delete -f ~/environment/nginx-tgb-svc.yaml
kubectl delete -f ~/environment/nginx-nlb-ip.yaml
kubectl delete -f ~/environment/nginx-nlb-instance.yaml
kubectl delete -f ~/environment/nginx.yaml

删除EKS集群和Cloud9环境

删除EKS托管与非托管节点组,最后删除EKS集群。

eksctl delete nodegroup --cluster $EKS_CLUSTER_NAME --name $EKS_NODEGROUP_NAME
eksctl delete nodegroup --cluster $EKS_CLUSTER_NAME --name $EKS_MANAGED_NODEGROUP_NAME
eksctl delete cluster --name $EKS_CLUSTER_NAME

 

最后,在AWS控制台的Cloud9服务的环境列表中删除eksworksohp演示环境。

总结

在EKS平台我们可以使用AWS Load Balancer Controller与NLB轻松的实现四层TCP流量的导入,并同时支持EC2 Instance与IP模式。同时因为有了NLB + IP模式的支持,使得在EKS Fargate模式下也可以应用NLB+IP模式来实现无服务器的EKS四层应用南北向流量的导入。另外新增的Target Group Binding功能不仅仅使得AWS Load Balancer Controller的内部实现解耦、更加高效,也可以满足将EKS集群内部的服务绑定到集群外部ALB/NLB的Target Group上的需求。

 

参考资料

  • Network load balancing on Amazon EKS https://docs.aws.amazon.com/eks/latest/userguide/load-balancing.html
  • AWS Load Balancer Controller 官方博客 https://aws.amazon.com/blogs/containers/introducing-aws-load-balancer-controller/
  • AWS Load Balancer Controller 在线文档 https://kubernetes-sigs.github.io/aws-load-balancer-controller/
  • EKS 工作坊 https://www.eksworkshop.com/

本篇作者

田大鹏

AWS解决方案架构师,负责帮助客户进行上云架构的设计和咨询。在电商及互联网行业有丰富的咨询和架构设计经验。加入 AWS 前曾于全球领先的存储和虚拟化企业,担任研发主管工程师及研发经理多种职位,负责在线存储及备份系统的多个子系统的高并发、高可用系统架构设计,应用微服务化等敏捷项目。