前言
关于webhook的应用场景网络上有很多介绍,这里就不再阐述了,这篇文章将带着我们从头开始部署自己的webhook。
本文适合对kubernetes和webhook有一定认知和了解的读者,帮助读者快速部署自己的webhook,话不多说直接开始。
准备
- 您需要会容器和镜像的知识,至少确保您会制作与运行镜像。
- 您已经部署好kubernetes环境。
- 您或许需要有一定编码来编写自己的webhook。
编写webhook服务
webhook是一个web服务,对外提供http接口供kubernetes调用,接口的定义参考:webhook请求与响应。
目前各语言都有一些对开源依赖提供了对webhook请求对象的封装,笔者使用Java开发的webhook,使用了如下Maven依赖:
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model</artifactId>
<version>5.5.0</version>
</dependency>
接口代码如下:
@RequestMapping("/validate")
public AdmissionReview validateAdmissionReview(@RequestBody AdmissionReview requestBody) {
AdmissionRequest request = requestBody.getRequest();
AdmissionResponse response = new AdmissionResponse();
response.setAllowed(true);
response.setUid(request.getUid());
requestBody.setResponse(response);
return requestBody;
}
另外webhook服务被要求提供HTTPS服务,所以我们需要为服务创建证书。
证书创建
kubernetes要求webhook使用带有SAN的证书,这里直接为大家提供生成脚本(请准备好openssl,按顺序执行一遍):
# 根密钥
openssl genpkey -algorithm RSA -out ca_key.pem -aes256
# 根证书生成请求
openssl req -sha256 -new -key ca_key.pem -out ca.csr
# 签名生成根证书
openssl x509 -req -sha256 -in ca.csr -signkey ca_key.pem -out ca.pem
# 生成服务器密钥和服务器证书请求
openssl req -sha256 -newkey rsa:2048 -nodes -keyout key.pem -out csr.pem -config cert.conf
# 用根证书签署请求文件得到服务器证书
openssl x509 -req -sha256 -in ca.csr -out cert.pem -CA ca.pem -CAkey ca_key.pem -CAcreateserial -days 365 -extensions v3_req -extfile cert.conf
# 服务器证书+根密钥打包为PKCS12
openssl pkcs12 -export -in cert.pem -inkey ca_key.pem -out cert.p12
其中 cert.conf
文件内容如下:
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = webhooks.default.svc
DNS.2 = webhooks
DNS.3 = webhooks.default.cluster.local
cert.conf
的 DNS 列出了证书生效的域名,这里根据webhook在集群中实际访问域名修改。
执行命令过程中会要求输入一些信息如下:
Enter PEM pass phrase:
上面的信息提示我们为密钥设置密码,最少4位数,如:1234.
Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:webhooks.default.svc
Email Address []:
需要注意 Common Name
是webhook的域名,需要根据实际访问域名做调整。
最终生成的 cert.p12
就是服务器证书的 PKCS12 文件,将证书配在服务中即可,如下以Springboot项目为例配置yaml:
server:
ssl:
key-store-type: PKCS12
key-store: classpath:cert.p12
key-store-password: 1234
enabled: true
port: 443
至此 webhook 服务本身的工作基本完成,可以先在本地用浏览器测试接口和证书的正确性(添加系统根证书)。
将 webhook 部署到 kubernetes
首先我们需要将webhook打包成镜像,这里就不再讲解打包镜像的方法。
这里我直接贴出webhook的deployment.yaml (其实就是部署Deployment和Service):
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webhooks
name: webhooks
namespace: default
spec:
selector:
matchLabels:
app: webhooks
template:
metadata:
labels:
app: webhooks
spec:
containers:
- image: 'k8s-webhooks:latest'
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 443
timeoutSeconds: 5
name: webhooks
ports:
- containerPort: 443
name: https
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
annotations: {}
labels:
app: webhooks
name: webhooks
namespace: default
spec:
clusterIP: None
clusterIPs:
- None
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: 5nb2b7
port: 443
protocol: TCP
targetPort: 443
selector:
app: webhooks
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
至此,我们可以验证一下kubernetes中的webhook和service是否能正常访问。
添加RBAC
webhook需要一个用户承载监听和修改对象的权限(可以参考如下yaml创建):
apiVersion: v1
kind: ServiceAccount
metadata:
name: admission-webhook
labels:
app: admission-webhook
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: admission-webhook-cr
labels:
app: admission-webhook
rules:
- apiGroups:
- qikqiak.com
resources:
- "*"
verbs:
- "*"
- apiGroups:
- ""
resources:
- pods
- events
verbs:
- "*"
- apiGroups:
- apps
resources:
- deployments
- daemonsets
- replicasets
- statefulsets
verbs:
- "*"
- apiGroups:
- autoscaling
resources:
- '*'
verbs:
- '*'
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admission-webhook-crb
labels:
app: admission-webhook
subjects:
- kind: ServiceAccount
name: admission-webhook-sa
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admission-webhook-cr
创建 webhook 对象
最后我们在 kubernetes 中部署一个 MutatingWebhookConfiguration:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: mutating-webhook-cfg
labels:
app: admission-webhook
webhooks:
- name: mutating-k8s.webhook.hkvax.com
clientConfig:
service:
name: webhooks
namespace: default
path: "/validate"
port: 443
caBundle: $CA_BUNDLE
sideEffects: None
admissionReviewVersions: ["v1", "v1beta1"]
rules:
- operations: [ "CREATE","UPDATE" ]
apiGroups: ["apps", ""]
apiVersions: ["v1"]
resources: ["deployments","services"]
objectSelector:
matchLabels:
admission-webhook: enabled
objectSelector
字段中指定了webhook的匹配规则,这里只匹配了标签中拥有admission-webhook: enabled
的对象。
yaml中 $CA_BUNDLE 是webhook服务的根证书(BASE64编码),可以直接通过以下脚本获取:
$(< ca.pem base64 | tr -d '\n')
其中 ca.pem
是我们在篇头创建证书时生成的文件。
验证
我们可以通过 kubectl
修改 deployment, 添加admission-webhook: enabled
标签后保存。具体指令如下:
kubectl edit deployment xxx
当然我们也可以通过譬如kubord这样的管理控制台直接修改。
修改完成后观察 webhook 服务中的日志,如果webhook正常收到了请求则表示证书没有问题(笔者在证书环境卡了很长时间,最终才得出了文中给出的证书脚本)。