上次更新时间:2021 年 3 月 30 日
我想提供对我的 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。有关更多信息,请参阅 NGINX 网站上的 nginxinc/kubernetes-ingress 和 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
注意:有关示例配置,请参阅 NGINX GitHub 网站上的 ConfigMap 和注释。
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,您可以使用类型为 NodePort 或 LoadBalancer 的服务对象。以下步骤使用 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-app 和 apache-app)。请参阅以下示例。
注意:此步骤假定您在运行两个微服务(用于演示目的)。通过 Kubernetes 在内部公开微服务作为默认类型。
hostname-app 的 hostname-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-app 的 apache-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 状态代码。根据定义的规则,入口控制器不会将流量转移到指定的后端服务,除非请求与配置匹配。由于已针对入口对象配置主机字段,您必须为请求的主机标头提供相同的主机名。
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: Fri, 26 Mar 2021 15:49:43 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-1.elb.amazonaws.com/
输出示例:
HTTP/1.1 200 OK
Server: nginx/1.19.8
Date: Fri, 26 Mar 2021 15:50:27 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: 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 响应。