专栏首页腾讯云TStack专栏玩转K8S AdmissionWebhook

玩转K8S AdmissionWebhook

ice yao

喜欢看动漫的IT男,还是火影迷、海贼迷、死神迷、妖尾迷、全职猎人迷、龙珠迷、网球王子迷

环境准备

  • OS: CentOS 7.5
  • Kubernetes v1.11.6
  • Etcd 3.3.10
  • Docker 1.13.1

什么是AdmissionWebhook

什么是AdmissionWebhook,就要先了解K8S中的admission controller, 按照官方的解释是: admission controller是拦截(经过身份验证)API Server请求的网关,并且可以修改请求对象或拒绝请求。

简而言之,它可以认为是拦截器,类似web框架中的middleware。

K8S默认提供很多内置的admission controller,通过kube-apiserver启动命令参数可以 查看到支持的admission controller plugin有哪些。

[root@node220]# kube-apiserver --help |grep enable-admission-plugins

# 支持的plugin有如下
AlwaysAdmit, AlwaysDeny, AlwaysPullImages, 
DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, 
DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, 
ImagePolicyWebhook, Initializers, LimitPodHardAntiAffinityTopology, 
LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, 
NamespaceExists, NamespaceLifecycle, NodeRestriction, 
OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, 
PersistentVolumeLabel, PodNodeSelector, PodPreset, PodSecurityPolicy, 
PodTolerationRestriction, Priority, ResourceQuota, SecurityContextDeny, 
ServiceAccount, StorageObjectInUseProtection, ValidatingAdmissionWebhook. 

这里enable的admission-plugins如下

--enable-admission-plugins=PersistentVolumeClaimResize,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,NodeRestriction,ValidatingAdmissionWebhook,MutatingAdmissionWebhook 

这里不对每个plugin详细说明,网上都可以搜到相关资料。 总体来说,admission-plugins分为三大类:

1.修改类型(mutating)

2.验证类型(validating)

3.既是修改又是验证类型(mutating&validating)

这些admission plugin构成一个顺序链,先后顺序决定谁先调用,但不会影响使用。

这里关心的plugin有两个

一、MutatingAdmissionWebhook, ValidatingAdmissionWebhook

  • MutatingAdmissionWebhook: 做修改操作的AdmissionWebhook 
  • ValidatingAdmissionWebhook: 做验证操作的AdmissionWebhook

引用kubernetes官方博客的一张图来说明MutatingAdmissionWebhook和ValidatingAdmissionWebhook所处的位置:

解释下这个过程:

1.api请求到达K8S API Server 2.请求要先经过认证

  • kubectl调用需要kubeconfig
  • 直接调用K8S api需要证书+bearToken
  • client-go调用也需要kubeconfig

3.执行一连串的admission controller,包括MutatingAdmissionWebhook和ValidatingAdmissionWebhook, 先串行执行MutatingAdmission的Webhook list 4.对请求对象的schema进行校验 5.并行执行ValidatingAdmission的Webhook list 6.最后写入etcd

二. Initializers vs AdmissionWebhook区别

二者都能实现动态可扩展载入admission controller, Initializers是串行执行,在高并发场景容易导致对象停留在uninitialized状态,影响继续调度。 Alpha Initializers特性在k8s 1.14版本被移除了,详情见https://github.com/kubernetes/apimachinery/issues/60。 相比Initializers,官方更推荐AdmissionWebhook;MutatingAdmissionWebhook是串行执行,ValidatingAdmissionWebhook是并行执行,性能更好。

AdmissionWebhook应用场景

Istio相信大家都有听过,Istio就是采用AdmissionWebhook实现sidecar容器自动注入。我目前用到的应用场景有两个,当然肯定还有其它应用场景。

  • 自动打标签 比如启动一个应用,应用包括deployment、service、ingress; 怎么快速过滤出哪些资源属于应用? 在K8S中,pod、service、ingress 都是独立的资源,通过给这些资源打上label,是最快速的方式。
  • 自动注入sidecar容器 应用启动后,应用的监控、日志如何处理?借助sidecar容器注入到其pod中

