如何使用Helm在DigitalOcean Kubernetes上设置Nginx入口

Kubernetes Ingresses为您提供了一种灵活的方式,可以将来自群集之外的流量路由到内部Kubernetes服务。 Helm https://helm.sh/是管理Kubernetes的包管理器。在本指南中,您将使用Helm设置Kubernetes维护的Nginx入口控制器。然后,您将创建一个Ingress资源,以将来自您的域的流量路由到示例Hello World后端服务。

作者选择了自由和开源基金作为Write for DOnations计划的一部分进行捐赠。

介绍

Kubernetes Ingresses为您提供了一种灵活的方式,可以将来自群集之外的流量路由到内部Kubernetes服务。 Ingress 资源是Kubernetes中的对象,用于定义将HTTP和HTTPS流量路由到服务的规则。 要使这些工作,必须存在Ingress 控制器 ; 它的作用是通过接受流量(最有可能通过负载均衡器)并将其路由到适当的服务来实现规则。 大多数入口控制器仅对所有入口使用一个全局负载均衡器,这比根据您希望公开的每个服务创建负载均衡器更有效。

Helm是管理Kubernetes的包管理员。 将Helm Charts与Kubernetes一起使用可提供可配置性和生命周期管理,以更新,回滚和删除Kubernetes应用程序。

在本指南中,您将使用Helm设置Kubernetes维护的Nginx入口控制器 然后,您将创建一个Ingress资源,以将来自您的域的流量路由到示例Hello World后端服务。 设置Ingress后,您将在集群中安装Cert-Manager ,以便能够自动配置Let的加密TLS证书以保护您的Ingress。

先决条件

  • DigitalOcean Kubernetes集群,其连接配置配置为kubectl默认值。 有关如何配置kubectl的说明显示在创建群集时显示的“ 连接到群集”步骤下。 要了解如何在DigitalOcean上创建Kubernetes集群,请参阅Kubernetes快速入门

  • Helm软件包管理器安装在本地计算机上,并且Tiller安装在您的集群上。 使用Helm Package Manager教程完成如何在Kubernetes群集上安装软件的第1步和2。

  • 完全注册的域名,包含两个可用的A记录。 本教程将始终使用hw1.example.comhw2.example.com 您可以在Namecheap上购买域名,在Freenom上免费获取一个域名,或使用您选择的域名注册商。

第1步 - 设置Hello World部署

在本节中,在部署Nginx Ingress之前,您将部署一个名为hello-kubernetes的Hello World应用程序,以获得一些要为其路由流量的服务。 要确认Nginx Ingress在接下来的步骤中是否正常工作,您将每次部署两次,每次都有一个不同的欢迎消息,当您从浏览器访问它时将显示该消息。

您将在本地计算机上存储部署配置。 第一个部署配置将位于名为hello-kubernetes-first.yaml的文件中。 使用文本编辑器创建它:

nano hello-kubernetes-first.yaml

添加以下行:

HELLO-kubernetes-first.yaml
apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-first
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-first
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-first
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-first
  template:
    metadata:
      labels:
        app: hello-kubernetes-first
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.5
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the first deployment!

此配置定义部署和服务。 部署包括paulbouwer/hello-kubernetes:1.5的三个副本paulbouwer/hello-kubernetes:1.5图像和名为MESSAGE的环境变量 - 当您访问应用程序时,您将看到它的值。 此处的服务定义为在端口80处公开部署集群。

保存并关闭文件。

然后,通过运行以下命令在Kubernetes中创建hello-kubernetes应用程序的第一个变体:

kubectl create -f hello-kubernetes-first.yaml

您将看到以下输出:

service/hello-kubernetes-first created
deployment.apps/hello-kubernetes-first created

要验证服务的创建,请运行以下命令:

kubectl get service hello-kubernetes-first

输出将如下所示:

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
hello-kubernetes-first   ClusterIP   10.245.85.236   <none>        80:31623/TCP   35s

您将看到新创建的服务已分配了ClusterIP,这意味着它正常工作。 发送给它的所有流量都将转发到端口8080上的选定部署。 现在您已经部署了hello-kubernetes应用程序的第一个变体,您将处理第二个变种。

打开一个名为hello-kubernetes-second.yaml的文件进行编辑:

