点赞
评论
收藏
分享
举报
在 Kubernetes 中实现自助 DNS 和证书管理
发表于2023-05-10 10:49

浏览 670

文章标签

原文作者: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 记录即被清理。

该解决方案利用了以下技术(安装和配置说明如下):

在配置该解决方案之前,您需要:

  • 带 egress (LoadBalancer) 对象的 Kubernetes 云安装。该解决方案使用 Linode,但其他云提供商也可以。
  • 一个使用 Cloudflare 托管的域名,我们选择 Cloudflare 是因为它是 cert-manager 支持的 DNS 提供商之一,并且支持 ExternalDNS(截至本文撰写时,处于 beta 测试阶段)。我们强烈建议不要将该域名用于生产环境或任何其他关键目的。
  • 访问 Cloudflare API(包括在免费套餐中)。
  • Helm 用于安装和部署 Kubernetes。
  • kubectl 作为 Kubernetes 的命令行接口。
  • K9s(可选),一个结构良好的实体用户界面 (TUI),为与 Kubernetes 进行交互提供了一种更有条理的方式。

我们还假设您对 Kubernetes 有基本的了解(如何应用清单,使用 Helm 图表,以及使用 kubectl 命令来查看输出和排除故障)。了解 Let’s Encrypt 的基本概念会有所帮助,但不是必须的;要想了解概况,请查看我们的博客。您也不需要了解 cert-manager 的工作原理,但如果您对它(以及证书)如何与 NGINX Ingress Controller 协同工作感兴趣,请参阅我最近的帖子《在 Kubernetes 环境中实现证书管理自动化》

我们已经在 MacOS 和 Linux 上测试了该解决方案。虽然我们还没有在 Windows Subsystem for Linux 版本 2 (WSL2) 上进行测试,但预计不会有任何问题。

注意: 该解决方案只是一个示例概念验证,不得用于生产环境。它并未包含所有运维和安全的最佳实践。

部署解决方案

按照这些部分中的步骤来部署解决方案:

下载软件

  1. 下载您的 Cloudflare API 令牌
  2. 复制 NGINX Ingress Controller 仓库:
$ 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'.

部署 NGINX Ingress Controller

  1. 使用 Helm,部署 NGINX Ingress Controller。请注意,我们正在添加三个非标准的配置选项:
  • controller.enableCustomResources——指示 Helm 安装用于创建 NGINX VirtualServer 和 VirtualServerRoute 自定义资源的自定义资源定义 (CRD)。
  • controller.enableCertManager——将 NGINX Ingress Controller 配置为与 cert-manager 组件通信。
  • controller.enableExternalDNS——将 Ingress controller 配置为与 ExternalDNS 组件通信。
$ 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

在该解决方案中,cert-manager 在获取 TLS 证书时,使用 DNS-01 挑战类型,这需要在创建 ClusterIssuer 资源时提供 Cloudflare API 令牌。在该解决方案中,API 令牌作为 Kubernetes Secret 提供。

  1. 使用 Helm 部署 cert-manager:
$ 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

部署 ExternalDNS

同 cert-manager 一样,ExternalDNS 项目需要使用 Cloudflare API 令牌来管理 DNS。 两个项目可以使用相同令牌,但并不是必须的。

  1. 为 NGINX Ingress Controller 创建 ExternalDNS CRD,以实现项目间的集成。
$ 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 管理相关的所有写入和更新操作。
  • 创建一个 ClusterRole 对象(也称 external-dns)以定义所需的权限。
  • 将 ClusterRole 绑定到 ServiceAccount。
$ 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 部署。

  • 创建域过滤器,以限制 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 示例应用进行测试。

  1. 部署 Cafe 应用。
$ 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

验证解决方案

  1. 验证 DNS A 记录 – 即在 ANSWER SECTION 块中,FQDN(此处为 cafe.example.com)被映射到正确的 IP 地址 (www.xxx.yyy.zzz)。
$ 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 Ingress controller 时后台会发生什么?

