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

上次更新时间:2020 年 1 月 29 日

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

简短描述

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

注意:入口控制器比负载均衡器更有效率且更具成本效益。此外,您还可能需要预留您的负载均衡器以将流量发送到不同的微服务。

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

解决方法

以下解决方法使用 nginxinc/kubernetes-ingress 入口控制器。可供公共使用的另一个入口控制器是 kubernetes/ingress-nginx。有关更多信息,请参阅 Differences Between nginxinc/kubernetes-ingress and kubernetes/ingress-nginx Ingress Controllers

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

1.    要下载用于 Kubernetes 的 NGINX 入口控制器,请运行以下命令:

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

2.    要选择用于部署入口控制器的目录,请运行以下命令:

cd kubernetes-ingress/deployments/

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

3.    要为默认服务器创建专用命名空间、服务账户和 TLS 证书(具有密钥),请运行以下命令:

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

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

4.    要创建 ConfigMap 来自定义您的 NGINX 配置,请运行以下命令:

kubectl apply -f common/nginx-config.yaml

注意:有关示例配置,请参阅 ConfigMap and Annotations

5.    要配置基于角色的访问控制 (RBAC),请创建 ClusterRole,然后将 ClusterRole 绑定到步骤 3 中的服务账户。

kubectl apply -f rbac/rbac.yaml

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

6.    要部署入口控制器,请运行以下命令。

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

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

您会收到类似如下内容的输出:

NAME                            READY   STATUS    RESTARTS   AGE
nginx-ingress-fb4f4b44c-xmq6z   1/1     Running   0          3d7h

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

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

对于部署 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 协议,以便您可以将代理信息传递到入口控制器,请将以下密钥添加到步骤 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
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

注意:有关更多信息,请参阅 Name based virtual hosting

6.    要应用您的配置,请运行以下命令:

kubectl apply -f micro-ingress.yaml

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

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

 Name:             micro-ingress
 Namespace:        default
 Address:          
 Default backend:  default-http-backend:80 (<none>)
 Rules:
  Host                   Path  Backends
  ----                   ----  --------
  hostname.mydomain.com  
                            hostname-svc:80 (192.168.2.45:9376,192.168.3.236:9376)
  apache.mydomain.com    
                            apache-svc:80 (192.168.2.47:80,192.168.3.45:80)

测试 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 状态代码。根据定义的规则,入口控制器不会将流量转移到指定的后端服务,除非请求与配置匹配。由于已针对入口对象配置主机字段,您必须为请求的主机标头提供相同的主机名。

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

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

curl -I -H "Host: hostname.mydomain.com"
http://aaa25a5010daa11eaa41e121e71bd6ca-113564610.us-east-1.elb.amazonaws.com/

您会收到类似如下内容的输出:

HTTP/1.1 200 OK
Server: nginx/1.17.5
Content-Type: text/html
Content-Length: 612
Connection: keep-alive

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

curl -I -H "Host: apache.mydomain.com"
http://aaa25a5010daa11eaa41e121e71bd6ca-113564610.us-east-1.elb.amazonaws.com/

您会收到类似如下内容的输出:

HTTP/1.1 200 OK
Server: nginx/1.17.5
Content-Type: text/html
Content-Length: 45
Connection: keep-alive

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

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

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: path-ingress
annotations:
  nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: hostname.mydomain.com
  http:
	paths:
	- path: /login
	  backend:
		serviceName: service1
		servicePort: 4200
	- path: /cart
	  backend:
		serviceName: service2
		servicePort: 8080

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


这篇文章对您有帮助吗?

我们可以改进什么?


需要更多帮助?