nano hello-kubernetes-second.yaml

添加以下行:

HELLO-kubernetes-second.yaml
apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-second
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-second
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-second
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-second
  template:
    metadata:
      labels:
        app: hello-kubernetes-second
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.5
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the second deployment!

保存并关闭文件。

该变体具有与先前配置相同的结构; 唯一的区别在于部署和服务名称,以避免冲突和消息。

现在使用以下命令在Kubernetes中创建它:

kubectl create -f hello-kubernetes-second.yaml

输出将是:

service/hello-kubernetes-second created
deployment.apps/hello-kubernetes-second created

通过列出所有服务来验证第二个服务已启动并正在运行:

kubectl get service

输出将类似于:

NAME                            TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
hello-kubernetes-first          ClusterIP      10.245.85.236    <none>          80:31623/TCP                 54s
hello-kubernetes-second         ClusterIP      10.245.99.130    <none>          80:30303/TCP                 12s
kubernetes                      ClusterIP      10.245.0.1       <none>          443/TCP                      5m

列出了hello-kubernetes-firsthello-kubernetes-second ,这意味着Kubernetes已成功创建它们。

您已经创建了两个hello-kubernetes应用程序的部署以及随附的服务。 每个消息都在部署规范中设置了不同的消息,允许您在测试期间区分它们。 在下一步中,您将安装Nginx Ingress Controller本身。

第2步 - 安装Kubernetes Nginx入口控制器

现在,您将使用Helm安装Kubernetes维护的Nginx入口控制器 请注意,有几个Nginx Ingresses

Nginx Ingress控制器由Pod和服务组成。 Pod运行Controller,它会不断轮询群集的API服务器上的/ingresses端点,以获取可用Ingress资源的更新。 该服务属于LoadBalancer类型,由于您要将其部署到DigitalOcean Kubernetes集群,因此集群将自动创建一个DigitalOcean负载均衡器 ,所有外部流量都将通过该负载均衡器流向Controller。 然后,Controller将流量路由到适当的服务,如Ingress Resources中所定义。

只有LoadBalancer服务知道自动创建的Load Balancer的IP地址。 某些应用程序(如ExternalDNS )需要知道其IP地址,但只能读取Ingress的配置。 通过在helm install期间将controller.publishService.enabled参数设置为true ,可以将Controller配置为在每个Ingress上发布IP地址。 建议启用此设置以支持可能取决于Load Balancer IP地址的应用程序。

要将Nginx Ingress Controller安装到群集,请运行以下命令:

helm install stable/nginx-ingress --name nginx-ingress --set controller.publishService.enabled=true

此命令从stable图表存储库安装Nginx Ingress Controller,命名Helm发行版nginx-ingress ,并将publishService参数设置为true

输出结果如下:

NAME:   nginx-ingress
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                      DATA  AGE
nginx-ingress-controller  1     0s

==> v1/Pod(related)
NAME                                            READY  STATUS             RESTARTS  AGE
nginx-ingress-controller-7658988787-npv28       0/1    ContainerCreating  0         0s
nginx-ingress-default-backend-7f5d59d759-26xq2  0/1    ContainerCreating  0         0s

==> v1/Service
NAME                           TYPE          CLUSTER-IP     EXTERNAL-IP  PORT(S)                     AGE
nginx-ingress-controller       LoadBalancer  10.245.9.107   <pending>    80:31305/TCP,443:30519/TCP  0s
nginx-ingress-default-backend  ClusterIP     10.245.221.49  <none>       80/TCP                      0s

==> v1/ServiceAccount
NAME           SECRETS  AGE
nginx-ingress  1        0s

==> v1beta1/ClusterRole
NAME           AGE
nginx-ingress  0s

==> v1beta1/ClusterRoleBinding
NAME           AGE
nginx-ingress  0s

==> v1beta1/Deployment
NAME                           READY  UP-TO-DATE  AVAILABLE  AGE
nginx-ingress-controller       0/1    1           0          0s
nginx-ingress-default-backend  0/1    1           0          0s

==> v1beta1/Role
NAME           AGE
nginx-ingress  0s

==> v1beta1/RoleBinding
NAME           AGE
nginx-ingress  0s

NOTES:
...

