Tips
Go
(18条消息) Go语言自学系列 | golang包_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之channel的遍历_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之select switch_COCOgsta的博客-CSDN博客_golang select switch
(18条消息) Go语言自学系列 | golang并发编程之runtime包_COCOgsta的博客-CSDN博客_golang runtime包
(18条消息) Go语言自学系列 | golang接口值类型接收者和指针类型接收者_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之Timer_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang方法_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之WaitGroup实现同步_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang构造函数_COCOgsta的博客-CSDN博客_golang 构造函数
(18条消息) Go语言自学系列 | golang方法接收者类型_COCOgsta的博客-CSDN博客_golang 方法接收者
(18条消息) Go语言自学系列 | golang接口_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang接口和类型的关系_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang结构体_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang结构体_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang标准库os模块 - File文件读操作_COCOgsta的博客-CSDN博客_golang os.file
(18条消息) Go语言自学系列 | golang继承_COCOgsta的博客-CSDN博客_golang 继承
(18条消息) Go语言自学系列 | golang嵌套结构体_COCOgsta的博客-CSDN博客_golang 结构体嵌套
(18条消息) Go语言自学系列 | golang并发编程之Mutex互斥锁实现同步_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发变成之通道channel_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之原子操作详解_COCOgsta的博客-CSDN博客_golang 原子操作
(18条消息) Go语言自学系列 | golang并发编程之原子变量的引入_COCOgsta的博客-CSDN博客_go 原子变量
(18条消息) Go语言自学系列 | golang并发编程之协程_COCOgsta的博客-CSDN博客_golang 协程 并发
(18条消息) Go语言自学系列 | golang接口嵌套_COCOgsta的博客-CSDN博客_golang 接口嵌套
(18条消息) Go语言自学系列 | golang包管理工具go module_COCOgsta的博客-CSDN博客_golang 包管理器
(18条消息) Go语言自学系列 | golang标准库os模块 - File文件写操作_COCOgsta的博客-CSDN博客_go os模块
(18条消息) Go语言自学系列 | golang结构体的初始化_COCOgsta的博客-CSDN博客_golang 结构体初始化
(18条消息) Go语言自学系列 | golang通过接口实现OCP设计原则_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang标准库os包进程相关操作_COCOgsta的博客-CSDN博客_golang os包
(18条消息) Go语言自学系列 | golang标准库ioutil包_COCOgsta的博客-CSDN博客_golang ioutil
(18条消息) Go语言自学系列 | golang标准库os模块 - 文件目录相关_COCOgsta的博客-CSDN博客_go语言os库
Golang技术栈,Golang文章、教程、视频分享!
(18条消息) Go语言自学系列 | golang结构体指针_COCOgsta的博客-CSDN博客_golang 结构体指针
Ansible
太厉害了,终于有人能把Ansible讲的明明白白了,建议收藏_互联网老辛
ansible.cfg配置详解
Docker
Docker部署
linux安装docker和Docker Compose
linux 安装 docker
Docker中安装Docker遇到的问题处理
Docker常用命令
docker常用命令小结
docker 彻底卸载
Docker pull 时报错:Get https://registry-1.docker.io/v2/library/mysql: net/http: TLS handshake timeout
Docker 拉镜像无法访问 registry-x.docker.io 问题(Centos7)
docker 容器内没有权限
Linux中关闭selinux的方法是什么?
docker run 生成 docker-compose
Docker覆盖网络部署
docker pull后台拉取镜像
docker hub
Redis
Redis 集群别乱搭,这才是正确的姿势
linux_离线_redis安装
怎么实现Redis的高可用?(主从、哨兵、集群) - 雨点的名字 - 博客园
redis集群离线安装
always-show-logo yes
Redis集群搭建及原理
[ERR] Node 172.168.63.202:7001 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or contains some - 亲爱的不二999 - 博客园
Redis daemonize介绍
redis 下载地址
Redis的redis.conf配置注释详解(三) - 云+社区 - 腾讯云
Redis的redis.conf配置注释详解(一) - 云+社区 - 腾讯云
Redis的redis.conf配置注释详解(二) - 云+社区 - 腾讯云
Redis的redis.conf配置注释详解(四) - 云+社区 - 腾讯云
Linux
在终端连接ssh的断开关闭退出的方法
漏洞扫描 - 灰信网(软件开发博客聚合)
find 命令的参数详解
vim 编辑器搜索功能
非root安装rpm时,mockbuild does not exist
Using a SSH password instead of a key is not possible because Host Key checking
(9条消息) 安全扫描5353端口mDNS服务漏洞问题_NamiJava的博客-CSDN博客_5353端口
Linux中使用rpm命令安装rpm包
ssh-copy-id非22端口的使用方法
How To Resolve SSH Weak Key Exchange Algorithms on CentOS7 or RHEL7 - infotechys.com
Linux cp 命令
yum 下载全量依赖 rpm 包及离线安装(终极解决方案) - 叨叨软件测试 - 博客园
How To Resolve SSH Weak Key Exchange Algorithms on CentOS7 or RHEL7 - infotechys.com
RPM zlib 下载地址
运维架构网站
欢迎来到 Jinja2
/usr/local/bin/ss-server -uv -c /etc/shadowsocks-libev/config.json -f /var/run/s
ruby 安装Openssl 默认安装位置
Linux 常用命令学习 | 菜鸟教程
linux 重命名文件和文件夹
linux命令快速指南
ipvsadm
Linux 下查找日志中的关键字
Linux 切割大 log 日志
CentOS7 关于网络的设置
rsync 命令_Linux rsync 命令用法详解:远程数据同步工具
linux 可视化界面安装
[问题已处理]-执行yum卡住无响应
GCC/G++升级高版本
ELK
Docker部署ELK
ELK+kafka+filebeat+Prometheus+Grafana - SegmentFault 思否
(9条消息) Elasticsearch设置账号密码_huas_xq的博客-CSDN博客_elasticsearch设置密码
Elasticsearch 7.X 性能优化
Elasticsearch-滚动更新
Elasticsearch 的内存优化_大数据系统
Elasticsearch之yml配置文件
ES 索引为Yellow状态
Logstash:Grok filter 入门
logstash grok 多项匹配
Mysql
Mysql相关Tip
基于ShardingJDBC实现数据库读写分离 - 墨天轮
MySQL-MHA高可用方案
京东三面:我要查询千万级数据量的表,怎么操作?
OpenStack
(16条消息) openstack项目中遇到的各种问题总结 其二(云主机迁移、ceph及扩展分区)_weixin_34104341的博客-CSDN博客
OpenStack组件介绍
百度大佬OpenStack流程
openstack各组件介绍
OpenStack生产实际问题总结(一)
OpenStack Train版离线部署
使用Packstack搭建OpenStack
K8S
K8S部署
K8S 集群部署
kubeadm 重新 init 和 join-pudn.com
Kubernetes 实战总结 - 阿里云 ECS 自建 K8S 集群 Kubernetes 实战总结 - 自定义 Prometheus
【K8S实战系列-清理篇1】k8s docker 删除没用的资源
Flannel Pod Bug汇总
Java
Jdk 部署
JDK部署
java线程池ThreadPoolExecutor类使用详解 - bigfan - 博客园
ShardingJDBC实现多数据库节点分库分表 - 墨天轮
Maven Repository: Search/Browse/Explore
其他
Git在阿里,我们如何管理代码分支?
chrome F12调试网页出现Paused in debugger
体验IntelliJ IDEA的远程开发(Remote Development) - 掘金
Idea远程调试
PDF转MD
强哥分享干货
优秀开源项目集合
vercel 配合Github 搭建项目Doc门户
如何用 Github Issues 写技术博客?
Idea 2021.3 Maven 3.8.1 报错 Blocked mirror for repositories 解决
列出maven依赖
[2022-09 持续更新] 谷歌 google 镜像 / Sci-Hub 可用网址 / Github 镜像可用网址总结
阿里云ECS迁移
linux访问github
一文教你使用 Docker 启动并安装 Nacos-腾讯云开发者社区-腾讯云
Nginx
Nginx 部署
Nginx 部署安装
Nginx反向代理cookie丢失的问题_longzhoufeng的博客-CSDN博客_nginx 代理后cookie丢失
Linux 系统 Https 证书生成与Nginx配置 https
数据仓库
实时数仓
松果出行 x StarRocks:实时数仓新范式的实践之路
实时数据仓库的一些分层和分层需要处理的事情,以及数据流向
湖仓一体电商项目
湖仓一体电商项目(一):项目背景和架构介绍
湖仓一体电商项目(二):项目使用技术及版本和基础环境准备
湖仓一体电商项目(三):3万字带你从头开始搭建12个大数据项目基础组件
数仓笔记
数仓学习总结
数仓常用平台和框架
数仓学习笔记
数仓技术选型
尚硅谷教程
尚硅谷学习笔记
尚硅谷所有已知的课件资料
尚硅谷大数据项目之尚品汇(11数据质量管理V4.0)
尚硅谷大数据项目之尚品汇(10元数据管理AtlasV4.0)
尚硅谷大数据项目之尚品汇(9权限管理RangerV4.0)
尚硅谷大数据项目之尚品汇(8安全环境实战V4.0)
尚硅谷大数据项目之尚品汇(7用户认证KerberosV4.1)
尚硅谷大数据项目之尚品汇(6集群监控ZabbixV4.1)
尚硅谷大数据项目之尚品汇(5即席查询PrestoKylinV4.0)
尚硅谷大数据项目之尚品汇(4可视化报表SupersetV4.0)
尚硅谷大数据项目之尚品汇(3数据仓库系统)V4.2.0
尚硅谷大数据项目之尚品汇(2业务数据采集平台)V4.1.0
尚硅谷大数据项目之尚品汇(1用户行为采集平台)V4.1.0
数仓治理
数据中台 元数据规范
数据中台的那些 “经验与陷阱”
2万字详解数据仓库数据指标数据治理体系建设方法论
数据仓库,为什么需要分层建设和管理? | 人人都是产品经理
网易数帆数据治理演进
数仓技术
一文看懂大数据生态圈完整知识体系
阿里云—升舱 - 数据仓库升级白皮书
最全企业级数仓建设迭代版(4W字建议收藏)
基于Hue,Dolphinscheduler,HIVE分析数据仓库层级实现及项目需求案例实践分析
详解数据仓库分层架构
数据仓库技术细节
大数据平台组件介绍
总览 2016-2021 年全球机器学习、人工智能和大数据行业技术地图
Apache DolphinScheduler 3.0.0 正式版发布!
数据仓库面试题——介绍下数据仓库
数据仓库为什么要分层,各层的作用是什么
Databend v0.8 发布,基于 Rust 开发的现代化云数据仓库 - OSCHINA - 中文开源技术交流社区
数据中台
数据中台设计
大数据同步工具之 FlinkCDC/Canal/Debezium 对比
有数数据开发平台文档
Shell
Linux Shell 命令参数
shell 脚本编程
一篇教会你写 90% 的 Shell 脚本
Kibana
Kibana 查询语言(KQL)
Kibana:在 Kibana 中的四种表格制作方式
Kafka
Kafka部署
canal 动态监控 Mysql,将 binlog 日志解析后,把采集到的数据发送到 Kafka
OpenApi
OpenAPI 标准规范,了解一下?
OpenApi学术论文
贵阳市政府数据开放平台设计与实现
OpenAPI简介
开放平台:运营模式与技术架构研究综述
管理
技术部门Leader是不是一定要技术大牛担任?
华为管理体系流程介绍
DevOps
*Ops
XOps 已经成为一个流行的术语 - 它是什么?
Practical Linux DevOps
Jenkins 2.x实践指南 (翟志军)
Jenkins 2权威指南 ((美)布伦特·莱斯特(Brent Laster)
DevOps组件高可用的思路
KeepAlived
VIP + KEEPALIVED + LVS 遇到Connection Peer的问题的解决
MinIO
MinIO部署
Minio 分布式集群搭建部署
Minio 入门系列【16】Minio 分片上传文件 putObject 接口流程源码分析
MinioAPI 浅入及问题
部署 minio 兼容 aws S3 模式
超详细分布式对象存储 MinIO 实战教程
Hadoop
Hadoop 部署
Hadoop集群部署
windows 搭建 hadoop 环境(解决 HADOOP_HOME and hadoop.home.dir are unset
Hadoop 集群搭建和简单应用(参考下文)
Hadoop 启动 NameNode 报错 ERROR: Cannot set priority of namenode process 2639
jps 命令查看 DataNode 进程不见了 (hadoop3.0 亲测可用)
hadoop 报错: Operation category READ is not supported in state standby
Spark
Spark 部署
Spark 集群部署
spark 心跳超时分析 Cannot receive any reply in 120 seconds
Spark学习笔记
apache spark - Failed to find data source: parquet, when building with sbt assembly
Spark Thrift Server 架构和原理介绍
InLong
InLong 部署
Apache InLong部署文档
安装部署 - Docker 部署 - 《Apache InLong v1.2 中文文档》 - 书栈网 · BookStack
基于 Apache Flink SQL 的 InLong Sort ETL 方案解析
关于 Apache Pulsar 在 Apache InLong 接入数据
zookeeper
zookeeper 部署
使用 Docker 搭建 Zookeeper 集群
美团技术团队
StarRocks
StarRocks技术白皮书(在线版)
JuiceFS
AI 场景存储优化:云知声超算平台基于 JuiceFS 的存储实践
JuiceFS 在 Elasticsearch/ClickHouse 温冷数据存储中的实践
JuiceFS format
元数据备份和恢复 | JuiceFS Document Center
JuiceFS 元数据引擎选型指南
Apache Hudi 使用文件聚类功能 (Clustering) 解决小文件过多的问题
普罗米修斯
k8s 之 Prometheus(普罗米修斯)监控,简单梳理下 K8S 监控流程
k8s 部署 - 使用helm3部署监控prometheus(普罗米修斯),从零到有,一文搞定
k8s 部署 - 使用 helm3 部署监控 prometheus(普罗米修斯),从零到有,一文搞定
k8s 部署 - 如何完善 k8s 中 Prometheus(普罗米修斯)监控项目呢?
k8s 部署 - k8s 中 Prometheus(普罗米修斯)的大屏展示 Grafana + 监控报警
zabbix
一文带你掌握 Zabbix 监控系统
Stream Collectors
Nvidia
Nvidia API
CUDA Nvidia驱动安装
NVIDIA驱动失效简单解决方案:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver.
ubuntu 20 CUDA12.1安装流程
nvidia开启持久化模式
nvidia-smi 开启持久化
Harbor
Harbor部署文档
Docker 爆出 it doesn't contain any IP SANs
pandoc
其他知识
大模型
COS 597G (Fall 2022): Understanding Large Language Models
如何优雅的使用各类LLM
ChatGLM3在线搜索功能升级
当ChatGLM3能用搜索引擎时
OCR神器,PDF、数学公式都能转
Stable Diffusion 动画animatediff-cli-prompt-travel
基于ERNIE Bot自定义虚拟数字人生成
pika负面提示词
开通GPT4的方式
GPT4网站
低价开通GPT Plus
大模型应用场景分享
AppAgent AutoGPT变体
机器学习
最大似然估计
权衡偏差(Bias)和方差(Variance)以最小化均方误差(Mean Squared Error, MSE)
伯努利分布
方差计算公式
均值的高斯分布估计
没有免费午餐定理
贝叶斯误差
非参数模型
最近邻回归
表示容量
最优容量
权重衰减
正则化项
Sora
Sora官方提示词
看完32篇论文,你大概就知道Sora如何炼成? |【经纬低调出品】
Sora论文
Sora 物理悖谬的几何解释
Sora 技术栈讨论
RAG垂直落地
DB-GPT与TeleChat-7B搭建相关RAG知识库
ChatWithRTX
ChatRTX安装教程
ChatWithRTX 踩坑记录
ChatWithRTX 使用其他量化模型
ChatWithRTX介绍
RAG 相关资料
英伟达—大模型结合 RAG 构建客服场景自动问答
又一大模型技术开源!有道自研RAG引擎QAnything正式开放下载
收藏!RAG入门参考资料开源大总结:RAG综述、介绍、比较、预处理、RAG Embedding等
RAG调研
解决现代RAG实际生产问题
解决现代 RAG 系统中的生产问题-II
Modular RAG and RAG Flow: Part Ⅰ
Modular RAG and RAG Flow: Part II
先进的Retriever技术来增强你的RAGs
高级RAG — 使用假设文档嵌入 (HyDE) 改进检索
提升 RAG:选择最佳嵌入和 Reranker 模型
LangGraph
增强型RAG:re-rank
LightRAG:使用 PyTorch 为 LLM 应用程序提供支持
RAG 101:分块策略
模型训练
GPU相关资料
[教程] conda安装简明教程(基于miniconda和Windows)
PyTorch CUDA对应版本 | PyTorch
资料
李一舟课程全集
零碎资料
苹果各服共享ID
数据中心网络技术概览
华为大模型训练学习笔记
百度AIGC工程师认证考试答案(可换取工信部证书)
百度智能云生成式AI认证工程师 考试和证书查询指南
深入理解 Megatron-LM(1)基础知识
QAnything
接入QAnything的AI问答知识库,可私有化部署的企业级WIKI知识库
wsl --update失效Error code: Wsl/UpdatePackage/0x80240438的解决办法
Docker Desktop 启动docker engine一直转圈解决方法
win10开启了hyper-v,docker 启动还是报错 docker desktop windows hypervisor is not present
WSL虚拟磁盘过大,ext4迁移 Windows 中创建软链接和硬链接
WSL2切换默认的Linux子系统
Windows的WSL子系统,自动开启sshd服务
新版docker desktop设置wsl(使用windown的子系统)
WSL 开启ssh
Windows安装网易开源QAnything打造智能客服系统
芯片
国内互联网大厂自研芯片梳理
超算平台—算力供应商
Linux 磁盘扩容
Linux使用growpart工具进行磁盘热扩容(非LVM扩容方式)
关于centos7 扩容提示no tools available to resize disk with 'gpt' - o夜雨随风o - 博客园
(小插曲)neo4j配置apoc插件后检查版本发现:Unknown function ‘apoc.version‘ “EXPLAIN RETURN apoc.version()“
vfio-pci与igb_uio映射硬件资源到DPDK的流程分析
KubeVirt
vnc server配置、启动、重启与连接 - 王约翰 - 博客园
虚拟机Bug解决方案
kubevirt 如何通过CDI上传镜像文件
在 K8S 上也能跑 VM!KubeVirt 簡介與建立(部署篇) | Cloud Solutions
KubeVirt 04:容器化数据导入 – 小菜园
Python
安装 flash_attn
手把手教你在linux上安装pytorch与cuda
AI
在启智社区基于PyTorch运行国产算力卡的模型训练实验
Scaling law
免费的GPT3.5 API
AI Engineer Roadmap & Resources 🤖
模型排行
edk2
K8S删除Evicted状态的pod
docker 中启动 docker
远程本地多用户桌面1.17(一种不让电脑跟你抢键鼠的思路) - 哔哩哔哩
华为鲲鹏服务器(ARM架构)部署Prometheus
在Linux上安装配置Grafana_AI开发平台ModelArts_华为云
abrt-ccpp干崩服务器查询记录
kubevirt 中文社区
VNCServer 连接方法
Pod创建流程代码版本[kubelet篇]
[译]深入剖析 Kubernetes MutatingAdmissionWebhook-腾讯云开发者社区-腾讯云
[译]深入剖析 Kubernetes MutatingAdmissionWebhook-腾讯云开发者社区-腾讯云
深入理解 Kubernetes Admission Webhook-阳明的博客
CentOS7 安装 mbedtls和mbedtls-devel
-
+
首页
[译]深入剖析 Kubernetes MutatingAdmissionWebhook-腾讯云开发者社区-腾讯云
![](https://ask.qcloudimg.com/http-save/yehe-1952081/etjw52r87v.jpeg) > 翻译自 《Diving into Kubernetes MutatingAdmissionWebhook》 原文链接:https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74 对于在数据持久化之前,拦截到 Kubernetes API server 的请求, `Admissioncontrollers` 是非常有用的工具。然而,由于其需要由集群管理员在 kube-apiserver 中编译成二进制文件,所以使用起来不是很灵活。从 Kubernetes 1.7 起,引入了 `Initializers` 和 `ExternalAdmissionWebhooks`,用以解决这个问题。在 Kubernetes 1.9 中, `Initializers` 依然停留在 alpha 版本,然而 `ExternalAdmissionWebhooks` 被提升到了 beta 版,且被分成了 `MutatingAdmissionWebhook` 和 `ValidatingAdmissionWebhook`。 `MutatingAdmissionWebhook` 和 `ValidatingAdmissionWebhook` 二者合起来就是一个特殊类型的 `admission controllers`,一个处理资源更改,一个处理验证。验证是通过匹配到 `MutatingWebhookConfiguration` 中定义的规则完成的。 在这篇文章中,我会深入剖析 `MutatingAdmissionWebhook` 的细节,并一步步实现一个可用的 `webhook admission server`。 ### Webhooks 的好处 Kubernetes 集群管理员可以使用 `webhooks` 来创建额外的资源更改及验证准入插件,这些准入插件可以通过 apiserver 的准入链来工作,而不需要重新编译 apiserver。这使得开发者可以对于很多动作都可以自定义准入逻辑,比如对任何资源的创建、更新、删除,给开发者提供了很大的自由和灵活度。可以使用的应用数量巨大。一些常见的使用常见包括: 1. 在创建资源之前做些更改。Istio 是个非常典型的例子,在目标 pods 中注入 Envoy sidecar 容器,来实现流量管理和规则执行。 2. 自动配置 `StorageClass`。监听 `PersistentVolumeClaim` 资源,并按照事先定好的规则自动的为之增添对应的 `StorageClass`。使用者无需关心 `StorageClass` 的创建。 3. 验证复杂的自定义资源。确保只有其被定义后且所有的依赖项都创建好并可用,自定义资源才可以创建。 4. namespace 的限制。在多租户系统中,避免资源在预先保留的 namespace 中被创建。 除了以上列出来的使用场景,基于 `webhooks` 还可以创建更多应用。 ### Webhooks 和 Initializers 基于社区的反馈,以及对 `ExternalAdmissionWebhooks` 和 `Initializers` 的 alpha 版本的使用案例,Kubernetes 社区决定将 webhooks 升级到 beta 版,并且将其分成两种 webhooks( `MutatingAdmissionWebhook` 和 `ValidatingAdmissionWebhook`)。这些更新使得 webhooks 与其他 `admission controllers` 保持一致,并且强制 `mutate-before-validate`。 `Initializers` 可以在 Kubernetes 资源创建前更改,从而实现动态准入控制。如果你对 `Initializers` 不熟悉,可以参考这篇文章。 所以,到底 `Webhooks` 和 `Initializers` 之间的区别是什么呢? 1. `Webhooks` 可以应用于更多操作,包括对于资源 "增删改" 的 "mutate" 和 "admit";然而 `Initializers` 不可以对 "删" 资源进行 "admit"。 2. `Webhooks` 在创建资源前不允许查询;然而 `Initializers` 可以监听未初始化的资源,通过参数 `?includeUninitialized=true` 来实现。 3. 由于 `Initializers` 会把 "预创建" 状态也持久化到 etcd,因此会引入高延迟且给 etcd 带来负担,尤其在 apiserver 升级或失败时;然而 Webhooks 消耗的内存和计算资源更少。 4. `Webhooks` 比 `Initializers` 对失败的保障更强大。 `Webhooks` 的配置中可以配置失败策略,用以避免资源在创建的时候被 hang 住。然而 `Initializers` 在尝试创建资源的时候可能会 block 住所有的资源。 除了上面列举的不同点, `Initializer` 在较长一段开发时间内还存在很多已知问题,包括配额补充错误等。 `Webhooks` 升级为 beta 版也就预示着在未来 `Webhooks` 会是开发目标。如果你需要更稳定的操作,我推荐使用 `Webhooks`。 ### MutatingAdmissionWebhook 如何工作 `MutatingAdmissionWebhook` 在资源被持久化到 etcd 前,根据规则将其请求拦截,拦截规则定义在 `MutatingWebhookConfiguration` 中。 `MutatingAdmissionWebhook` 通过对 `webhook server` 发送准入请求来实现对资源的更改。而 `webhook server` 只是一个简单的 http 服务器。 下面这幅图详细描述了 `MutatingAdmissionWebhook` 如何工作: ![](https://ask.qcloudimg.com/http-save/yehe-1952081/mk1ky3lgm6.jpeg) `MutatingAdmissionWebhook` 需要三个对象才能运行: #### MutatingWebhookConfiguration `MutatingAdmissionWebhook` 需要根据 `MutatingWebhookConfiguration` 向 apiserver 注册。在注册过程中, `MutatingAdmissionWebhook` 需要说明: 1. 如何连接 `webhook admission server`; 2. 如何验证 `webhook admission server`; 3. `webhook admission server` 的 URL path; 4. webhook 需要操作对象满足的规则; 5. `webhook admission server` 处理时遇到错误时如何处理。 #### MutatingAdmissionWebhook 本身 `MutatingAdmissionWebhook` 是一种插件形式的 `admission controller` ,且可以配置到 apiserver 中。 `MutatingAdmissionWebhook` 插件可以从 `MutatingWebhookConfiguration` 中获取所有感兴趣的 `admission webhooks`。 然后 `MutatingAdmissionWebhook` 监听 apiserver 的请求,拦截满足条件的请求,并并行执行。 #### Webhook Admission Server `WebhookAdmissionServer` 只是一个附着到 k8s apiserver 的 http server。对于每一个 apiserver 的请求, `MutatingAdmissionWebhook` 都会发送一个 `admissionReview` 到相关的 `webhook admission server`。 `webhook admission server` 再决定如何更改资源。 ### MutatingAdmissionWebhook 教程 编写一个完整的 `WebhookAdmissionServer` 可能令人生畏。为了方便起见,我们编写一个简单的 `WebhookAdmissionServer` 来实现注入 nginx sidecar 容器以及挂载 volume。完整代码在 kube-mutating-webhook-tutorial。这个项目参考了 Kubernetes webhook 示例和 Istio sidecar 注入实现。 在接下来的段落里,我会向你展示如何编写可工作的容器化 `webhook admission server`,并将其部署到 Kubernetes 集群中。 #### 前置条件 `MutatingAdmissionWebhook` 要求 Kubernetes 版本为 1.9.0 及以上,其 `admissionregistration.k8s.io/v1beta1` API 可用。确保下面的命令: ```javascript kubectl api-versions | grep admissionregistration.k8s.io/v1beta1 ``` 其输出为: ```javascript admissionregistration.k8s.io/v1beta1 ``` 另外, `MutatingAdmissionWebhook` 和 `ValidatingAdmissionWebhook` 准入控制器需要以正确的顺序加入到 `kube-apiserver` 的 `admission-control` 标签中。 #### 编写 Webhook Server `WebhookAdmissionServer` 是一个简单的 http 服务器,遵循 Kubernetes API。我粘贴部分伪代码来描述主逻辑: ```javascript sidecarConfig, err := loadConfig(parameters.sidecarCfgFile) pair, err := tls.LoadX509KeyPair(parameters.certFile, parameters.keyFile) whsvr := &WebhookServer { sidecarConfig: sidecarConfig, server: &http.Server { Addr: fmt.Sprintf(":%v", 443), TLSConfig: &tls.Config{Certificates: []tls.Certificate{pair}}, }, } // define http server and server handler mux := http.NewServeMux() mux.HandleFunc("/mutate", whsvr.serve) whsvr.server.Handler = mux // start webhook server in new rountine go func() { if err := whsvr.server.ListenAndServeTLS("", ""); err != nil { glog.Errorf("Filed to listen and serve webhook server: %v", err) } }() ``` 以上代码的详解: 1. `sidecarCfgFile` 包含了 sidecar 注入器模板,其在下面的 ConfigMap 中定义; 2. `certFile` 和 `keyFile` 是秘钥对,会在 `webhook server` 和 apiserver 之间的 TLS 通信中用到; 3. 19 行开启了 https server,以监听 443 端口路径为 `'/mutate'`。 接下来我们关注处理函数 `serve` 的主要逻辑: ```javascript // Serve method for webhook server func (whsvr *WebhookServer) serve(w http.ResponseWriter, r *http.Request) { var body []byte if r.Body != nil { if data, err := ioutil.ReadAll(r.Body); err == nil { body = data } } var reviewResponse *v1beta1.AdmissionResponse ar := v1beta1.AdmissionReview{} deserializer := codecs.UniversalDeserializer() if _, _, err := deserializer.Decode(body, nil, &ar); err != nil { glog.Error(err) reviewResponse = toAdmissionResponse(err) } else { reviewResponse = mutate(ar) } response := v1beta1.AdmissionReview{} if reviewResponse != nil { response.Response = reviewResponse response.Response.UID = ar.Request.UID } // reset the Object and OldObject, they are not needed in a response. ar.Request.Object = runtime.RawExtension{} ar.Request.OldObject = runtime.RawExtension{} resp, err := json.Marshal(response) if err != nil { glog.Error(err) } if _, err := w.Write(resp); err != nil { glog.Error(err) } } ``` 函数 `serve` 是一个简单的 http 处理器,参数为 `http request` 和 `response writer`。 1. 首先将请求组装为 `AdmissionReview`,其中包括 `object`、 `oldobject` 及 `userInfo` ... 2. 然后触发 Webhook 主函数 `mutate` 来创建 `patch`,以实现注入 sidecar 容器及挂载 volume。 3. 最后,将 `admission decision` 和额外 `patch` 组装成响应,并发送回给 apiserver。 对于函数 `mutate` 的实现,你可以随意发挥。我就以我的实现方式做个例子: ```javascript // main mutation process func (whsvr *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { req := ar.Request var pod corev1.Pod if err := json.Unmarshal(req.Object.Raw, &pod); err != nil { glog.Errorf("Could not unmarshal raw object: %v", err) return &v1beta1.AdmissionResponse { Result: &metav1.Status { Message: err.Error(), }, } } // determine whether to perform mutation if !mutationRequired(ignoredNamespaces, &pod.ObjectMeta) { glog.Infof("Skipping mutation for %s/%s due to policy check", pod.Namespace, pod.Name) return &v1beta1.AdmissionResponse { Allowed: true, } } annotations := map[string]string{admissionWebhookAnnotationStatusKey: "injected"} patchBytes, err := createPatch(&pod, whsvr.sidecarConfig, annotations) return &v1beta1.AdmissionResponse { Allowed: true, Patch: patchBytes, PatchType: func() *v1beta1.PatchType { pt := v1beta1.PatchTypeJSONPatch return &pt }(), } } ``` 从上述代码中可以看出,函数 `mutate` 请求了 `mutationRequired` 来决定这个改动是否被允许。对于被允许的请求,函数 `mutate` 从另一个函数 `createPatch` 中获取到修改体 `'patch'`。注意这里函数 `mutationRequired` 的诡计,我们跳过了带有注解 `sidecar-injector-webhook.morven.me/inject:true`。这里稍后会在部署 `deployment` 的时候提到。完整代码请参考这里。 #### 编写 Dockerfile 并构建 创建构建脚本: ```javascript dep ensure CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o kube-mutating-webhook-tutorial . docker build --no-cache -t morvencao/sidecar-injector:v1 . rm -rf kube-mutating-webhook-tutorial docker push morvencao/sidecar-injector:v1 ``` 以下面为依赖编写 Dockerfile 文件: ```javascript FROM alpine:latest ADD kube-mutating-webhook-tutorial /kube-mutating-webhook-tutorial ENTRYPOINT ["./kube-mutating-webhook-tutorial"] ``` 在手动构建容器前,你需要 Docker ID 账号并将 image name 和 tag (Dockerfile 和 deployment.yaml 文件中)修改成你自己的,然后执行以下命令: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# ./build Sending build context to Docker daemon 44.89MB Step 1/3 : FROM alpine:latest ---> 3fd9065eaf02 Step 2/3 : ADD kube-mutating-webhook-tutorial /kube-mutating-webhook-tutorial ---> 432de60c2b3f Step 3/3 : ENTRYPOINT ["./kube-mutating-webhook-tutorial"] ---> Running in da6e956d1755 Removing intermediate container da6e956d1755 ---> 619faa936145 Successfully built 619faa936145 Successfully tagged morvencao/sidecar-injector:v1 The push refers to repository [docker.io/morvencao/sidecar-injector] efd05fe119bb: Pushed cd7100a72410: Layer already exists v1: digest: sha256:7a4889928ec5a8bcfb91b610dab812e5228d8dfbd2b540cd7a341c11f24729bf size: 739 ``` #### 编写 Sidecar 注入配置 现在我们来创建一个 Kubernetes `ConfigMap`,包含需要注入到目标 pod 中的容器和 `volume` 信息: ```javascript apiVersion: v1 kind: ConfigMap metadata: name: sidecar-injector-webhook-configmap data: sidecarconfig.yaml: | containers: - name: sidecar-nginx image: nginx:1.12.2 imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: - name: nginx-conf mountPath: /etc/nginx volumes: - name: nginx-conf configMap: name: nginx-configmap ``` 从上面的清单中看,这里需要另一个包含 `nginx conf` 的 `ConfigMap`。完整 yaml 参考 nginxconfigmap.yaml。 然后将这两个 ConfigMap 部署到集群中: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl create -f ./deployment/nginxconfigmap.yaml configmap "nginx-configmap" created [root@mstnode kube-mutating-webhook-tutorial]# kubectl create -f ./deployment/configmap.yaml configmap "sidecar-injector-webhook-configmap" created ``` #### 创建包含秘钥对的 Secret 由于准入控制是一个高安全性操作,所以对外在的 `webhook server` 提供 TLS 是必须的。作为流程的一部分,我们需要创建由 Kubernetes CA 签名的 TLS 证书,以确保 `webhook server` 和 apiserver 之间通信的安全性。对于 CSR 创建和批准的完整步骤,请参考 这里 。 简单起见,我们参考了 Istio 的脚本并创建了一个类似的名为 `webhook-create-signed-cert.sh` 的脚本,来自动生成证书及秘钥对并将其加入到 `secret` 中。 ```javascript #!/bin/bash while [[ $# -gt 0 ]]; do case ${1} in --service) service="$2" shift ;; --secret) secret="$2" shift ;; --namespace) namespace="$2" shift ;; esac shift done [ -z ${service} ] && service=sidecar-injector-webhook-svc [ -z ${secret} ] && secret=sidecar-injector-webhook-certs [ -z ${namespace} ] && namespace=default csrName=${service}.${namespace} tmpdir=$(mktemp -d) echo "creating certs in tmpdir ${tmpdir} " cat <<EOF >> ${tmpdir}/csr.conf [req] req_extensions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = ${service} DNS.2 = ${service}.${namespace} DNS.3 = ${service}.${namespace}.svc EOF openssl genrsa -out ${tmpdir}/server-key.pem 2048 openssl req -new -key ${tmpdir}/server-key.pem -subj "/CN=${service}.${namespace}.svc" -out ${tmpdir}/server.csr -config ${tmpdir}/csr.conf # clean-up any previously created CSR for our service. Ignore errors if not present. kubectl delete csr ${csrName} 2>/dev/null || true # create server cert/key CSR and send to k8s API cat <<EOF | kubectl create -f - apiVersion: certificates.k8s.io/v1beta1 kind: CertificateSigningRequest metadata: name: ${csrName} spec: groups: - system:authenticated request: $(cat ${tmpdir}/server.csr | base64 | tr -d '\n') usages: - digital signature - key encipherment - server auth EOF # verify CSR has been created while true; do kubectl get csr ${csrName} if [ "$?" -eq 0 ]; then break fi done # approve and fetch the signed certificate kubectl certificate approve ${csrName} # verify certificate has been signed for x in $(seq 10); do serverCert=$(kubectl get csr ${csrName} -o jsonpath='{.status.certificate}') if [[ ${serverCert} != '' ]]; then break fi sleep 1 done if [[ ${serverCert} == '' ]]; then echo "ERROR: After approving csr ${csrName}, the signed certificate did not appear on the resource. Giving up after 10 attempts." >&2 exit 1 fi echo ${serverCert} | openssl base64 -d -A -out ${tmpdir}/server-cert.pem # create the secret with CA cert and server cert/key kubectl create secret generic ${secret} \ --from-file=key.pem=${tmpdir}/server-key.pem \ --from-file=cert.pem=${tmpdir}/server-cert.pem \ --dry-run -o yaml | kubectl -n ${namespace} apply -f - ``` 运行脚本后,包含证书和秘钥对的 `secret` 就被创建出来了: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# ./deployment/webhook-create-signed-cert.sh creating certs in tmpdir /tmp/tmp.wXZywp0wAF Generating RSA private key, 2048 bit long modulus ...........................................+++ ..........+++ e is 65537 (0x10001) certificatesigningrequest "sidecar-injector-webhook-svc.default" created NAME AGE REQUESTOR CONDITION sidecar-injector-webhook-svc.default 0s https://mycluster.icp:9443/oidc/endpoint/OP#admin Pending certificatesigningrequest "sidecar-injector-webhook-svc.default" approved secret "sidecar-injector-webhook-certs" created ``` #### 创建 Sidecar 注入器的 Deployment 和 Service deployment 带有一个 pod,其中运行的就是 `sidecar-injector` 容器。该容器以特殊参数运行: 1. `sidecarCfgFile` 指的是 sidecar 注入器的配置文件,挂载自上面创建的 ConfigMap `sidecar-injector-webhook-configmap`。 2. `tlsCertFile` 和 `tlsKeyFile` 是秘钥对,挂载自 Secret `injector-webhook-certs`。 3. `alsologtostderr`、 `v=4` 和 `2>&1` 是日志参数。 ```javascript apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sidecar-injector-webhook-deployment labels: app: sidecar-injector spec: replicas: 1 template: metadata: labels: app: sidecar-injector spec: containers: - name: sidecar-injector image: morvencao/sidecar-injector:v1 imagePullPolicy: IfNotPresent args: - -sidecarCfgFile=/etc/webhook/config/sidecarconfig.yaml - -tlsCertFile=/etc/webhook/certs/cert.pem - -tlsKeyFile=/etc/webhook/certs/key.pem - -alsologtostderr - -v=4 - 2>&1 volumeMounts: - name: webhook-certs mountPath: /etc/webhook/certs readOnly: true - name: webhook-config mountPath: /etc/webhook/config volumes: - name: webhook-certs secret: secretName: sidecar-injector-webhook-certs - name: webhook-config configMap: name: sidecar-injector-webhook-configmap ``` Service 暴露带有 `app=sidecar-injector` label 的 pod,使之在集群中可访问。这个 Service 会被 `MutatingWebhookConfiguration` 中定义的 `clientConfig` 部分访问,默认的端口 `spec.ports.port` 需要设置为 443。 ```javascript apiVersion: v1 kind: Service metadata: name: sidecar-injector-webhook-svc labels: app: sidecar-injector spec: ports: - port: 443 targetPort: 443 selector: app: sidecar-injector ``` 然后将上述 Deployment 和 Service 部署到集群中,并且验证 sidecar 注入器的 `webhook server`是否 running: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl create -f ./deployment/deployment.yaml deployment "sidecar-injector-webhook-deployment" created [root@mstnode kube-mutating-webhook-tutorial]# kubectl create -f ./deployment/service.yaml service "sidecar-injector-webhook-svc" created [root@mstnode kube-mutating-webhook-tutorial]# kubectl get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE sidecar-injector-webhook-deployment 1 1 1 1 2m [root@mstnode kube-mutating-webhook-tutorial]# kubectl get pod NAME READY STATUS RESTARTS AGE sidecar-injector-webhook-deployment-bbb689d69-fdbgj 1/1 Running 0 3m ``` #### 动态配置 webhook 准入控制器 `MutatingWebhookConfiguration` 中具体说明了哪个 `webhook admission server` 是被使用的并且哪些资源受准入服务器的控制。建议你在创建 `MutatingWebhookConfiguration` 之前先部署 `webhook admission server`,并确保其正常工作。否则,请求会被无条件接收或根据失败规则被拒。 现在,我们根据下面的内容创建 `MutatingWebhookConfiguration`: ```javascript apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: name: sidecar-injector-webhook-cfg labels: app: sidecar-injector webhooks: - name: sidecar-injector.morven.me clientConfig: service: name: sidecar-injector-webhook-svc namespace: default path: "/mutate" caBundle: ${CA_BUNDLE} rules: - operations: [ "CREATE" ] apiGroups: [""] apiVersions: ["v1"] resources: ["pods"] namespaceSelector: matchLabels: sidecar-injector: enabled ``` 第 8 行: `name` - webhook 的名字,必须指定。多个 webhook 会以提供的顺序排序; 第 9 行: `clientConfig` - 描述了如何连接到 `webhook admission server` 以及 TLS 证书; 第 15 行: `rules` - 描述了 `webhook server` 处理的资源和操作。在我们的例子中,只拦截创建 pods 的请求; 第 20 行: `namespaceSelector` - `namespaceSelector` 根据资源对象是否匹配 `selector` 决定了是否针对该资源向 `webhook server` 发送准入请求。 在部署 `MutatingWebhookConfiguration` 前,我们需要将 `${CA_BUNDLE}` 替换成 apiserver 的默认 `caBundle`。我们写个脚本来自动匹配: ```javascript #!/bin/bash set -o errexit set -o nounset set -o pipefail ROOT=$(cd $(dirname $0)/../../; pwd) export CA_BUNDLE=$(kubectl get configmap -n kube-system extension-apiserver-authentication -o=jsonpath='{.data.client-ca-file}' | base64 | tr -d '\n') if command -v envsubst >/dev/null 2>&1; then envsubst else sed -e "s|\${CA_BUNDLE}|${CA_BUNDLE}|g" fi ``` 然后执行: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# cat ./deployment/mutatingwebhook.yaml |\ > ./deployment/webhook-patch-ca-bundle.sh >\ > ./deployment/mutatingwebhook-ca-bundle.yaml ``` 我们看不到任何日志描述 `webhook server` 接收到准入请求,似乎该请求并没有发送到 `webhook server` 一样。所以有一种可能性是这是被 `MutatingWebhookConfiguration` 中的配置触发的。再确认一下 `MutatingWebhookConfiguration` 我们会发现下面的内容: ```javascript namespaceSelector: matchLabels: sidecar-injector: enabled ``` #### 通过 namespaceSelector 控制 sidecar 注入器 我们在 `MutatingWebhookConfiguration` 中配置了 `namespaceSelector`,也就意味着只有在满足条件的 namespace 下的资源能够被发送到 `webhook server`。于是我们将 default 这个 namespace 打上标签 `sidecar-injector=enabled`: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl label namespace default sidecar-injector=enabled namespace "default" labeled [root@mstnode kube-mutating-webhook-tutorial]# kubectl get namespace -L sidecar-injector NAME STATUS AGE sidecar-injector default Active 1d enabled kube-public Active 1d kube-system Active 1d ``` 现在我们配置的 `MutatingWebhookConfiguration` 会在 pod 创建的时候就注入 sidecar 容器。将运行中的 pod 删除并确认是否创建了新的带 sidecar 容器的 pod: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl delete pod sleep-6d79d8dc54-r66vz pod "sleep-6d79d8dc54-r66vz" deleted [root@mstnode kube-mutating-webhook-tutorial]# kubectl get pods NAME READY STATUS RESTARTS AGE sidecar-injector-webhook-deployment-bbb689d69-fdbgj 1/1 Running 0 29m sleep-6d79d8dc54-b8ztx 0/2 ContainerCreating 0 3s sleep-6d79d8dc54-r66vz 1/1 Terminating 0 11m [root@mstnode kube-mutating-webhook-tutorial]# kubectl get pod sleep-6d79d8dc54-b8ztx -o yaml apiVersion: v1 kind: Pod metadata: annotations: kubernetes.io/psp: default sidecar-injector-webhook.morven.me/inject: "true" sidecar-injector-webhook.morven.me/status: injected labels: app: sleep pod-template-hash: "2835848710" name: sleep-6d79d8dc54-b8ztx namespace: default spec: containers: - command: - /bin/sleep - infinity image: tutum/curl imagePullPolicy: IfNotPresent name: sleep resources: {} volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-d7t2r readOnly: true - image: nginx:1.12.2 imagePullPolicy: IfNotPresent name: sidecar-nginx ports: - containerPort: 80 protocol: TCP resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /etc/nginx name: nginx-conf volumes: - name: default-token-d7t2r secret: defaultMode: 420 secretName: default-token-d7t2r - configMap: defaultMode: 420 name: nginx-configmap name: nginx-conf ... ``` 可以看到,sidecar 容器和 volume 被成功注入到应用中。至此,我们成功创建了可运行的带 `MutatingAdmissionWebhook` 的 sidecar 注入器。通过 `namespaceSelector`,我们可以轻易的控制在特定的 namespace 中的 pods 是否需要被注入 sidecar 容器。 但这里有个问题,根据以上的配置,在 default 这个 namespace 下的所有 pods 都会被注入 sidecar 容器,无一例外。 #### 通过注解控制 sidecar 注入器 多亏了 `MutatingAdmissionWebhook` 的灵活性,我们可以轻易的自定义变更逻辑来筛选带有特定注解的资源。还记得上面提到的注解 `sidecar-injector-webhook.morven.me/inject:"true"` 吗?在 sidecar 注入器中这可以当成另一种控制方式。在 `webhook server` 中我写了一段逻辑来跳过那行不带这个注解的 pod。 我们来尝试一下。在这种情况下,我们创建另一个 sleep 应用,其 `podTemplateSpec` 中不带注解 `sidecar-injector-webhook.morven.me/inject:"true"`: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl delete deployment sleep deployment "sleep" deleted [root@mstnode kube-mutating-webhook-tutorial]# cat <<EOF | kubectl create -f - apiVersion: extensions/v1beta1 > kind: Deployment > metadata: > name: sleep > spec: > replicas: 1 > template: > metadata: > labels: > app: sleep > spec: > containers: > - name: sleep > image: tutum/curl > command: ["/bin/sleep","infinity"] > imagePullPolicy: IfNotPresent > EOF deployment "sleep" created ``` 然后确认 sidecar 注入器是否跳过了这个 pod: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE sidecar-injector-webhook-deployment 1 1 1 1 45m sleep 1 1 1 1 17s [root@mstnode kube-mutating-webhook-tutorial]# kubectl get pod NAME READY STATUS RESTARTS AGE sidecar-injector-webhook-deployment-bbb689d69-fdbgj 1/1 Running 0 45m sleep-776b7bcdcd-4bz58 1/1 Running 0 21s ``` 结果显示,这个 sleep 应用只包含一个容器,没有额外的容器和 volume 注入。然后我们将这个 deployment 增加注解,并确认其重建后是否被注入 sidecar: ```javascript [root@mstnode kube-mutating-webhook-tutorial]# kubectl patch deployment sleep -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar-injector-webhook.morven.me/inject": "true"}}}}}' deployment "sleep" patched [root@mstnode kube-mutating-webhook-tutorial]# kubectl delete pod sleep-776b7bcdcd-4bz58 pod "sleep-776b7bcdcd-4bz58" deleted [root@mstnode kube-mutating-webhook-tutorial]# kubectl get pods NAME READY STATUS RESTARTS AGE sidecar-injector-webhook-deployment-bbb689d69-fdbgj 1/1 Running 0 49m sleep-3e42ff9e6c-6f87b 0/2 ContainerCreating 0 18s sleep-776b7bcdcd-4bz58 1/1 Terminating 0 3m ``` 与预期一致,pod 被注入了额外的 sidecar 容器。至此,我们就获得了一个可工作的 sidecar 注入器,可由 `namespaceSelector` 或更细粒度的由注解控制。 ### 总结 `MutatingAdmissionWebhook` 是 Kubernetes 扩展功能中最简单的方法之一,工作方式是通过全新规则控制、资源更改。 此功能使得更多的工作模式变成了可能,并且支持了更多生态系统,包括服务网格平台 Istio。从 Istio 0.5.0 开始,Istio 的自动注入部分的代码被重构,实现方式从 `initializers` 变更为 `MutatingAdmissionWebhook`。 ### 参考文献 - http://blog.kubernetes.io/2018/01/extensible-admission-is-beta.html - https://docs.google.com/document/d/1c4kdkY3ha9rm0OIRbGleCeaHknZ-NR1nNtDp-i8eH8E/view - https://v1-8.docs.kubernetes.io/docs/admin/extensible-admission-controllers/ - https://github.com/kubernetes/kubernetes/tree/release-1.9/test/images/webhook
yg9538
2024年12月12日 11:00
101
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档
PDF文档(打印)
分享
链接
类型
密码
更新密码