如何提供对 Amazon EKS 集群中的多个 Kubernetes 服务的外部访问权限?

7 分钟阅读
0

我想提供对我的 Amazon Elastic Kubernetes Service (Amazon EKS) 集群中多个 Kubernetes 服务的外部访问权限。

简短描述

使用用于 Kubernetes 的 NGINX 入口控制器或 AWS 负载均衡器控制器提供对 Amazon EKS 集群中的多个 Kubernetes 服务的外部访问权限。NGINX 入口控制器主要由 NGINX 维护。要检查 NGINX 入口控制器的问题,请参阅 GitHub 网站上的问题列表。AWS 负载均衡器控制器主要由 Amazon Web Services (AWS) 维护。要检查 AWS 负载均衡器控制器上的问题,请参阅 GitHub 网站上的问题列表

**重要提示:**入口控制器和 IngressClass(来自 Kubernetes 网站)与入口(来自 Kubernetes 网站)不同。入口是一种 Kubernetes 资源,可将集群外部的 HTTP 和 HTTPS 路由公开到集群内的服务。入口控制器通常可使用负载均衡器完成入口用途(通常使用负载均衡器)。您不能在没有入口控制器的情况下使用入口。IngressClass 用于标识哪个入口控制用于完成入口对象请求。

前提条件:安装 AWS 负载均衡器控制器。最佳实践是使用 AWS 负载均衡器控制器为 Amazon EKS 中的 LoadBalancer 类型服务对象创建和管理网络负载均衡器。

解决方法

以下解决方案使用 Kubernetes GitHub 网站上的 kubernetes/ingress-nginx 入口控制器。可供公众使用的另一个入口控制器是来自 NGINX GitHub 网站的 nginxinc/kubernetes-ingress

部署用于 Kubernetes 的 NGINX 入口控制器

您可以通过传输控制协议(TCP)或传输层安全性协议(TLS)部署用于 Kubernetes 的 NGINX 入口控制器。

**注意:**以下解决方案已在 Amazon EKS 版本 1.22、NGINX 入口控制器版本 1.3.0 和 AWS 负载均衡器控制器版本 2.4.3 上进行了测试。

(选项 1)网络负载均衡器上的 NGINX 入口控制器及 TCP

1.    获取 YAML 文件以部署以下 Kubernetes 对象:namespaceserviceaccountsconfigmapclusterrolesclusterrolebindingsrolesrolebindingsservicesdeploymentsingressclassesvalidatingwebhookconfigurations

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/deploy.yaml

2.    编辑文件。然后,在 ingress-nginx-controller 服务对象部分,将所有 service.beta.kubernetes.io 注释替换为以下内容:

service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

3.    应用清单:

kubectl apply -f deploy.yaml

示例输出:

namespace/ingress-nginx created 
serviceaccount/ingress-nginx created 
configmap/ingress-nginx-controller created 
clusterrole.rbac.authorization.k8s.io/ingress-nginx created 
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created 
role.rbac.authorization.k8s.io/ingress-nginx created 
rolebinding.rbac.authorization.k8s.io/ingress-nginx created 
service/ingress-nginx-controller-admission created 
service/ingress-nginx-controller created 
deployment.apps/ingress-nginx-controller created 
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created 
serviceaccount/ingress-nginx-admission created 
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created 
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created

(选项 2) 网络负载均衡器上的 NGINX 入口控制器 TLS 终止

默认情况下,先前的解决方案将会终止 NGINX 入口控制器中的 TLS。此外,您还可以配置 NGINX 入口服务,以终止网络负载均衡器处的 TLS。

1.    下载 deploy.yaml 模板:

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml

2.    编辑文件。然后,在 ingress-nginx-controller 服务对象部分,将所有 service.beta.kubernetes.io 注释替换为以下内容:

service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

**注意:**请确保包含 service.beta.kubernetes.io/aws-load-balancer-ssl-cert 的 ARN。

3.    编辑文件,然后更改 Kubernetes 集群的 Amazon Virtual Private Cloud (Amazon VPC) CIDR:

proxy-real-ip-cidr: XXX.XXX.XXX/XX

4.    应用清单:

kubectl apply -f deploy.yaml

**注意:**先前的清单使用 ExternalTrafficPolicy 作为 local 以保留源(客户端)IP 地址。在 Amazon VPC 中将此配置与自定义 DHCP 名称结合使用会导致出现问题。为防止问题发生,请将以下补丁应用于 kube-proxy

kubectl edit daemonset kube-proxy -n kube-system

5.    编辑清单以包含以下片段:

spec:
  template:
    spec:
      containers:
        - name: kube-proxy
          command:
            - kube-proxy
            - --hostname-override=$(NODE_NAME)
            - --v=2
            - --config=/var/lib/kube-proxy-config/config
           env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: spec.nodeName

验证已部署的资源

AWS 负载均衡器控制器

命令:

kubectl get all -n kube-system --selector app.kubernetes.io/instance=aws-load-balancer-controller

示例输出:

