本地环境部署Ngnix_ingress_certmanager.md 16 KB

本地环境部署 K8s Nginx ingress

[TOC]

开始之前

国内可能会无法连接一些网站,需要准备好代理,然后运行

export http_proxy=192.168.11.61:11714
export https_proxy=192.168.11.61:11714
export no_proxy=.cn,.aliyun.com,.aliyuncs.com,.163.com,.baiduce.com,.qiniu.com,.daocloud.io,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10,169.254.0.0/16

请将192.168.11.61:11714修改成你的代理服务器地址和端口。

1. 部署并曝露 Nginx Ingress 的 80 和 443 端口

云厂商方案:使用 LoadBalancer 曝露 80 和 443 端口,并通过 DNS 配置将流量指向负载均衡器。

在裸机环境中,有几种方式可以暴露 Nginx Ingress Controller 的 80 和 443 端口:

  1. 通过集群外的负载均衡软件
  2. 通过 MetalLB 组件
  3. 通过 HostNetwork 模式,将 Nginx-Ingress-Controller 部署成 DaemonSet
  4. 修改 Kubelet 将 NodePort 地址范围修改成 1-32767 端口

可以根据具体需求选择一种方式。可以重点关注一下 MetalLB 组件。

2. 部署 cert-manager

请将下文的 yourdomain.com 替换成真实的域名。

2.1 安装 Cert-Manager

  1. 添加 Helm 仓库并安装 cert-manager

    helm repo add jetstack https://charts.jetstack.io
    helm repo update
       
    # 安装最新版本:
    helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
    # 指定安装版本:
    helm install cert-manager jetstack/cert-manager \
     --namespace cert-manager \
     --create-namespace \
     --version v1.16.2 \
     --set crds.enabled=true
    
  2. 验证 cert-manager 是否成功部署

    kubectl get pods --namespace cert-manager
    

2.1 部署 cert-manager-alidns-webhook

本地环境通常无法通过公网访问,无法通过http的方式让CA验证域名所有权。需要通过DNS的方式让CA验证域名所有权。下面以阿里云DNS为例。其他的DNS resolver

  1. 添加 cert-manager-webhook-alidns Helm 仓库

    helm repo add cert-manager-alidns-webhook https://devmachine-fr.github.io/cert-manager-alidns-webhook
    helm repo update
    
  2. 安装 cert-manager-alidns-webhook

    helm install alidns-webhook cert-manager-alidns-webhook/alidns-webhook \
     --namespace cert-manager \
     --set groupName=acme.yourdomain.com
    

配置说明

  • groupName 应该是唯一的,建议使用你的域名或类似标识。
  1. 创建阿里云AKSK secret:

在阿里云控制台创建一个RAM用户,并赋予DNSFullAccess 策略。在这个用户下创建access key。然后在k8s 创建secret:

   kubectl -n cert-manager create secret generic alidns-secrets --from-literal="access-token=yourtoken" --from-literal="secret-key=yoursecretkey"

​ 确保将 yourtokenyoursecretkey 修改成从阿里云控制台获得的 AK/SK。

3. 配置 ClusterIssuer 和 Issuer

请将下文的 yourdomain.com 替换成真实的域名。

步骤 1:创建 Let's Encrypt ClusterIssuer

  1. 创建 ClusterIssuer 文件:

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
     name: letsencrypt-staging
    spec:
     acme:
       server: https://acme-staging-v02.api.letsencrypt.org/directory
       email: your-email@example.com
       privateKeySecretRef:
         name: letsencrypt-staging
       solvers:
       - dns01:
           webhook:
             groupName: acme.yourdomain.com
             solverName: alidns-solver
             config:
               regionId: cn-beijing
               accessTokenSecretRef:
                 name: alidns-secrets
                 key: access-token
               secretKeySecretRef:
                 name: alidns-secrets
                 key: secret-key
         selector:
           dnsZones:
           - yourdomain.com
    
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
     name: letsencrypt-prod
    spec:
     acme:
       server: https://acme-v02.api.letsencrypt.org/directory
       email: your-email@example.com
       privateKeySecretRef:
         name: letsencrypt-prod
       solvers:
       - dns01:
           webhook:
             groupName: acme.yourdomain.com
             solverName: alidns-solver
             config:
               regionId: cn-beijing
               accessTokenSecretRef:
                 name: alidns-secrets
                 key: access-token
               secretKeySecretRef:
                 name: alidns-secrets
                 key: secret-key
         selector:
           dnsZones:
           - yourdomain.com
       
    
  2. 应用配置

    kubectl apply -f letsencrypt-staging.yaml
    kubectl apply -f letsencrypt-prod.yaml
    

配置说明

  • groupName 需要和之前helm指定的一致。
  • email 需要修改为你的邮箱。

