为什么要管理TLS Secret证书
使用ingress将服务以https暴露到集群外边时,需要ssl证书。在https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tls这个例子中, ingress的定义如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo
namespace: default
spec:
tls:
- hosts:
- foo.bar.com
secretName: foo-secret
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: echoheaders-x
servicePort: 80
path: /对于域名foo.bar.com的证书引用的是相同namespace下的secret foo-secret。
这说明在Kubernetes中管理站点的TLS证书,使用的是Secret。
假设在已经取得foo.bar.com的证书和私钥分别为foo.bar.com.crt和foo.bar.com.key,使用下面的命令就可以在default命名空间中创建TLS类型的Secret:
kubectl create secret tls foo-secret --cert=foo.bar.com.crt --key=foo.bar.com.key -n default实际情况中,我们的证书往往都是泛域名的证书,例如对于frognew.com,是支持*.frognew.com所有的二级域名的。
不同的服务的Ingress被创建在不同的namespace中,每个namespace中都需要创建TLS Secret。
因此需要一种更加整合和高效的方式管理TLS Secret。
先来看一下微服务在开发和部署上要考虑的两个问题:
- 微服务在开发上需要考虑如何“拆”的问题(拆分的时机、拆分的粒度、拆分的方式)
- 微服务在部署时需要考虑整合与集成的问题,即如何“合”
使用helm管理Ingress的TLS Secret证书
一个产品由多个微服务组成,这个产品部署到Kubernetes上,每个服务都可能需要在Kubernetes上创建下面几种资源:Ingress, Service, Deployment, ConfigMap, Secret,Job,CronJob等等。我们已经使用Helm,将产品的各个微服务在部署上当成一个逻辑整体,即为每个产品创建一个helm chart,这个helmchart包含了产品所有微服务的部署,将前面每个服务所需要的资源模板化。本篇要解决的是如何整合和高效的管理Ingress的TLS Secret,即将TLS Secret的创建也集成到产品的这个helm chart中。
helm的模板功能十分强大,这里演示一下如何使用heml chart在Kubernetes管理TLS证书,先简单实现一下:
chart的模板文件tls-secrets.yaml:
{% raw %}
{{- range $tlsSecretName, $tlsSecret := .Values.tlsSecrets }}
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
name: {{ $tlsSecretName }}
labels:
chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }}
release: {{ $.Release.Name }}
heritage: {{ $.Release.Service }}
data:
tls.crt: {{ $tlsSecret.certificate | b64enc }}
tls.key: {{ $tlsSecret.key | b64enc }}
{{- end }}
{% endraw %}values.yaml:
tlsSecrets:
foo-secret:
certificate: |-
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----
key: |-
-----BEGIN PRIVATE KEY-----
......
-----END PRIVATE KEY----- values.yaml中提供每个TLS Secret的证书和私钥的文本内容,在tls-secrets.yaml中使用模板的b64enc函数,将证书内容编码成Secret所需的Base64。 这样TLS Secret也使用helm管理起来了。
我们的实践
我们实际实践中使用的是另一种方式,利用了helm的文件访问功能Accessing Files Inside Templates。
将证书文件直接放到Chart目录的files子目录下:
.
├── charts
├── Chart.yaml
├── files
│ └── frognew.com
│ ├── cert.pem
│ ├── chain.pem
│ ├── fullchain.pem
│ ├── privkey.pem
│ └── README
├── templates
├── ......
│ └── tls-secrets.yaml
├── values.yamlchart的模板文件tls-secrets.yaml:
{% raw %}
{{- range $tlsSecretName, $tlsSecret := .Values.tlsSecrets }}
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
name: {{ $tlsSecretName }}
labels:
chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }}
release: {{ $.Release.Name }}
heritage: {{ $.Release.Service }}
data:
tls.crt: {{ $.Files.Get $tlsSecret.certificate | b64enc }}
tls.key: {{ $.Files.Get $tlsSecret.key | b64enc }}
{{- end }}
{% endraw %}values.yaml:
tlsSecrets:
frognew-tls-secret:
certificate: "files/frognew.com/fullchain.pem"
key: "files/frognew.com/privkey.pem"使用Files.Get去读取证书文件内容,通过b64enc编码为Base64。
- 这种将证书文件放到Chart中的使用方式需要注意受限于Kubernetes限制,Chart的大小不能超过1MB。
- 关于在Helm模板中访问文件的能力还有很多高级用法,具体可以查看Accessing Files Inside Templates
总结
本文介绍了如何使用Helm在Kubernetes中整合管理Ingress的TLS Secret证书,其实对于其它类型的Secret也是通用的。例如对于Opaque Secret、kubernetes.io/dockercfg Secret都可以纳入到helm chart管理中。这样部署一个应用所需要的所有资源就全部纳入Helm Chart管理了。