NAME                                                READY   STATUS    RESTARTS   AGE   IP               NODE                                           NOMINATED NODE   READINESS GATES
pod/aws-load-balancer-controller-85cd8965dc-ctkjt   1/1     Running   0          48m   192.168.37.36    ip-192-168-59-225.us-east-2.compute.internal   none             none 
pod/aws-load-balancer-controller-85cd8965dc-wpwx9   1/1     Running   0          48m   192.168.53.110   ip-192-168-59-225.us-east-2.compute.internal   none>         none 
NAME                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR 
service/aws-load-balancer-webhook-service   ClusterIP   10.100.154.44   none          443/TCP   19h   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller 
NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS                   IMAGES                                                                                    SELECTOR 
deployment.apps/aws-load-balancer-controller   2/2     2            2           19h   aws-load-balancer-controller 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.0   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller 
NAME                                                      DESIRED   CURRENT   READY   AGE   CONTAINERS                     IMAGES                                                                                    SELECTOR 
replicaset.apps/aws-load-balancer-controller-85cd8965dc   2         2         2       19h   aws-load-balancer-controller   602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.0   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller,pod-template-hash=85cd8965dc

NGINX 入口控制器

命令:

kubectl get all -n ingress-nginx --selector app.kubernetes.io/instance=ingress-nginx

示例输出:

NAME                                           READY  STATUS   RESTARTS  AGE   IP               NODE                                           NOMINATED NODE  READINESS GATES
pod/ingress-nginx-controller-54d8b558d4-k4pdf  1/1    Running  0         56m   192.168.46.241   ip-192-168-59-225.us-east-2.compute.internal   none            none
NAME                                        TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     PORT(S)                      AGE   SELECTOR
service/ingress-nginx-controller            LoadBalancer   10.100.99.129   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80:32578/TCP,443:30724/TCP   15h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
service/ingress-nginx-controller-admission  ClusterIP      10.100.190.61   none                                                                            443/TCP                      15h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
NAME                                       READY   UP-TO-DATE   AVAILABLE    AGE   CONTAINERS   IMAGES                                                                                                               SELECTOR
deployment.apps/ingress-nginx-controller   1/1     1            1            15h   controller   k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
NAME                                                  DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                                                                                                               SELECTOR
replicaset.apps/ingress-nginx-controller-54d8b558d4   1         1         1       15h   controller   k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx,pod-template-hash=54d8b558d4
NAME                                       COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES                                                                                                                         SELECTOR
job.batch/ingress-nginx-admission-create   1/1           2s         15h   create       k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660   controller-uid=242bdf56-de16-471d-a691-1ca1dbc10a41
job.batch/ingress-nginx-admission-patch    1/1           2s         15h   patch        k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660   controller-uid=a9e710d2-5001-4d40-a435-ddc8993bfe42

IngressClass

命令:

kubectl get ingressclass

示例输出:

NAME    CONTROLLER             PARAMETERS                             AGE 
alb     ingress.k8s.aws/alb    IngressClassParams.elbv2.k8s.aws/alb   19h 
nginx   k8s.io/ingress-nginx   none                                   15h

测试部署设置

**注意:**以下步骤将运行两个微服务。如果 Kubernetes 为默认类型,则会在内部公开微服务。

1.    设置部署或微服务。例如,hostname-appapache-app

hostname-apphostname-app-svc.yaml 文件的示例:

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: hostname-app
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hostname-app
  template:
    metadata:
      labels:
        app: hostname-app
    spec:
      containers:
      - name: hostname-app
        image: k8s.gcr.io/serve_hostname:1.1 

--- 
apiVersion: v1 
kind: Service 
metadata:
  name: hostname-svc
  namespace: default 
spec:
  ports:
  - port: 80
    targetPort: 9376
    protocol: TCP
  selector:
    app: hostname-app

apache-appapache-app-svc.yaml 文件的示例:

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: apache-app
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: apache-app
  template:
    metadata:
      labels:
        app: apache-app
    spec:
      containers:
      - name: apache-app
        image: httpd:latest
        ports:
        - containerPort: 80 

--- 
apiVersion: v1 
kind: Service 
metadata:
  name: apache-svc
  namespace: default
  labels: 
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: apache-app

2.    应用您的配置。

hostname-app:

kubectl apply -f hostname-app-svc.yaml

apache-app:

kubectl apply -f apache-app-svc.yaml

3.    验证是否已创建资源。

部署

命令:

kubectl get deployment hostname-app apache-app -n default

示例输出:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE 
hostname-app   2/2     2            2           29m
apache-app     2/2     2            2           29m

服务

命令:

kubectl get svc apache-svc hostname-svc -n default

示例输出:

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE 
apache-svc     ClusterIP   10.100.73.51    none          80/TCP    29m 
hostname-svc   ClusterIP   10.100.100.44   none          80/TCP    29m

测试 NGINX 入口控制器

1.    访问您从命令行中检索到的负载均衡器的 DNS URL:

curl -I ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com

示例输出:

HTTP/1.1 404 Not Found 
Date: Thu, 03 Mar 2022 14:03:11 GMT 
Content-Type: text/html 
Content-Length: 146 
Connection: keep-alive