步骤 2:创建 Let's Encrypt Issuer

  1. 创建 Issuer 文件:

    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
     name: letsencrypt-staging-issuer
     namespace: your-namespace
    spec:
     acme:
       server: https://acme-staging-v02.api.letsencrypt.org/directory
       email: your-email@example.com
       privateKeySecretRef:
         name: letsencrypt-staging
       solvers:
       - dns01:
           webhook:
             groupName: acme.yourdomain.com
             solverName: alidns-solver
             config:
               regionId: cn-beijing
               accessTokenSecretRef:
                 name: alidns-secrets
                 key: access-token
               secretKeySecretRef:
                 name: alidns-secrets
                 key: secret-key
         selector:
           dnsZones:
           - yourdomain.com
    
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
     name: letsencrypt-prod-issuer
     namespace: your-namespace
    spec:
     acme:
       server: https://acme-v02.api.letsencrypt.org/directory
       email: your-email@example.com
       privateKeySecretRef:
         name: letsencrypt-prod
       solvers:
       - dns01:
           webhook:
             groupName: acme.yourdomain.com
             solverName: alidns-solver
             config:
               regionId: cn-beijing
               accessTokenSecretRef:
                 name: alidns-secrets
                 key: access-token
               secretKeySecretRef:
                 name: alidns-secrets
                 key: secret-key
         selector:
           dnsZones:
           - yourdomain.com
    
  2. 应用配置

    kubectl apply -f letsencrypt-staging-issuer.yaml
    kubectl apply -f letsencrypt-prod-issuer.yaml
    

配置说明

  • groupName 需要和之前helm指定的一致。
  • email 需要修改为你的邮箱。
  • namespace 需要和你的应用的 namespace 一致,否则无法找到 Issuer, 无法颁发证书。而之前的ClusterIssuer是Cluster级别的,不需要指定namespace。

4. 部署测试应用并请求证书

步骤 1:部署测试应用

  1. 创建测试应用的 Deployment 和 Service

    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: test-app
     namespace: your-namespace
    spec:
     replicas: 1
     selector:
       matchLabels:
         app: test-app
     template:
       metadata:
         labels:
           app: test-app
       spec:
         containers:
         - name: test-app
           image: nginx:alpine
           ports:
           - containerPort: 80
    
    apiVersion: v1
    kind: Service
    metadata:
     name: test-app
     namespace: your-namespace
    spec:
     selector:
       app: test-app
     ports:
     - port: 80
       targetPort: 80
    
  2. 应用配置

    kubectl apply -f test-app-deployment.yaml
    kubectl apply -f test-app-service.yaml
    

步骤 2:创建 Ingress 资源并请求证书

  1. 创建 Ingress 资源

使用 Let's Encrypt Staging 请求证书:

   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: test-app-ingress
     namespace: your-namespace
     annotations:
       cert-manager.io/cluster-issuer: "letsencrypt-staging"
   spec:
     rules:
     - host: ingress-test.yourdomain.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: test-app
               port:
                 number: 80
     tls:
     - hosts:
       - ingress-test.yourdomain.com
       secretName: test-app-tls
  1. 应用配置

    kubectl apply -f test-app-ingress.yaml
    
  2. 验证证书颁发情况

查看 Ingress 的证书是否成功颁发:

   kubectl describe certificate test-app-tls -n your-namespace
  1. 测试从浏览器访问

    先在阿里云DNS控制台创建DNS记录。

    • 通过集群外的负载均衡软件方式,请指向负载均衡软件所在机器的IP。
    • 通过MetalLB组件方式的,请指向 ingress-nginx service 获得的EXTERNAL-IP
    • 通过HostNetwork 和 修改 NodePort 方式,请指向一个或多个 node 的 IP。

​ 然后在本地浏览器访问 https://ingress-test.yourdomain.com

步骤 3:切换到 Let's Encrypt Production

  1. 更新 Ingress 资源

cert-manager.io/cluster-issuer 注解从 letsencrypt-staging 更改为 letsencrypt-prod

   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: test-app-ingress
     namespace: your-namespace
     annotations:
       cert-manager.io/cluster-issuer: "letsencrypt-prod"
   spec:
     rules:
     - host: ingress-test.yourdomain.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: test-app
               port:
                 number: 80
     tls:
     - hosts:
       - ingress-test.yourdomain.com
       secretName: test-app-tls
  1. 应用更新

    kubectl apply -f test-app-ingress.yaml
    

步骤4. 使用 ECC 证书并配置密钥大小和轮换策略

步骤 1:指定颁发 ECC 证书

  1. 修改 Ingress 或 Certificate 资源的注解

注解文档

添加以下注解来指定 ECC 证书并设置密钥大小和轮换策略:

   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: test-app-ingress
     namespace: your-namespace
     annotations:
       cert-manager.io/cluster-issuer: "letsencrypt-prod"
       cert-manager.io/private-key-algorithm: "ECDSA"
       cert-manager.io/private-key-size: "256"
       cert-manager.io/private-key-rotation-policy: "Always"
   spec:
     rules:
     - host: ingress-test.yourdomain.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: test-app
               port:
                 number: 80
     tls:
     - hosts:
       - ingress-test.yourdomain.com
       secretName: test-app-tls