收集应用日志的sidecar容器可以像下图所示,应用监控的sidecar容器类似

AdmissionWebhook demo

进入实战阶段,看demo

demo地址:https://github.com/yaoice/webhook-demo

实现的功能有:

  • 针对admission-webhook-example=enabled标签的命名空间生效
  • 自动打标签(pod、deplpoyment、service、ingress自动打上app.kubernetes.io/name=not_available的标签)
  • sidecar自动注入(pod自动带上nginx sidecar container)

克隆demo项目

git clone https://github.com/yaoice/webhook-demo.git

利用脚本(istio团队提供的)生成CertificateSigningRequest,再生成secret(给后面的webhook-api使用)

./deployment/webhook-create-signed-cert.sh 

利用脚本生成mutatingwebhook和validatingwebhook yaml,变量CA_BUNDLE自动从kubeconfig中获取

cat ./deployment/validatingwebhook.yaml | ./deployment/webhook-patch-ca-bundle.sh > ./deployment/validatingwebhook-ca-bundle.yaml
cat ./deployment/mutatingwebhook.yaml | ./deployment/webhook-patch-ca-bundle.sh > ./deployment/mutatingwebhook-ca-bundle.yaml  

编译镜像

docker build --rm -t test/admission-webhook-example:v1 -f docker/Dockerfile .

部署webhook-api

kubectl apply -f ./deployment/mutatingwebhook-ca-bundle.yaml 
kubectl apply -f ./deployment/validatingwebhook-ca-bundle.yaml
kubectl apply -f configmap.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f nginxconfigmap.yaml   # 这里sidecar是nginx, sidecar依赖的configmap

给default命名空间打label,只对admission-webhook-example标签的命名空间生效

kubectl label namespace default admission-webhook-example=enabled

部署一个busybox,sidecar是nginx

kubectl apply -f ./deployment/sleep.yaml

pod自动打上app.kubernetes.io/name标签, pod中有两个container

kubectl get pod sleep-5588cb5f94-5dl8f --show-labels 
NAME                     READY     STATUS    RESTARTS   AGE       LABELS
sleep-5588cb5f94-5dl8f   2/2       Running   0          27s       app.kubernetes.io/name=not_available,app=sleep,pod-template-hash=1144761950 

service自动打上app.kubernetes.io/name标签

kubectl get svc sleep --show-labels 
NAME      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE       LABELS
sleep     ClusterIP   10.68.4.5    <none>        80/TCP    4m        app.kubernetes.io/name=not_available

ingress自动打上app.kubernetes.io/name标签

kubectl get ingresses.extensions sleep --show-labels 
NAME      HOSTS          ADDRESS   PORTS     AGE       LABELS
sleep     xx.sleep.com             80        4m        app.kubernetes.io/name=not_available

开发调试

如果K8S装在远端Server上,在本地如何调试?

1. 在goland中启动webhook api, 监听在本地6443

2. 利用ssh反向代理

ssh -R 6443:127.0.0.1:6443 root@<k8s-master-ip>

监听在K8S Server上的6443,会重定向到本地的6443

3. 利用K8S headless service指向k8s-master-ip的6443

[root@node66 ~]# cat /data/deployment/service.yaml 
 apiVersion: v1
 kind: Service
 metadata:
   name: admission-webhook-example-svc
 spec:
   ports:
   - port: 443
     targetPort: 6443

 ---
 apiVersion: v1
 kind: Endpoints
 metadata:
   name: admission-webhook-example-svc
 subsets:
   - addresses:
       - ip: <k8s-master-ip>
     ports:
       - port: 6443

执行上述操作步骤后,在本地就可以设置断点调试了

发散思维

AdmissionWebhook多集群应用

如果有多个K8S集群,那是不是要在每个集群都启动一个Webhook API呢?所以就有了下面的架构,所有集群共享一个Webhook API。

cluster c1、c2中的Webhook配置会指向各自集群内部的service,这个service其实是headless service, 它指向的是cluster A的service(需要暴露给其它集群能够访问,nodePort也可以),这样所有集群就共享一个Webhook API了。

总结

