护卫 NGINX-ingress¶
本教程将详细介绍如何使用 NGINX 安装和保护集群的入口。
步骤 1 - 安装 Helm¶
如果你安装了 helm,跳过这一节。
安装cert-manager
最简单的方法是使用Helm
,这是 Kubernetes 源的模板和部署工具。
首先,确保 Helm 客户端按照Helm 安装说明进行安装.
步骤 2 - 部署 NGINX 入口控制器¶
一个kubernetes入口控制器
被设计为 HTTP 和 HTTPS 流量的接入点,以访问集群中运行的软件。 ingress-nginx-controller
通过提供由云提供商的负载均衡器支持的 HTTP 代理服务来实现这一点。
你可以从关于ingress-nginx
的文档中获得更多关于ingress-nginx
及其工作原理的详细信息。
为 ingress-nginx 添加最新的 helm 存储库
用最新的图表更新 helm 库:
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "coreos" chart repository
Update Complete. ⎈ Happy Helming!⎈
使用helm
安装 NGINX Ingress 控制器:
云提供商提供并链接一个公共 IP 地址可能需要一到两分钟。 当它完成后,您可以使用 kubectl
命令看到外部 IP 地址:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 13m
quickstart-ingress-nginx-controller LoadBalancer 10.0.114.241 <pending> 80:31635/TCP,443:30062/TCP 8m16s
quickstart-ingress-nginx-controller-admission ClusterIP 10.0.188.24 <none> 443/TCP 8m16s
该命令显示集群中的所有服务(在default
名称空间中),以及它们拥有的任何外部 IP 地址。 当您第一次创建控制器时,您的云提供商还没有通过LoadBalancer
分配 IP 地址。 在此之前,服务的外部 IP 地址将被列为<pending>
。
您的云提供商可以选择在创建入口控制器之前保留一个 IP 地址,并使用该 IP 地址,而不是从池中分配 IP 地址。 请阅读您的云提供商的文档,了解如何安排这一点。
步骤 3 - 分配 DNS 名称¶
分配给入口控制器的外部 IP 是所有传入流量都应该路由到的 IP。 要启用此功能,请将其添加到您控制的 DNS 区域,例如www.example.com
。
这个快速入门假设您知道如何将 DNS 条目分配给 IP 地址,并且会这样做。
步骤 4 - 部署示例服务¶
您的服务可以有自己的图表,也可以直接使用清单部署它。 本快速入门使用清单创建和公开示例服务。 示例服务使用kuard
,一个演示应用程序。
快速启动示例为示例使用了三个清单。 前两个是一个示例部署和一个关联的服务:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kuard
spec:
selector:
matchLabels:
app: kuard
replicas: 1
template:
metadata:
labels:
app: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:1
imagePullPolicy: Always
name: kuard
ports:
- containerPort: 8080
apiVersion: v1
kind: Service
metadata:
name: kuard
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
selector:
app: kuard
您可以在本地创建、下载和引用这些文件,也可以从本文档的 GitHub 源存储库引用它们。 要直接从 GitHub 安装教程文件中的示例服务,请执行以下操作:
kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/deployment.yaml
# expected output: deployment.extensions "kuard" created
kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml
# expected output: service "kuard" created
Kubernetes 使用Ingress 源在集群外部公开这个示例服务。 您需要下载并修改示例清单,以反映您拥有或控制的域,以完成此示例。
你可以从一个示例入口开始:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations:
kubernetes.io/ingress.class: "nginx"
#cert-manager.io/issuer: "letsencrypt-staging"
spec:
tls:
- hosts:
- example.example.com
secretName: quickstart-example-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80
您可以从 GitHub 下载清单示例,编辑它,并使用下面的命令将清单提交到 Kubernetes。 在编辑器中编辑文件,保存后:
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress.yaml
# expected output: ingress.extensions "kuard" created
Note
我们上面展示的ingress示例中有一个host
定义。 当请求的主机名与入口中的定义匹配时,ingress-nginx-controller
将路由流量。 您可以在规则中部署一个没有“主机”定义的入口,但该模式不适用于TLS证书,因为TLS证书需要完全限定的域名。
一旦它被部署,你可以使用命令kubectl get ingress
来查看入口的状态:
完全创建入口可能需要几分钟时间,具体时间取决于您的服务提供商。 当它被创建并链接到位时,入口也会显示一个地址:
Note
ingress上的IP地址可能与ingress-nginx-controller
拥有的IP地址不匹配。 这很好,这是托管Kubernetes集群的服务提供者的一个怪癖/实现细节。 由于我们使用ingress-nginx-controller
而不是任何云提供商特定的入口后端, 使用为quickstart-ingress-nginx-controller
LoadBalancer
源定义和分配的IP地址作为您服务的主要接入点。
确保您可以通过上面添加的域名访问该服务,例如 http://www.example.com
。 最简单的方法是打开浏览器,输入您在 DNS 中设置的名称,我们刚刚为其添加了入口。
你也可以使用像 curl
这样的命令行工具来检查入口。
这个 curl 命令的选项将在任何重定向之后提供详细输出,在输出中显示 TLS 报头,并且不会在不安全的证书上出现错误。 使用ingress-nginx-controller
,该服务将使用 TLS 证书,但它将使用ingress-nginx-controller
提供的自签名证书作为默认值。 浏览器将显示一个警告,这是一个无效的证书。这是预期的,也是正常的,因为我们还没有使用证书管理器为我们的站点获取完全受信任的证书。
Warning
确保你的入口是可用的,并在互联网上正确响应是至关重要的。 这个快速入门示例使用Let’s Encrypt来提供证书,它期望并验证服务可用, 并且在颁发证书的过程中使用该验证作为对域的请求属于对域有足够控制的人的证明。
步骤 5 - 部署 cert-manager¶
我们需要安装 cert-manager 来完成 Kubernetes 的工作,以请求证书并响应验证它的挑战。 我们可以使用 Helm 或普通的 Kubernetes 清单来安装 cert-manager。
因为我们之前安装了 Helm,我们会假设你想要使用 Helm;按照 Helm guide。 其他方法请参考 cert-manager 的安装文档。
cert-manager 主要使用两种不同的自定义 Kubernetes 源(称为CRDs
)来配置和控制它的操作方式,以及存储状态。 这些源是颁发者和证书。
Issuers(颁发者)¶
颁发者定义了证书管理器 如何 请求 TLS 证书。 颁发者在 Kubernetes 中是特定于单个名称空间的,但也有一个ClusterIssuer
,它意味着是一个集群范围的版本。
注意确保您的颁发者与要创建的证书在相同的名称空间中创建。 您可能需要在kubectl create
命令中添加-n my-namespace
。
你的另一个选择是用ClusterIssuers
替换你的issuer
;ClusterIssuers
源适用于集群中的所有 Ingress 源。 如果使用ClusterIssuers
,请记住将 Ingress 注释cert-manager.io/issuer
更新为 cert-manager.io/cluster-issuer
。
如果您发现颁发者有问题,请遵循故障排除颁发 ACME 证书指南。
关于Issuers
和 ClusterIssuers
之间的区别的更多信息 - 包括您可以在颁发者概念上找到它们。
Certificate(证书)¶
证书源允许您指定要请求的证书的详细信息。 它们引用颁发者来定义它们将*如何*发行。
有关更多信息,请参见证书概念.
步骤 6 - 配置一个 Let's Encrypt Issuer¶
在本例中,我们将为 Let’s Encrypt 设置两个颁发者:staging 和 production。
Let's Encrypt 产品发行方有非常严格的速率限制。 当你在尝试和学习时,很容易就会触及这些极限。 由于存在这种风险,我们将从 Let's Encrypt staging 发行方开始,一旦我们对它的工作感到满意,我们将切换到 production 发行方。
注意,您将看到来自预演颁发者的关于不受信任证书的警告,但这是完全预期的。
在本地创建这个定义,并将电子邮件地址更新为您自己的。 此电子邮件是 Let's Encrypt 要求的,用于通知您证书过期和更新。
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
编辑完成后,应用自定义源:
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/staging-issuer.yaml
# expected output: issuer.cert-manager.io "letsencrypt-staging" created
还要创建一个生产颁发者并部署它。 与预演发布者一样,您需要更新此示例并添加您自己的电子邮件地址。
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/production-issuer.yaml
# expected output: issuer.cert-manager.io "letsencrypt-prod" created
这两个颁发者都被配置为使用HTTP01
挑战提供程序。
创建颁发者后检查它的状态:
$ kubectl describe issuer letsencrypt-staging
Name: letsencrypt-staging
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"cert-manager.io/v1","kind":"Issuer","metadata":{"annotations":{},"name":"letsencrypt-staging","namespace":"default"},(...)}
API Version: cert-manager.io/v1
Kind: Issuer
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T18:03:54Z
Generation: 0
Resource Version: 9092
Self Link: /apis/cert-manager.io/v1/namespaces/default/issuers/letsencrypt-staging
UID: 25b7ae77-ea93-11e8-82f8-42010a8a00b5
Spec:
Acme:
Email: email@example.com
Private Key Secret Ref:
Key:
Name: letsencrypt-staging
Server: https://acme-staging-v02.api.letsencrypt.org/directory
Solvers:
Http 01:
Ingress:
Class: nginx
Status:
Acme:
Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7374163
Conditions:
Last Transition Time: 2018-11-17T18:04:00Z
Message: The ACME account was registered with the ACME server
Reason: ACMEAccountRegistered
Status: True
Type: Ready
Events: <none>
您应该看到颁发者列出了一个注册帐户。
步骤 7 - 部署 TLS 入口源¶
所有必要的配置就绪之后,我们现在就可以开始请求 TLS 证书了。 主要有两种方法:在入口上使用ingress-shim
注释或直接创建证书源。
在本例中,我们将向入口添加注释,并利用 ingress-shim 让它代表我们创建证书源。 创建证书后,证书管理器将更新或创建入口源,并使用该源验证域。 验证和颁发后,证书管理器将创建或更新证书中定义的秘密。
Note
在入口中使用的秘密应该与证书中定义的秘密相匹配。 没有任何显式的检查,所以输入错误将导致ingress-nginx-controller
回落到它的自签名证书。 在我们的示例中,我们在ingress(和ingress-shim)上使用注释,它们将为您创建正确的秘密。
编辑入口,添加在前面例子中被注释掉的注释:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: "letsencrypt-staging"
spec:
tls:
- hosts:
- example.example.com
secretName: quickstart-example-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80
应用它:
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls.yaml
# expected output: ingress.extensions "kuard" configured
证书管理器将读取这些注释并使用它们创建一个证书,您可以请求并查看:
$ kubectl get certificate
NAME READY SECRET AGE
quickstart-example-tls True quickstart-example-tls 16m
证书管理器反映证书对象中每个请求的进程状态。 您可以使用kubectl describe
命令查看该信息:
$ kubectl describe certificate quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T17:58:37Z
Generation: 0
Owner References:
API Version: networking.k8s.io/v1
Block Owner Deletion: true
Controller: true
Kind: Ingress
Name: kuard
UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
Resource Version: 9295
Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tls
UID: 68d43400-ea92-11e8-82f8-42010a8a00b5
Spec:
Dns Names:
www.example.com
Issuer Ref:
Kind: Issuer
Name: letsencrypt-staging
Secret Name: quickstart-example-tls
Status:
Acme:
Order:
URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/7374163/13665676
Conditions:
Last Transition Time: 2018-11-17T18:05:57Z
Message: Certificate issued successfully
Reason: CertIssued
Status: True
Type: Ready
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 9m cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 8m cert-manager Domain "www.example.com" verified with "http-01" validation
Normal IssueCert 8m cert-manager Issuing certificate...
Normal CertObtained 7m cert-manager Obtained certificate from ACME server
Normal CertIssued 7m cert-manager Certificate issued Successfully
与此源相关并列在describe
结果底部的事件显示了请求的状态。 在上面的示例中,证书在几分钟内被验证并颁发。
完成后,证书管理器将根据入口源中使用的秘密创建一个包含证书详细信息的秘密。 你也可以使用 describe 命令来查看一些细节:
$ kubectl describe secret quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: cert-manager.io/certificate-name=quickstart-example-tls
Annotations: cert-manager.io/alt-names=www.example.com
cert-manager.io/common-name=www.example.com
cert-manager.io/issuer-kind=Issuer
cert-manager.io/issuer-name=letsencrypt-staging
Type: kubernetes.io/tls
Data
====
tls.crt: 3566 bytes
tls.key: 1675 bytes
现在我们有信心所有的配置都是正确的,你可以更新入口中的注释来指定生产颁发者:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- example.example.com
secretName: quickstart-example-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80
$ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls-final.yaml
ingress.extensions "kuard" configured
您还需要删除现有的秘密,证书管理器正在监视该秘密,并将使它使用更新后的颁发者重新处理请求。
这将启动获取新证书的过程,使用 describe 可以查看状态。 在更新了生产证书之后,您应该看到示例 KUARD 在您的域中运行,其中包含已签名的 TLS 证书。
$ kubectl describe certificate quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T18:36:48Z
Generation: 0
Owner References:
API Version: networking.k8s.io/v1
Block Owner Deletion: true
Controller: true
Kind: Ingress
Name: kuard
UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
Resource Version: 283686
Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tls
UID: bdd93b32-ea97-11e8-82f8-42010a8a00b5
Spec:
Dns Names:
www.example.com
Issuer Ref:
Kind: Issuer
Name: letsencrypt-prod
Secret Name: quickstart-example-tls
Status:
Conditions:
Last Transition Time: 2019-01-09T13:52:05Z
Message: Certificate does not exist
Reason: NotFound
Status: False
Type: Ready
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Generated 18s cert-manager Generated new private key
Normal OrderCreated 18s cert-manager Created Order resource "quickstart-example-tls-889745041"
您可以通过在证书管理器为您的证书创建的订单源上运行kubectl describe
来查看 ACME 订单的当前状态:
$ kubectl describe order quickstart-example-tls-889745041
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"
在这里,我们可以看到 cert-manager 创建了 1 个'Challenge'源来完成订单。 您可以通过在自动创建的挑战源上运行kubectl describe
来深入了解当前 ACME 挑战的状态:
$ kubectl describe challenge quickstart-example-tls-889745041-0
...
Status:
Presented: true
Processing: true
Reason: Waiting for http-01 challenge propagation
State: pending
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 15s cert-manager Challenge scheduled for processing
Normal Presented 14s cert-manager Presented challenge using http-01 challenge mechanism
从上面,我们可以看到挑战已经'presented',cert-manager 正在等待挑战记录传播到入口控制器。 你应该留意挑战源上的新事件,因为'success'事件应该在一分钟左右打印出来(取决于你的入口控制器更新规则的速度):
$ kubectl describe challenge quickstart-example-tls-889745041-0
...
Status:
Presented: false
Processing: false
Reason: Successfully authorized domain
State: valid
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 71s cert-manager Challenge scheduled for processing
Normal Presented 70s cert-manager Presented challenge using http-01 challenge mechanism
Normal DomainVerified 2s cert-manager Domain "www.example.com" verified with "http-01" validation
Note
如果您的挑战没有变得'valid',并且仍然处于'pending'状态(或进入'failed' 状态),则很可能存在某种配置错误。 阅读挑战源参考文档了解更多关于调试失败挑战的信息。
一旦挑战完成,相应的挑战源将被删除,'Order'将被更新以反映 Order 的新状态:
$ kubectl describe order quickstart-example-tls-889745041
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"
Normal OrderValid 16s cert-manager Order completed successfully
最后,Certificate
源将被更新以反映颁发过程的状态。 如果一切正常,你应该能够describe
证书,并看到如下内容:
$ kubectl describe certificate quickstart-example-tls
Status:
Conditions:
Last Transition Time: 2019-01-09T13:57:52Z
Message: Certificate is up to date and has not expired
Reason: Ready
Status: True
Type: Ready
Not After: 2019-04-09T12:57:50Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Generated 11m cert-manager Generated new private key
Normal OrderCreated 11m cert-manager Created Order resource "quickstart-example-tls-889745041"
Normal OrderComplete 10m cert-manager Order "quickstart-example-tls-889745041" completed successfully