注意:对于所有未定义入口规则的域请求,默认服务器将会返回 404 Not Found(404 未找到)页面。根据定义的规则,除非请求与配置匹配,否则入口控制器不会将流量转移到特定后端服务。由于已针对入口对象配置主机字段,您必须为请求的主机标头提供相同的主机名。在测试环境中,使用 curl 标志提供主机标头。在生产环境中,将负载均衡器 DNS 名称映射到任何 DNS 提供商上的主机名 (例如 Amazon Route 53)。

2.    实施入口,使其使用 NGINX 入口控制器提供的单个负载均衡器与您的服务连接。

示例 micro-ingress.yaml

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: micro-ingress
  namespace: default
  annotations: 
    kubernetes.io/ingress.class: nginx 
spec:
  rules:
    - host: hostname.mydomain.com
      http:
        paths:
        - backend:
            service:
              name: hostname-svc
              port:
                number: 80
          path: /
          pathType: Prefix
  - host: apache.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: apache-svc
            port:
              number: 80
        path: /
        pathType: Prefix

**注意:**有关更多信息,请参阅基于名称的虚拟主机(来自 Kubernetes 网站)

3.    验证是否已创建资源。

入口

命令:

kubectl get ingress -n default

示例输出:

NAME           CLASS   HOSTS                                       ADDRESS                                                                         PORTS   AGE 
micro-ingress  none    hostname.mydomain.com,apache.mydomain.com   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80      29m

4.    将主机标头添加到请求。

第一个配置的域:

curl -i -H "Host: hostname.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/

示例输出:

HTTP/1.1 200 OK Date: Sat, 26 Mar 2022 18:50:38 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 29 Connection: keep-alive

第二个配置的域:

curl -i -H "Host: apache.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/

示例输出:

HTTP/1.1 200 OK 
Date: Sat, 26 Mar 2022 18:51:00 GMT 
Content-Type: text/html 
Content-Length: 45 
Connection: keep-alive 
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT 
ETag: "2d-432a5e4a73a80" 
Accept-Ranges: bytes

在添加主机标头后,如果流量与入口中定义的规则匹配,则入口控制器会将它重定向到后端配置的服务。

要保持相同的域名,但根据访问的路径转移流量,您必须通过入口添加基于路径的路由。

例如:

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: path-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginxd
    nginx.ingress.kubernetes.io/rewrite-target: / 
spec:
  rules:
  - host: mydomain.com
    http:
      paths:
      - backend:
          service:
            name: hostname-svc
            port:
              number: 80
        path: /hostname
        pathType: Prefix
  - host: mydomain.com
    http:
      paths:
      - backend:
          service:
            name: apache-svc
            port:
              number: 80
        path: /apache
        pathType: Prefix

注意:如果请求的主机标头为 mydomain.com,则上述示例只会返回 200 响应。可以在 /hostname/apache 路径上访问这些请求。对于所有其他请求,则会返回 404 响应。

5.    验证是否已添加基于路径的路由:

命令:

kubectl get ingress -n default

输出:

NAME            CLASS  HOSTS                                       ADDRESS                                                                         PORTS  AGE
micro-ingress   none   hostname.mydomain.com,apache.mydomain.com   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     164m
path-ingress    none   mydomain.com,mydomain.com                   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     120m

命令:

curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/hostname

-或者-

curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/apache

使用 AWS 负载均衡器控制器测试入口

1.    使用以下示例入口清单启动应用程序负载均衡器:

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: micro-ingress-alb
  namespace: default
  annotations:
    kubernetes.io/ingress.class: alb 
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip 
spec:
  rules:
  - host: alb.hostname.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: hostname-svc
            port:
              number: 80
        path: /
        pathType: Prefix
   - host: alb.apache.mydomain.com
     http:
       - backend:
            service:
              name: apache-svc
              port:
                number: 80
         path: /
         pathType: Prefix

2.    验证是否已启动应用程序负载均衡器。

命令:

kubectl get ingress -n default

输出:

NAME               CLASS  HOSTS                                               ADDRESS                                                                         PORTS  AGE
micro-ingress      none   hostname.mydomain.com,apache.mydomain.com           ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     164m
micro-ingress-alb  none   alb.hostname.mydomain.com,alb.apache.mydomain.com   k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com          80     18m
path-ingress       none   mydomain.com,mydomain.com                           ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     120m

基于第一个配置的域的请求:

curl -i -H "Host: alb.hostname.mydomain.com" http://k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com

示例输出:

HTTP/1.1 200 OK Date: Sat, 26 Mar 2022 20:46:02 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 29 Connection: keep-alive

基于第二个配置的域的请求:

curl -i -H "Host: alb.apache.mydomain.com" http://k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com

示例输出:

HTTP/1.1 200 OK 
Date: Sat, 26 Mar 2022 20:46:14 GMT 
Content-Type: text/html Content-Length: 45 
Connection: keep-alive 
Server: Apache/2.4.53 (Unix) 
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT 
ETag: "2d-432a5e4a73a80" 
Accept-Ranges: bytes

相关视频

AWS 官方
AWS 官方已更新 2 年前