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

上次更新日期:2021 年 10 月 11 日

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

简短描述

使用用于 Kubernetes 的 NGINX 入口控制器提供对 Amazon EKS 集群中的多个 Kubernetes 服务的外部访问权限。

注意:NGINX 入口控制器比负载均衡器更有效率且更具成本效益。此外,您还可能需要预留您的负载均衡器以将流量发送到不同的微服务。NGINX 入口控制器主要由 NGINX 维护。要检查 NGINX 入口控制器的问题,请参阅 GitHub 上的问题列表

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

解决方法

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

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

1.    下载用于 Kubernetes 的 NGINX 入口控制器:

git clone https://github.com/nginxinc/kubernetes-ingress.git

2.    选择用于部署入口控制器的目录:

cd kubernetes-ingress/deployments/

注意:部署目录运行以下步骤中的所有命令。

3.    验证您使用的是 NGINX 入口控制器的稳定版本,而不是边缘版本(截至 2021 年 3 月实验性):

git checkout v1.10.1

注意:有关 NGINX 入口控制器版本的更多信息,请参阅 GitHub 上的 NGINX 入口控制器版本

4.    为默认服务器创建专用命名空间、服务账户和 TLS 证书(具有密钥):

kubectl apply -f common/ns-and-sa.yaml
kubectl apply -f common/default-server-secret.yaml

注意:对于未定义入口规则的域的所有请求,默认服务器会返回“未找到”页面,其中含有 404 状态代码。使用生成的自签名证书和密钥进行测试。最佳做法是将您自己的证书和密钥用于生产环境。

5.    创建 ConfigMap 来自定义您的 NGINX 配置:

kubectl apply -f common/nginx-config.yaml

6.    配置基于角色的访问控制 (RBAC),创建 ClusterRole,然后将 ClusterRole 绑定到第 3 步中的服务账户。例如:

kubectl apply -f rbac/rbac.yaml

注意:ClusterRole 提供用于与 Amazon EKS 集群交互的入口控制器权限。

7.    如果您的 Kubernetes 集群版本为 1.18 或更高版本,则创建 NGINX 入口类:

kubectl apply -f common/ingress-class.yaml

8.    部署入口控制器:

kubectl apply -f deployment/nginx-ingress.yaml
kubectl get pods --namespace=nginx-ingress

注意:您可以使用“部署”或 DaemonSet 选项部署入口控制器。“部署”选项允许您动态更改入口控制器副本的数量。DaemonSet 选项允许您在每个节点或节点子集上部署入口控制器。前面的第 7 步使用 Deployment(部署)选项。

输出示例:

NAME                            READY   STATUS    RESTARTS   AGE
nginx-ingress-fb4f4b44c-xmq6z   1/1     Running   0          12s

您的入口控制器现在可以接受来自入口对象的请求。

访问入口控制器并运行您的应用程序

对于部署 ingress-controller,使用类型为 NodePortLoadBalancer 的服务对象。以下步骤使用 LoadBalancer 类型。

1.    应用您的配置:

kubectl apply -f service/loadbalancer-aws-elb.yaml

kubectl get svc --namespace=nginx-ingress

输出示例:

NAME          TYPE         EXTERNAL-IP                                      PORT(S)
nginx-ingress LoadBalancer aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com 80:32462/TCP,443:32226/TCP

注意:Amazon EKS 会在启用 PROXY 协议的情况下在 TCP 模式中分配 Classic Load Balancer,以传递客户端的信息(IP 地址和端口)。您必须将此代理信息传递到入口控制器。

2.    将 NGINX 配置为使用 PROXY 协议,以便将代理信息传递给 Ingress 控制器。然后,将以下密钥添加到步骤 1 中的 nginx-config.yaml 文件。例如:

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
  namespace: nginx-ingress
data:
  proxy-protocol: "True"
  real-ip-header: "proxy_protocol"
  set-real-ip-from: "0.0.0.0/0"

注意:通过您之前创建的 ConfigMap 将代理信息传递到入口控制器。

3.    更新 ConfigMap:

kubectl apply -f common/nginx-config.yaml

4.    设置您的部署或微服务(例如,hostname-appapache-app)。请参阅以下示例。

注意:此步骤假定您在运行两个微服务(用于演示目的)。通过 Kubernetes 在内部公开微服务作为默认类型。

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

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-app
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
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
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
  labels:
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: apache-app

应用您的配置:

kubectl apply -f hostname-app-svc.yaml
kubectl apply -f apache-app-svc.yaml

5.    实施入口,使其使用入口控制器提供的单一负载均衡器与您的服务连接。请参阅以下 micro-ingress.yaml 示例:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: micro-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: hostname.mydomain.com
      http:
        paths:
          - backend:
              serviceName: hostname-svc
              servicePort: 80
    - host: apache.mydomain.com
      http:
        paths:
          - backend:
              serviceName: apache-svc
              servicePort: 80

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

6.    应用您的配置:

kubectl apply -f micro-ingress.yaml

注意:此入口资源定义用于将 hostname.mydomain.com 的任何数据重定向到 hostname-svc 及将 apache.mydomain.com 的任何数据重定向到 apache-svc 的规则。与规则不符的任何请求都会返回 404“未找到”错误消息。

如果您描述入口,将收到一条与以下内容类似的消息:

kubectl describe ingress micro-ingress                       

Name:             micro-ingress
Namespace:        default
Address:
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host                   Path  Backends
  ----                   ----  --------
  hostname.mydomain.com
                            hostname-svc:80 (192.168.47.163:9376,192.168.70.76:9376)
  apache.mydomain.com
                            apache-svc:80 (192.168.37.44:80,192.168.84.218:80)
Annotations:             kubernetes.io/ingress.class: nginx
Events:
  Type    Reason          Age   From                      Message
  ----    ------          ----  ----                      -------
  Normal  AddedOrUpdated  23s   nginx-ingress-controller  Configuration for default/micro-ingress was added or updated

测试 NGINX 入口控制器

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

curl -I http://aaa71bxxxxx-11xxxxx10.us-east-1.elb.amazonaws.com/

注意:负载均衡器终端节点来自上一节访问入口控制器并运行应用程序

输出示例:

HTTP/1.1 404 Not Found
Server: nginx/1.17.5
Date: Mon, 25 Nov 2019 20:50:58 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

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

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

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

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

输出示例:

HTTP/1.1 200 OK
Server: nginx/1.19.8
Date: Thu, 30 Sep 2021 19:50:08 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 29
Connection: keep-alive

hostname-app-5bf66fcc9f-fr8kn

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

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

输出示例:

HTTP/1.1 200 OK
Server: nginx/1.19.8
Date: Thu, 30 Sep 2021 19:44:22 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

<html><body><h1>It works!</h1></body></html>

在添加主机标头后,入口控制器可以将流量重定向到后端配置的服务,因为它与入口中定义的配置匹配。

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

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: path-ingress
  annotations:
    nginx.org/rewrites: "serviceName=apache-svc rewrite=/"
spec:
  rules:
  - host: mydomain.com
    http:
      paths:
      - path: /hostname
        backend:
          serviceName: hostname-svc
          servicePort: 80
      - path: /apache
        backend:
          serviceName: apache-svc
          servicePort: 80

在请求将 mydomain.com 作为主机标头时,上述示例仅返回 200 响应。可以在 /hostname/apache 路径上访问这些请求。对于所有其他请求,则会返回 404 响应。

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

– 或 –

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

这篇文章对您有帮助吗?


您是否需要账单或技术支持?