配置说明

  • private-key-size: "256":指定 ECC 密钥的大小为 256 位。常用的 ECC 密钥大小有 256、384 和 521 位,256 位通常足够提供高强度的安全性。
  • private-key-rotation-policy: "Always":启用私钥轮换策略,即每次证书更新时都生成新的私钥。这种策略有助于提高安全性,因为它减少了私钥泄露或被攻击的风险。
  1. 应用更新

    kubectl apply -f test-app-ingress.yaml
    

5. 总结

  • 部署并曝露 Nginx Ingress 的 80 和 443 端口

    • 云厂商方案:使用 LoadBalancer 曝露 80 和 443 端口,并通过 DNS 配置将流量指向负载均衡器。

    • 裸机环境方案:

    • 负载均衡软件:使用 Nginx 或 HAProxy 将流量转发到 Ingress Controller。

    • MetalLB:使用 MetalLB 组件在裸机环境中实现 LoadBalancer。

    • HostNetwork:将 Nginx Ingress Controller 作为 DaemonSet 部署,并直接监听 80 和 443 端口。

    • 修改 Kubelet NodePort 范围:扩展 NodePort 范围以允许 80 和 443 端口。

  • Cert manager 和 Ingress 配置 SSL 证书:使用 cert-manager 自动管理和应用 SSL

    • Cert-Manager 和 Alidns Webhook:通过 Helm 安装 Cert-Manager 和 cert-manager-alidns-webhook。
    • ClusterIssuer 和 Issuer:配置 Let's Encrypt 的 Staging 和 Production Issuer。
    • 测试应用部署:使用 Let's Encrypt Staging 验证证书颁发流程,成功后切换到 Production。
    • ECC 证书配置:通过注解指定 ECC 证书,并设置密钥大小和轮换策略以增强安全性。

6. 清理资源

1. 清理测试应用和证书

删除测试应用的 Deployment 和 Service

kubectl delete deployment test-app -n your-namespace
kubectl delete service test-app -n your-namespace

删除 Ingress 资源和证书

kubectl delete ingress test-app-ingress -n your-namespace
kubectl delete certificate test-app-tls -n your-namespace

删除 Issuer 和 ClusterIssuer

kubectl delete issuer letsencrypt-staging-issuer -n your-namespace
kubectl delete issuer letsencrypt-prod-issuer -n your-namespace
kubectl delete clusterissuer letsencrypt-staging
kubectl delete clusterissuer letsencrypt-prod

2. 清理 Cert-Manager 和 Alidns Webhook

删除 Cert-Manager 和 Alidns Webhook

helm uninstall cert-manager -n cert-manager
helm uninstall cert-manager-webhook-alidns -n cert-manager
kubectl delete namespace cert-manager

3. 清理 Nginx Ingress Controller

删除 Nginx Ingress Controller

helm uninstall ingress-nginx -n ingress-nginx
kubectl delete namespace ingress-nginx

4. 清理暴露 80 和 443 端口的资源

清理负载均衡软件(如 NGINX 或 HAProxy 配置文件)

如果你使用了集群外的负载均衡软件如 NGINX 或 HAProxy,请移除你为暴露 80 和 443 端口而添加的配置。具体步骤请参考之前的文档

删除 MetalLB 资源(如果使用了 MetalLB 方式)

kubectl delete -f metallb-addresspool.yaml
kubectl delete -f metallb-l2advertisement.yaml
kubectl delete -f metallb-native.yaml
helm uninstall metallb -n metallb-system
kubectl delete namespace metallb-system

对于 HostNetwork

之前删除 Nginx Ingress Controller就已经完成清理。

恢复kube-apiserver 启动参数(如果修改过 NodePort 范围)

如果你修改过 kube-apiserver 的 --service-node-port-range 范围,请恢复默认设置 --service-node-port-range=30000-32767

kubeadm 部署中,编辑 /etc/kubernetes/manifests/kube-apiserver.yaml

在手动以服务部署 kube-apiserver 时,编辑 /etc/systemd/system/kube-apiserver.service

具体步骤请参考之前的文档

最终清理总结

  • 删除应用和证书:删除所有测试应用、证书、Ingress 和相关资源。
  • 清理 Cert-Manager 和 Alidns Webhook:删除 Cert-Manager 和 Alidns Webhook 以及它们的命名空间。
  • 删除 Nginx Ingress Controller:卸载 Nginx Ingress Controller 并删除相关的命名空间。
  • 清理暴露端口的配置:移除所有暴露 80 和 443 端口的配置,包括 MetaLB 和集群外的负载均衡软件配置,恢复 Kubelet 的 NodePort 配置。