在该解决方案部署时,后台会进行很多操作。该图显示了当开发人员使用 NGINX VirtualServer 自定义资源部署 NGINX Ingress Controller 时后台进行的操作。请注意,一些操作细节已被省略。

  1. 开发人员使用 NGINX CRD 部署 VirtualServer 资源
  2. Kubernetes 使用 NGINX Ingress Controller 创建 VirtualServer
  3. NGINX Ingress Controller 调用 ExternalDNS 来创建 DNS A 记录
  4. ExternalDNS 在 DNS 中创建 A 记录
  5. NGINX Ingress Controller 调用 cert-manager 来请求 TLS 证书
  6. cert-manager 添加 DNS 记录,以用于 DNS-01 挑战
  7. cert-manager 联系 Let’s Encrypt 以完成挑战
  8. Let’s Encrypt 根据 DNS 验证挑战
  9. Let’s Encrypt 颁发 TLS 证书
  10. cert-manager 向 NGINX Ingress Controller 提供 TLS 证书
  11. NGINX Ingress Controller 将受 TLS 保护的外部请求路由到应用 pod

故障排除

考虑到 Kubernetes 的复杂性以及我们所使用的组件,很难提供一套全面的故障排除指南。也就是说,只能提供一些基本建议来帮助您确定问题。

  • 使用 kubectl getkubectl describe 命令来验证部署对象的配置。
  • 使用 kubectl logs <component> 命令来查看各种已部署组件的日志文件。
  • 使用 K9s 来检查安装;该软件用黄色或红色(根据严重程度)突出显示问题,并提供一个界面来访问日志和对象细节。

如果仍有问题,请通过添加“小N助手(微信号:nginxoss)”加入到我们的官方微信群,与我们进行直接交流。

如欲体验基于 NGINX Plus 的 NGINX Ingress Controller,请立即下载 30 天免费试用版,或者联系我们讨论您的用例


NGINX唯一中文官方社区 ,尽在 nginx.org.cn

更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源:

开源社区官网:https://www.nginx.org.cn/

微信公众号:https://mp.weixin.qq.com/s/XVE5yvDbmJtpV2alsIFwJg

已修改于2023-05-10 13:49
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
239
文章
21
问答
198
粉丝
相关文章
介绍nginx网页配置工具QQ技术交流群1:1106758598QQ技术交流群2:560797506邮箱: cym1102@qq.com官网地址: http://www.nginxwebui.cn码云: https://gitee.com/cym1102/nginxWebUIgithub: https://github.com/cym1102/nginxWebUI功能特点nginxWebUI也可管理多个nginx服务器集群,随时一键切换到对应服务器上进行nginx配置,也可以一键将某台服务器配置同步到其他服务器,方便集群管理.部署此项目后,配置nginx再也不用上网各种搜索配置代码,再也不用手动申请和配置ssl证书,只需要在本项目中进行增删改查就可方便的配置和启动nginx。技术说明本项目是基于springBoot的web系统,数据库使用sqlite,因此服务器上不需要安装任何数据库项目启动时会释放一个.sqlite.db到系统用户文件夹中,注意进行备份本系统通过Let'sencrypt申请证书,使用acme.sh脚本
点赞 6
浏览 6.4k
  前三周学习了陶辉老师的“NGINX基础培训系列课程”,感觉受益良多,在这里想把一些知识点记录一下,和大家分享一下知识点,也方便日后的随手查看,温故知新。  首先,我们了解到了Nginx的版本,Nginx发布版本分为主线版本和稳定版本,区分两个版本也非常简单,主线版本版本号为单数,比如1.19,稳定版本为双数,比如1.18,今天我要说的是稳定版本,这个版本会尽量少的减少Nginx的bug问题,适用于生产环境,这里我不建议使用Nginx和其他软件一样在生产环境中落后一个或多个大版本使用,之前生产环境做过漏扫,发现我们编译自带的Nginx版本为:nginx/1.13.3(查询命令为nginx-V),结果出现了多个漏洞,四个高危和一个中危漏洞:        通过升级Nginx到稳定版最新版本后修复!  其次,是Nginx发行版本的选择,目前比较流行的有:nginx、nginxplus、Tengine、openresty、ope
点赞 1
浏览 3.5k
感谢您参加“NGINX从入门到精通进阶系列培训”!以下为培训的问答、课件和录像,希望您能通过此培训学有所得,祝学习进步!>问与答:- 基础篇+高级篇 - 应用篇+实战篇(New)>课件(PPT):基础篇:-NGINX概要、安装、配置:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-Setup.pdf-NGINX日志、运维:https://interact.f5.com/rs/653-SMC-783/images/cnfeb22-nginxcorecourse-maintenance.pdf高级篇:-NGINX变量、API:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-API.pdf-NGINXSSL、NJS:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-SSL.pdf
点赞 10
浏览 5k