Helm记录了它创建的Kubernetes中的哪些资源作为图表安装的一部分。

您可以通过运行以下方式观察Load Balancer:

kubectl get services -o wide -w nginx-ingress-controller

您已经安装了由Kubernetes社区维护的Nginx Ingress。 它将HTTP和HTTPS流量从Load Balancer路由到适当的后端服务,在Ingress Resources中配置。 在下一步中,您将使用Ingress资源公开hello-kubernetes应用程序部署。

第3步 - 使用Ingress公开应用程序

现在,您将创建一个Ingress资源,并使用它来在您想要的域中公开hello-kubernetes应用程序部署。 然后,您将通过浏览器访问它来测试它。

您将Ingress存储在名为hello-kubernetes-ingress.yaml的文件中。 使用您的编辑器创建它:

nano hello-kubernetes-ingress.yaml

将以下行添加到您的文件中:

HELLO-kubernetes-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: hw1.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-first
          servicePort: 80
  - host: hw2.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-second
          servicePort: 80

在上面的代码中,您定义名为hello-kubernetes-ingress的Ingress资源。 然后,指定两个主机规则,以便将hw1.example.com路由到hello-kubernetes-first服务,并将hw2.example.com从第二个部署( hello-kubernetes-second )路由到服务。

请记住用您自己的域替换突出显示的域,然后保存并关闭该文件。

通过运行以下命令在Kubernetes中创建它:

kubectl create -f hello-kubernetes-ingress.yaml

接下来,您需要确保通过A记录将两个域指向Load Balancer。 这是通过您的DNS提供商完成的。 要在DigitalOcean上配置DNS记录,请参阅如何管理DNS记录

您现在可以在浏览器中导航到hw1.example.com 您将看到以下内容:

你好Kubernetes  - 第一次部署

第二个变体( hw2.example.com )将显示不同的消息:

你好Kubernetes  - 第二次部署

有了这个,您已经验证了Ingress Controller正确路由请求; 在这种情况下,从您的两个域到两个不同的服务。

您已创建并配置了Ingress资源,以便为您的域中的hello-kubernetes应用程序部署提供服务。 在下一步中,您将设置Cert-Manager,这样您就可以使用Let's Encrypt中的免费TLS证书来保护您的Ingress资源。

第4步 - 使用Cert-Manager保护Ingress

要保护Ingress资源,您需要安装Cert-Manager,为生产创建ClusterIssuer,并修改Ingress的配置以利用TLS证书。 ClusterIssuers是Kubernetes中的证书管理器资源,用于提供TLS证书。 安装和配置后,您的应用将在HTTPS后面运行。

在通过Helm将Cert-Manager安装到群集之前,您将通过运行以下命令从jetstack / cert-manager存储库手动应用所需的CRD (自定义资源定义):

kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml

您将看到以下输出:

customresourcedefinition.apiextensions.k8s.io/certificates.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/challenges.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/issuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/orders.certmanager.k8s.io created

这表明Kubernetes已经为cert-manager应用了您需要的自定义资源。

注意:如果您已经学习了本教程和先决条件,那么您还没有创建名为cert-manager的Kubernetes命名空间,因此您不必在此注释块中运行该命令。 但是,如果群集上存在此命名空间,则需要通知Cert-Manager不要使用以下命令对其进行验证:

kubectl label namespace cert-manager certmanager.k8s.io/disable-validation="true"

Cert-Manager的Webhook组件需要TLS证书才能与Kubernetes API服务器安全地通信。 为了让Cert-Manager第一次为它生成证书,必须在部署它的命名空间上禁用资源验证。否则,它将陷入无限循环; 无法联系API并且无法生成TLS证书。

输出将是:

namespace/cert-manager labeled

接下来,您需要将Jetstack Helm存储库添加到Helm,后者托管Cert-Manager图表。 为此,请运行以下命令:

helm repo add jetstack https://charts.jetstack.io

Helm将显示以下输出:

"jetstack" has been added to your repositories

最后,将Cert-Manager安装到cert-manager名称空间中:

helm install --name cert-manager --namespace cert-manager jetstack/cert-manager

您将看到以下输出:

NAME:   cert-manager
LAST DEPLOYED: ...
NAMESPACE: cert-manager
STATUS: DEPLOYED

