浏览 741
原文作者:Jason Schmidt of F5
原文链接:在 Kubernetes 中实现自助 DNS 和证书管理
转载来源:NGINX 官方网站
NGINX唯一中文官方社区 ,尽在 nginx.org.cn
应用开发的最终目标无疑是将应用暴露到互联网上。对于开发人员来说,Kubernetes 提供了 Ingress controller(Ingress 控制器)作为将请求路由到应用的机制,在一定程度上简化了这个过程。
但并非一切都支持自助服务(尽管您可能希望如此):您仍然需要使用域名系统 (DNS) 中的记录,将应用的域名映射到 Ingress controller 的 IP 地址,并且仍然需要使用 TLS 证书来保护 HTTPS 连接。在大多数组织中,您自己并不拥有 DNS 或 TLS,必须与拥有 DNS 或 TLS 的一个或多个工作组进行协调。
对运维人员来说,事情未必变得更加简单。大多数组织很少需要更新 DNS 记录,因此对应的流程(包括业务规则和技术步骤)往往比较模糊或干脆没有。这意味着,当您需要添加 DNS 记录时,您首先需要查找文档,询问同事,或者(在最坏的情况下)自己想办法。您还需要确保遵守所有安全规则,并确保为防火墙正确标记 Ingress。
幸运的是,有一种方法可以让开发人员和运维人员的工作变得更轻松。在这篇文章中,我们演示了运维人员可如何配置 Kubernetes 部署,以便开发人员能够在 Kubernetes 环境中自助更新 DNS 记录和生成 TLS 证书。通过提前构建基础架构,您可以确保满足所有必要的业务要求和技术要求。
借助这款解决方案,如果开发人员需要将应用暴露到互联网上,只需按照提供的模板创建一个 Ingress controller 即可,提供的模板中包含一个位于 Kubernetes 安装所管理的域中的全限定域名 (FQDN)。Kubernetes 使用该模板为 Ingress controller 分配一个 IP 地址,创建 DNS A
记录将 FQDN 映射到 IP 地址,为 FQDN 生成 TLS 证书并将其添加到 Ingress controller。清理也同样简单:当 Ingress 被删除时,DNS 记录即被清理。
该解决方案利用了以下技术(安装和配置说明如下):
在配置该解决方案之前,您需要:
LoadBalancer
) 对象的 Kubernetes 云安装。该解决方案使用 Linode,但其他云提供商也可以。kubectl
作为 Kubernetes 的命令行接口。我们还假设您对 Kubernetes 有基本的了解(如何应用清单,使用 Helm 图表,以及使用 kubectl
命令来查看输出和排除故障)。了解 Let’s Encrypt 的基本概念会有所帮助,但不是必须的;要想了解概况,请查看我们的博客。您也不需要了解 cert-manager 的工作原理,但如果您对它(以及证书)如何与 NGINX Ingress Controller 协同工作感兴趣,请参阅我最近的帖子《在 Kubernetes 环境中实现证书管理自动化》。
我们已经在 MacOS 和 Linux 上测试了该解决方案。虽然我们还没有在 Windows Subsystem for Linux 版本 2 (WSL2) 上进行测试,但预计不会有任何问题。
注意: 该解决方案只是一个示例概念验证,不得用于生产环境。它并未包含所有运维和安全的最佳实践。
按照这些部分中的步骤来部署解决方案:
$ git clone https://github.com/nginxinc/kubernetes-ingress.git
Cloning into 'kubernetes-ingress'...
remote: Enumerating objects: 45176, done.
remote: Counting objects: 100% (373/373), done.
remote: Compressing objects: 100% (274/274), done.
remote: Total 45176 (delta 173), reused 219 (delta 79), pack-reused 44803
Receiving objects: 100% (45176/45176), 60.45 MiB | 26.81 MiB/s, done.
Resolving deltas: 100% (26592/26592), done.
3. 验证您是否可以连接到 Kubernetes 集群。
$ kubectl cluster-info
Kubernetes control plane is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443
KubeDNS is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
$ helm install nginx-kic nginx-stable/nginx-ingress --namespace nginx-ingress --set controller.enableCustomResources=true --create-namespace --set controller.enableCertManager=true --set controller.enableExternalDNS=true
NAME: nginx-kic
LAST DEPLOYED: Day Mon DD hh:mm:ss YYYY
NAMESPACE: nginx-ingress
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The NGINX Ingress Controller has been installed.
2. 验证 NGINX Ingress Controller 是否正在运行,并注意 EXTERNAL-IP 字段的值——NGINX Ingress Controller 的 IP 地址(此处为 www.xxx.yyy.zzz)。为方便阅读,输出结果分成了两行。
$ kubectl get services --namespace nginx-ingress
NAME TYPE CLUSTER-IP ...
nginx-kic-nginx-ingress LoadBalancer 10.128.152.88 ...
... EXTERNAL-IP PORT(S) AGE
... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8m
在该解决方案中,cert-manager 在获取 TLS 证书时,使用 DNS-01 挑战类型,这需要在创建 ClusterIssuer 资源时提供 Cloudflare API 令牌。在该解决方案中,API 令牌作为 Kubernetes Secret 提供。
$ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=true
NAME: cert-manager
LAST DEPLOYED: Day Mon DD hh:mm:ss YYYY
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.9.1 has been deployed successfully!
2. 将 Cloudflare API 令牌部署为 Kubernetes Secret,并用它替换 <your-API-token>:
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: Cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
stringData:
api-token: "<your-API-token>"
EOF
secret/Cloudflare-api-token-secret created
3. 创建一个 ClusterIssuer 对象,指定 Cloudflare-api-token-secret(已在上一步中定义)作为检索令牌的位置。您也可以根据需要将 metadata.name 字段中的 example-issuer(以及 spec.acme.privateKeySecretRef.name 字段中的 example-issuer-account-key)替换为其他名称。
$ kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: example-issuer
namespace: cert-manager
spec:
acme:
email: example@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-issuer-account-key
solvers:
- dns01:
Cloudflare:
apiTokenSecretRef:
name: Cloudflare-api-token-secret
key: api-token
EOF
clusterissuer.cert-manager.io/example-issuer created
4. 验证 ClusterIssuer 是否已经部署完毕并准备就绪(READY 字段的值为 True)。
$ kubectl get clusterissuer
NAME READY AGE
example-issuer True 3h9m
同 cert-manager 一样,ExternalDNS 项目需要使用 Cloudflare API 令牌来管理 DNS。 两个项目可以使用相同令牌,但并不是必须的。
$ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yaml
customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org created
2. 创建外部 DNS 服务 (external-dns
)。由于该清单非常长,在此我们将其分成两部分。第一部分是配置账户、角色和权限。
external-dns
的 ServiceAccount 对象,以管理与 DNS 管理相关的所有写入和更新操作。external-dns
)以定义所需的权限。$ kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: ["externaldns.nginx.org"]
resources: ["dnsendpoints"]
verbs: ["get","watch","list"]
- apiGroups: ["externaldns.nginx.org"]
resources: ["dnsendpoints/status"]
verbs: ["update"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
EOF
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
清单的第二部分创建 ExternalDNS 部署。
domain-filter
设置为 example.com
。CF_API_TOKEN
环境变量设置为您的 Cloudflare API 令牌。对于 <your-API-token>
,可以用实际的令牌或包含令牌的 Secret 进行替换。在后一种情况下,您还需要使用环境变量将 Secret 投射到容器中。FREE_TIER
环境变量设置为 "true"
(适合 Cloudflare 付费用户)。$ kubectl apply -f - <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: k8s.gcr.io/external-dns/external-dns:v0.12.0
args:
- --source=service
- --source=ingress
- --source=crd
- --crd-source-apiversion=externaldns.nginx.org/v1
- --crd-source-kind=DNSEndpoint
- --domain-filter=example.com
- --provider=Cloudflare
env:
- name: CF_API_TOKEN
value: "<your-API-token>"
- name: FREE_TIER
value: "true"
EOF
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
deployment.apps/external-dns created
使用名为 Cafe 的标准 NGINX Ingress Controller 示例应用进行测试。
$ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yaml
deployment.apps/coffee created
service/coffee-svc created
deployment.apps/tea created
service/tea-svc created
2. 为 Cafe 应用部署 NGINX Ingress Controller。注意以下设置:
kind: VirtualServer
– 我们使用的是 NGINX VirtualServer 自定义资源,而不是标准的 Kubernetes Ingress 资源。spec.host
– 将 cafe.example.com
替换为待部署主机的名称。该主机必须在 ExternalDNS 管理的域内。spec.tls.cert-manager.cluster-issuer
– 如果您一直用的是本文中指定的值,则为 example-issuer
。如有必要,将其替换为您在“部署 cert-manager” 的第 3 步中选用的名称。spec.externalDNS.enable
– 值为 true
时,ExternalDNS 将创建一条 DNS A
记录。注意,这一步完成的时间在很大程度上取决于 DNS 提供商,因为 Kubernetes 正在与提供商的 DNS API 进行交互。
$ kubectl apply -f - <<EOF
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: cafe
spec:
host: cafe.example.com
tls:
secret: cafe-secret
cert-manager:
cluster-issuer: example-issuer
externalDNS:
enable: true
upstreams:
- name: tea
service: tea-svc
port: 80
- name: coffee
service: coffee-svc
port: 80
routes:
- path: /tea
action:
pass: tea
- path: /coffee
action:
pass: coffee
EOF
virtualserver.k8s.nginx.org/cafe created
$ dig cafe.example.com
; <<>> DiG 9.10.6 <<>> cafe.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22633
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cafe.example.com. IN A
;; ANSWER SECTION:
cafe.example.com. 279 IN A www.xxx.yyy.zzz
;; Query time: 1 msec
;; SERVER: 2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359#53(2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359)
;; WHEN: Day Mon DD hh:mm:ss TZ YYYY
;; MSG SIZE rcvd: 67
2. 检查证书是否有效(READY 字段的值为 True)。
$ kubectl get certificates
NAME READY SECRET AGE
cafe-secret True cafe-secret 8m51s
3. 验证您能否访问应用。
$ curl https://cafe.example.com/coffee
Server address: 10.2.2.4:8080
Server name: coffee-7c86d7d67c-lsfs6
Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
URI: /coffee
Request ID: 91077575f19e6e735a91b9d06e9684cd
$ curl https://cafe.example.com/tea
Server address: 10.2.2.5:8080
Server name: tea-5c457db9-ztpns
Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
URI: /tea
Request ID: 2164c245a495d22c11e900aa0103b00f
在该解决方案部署时,后台会进行很多操作。该图显示了当开发人员使用 NGINX VirtualServer 自定义资源部署 NGINX Ingress Controller 时后台进行的操作。请注意,一些操作细节已被省略。
A
记录A
记录考虑到 Kubernetes 的复杂性以及我们所使用的组件,很难提供一套全面的故障排除指南。也就是说,只能提供一些基本建议来帮助您确定问题。
kubectl
get
和 kubectl
describe
命令来验证部署对象的配置。kubectl
logs
<component>
命令来查看各种已部署组件的日志文件。如果仍有问题,请通过添加“小N助手(微信号:nginxoss)”加入到我们的官方微信群,与我们进行直接交流。
如欲体验基于 NGINX Plus 的 NGINX Ingress Controller,请立即下载 30 天免费试用版,或者联系我们讨论您的用例。
NGINX唯一中文官方社区 ,尽在 nginx.org.cn
更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源:
开源社区官网:https://www.nginx.org.cn/
按点赞数排序
按时间排序