AdmissionWebhook可以像拦截器一样拦截K8S api请求,要实现修改功能用MutatingAdmissionWebhook, 实现验证功能用ValidatingAdmissionWebhook。

写一个AdmissionWebhook API的要点:

1.AdmissionReview结构体 request请求信息通过AdmissionReview的Request字段可以获取到; response通过AdmissionReview的Response字段设置返回

// AdmissionReview describes an admission review request/response.
 type AdmissionReview struct {
     metav1.TypeMeta `json:",inline"`
     // Request describes the attributes for the admission request.
     // +optional
     Request *AdmissionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"`
     // Response describes the attributes for the admission response.
     // +optional
     Response *AdmissionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"`
 }

2.mutating是通过json patch方式实现的,对应的结构体定义如下:

 type patchOperation struct {
   Op    string      `json:"op"`
   Path  string      `json:"path"`
   Value interface{} `json:"value,omitempty"`
 }

 patches = append(patches, patchOperation{
   Op:    "add",
   Path: "/metadata/annotations",
   Value: true,
 })

参考链接

  • https://github.com/morvencao/kube-mutating-webhook-tutorial
  • https://github.com/banzaicloud/admission-webhook-example
  • https://banzaicloud.com/blog/k8s-admission-webhooks/
  • https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/

本文分享自微信公众号 - 腾讯云TStack(gh_035269c8aa5f),作者:ice yao

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 腾讯的一个应用服务,让全国短信诈骗发案率下降74%…

    麒麟由腾讯安全反诈骗实验室研发,是 TStack 平台里的一个重要的应用服务。通过地图,从空间、时间维度,直观的呈现伪基站的聚类的传播区域和实时运动轨迹,为警方...

    腾讯云TStack
  • 鲜肉除了会教你弹吉他,还能教你···

    那这个文件内如此多的设备哪些是物理硬盘呢?只要达到下面两个限制条件就判定为物理硬盘。

    腾讯云TStack
  • 五分钟聊T-SQL:数据压缩

    传说中数据压缩能压缩到原始数据的1/10,但是... ... 但是至少目前为止我还没遇到过这样的情形,通常情况下能压缩到原始数据的1/5-2/5的样子。

    腾讯云TStack
  • MySQL中的哥哥表、妹妹字段,是什么鬼?

    晚上,我被叫进宽大的办公室,总监正在煮茶。高压锅煮着长嘴茶壶,水蒸气缭绕。领导举手之间,淡黄茶水奔涌而出,倒立而下浇上茶叶,漏出两杯茶水。

    xjjdog
  • 数据库PostrageSQL-文件系统级别备份

    另外一种备份策略是直接复制PostgreSQL用于存储数据库中数据的文件,Section 18.2解释了这些文件的位置。你可以采用任何你喜欢的方式进行文件系统备...

    cwl_java
  • java每日一题20201022

    大家好,我是向同学,从今天继续每日一题,旨在为提高大家的基础知识。话说干了这么多年的开发,只知道会用,怎么用,用什么,隐约也知道了为什么用,但为啥JAVA总像一...

    用户7656790
  • 怎么理解Unicode,utf-8,ASCII这些编码?

    昨天文章发出来后,有几个读者问我,编码这块怎么掌握,感觉总是很模糊,就知道个utf-8编码,到底如何掌握。

    double
  • PHP数据结构(八) ——赫夫曼树实现字符串编解码(实践2)

    PHP数据结构(八)——赫夫曼树实现字符串编解码(实践2) (原创内容,转载请注明来源,谢谢) 公众号规定不能超过3000字,只能分两篇,见谅。 由于需要分两篇...

    用户1327360
  • Structured Streaming如何实现Parquet存储目录按时间分区

    StreamingPro现在支持以SQL脚本的形式写Structured Streaming流式程序了: mlsql-stream。不过期间遇到个问题,我希望按...

    用户2936994
  • iOS上传图片视图的封装【支持删除和添加】(采用Masonry进行布局,MVVM结构)

    demo源码下载:https://download.csdn.net/download/u011018979/15868813

    公众号iOS逆向

扫码关注云+社区

领取腾讯云代金券