RESOURCES:
==> v1/ClusterRole
NAME                                    AGE
cert-manager-edit                       3s
cert-manager-view                       3s
cert-manager-webhook:webhook-requester  3s

==> v1/Pod(related)
NAME                                     READY  STATUS             RESTARTS  AGE
cert-manager-5d669ffbd8-rb6tr            0/1    ContainerCreating  0         2s
cert-manager-cainjector-79b7fc64f-gqbtz  0/1    ContainerCreating  0         2s
cert-manager-webhook-6484955794-v56lx    0/1    ContainerCreating  0         2s

...

NOTES:
cert-manager has been deployed successfully!

In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).

More information on the different types of issuers and how to configure them
can be found in our documentation:

https://docs.cert-manager.io/en/latest/reference/issuers.html

For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:

https://docs.cert-manager.io/en/latest/reference/ingress-shim.html

输出显示安装成功。 如输出中的NOTES中所列,您需要设置颁发者以颁发TLS证书。

您现在将创建一个发出Let的加密证书,并将其配置存储在名为production_issuer.yaml的文件中。 创建它并打开它进行编辑:

nano production_issuer.yaml

添加以下行:

production_issuer.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
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: your_email_address
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    http01: {}

此配置定义了一个ClusterIssuer,它与Let的Encrypt联系以颁发证书。 您需要将your_email_address替换为您的电子邮件地址,以便收到有关证书安全性和到期的紧急通知。

保存并关闭文件。

kubectl

kubectl create -f production_issuer.yaml

您将看到以下输出:

clusterissuer.certmanager.k8s.io/letsencrypt-prod created

安装了Cert-Manager后,您就可以将证书引入上一步中定义的Ingress资源。 打开hello-kubernetes-ingress.yaml进行编辑:

nano hello-kubernetes-ingress.yaml

添加突出显示的行:

HELLO-kubernetes-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - hw1.example.com
    - hw2.example.com
    secretName: letsencrypt-prod
  rules:
  - host: hw1.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-first
          servicePort: 80
  - host: hw2.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-second
          servicePort: 80

spec下的tls块定义了什么秘密,您的站点(在hosts )的证书将存储他们的证书, letsencrypt-prod ClusterIssuer发布。 对于您创建的每个Ingress,这必须是不同的。

请记住将hw1.example.comhw2.example.com替换为您自己的域。 完成编辑后,保存并关闭文件。

通过运行以下命令将此配置重新应用于您的群集:

kubectl apply -f hello-kubernetes-ingress.yaml

您将看到以下输出:

ingress.extensions/hello-kubernetes-ingress configured

您需要等待几分钟才能让Let's Encrypt服务器为您的域颁发证书。 在此期间,您可以通过检查以下命令的输出来跟踪其进度:

kubectl describe certificate letsencrypt-prod

输出的结尾看起来类似于:

Events:
  Type    Reason              Age   From          Message
  ----    ------              ----  ----          -------
  Normal  Generated           56s   cert-manager  Generated new private key
  Normal  GenerateSelfSigned  56s   cert-manager  Generated temporary self signed certificate
  Normal  OrderCreated        56s   cert-manager  Created Order resource "hello-kubernetes-1197334873"
  Normal  OrderComplete       31s   cert-manager  Order "hello-kubernetes-1197334873" completed successfully
  Normal  CertIssued          31s   cert-manager  Certificate issued successfully

当您的最后一行输出读取Certificate issued successfully ,您可以按CTRL + C退出。 导航到浏览器中的某个域进行测试。 您将在浏览器的地址栏左侧看到挂锁,表示您的连接是安全的。

在此步骤中,您已使用Helm安装了Cert-Manager并创建了Let's Encrypt ClusterIssuer。 之后,您更新了Ingress资源以利用颁发者生成TLS证书。 最后,您已通过导航到浏览器中的某个域确认HTTPS可以正常工作。

结论

您现在已经使用Helm在DigitalOcean Kubernetes集群上成功设置了Nginx Ingress Controller和Cert-Manager。 您现在可以使用Let的加密TLS证书将您的应用程序公开到您的域中的Internet上。

有关Helm软件包管理器的更多信息,请阅读本简介文章