前言

说到免费的SSL证书,大家首先想到的肯定是Let’s Encrypt,而使用过Let’s Encrypt的同学应该也知道,其有效期只有三个月,三个月后要重新续期。github上也有类似的脚本可以做到自动续期。那如果是在k8s上使用该免费证书,又如何操作的呢?这里cert-manager就派上用场了。

环境

主机名

ip

角色

mldong01

192.168.0.245

master

mldong02

192.168.0.54

node01

mldong03

192.168.0.22

node02

三台主机为华为软开云的ECS,CentOS Linux release 7.6.1810 (Core)

什么是cert-manager

cert-manager 是一个云原生证书管理开源项目,用于在 Kubernetes 集群中提供 HTTPS 证书并自动续期,支持 Let’s Encrypt, HashiCorp Vault 这些免费证书的签发。在Kubernetes集群中,我们可以通过 Kubernetes Ingress 和 Let’s Encrypt 实现外部服务的自动化 HTTPS。

在Kubernetes集群中使用 HTTPS 协议,需要一个证书管理器、一个证书自动签发服务,主要通过 Ingress 来发布 HTTPS 服务,因此需要Ingress Controller并进行配置,启用 HTTPS 及其路由。

k8s中部署jenkins k8s中部署letsencrypt_github

  • Issuer/ClusterIssuer: 用于指示 cert-manager 用什么方式签发证书,本文主要讲解签发免费证书的 ACME 方式。ClusterIssuer 与 Issuer 的唯一区别就是 Issuer 只能用来签发自己所在 namespace 下的证书,ClusterIssuer 可以签发任意 namespace 下的证书。
  • Certificate: 用于告诉 cert-manager 我们想要什么域名的证书以及签发证书所需要的一些配置,包括对 Issuer/ClusterIssuer 的引用。

安装cert-manager

安装方式一

  1. 添加Jestack Helm存储库
helm repo add jetstack https://charts.jetstack.io
  1. 本地仓库搜
helm search repo cert-manager
  1. 创建命名空间
kubectl create namespace cert-manager
  1. 开始安装
helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --version v1.1.0 \
  --set installCRDs=true # 这个要开启,要不然创建ClusterIssuer会报错

这里可能存在一个坑,就是拉取镜像失败,pod创建失败,可以提前下载镜像-所有worker节点

## 注意版本号
docker pull quay.io/jetstack/cert-manager-cainjector:v1.1.0
docker pull quay.io/jetstack/cert-manager-controller:v1.1.0
docker quay.io/jetstack/cert-manager-webhook:v1.1.0
  1. 查看安装情况
kubectl get pods -n cert-manager -w
docker pull quay.io/jetstack/cert-manager-cainjector:v1.1.0
docker pull quay.io/jetstack/cert-manager-controller:v1.1.0
docker quay.io/jetstack/cert-manager-webhook:v1.1.0

k8s中部署jenkins k8s中部署letsencrypt_docker_02

k8s中部署jenkins k8s中部署letsencrypt_nginx_03

  1. 卸载(按需)
helm uninstall cert-manager -n cert-manager
  1. 删除命名空间(按需)
kubectl delete ns cert-manager

安装方式二

  • 安装cert-manager
# Kubernetes 1.16+
$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager.yaml

# Kubernetes <1.16
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager-legacy.yaml
  • 安装crds-要不然创建ClusterIssuer会报错
# Kubernetes 1.15+
$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager.crds.yaml

# Kubernetes <1.15
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager-legacy.crds.yaml

cert-manager使用案例

  1. 创建一个集群级的签发机构
# 配置
cat <<EOF >  cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
      name: letsencrypt-prod
    solvers:    
    - http01:
        ingress:
          class: nginx
EOF

