入口控制器是一个软件片段,为 Kubernetes 服务提供反向代理、可配置的流量路由和 TLS 终止。 Kubernetes 入口资源用于配置各个 Kubernetes 服务的入口规则和路由。 借助入口控制器和入口规则,可以使用单个 IP 地址将流量路由到 Kubernetes 群集中的多个服务。
本文介绍如何在 Azure Kubernetes 服务 (AKS) 群集中部署 NGINX 入口控制器。 生成自己的证书,并创建用于入口路由的 Kubernetes 机密。 最后,在 AKS 群集中运行两个应用程序(可通过单个 IP 地址访问其中的每个应用程序)。
也可执行以下操作:
- 创建具有外部网络连接的基本入口控制器
- 启用 HTTP 应用程序路由附加产品
- 创建使用内部、专用网络和 IP 地址的入口控制器
- 创建一个使用 Let's Encrypt 的入口控制器,以自动生成具有动态公共 IP 地址或具有静态公共 IP 地址的 TLS 证书
本文使用 Helm 3 在支持的 Kubernetes 版本上安装 NGINX 入口控制器。 确保使用最新版本的 Helm,并且有权访问 ingress-nginx Helm 存储库。 本文中概述的步骤可能与 Helm chart、NGINX 入口控制器或 Kubernetes 的先前版本不兼容。
有关配置和使用 Helm 的详细信息,请参阅在 Azure Kubernetes 服务 (AKS) 中使用 Helm 安装应用程序。
此外,本文假设你已有一个带有集成 ACR 的 AKS 群集。 若要更详细地了解如何创建具有集成 ACR 的 AKS 群集,请参阅使用 Azure 容器注册表从 Azure Kubernetes 服务进行身份验证。
本文还要求运行 Azure CLI 2.0.64 或更高版本。 运行 az --version
即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI。
本文使用 NGINX 入口控制器 Helm 图表,它依赖于三个容器映像。
使用 az acr import
将这些映像导入 ACR。
REGISTRY_NAME=<REGISTRY_NAME>
SOURCE_REGISTRY=k8sgcr.azk8s.cn
CONTROLLER_IMAGE=ingress-nginx/controller
CONTROLLER_TAG=v1.0.4
PATCH_IMAGE=ingress-nginx/kube-webhook-certgen
PATCH_TAG=v1.1.1
DEFAULTBACKEND_IMAGE=defaultbackend-amd64
DEFAULTBACKEND_TAG=1.5
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$CONTROLLER_IMAGE:$CONTROLLER_TAG --image $CONTROLLER_IMAGE:$CONTROLLER_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$PATCH_IMAGE:$PATCH_TAG --image $PATCH_IMAGE:$PATCH_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG --image $DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG
备注
除了将容器映像导入 ACR 之外,还可以将 Helm 图表导入 ACR。 有关详细信息,请参阅将 Helm 图表推送和拉取到 Azure 容器注册表。
若要创建入口控制器,请使用 Helm
来安装 nginx-ingress。 对于增加的冗余,NGINX 入口控制器的两个副本会在部署时具备 --set controller.replicaCount
参数。 若要充分利用正在运行的入口控制器副本,请确保 AKS 群集中有多个节点。
还需要在 Linux 节点上计划入口控制器。 Windows Server 节点不应运行入口控制器。 使用 --set nodeSelector
参数指定节点选择器,以告知 Kubernetes 计划程序在基于 Linux 的节点上运行 NGINX 入口控制器。
提示
以下示例为名为 ingress-basic 的入口资源创建 Kubernetes 命名空间,目的是在该命名空间内执行操作。 根据需要为你自己的环境指定一个命名空间。 如果 AKS 群集未启用 Kubernetes RBAC,请将 --set rbac.create=false
添加到 Helm 命令中。
提示
若要为对群集中容器的请求启用客户端源 IP 保留,请将 --set controller.service.externalTrafficPolicy=Local
添加到 Helm install 命令中。 客户端源 IP 存储在 X-Forwarded-For 下的请求头中。 使用启用了“客户端源 IP 保留”的入口控制器时,TLS 直通将不起作用。
# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>
# Use Helm to deploy an NGINX ingress controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
--version 4.0.13 \
--namespace ingress-basic --create-namespace \
--set controller.replicaCount=2 \
--set controller.nodeSelector."kubernetes\.io/os"=linux \
--set controller.image.registry=$ACR_URL \
--set controller.image.image=$CONTROLLER_IMAGE \
--set controller.image.tag=$CONTROLLER_TAG \
--set controller.image.digest="" \
--set controller.image.repository=$SOURCE_REGISTRY/$CONTROLLER_IMAGE \
--set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux \
--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
--set controller.admissionWebhooks.patch.image.registry=$ACR_URL \
--set controller.admissionWebhooks.patch.image.image=$PATCH_IMAGE \
--set controller.admissionWebhooks.patch.image.tag=$PATCH_TAG \
--set controller.admissionWebhooks.patch.image.digest="" \
--set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
--set defaultBackend.image.registry=$ACR_URL \
--set defaultBackend.image.image=$DEFAULTBACKEND_IMAGE \
--set defaultBackend.image.tag=$DEFAULTBACKEND_TAG \
--set defaultBackend.image.repository=$SOURCE_REGISTRY/$DEFAULTBACKEND_IMAGE \
--set defaultBackend.image.digest=""
在安装过程中,将为入口控制器创建一个 Azure 公共 IP 地址。 此公共 IP 地址在入口控制器的寿命期内是静态的。 如果你删除入口控制器,则公共 IP 地址分配会丢失。 如果你然后创建了另外的入口控制器,则会分配新的公共 IP 地址。 如果希望保持使用此公共 IP 地址,则可以改为创建具有静态公共 IP 地址的入口控制器。
若要获取公共 IP 地址,请使用 kubectl get service
命令。
kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller
将 IP 地址分配给服务需要几分钟时间。
$ kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-ingress-ingress-nginx-controller LoadBalancer 10.0.74.133 EXTERNAL_IP 80:32486/TCP,443:30953/TCP 44s app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx
请记下此公共 IP 地址,因为在最后一个步骤中测试部署时需要用到。
尚未创建入口规则。 如果浏览到公共 IP 地址,将显示 NGINX 入口控制器的默认 404 页面。
在本文中,我们将生成使用 openssl
的自签名证书。 对于生产用途,应该通过提供商或你自己的证书颁发机构 (CA) 请求受信任的已签名证书。 下一步骤将使用 TLS 证书和 OpenSSL 生成的私钥来生成 Kubernetes 机密。
以下示例生成有效期为 365 天的、名为 aks-ingress-tls.crt 的 2048 位 RSA X509 证书。 私钥文件名为 aks-ingress-tls.key。 Kubernetes TLS 机密需要这两个文件。
本文使用 demo.azure.com 使用者公用名,无需进行更改。 对于生产用途,请为 -subj
参数指定自己的组织值:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-out aks-ingress-tls.crt \
-keyout aks-ingress-tls.key \
-subj "/CN=demo.azure.com/O=aks-ingress-tls"
若使 Kubernetes 能够对入口控制器使用 TLS 证书和私钥,需要创建并使用一个机密。 机密只需定义一次,它使用上一步骤中创建的证书和密钥文件。 然后,可以在定义入口路由时引用此机密。
以下示例创建名为 aks-ingress-tls 的机密:
kubectl create secret tls aks-ingress-tls \
--namespace ingress-basic \
--key aks-ingress-tls.key \
--cert aks-ingress-tls.crt
已配置入口控制器和包含你的证书的机密。 若要查看运行中的入口控制器,请在 AKS 群集中运行两个演示应用程序。 此示例使用 kubectl apply
来部署一个简单“Hello world”应用程序的两个实例。
创建“aks-helloworld.yaml”文件,并将其复制到以下示例 YAML 中:
apiVersion: apps/v1
kind: Deployment
metadata:
name: aks-helloworld
spec:
replicas: 1
selector:
matchLabels:
app: aks-helloworld
template:
metadata:
labels:
app: aks-helloworld
spec:
containers:
- name: aks-helloworld
image: mcr.azk8s.cn/azuredocs/aks-helloworld:v1
ports:
- containerPort: 80
env:
- name: TITLE
value: "Welcome to Azure Kubernetes Service (AKS)"
---
apiVersion: v1
kind: Service
metadata:
name: aks-helloworld
spec:
type: ClusterIP
ports:
- port: 80
selector:
app: aks-helloworld
创建“ingress-demo.yaml”文件,并将其复制到以下示例 YAML 中:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-demo
spec:
replicas: 1
selector:
matchLabels:
app: ingress-demo
template:
metadata:
labels:
app: ingress-demo
spec:
containers:
- name: ingress-demo
image: mcr.azk8s.cn/azuredocs/aks-helloworld:v1
ports:
- containerPort: 80
env:
- name: TITLE
value: "AKS Ingress Demo"
---
apiVersion: v1
kind: Service
metadata:
name: ingress-demo
spec:
type: ClusterIP
ports:
- port: 80
selector:
app: ingress-demo
使用 kubectl apply
运行这两个演示应用程序:
kubectl apply -f aks-helloworld.yaml --namespace ingress-basic
kubectl apply -f ingress-demo.yaml --namespace ingress-basic
两个应用程序现在都在 Kubernetes 群集中运行,但它们配置了服务类型 ClusterIP
。 因此,无法通过 Internet 访问它们。 若要公开发布这两个应用程序,请创建 Kubernetes 入口资源。 该入口资源配置将流量路由到这两个应用程序之一的规则。
在以下示例中,传往地址 https://demo.azure.com/
的流量将路由到名为 aks-helloworld
的服务。 传往地址 https://demo.azure.com/hello-world-two
的流量将路由到 ingress-demo
服务。 在本文中,无需更改这些演示主机名。 对于生产用途,请提供在证书请求和生成过程中指定的名称。
提示
如果在证书请求过程中指定的主机名(CN 名称)与在入口路由中定义的主机不匹配,则入口控制器将显示“Kubernetes 入口控制器虚构证书”警告。 请确保证书和入口路由主机名匹配。
tls 节告知入口路由要对主机 demo.azure.com 使用名为 aks-ingress-tls 的机密。 同样,对于生产用途,请指定自己的主机地址。
创建名为 hello-world-ingress.yaml
的文件,并将其复制到以下示例 YAML 中。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ingress
namespace: ingress-basic
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
tls:
- hosts:
- demo.azure.com
secretName: aks-ingress-tls
rules:
- host: demo.azure.com
http:
paths:
- path: /hello-world-one(/|$)(.*)
pathType: Prefix
backend:
service:
name: aks-helloworld
port:
number: 80
- path: /hello-world-two(/|$)(.*)
pathType: Prefix
backend:
service:
name: ingress-demo
port:
number: 80
- path: /(.*)
pathType: Prefix
backend:
service:
name: aks-helloworld
port:
number: 80
使用 kubectl apply -f hello-world-ingress.yaml
命令创建入口资源。
kubectl apply -f hello-world-ingress.yaml
示例输出中显示创建了入口资源。
$ kubectl apply -f hello-world-ingress.yaml
ingress.networking.k8s.io/hello-world-ingress created
若要使用虚构的 demo.azure.com 主机测试证书,请使用 curl
并指定 --resolve 参数。 此参数告知要将 demo.azure.com 名称映射到入口控制器的公共 IP 地址。 请按以下示例中所示,指定自己的入口控制器的公共 IP 地址:
curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
未为此地址提供其他路径,因此入口控制器默认为 / 路由。 第一个演示应用程序已返回,如以下精简版示例输出中所示:
$ curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
[...]
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="/static/default.css">
<title>Welcome to Azure Kubernetes Service (AKS)</title>
[...]
curl
命令中的 -v 参数输出详细信息,包括收到的 TLS 证书。 在输出 curl 结果的中途,可以验证是否使用了你自己的 TLS 证书。 即使使用的是自签名证书, -k 参数也会继续加载页面。 以下示例显示了使用“颁发者:CN=demo.azure.com; O=aks-ingress-tls”证书:
[...]
* Server certificate:
* subject: CN=demo.azure.com; O=aks-ingress-tls
* start date: Oct 22 22:13:54 2018 GMT
* expire date: Oct 22 22:13:54 2019 GMT
* issuer: CN=demo.azure.com; O=aks-ingress-tls
* SSL certificate verify result: self signed certificate (18), continuing anyway.
[...]
现在向地址添加“/hello-world-two”路径,例如 https://demo.azure.com/hello-world-two
。 第二个使用自定义标题的演示应用程序已返回,如以下精简版示例输出中所示:
$ curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
[...]
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="/static/default.css">
<title>AKS Ingress Demo</title>
[...]
本文使用了 Helm 来安装入口组件和示例应用。 在部署 Helm 图表时,会创建若干 Kubernetes 资源。 这些资源包括 pod、部署和服务。 若要清理这些资源,可以删除整个示例命名空间,也可以删除单个资源。
若要删除整个示例命名空间,请使用 kubectl delete
命令并指定命名空间名称。 将会删除命名空间中的所有资源。
kubectl delete namespace ingress-basic
也可采用更细致的方法来删除单个已创建的资源。 使用 helm list
命令列出 Helm 版本。
helm list --namespace ingress-basic
查找名为“nginx-ingress”的图表,如以下示例输出中所示:
$ helm list --namespace ingress-basic
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
nginx-ingress ingress-basic 1 2020-01-06 19:55:46.358275 -0600 CST deployed nginx-ingress-1.27.1 0.26.1
使用 helm uninstall
命令卸载这些版本。
helm uninstall nginx-ingress --namespace ingress-basic
下面的示例将卸载 NGINX 入口部署。
$ helm uninstall nginx-ingress --namespace ingress-basic
release "nginx-ingress" uninstalled
接下来,删除两个示例应用程序:
kubectl delete -f aks-helloworld.yaml --namespace ingress-basic
kubectl delete -f ingress-demo.yaml --namespace ingress-basic
删除将流量定向到示例应用的入口路由:
kubectl delete -f hello-world-ingress.yaml
删除证书机密:
kubectl delete secret aks-ingress-tls --namespace ingress-basic
最后,可以删除自身命名空间。 使用 kubectl delete
命令并指定命名空间名称。
kubectl delete namespace ingress-basic
本文包含 AKS 的一些外部组件。 若要详细了解这些组件,请参阅以下项目页面:
也可执行以下操作:
- 创建具有外部网络连接的基本入口控制器
- 启用 HTTP 应用程序路由附加产品
- 创建使用内部、专用网络和 IP 地址的入口控制器
- 创建一个使用 Let's Encrypt 的入口控制器,以自动生成具有动态公共 IP 地址或具有静态公共 IP 地址的 TLS 证书