目前在使用Kubernetes遇到一个问题,那就是因为出口设备的限制,只有一个IP,而目前的这个IP的80与443是用Nginx进行反向代理的,如果我想用Kubernetes Nginx-Ingress接管入口,那势必需要将访问原Nginx的流量转发过去。
还好Kubernetes提供集群内访问外部资源的方法——Endpoint。在K8S常规的设计中,流量是按照Ingress->Service->Pod这的方式走的,Endpoint就是充当Pod的角色,只不过Endpoint会将流量引出集群,访问外部资源,比如外部的数据库集群等等。


1. 先跑通Http

一般来说,Service都是需要selector app的,但是我们这里使用noselector Service,它与Endpoint对应的方式为metadata.name相同即可。
假定我的集群外Nginx10.0.1.5

# 建立操作namespace
kubectl create ns nginx
# 定义Endnpoint与noselector Service
apiVersion: v1
kind: Endpoints
metadata:
  name: nginx-proxy-pass
subsets:
  - addresses:
    - ip: 10.0.1.5
    ports:
    - port: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-proxy-pass
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

最后我们来定义Ingress,这里暂时只考虑Http,先让整个流程可以跑通。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-proxy-pass-ingress
  namespace: nginx
spec:
  rules:
  - host: index.spex.top
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-proxy-pass
          servicePort: 80

接下来将需要一些操作,这里就不细说了,主要有:

  • 将IP地址80与443映射至Nginx-Ingress节点的LVS IP地址(如果做了LVS的话)
  • 反向代理服务器10.0.1.5需要配置好服务器信息,保证网站可正常访问
  • 域名解析服务器需要将域名映射至IP地址

至此应该可以正常访问Http的网站了。
但是现在肯定不够,没有Https是不行的,接下来配置Https。


2. Cert-Manager

在二进制部署环境,我们有acme.sh一类的服务可以来管理证书,在Kubernetes中,对应是Cert-Manager
ACME.SH自动申请管理SSL证书 - SPEX
原理都是相同的,都是使用的Letsencrypt的免费证书,而服务是为了方便申请与自动续期,使用繁琐程度大致相当。

2.1 安装

我们采用Helm方式安装,同时Cert-Manager需要在部署之前安装CRD,不然会报错。

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

# label namespace
kubectl label ns nginx certmanager.k8s.io/disable-validation="true"

# helm install
helm install --name cert-manager stable/cert-manager --namespace nginx

2.2 Issuer

Issuer是设置注册机构,分为IssuerClusterIssuer,类似RBACRoleClusterRole的关系,这里我们设置ClusterIssuer为模板,这样每个namespace在使用的时候都可以引用。

  • 因为是ClusterIssuer,所以并不需要指定namespace
  • spec.acme说明是以acme的方式申请证书。
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: i@spex.top
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}

2.3 Certificate

有注册机构了,接下来就可以申请证书了。

  • 因为我们使用的是ClusterIssuer,所以在spec.issuerRef中需要使用kind: ClusterIssuer。
  • metadata.name是secret名,最终会以这个名字存入secret供Ingress调用。
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: index.spex.top.tls
  namespace: nginx
spec:
  secretName: index.spex.top.com.tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - index.spex.top.com
  acme:
    config:
    - http01:
        ingressClass: nginx
      domains:
      - index.spex.top.com

查看证书:

kubectl get secret -n nginx
NAME                                       TYPE                                  DATA   AGE
cert-manager-token-sj7sz                   kubernetes.io/service-account-token   3      140m
cert-manager-webhook-ca                    kubernetes.io/tls                     3      135m
cert-manager-webhook-ca-sync-token-xfwnw   kubernetes.io/service-account-token   3      140m
cert-manager-webhook-token-s9rkl           kubernetes.io/service-account-token   3      140m
cert-manager-webhook-webhook-tls           kubernetes.io/tls                     3      135m
default-token-5hk8x                        kubernetes.io/service-account-token   3      4h58m
index.spex.top.tls                         kubernetes.io/tls                     3      61m
letsencrypt-prod                           Opaque                                1      62m

查看申请结果:

kubectl describe certificate -n nginx
···

Events:
  Type    Reason         Age   From          Message
  ----    ------         ----  ----          -------
  Normal  Generated      36m   cert-manager  Generated new private key
  Normal  OrderCreated   36m   cert-manager  Created Order resource "index.spex.top.tls-60021040"
  Normal  OrderComplete  30m   cert-manager  Order "index.spex.top.tls-60021040" completed successfully
  Normal  CertIssued     30m   cert-manager  Certificate issued successfully

2.4 更新Ingress

最后我们来更新刚刚的Ingress,增加来两个配置:

  • Annotations:nginx.ingress.kubernetes.io/ssl-redirect: "true" 这里是意思将Http 308重定向至Https,有两点需要注意,一是老旧的IE可能不支持308重定向,二是如果你映射Nginx-Ingress并不是使用80端口,而是别的,如8080,那么重定向将会错误,需要手动输入https://index.spex.top:8443
  • tls不同,这里就是用的刚刚Cert-Manager生成的secret证书。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-proxy-pass-ingress
  namespace: nginx
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  rules:
  - host: index.spex.top
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-proxy-pass
          servicePort: 80
  tls:
    - secretName: index.spex.top.tls
      hosts:
        - index.spex.top

3. 总结

可以看到最终选择了把证书放在了入口处,也就是Nginx-Ingress处,主要是为了简化内部的架构,内部完全是http的方式进行各种转发与代理。


感谢

1.Nginx Ingress 配置 HTTPS-吕啸腾的博客
2.在kubernetes上使用cert-manager自動更新Let’s Encrypt TLS憑證 - Ken Chen - Medium
3.利用cert-manager让Ingress启用免费的HTTPS证书 - imroc.io|roc的博客|Cloud Native|Kubernetes|Go|Golang
4.Installing on Kubernetes — cert-manager documentation

Last modification:August 27th, 2019 at 05:30 pm