说明:

  • metadata.name 是我们创建的签发机构的名称,后面我们创建证书的时候会引用它
  • spec.acme.email 是你自己的邮箱,证书快过期的时候会有邮件提醒,不过 cert-manager 会利用 acme 协议自动给我们重新颁发证书来续期
  • spec.acme.server 是 acme 协议的服务端,我们这里用 Let’s Encrypt,这个地址就写死成这样就行
  • spec.acme.privateKeySecretRef 指示此签发机构的私钥将要存储到哪个 Secret 对象中,名称不重要
  • spec.acme.http01 这里指示签发机构使用 HTTP-01 的方式进行 acme 协议 (还可以用 DNS 方式,acme 协议的目的是证明这台机器和域名都是属于你的,然后才准许给你颁发证书)
# 执行发布命令
kubectl apply -f cluster-issuer.yaml
  1. 域名解析添加A记录-记录值为集群中的任意worker节点,这里是阿里云
  2. 创建一个命名空间
kubectl create ns mldong-test
  1. 创建一个证书
# 配置
cat <<EOF >  b-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: b.mldong.com-tls
  namespace: mldong-test
spec:
  secretName: b.mldong.com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - b.mldong.com
EOF

说明:

  • spec.secretName 指示证书最终存到哪个 Secret 中
  • spec.issuerRef.kind 值为 ClusterIssuer 说明签发机构不在本 namespace 下,而是在全局
  • spec.issuerRef.name 我们创建的签发机构的名称 (ClusterIssuer.metadata.name)
  • spec.dnsNames 指示该证书的可以用于哪些域名,与域名解析的一致
  1. 另开终端查看cert-manager运行日志
kubectl logs -f $(kubectl get pods -n cert-manager | grep cert-manager | grep -v 'cainjector\|webhook' | awk '{print $1}') -n cert-manager
  1. 当然,也可以查看临时生成的专门验证证书的 Ingress 对象的运行情况
kubectl get pods -n mldong-test -w

临时对象cm-acme-http-solver-xxxx从创建到消亡的过程

k8s中部署jenkins k8s中部署letsencrypt_docker_04

  1. 执行发布命令
kubectl apply -f b-cert.yaml
  1. 查看certificate创建结果
[root@mldong cert-manager]# kubectl get certificate -n mldong-test
NAME               READY   SECRET             AGE
b.mldong.com-tls   True    b.mldong.com-tls   2m27s

当READY为True时即为成功,详细可看cert-manager运行日志。

发布一个nginx服务

上一篇已经装的阿里仓库中有nginx,我可以搜一下

  1. 本地仓库搜nginx
helm search repo nginx

k8s中部署jenkins k8s中部署letsencrypt_github_05

  1. 查看nginx配置说明
helm show values aliyuncs/nginx

详细配置说明见:https://github.com/bitnami/charts/tree/master/bitnami/nginx/

  1. 新建一个values.yaml配置
cat <<EOF >  nginx-values.yaml
ingress: 
  enabled: true
  hostname: b.mldong.com
  tls:
    - hosts:
      - b.mldong.com
      secretName: b.mldong.com-tls
EOF

注意,这里的secertName要与上面生成的certificate保持一致

  1. 安装nginx
helm install nginx aliyuncs/nginx -f nginx-values.yaml -n mldong-test
  1. 查看部署情况
kubectl get svc --namespace mldong-test -w nginx
  1. 我们也可以查看一下ingress的详情
kubectl get ingress nginx -o yaml -n mldong-test

k8s中部署jenkins k8s中部署letsencrypt_nginx_06

  1. 浏览器访问效果
  2. 删除nginx(按需)
helm uninstall nginx -n mldong-test

小结

使用cert-manager来管理https证书,是不是很方便?值得一得的是,当你第一次创建完certificate,之后续期啥都由cert-manager来自动管理,贼省心。这里简单总结一下流程。

  • 创建一个集群级的签发机构-ClusterIssuer-仅第一次需要
  • 添加一条域名解析记录-指向集群的任意worker节点
  • 根据解析的域名生成certificate
  • 发布应用
  • 发布Pod
  • 发布Service
  • 发布Ingress-这里配置tls证书,指向certificate