您好,登錄后才能下訂單哦!
Apiserver干的最重要的三個事就是:
admission controller非常有用,也是經常會用到的k8s的一個擴展方式,今天在源碼級別對其做一下介紹,以及如何自己去開發一個admission controller.
我們的應用場景是:我們希望把所有需要創建的pod都加上一個注解,因為我們早期是通過podpreset給pod注入lxcfs的配置的,但是用戶在寫yaml文件時很容易忘記加上,所以需要在apiserver上來個自動處理
metadata:
name: test-net
annotations:
initializer.kubernetes.io/lxcfs: "true" # 就是在pod的metadata里加上這個配置
已經有很多默認非常有用的admission插件,這里挑幾個介紹一下:
名稱 | 作用 |
---|---|
AlwaysPullImages | 把所有鏡像策略都調整成alwaysPull, 多租戶安全時比較有用 |
DefaultStorageClass | 默認存儲類型 |
DefaultTolerationSeconds | 節點notready:NoExecute時的容忍時間,比如有時我們升級kubelet,希望升級時pod不要漂移就會用到 |
DenyEscalatingExec | 拒絕遠程連接容器 |
ExtendedResourceToleration | 比如我有擴展資源,那么我可以通過它來玷污節點,防止不需要該資源的pod到我的機器上來,如GPU |
LimitRanger | 在多租戶配額時相當有用,如果pod沒配額,那么我可以默認給個很低的配額 |
NamespaceAutoProvision | 這個也非常有用,資源的namespace不存在時就創建一個 |
PodPreset | 可以對pod進行一些預處理設置 |
ResourceQuota | 多租戶配額時比較重要,看資源是否滿足resource quota中的配置 |
多租戶時經常會開啟這個,強制所有的鏡像必須去拉取,因為如果不這樣,那么別的租戶如果知道了你的鏡像名就可以寫一個yaml去啟動你的鏡像,強制拉時猶豫需要image pull secret所以無法拉取你的鏡像。
所以這個admission干的事就是把鏡像拉取策略都改成alwaysPull:
代碼位置:
kubernetes/plugin/pkg/admission/alwayspullimages/admission.go
func (a *AlwaysPullImages) Admit(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
// 你可以在attibutes里獲取到對象的一切信息,用戶信息等
if shouldIgnore(attributes) { // 檢查一下是不是你關注的object, 比如創建的一個configmap 那么顯然可以忽視
return nil
}
pod, ok := attributes.GetObject().(*api.Pod)
// 這里把initContainer和Container的拉取策略都給改了
for i := range pod.Spec.InitContainers {
pod.Spec.InitContainers[i].ImagePullPolicy = api.PullAlways
}
for i := range pod.Spec.Containers {
pod.Spec.Containers[i].ImagePullPolicy = api.PullAlways
}
return nil
}
# 還提供一個校驗接口,看是不是真的都已經被改了
func (a *AlwaysPullImages) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
pod, ok := attributes.GetObject().(*api.Pod)
for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].ImagePullPolicy != api.PullAlways {
return admission.NewForbidden(attributes,
field.NotSupported(field.NewPath("spec", "initContainers").Index(i).Child("imagePullPolicy"),
pod.Spec.InitContainers[i].ImagePullPolicy, []string{string(api.PullAlways)},
),
)
}
}
...
return nil
}
然后實現一個注冊函數:
func Register(plugins *admission.Plugins) {
plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
return NewAlwaysPullImages(), nil
})
}
type AlwaysPullImages struct {
*admission.Handler
}
最后需要在plugin里面把其注冊進去:
kubernetes/pkg/kubeapiserver/options/plugins.go
func RegisterAllAdmissionPlugins(plugins *admission.Plugins) {
imagepolicy.Register(plugins)
...
}
所以實現一個admission非常簡單,主要就是實現兩個接口即可。
很多情況下我們并不希望大動干戈去改apiserver代碼,所以apiserver提供了一種動態擴展admission的方式,非常推薦。
有兩種類型:
比較重要的是這個AdmissionReview結構體,包含一個請求一個響應
請求:有Object的詳細信息,用戶信息
響應: 最重要的是 1. 是否允許 2. 修改(patch)的類型 3. 修改(patch)的值, 這個符合json patch標準 (kubectl patch)
可在此 找到一個webhook server的例子
看一個具體例子,labelpatch,是給對象的元數據里加一些label的。
const (
// 特定的json patch格式
addFirstLabelPatch string = `[
{ "op": "add", "path": "/metadata/labels", "value": {"added-label": "yes"}}
]`
addAdditionalLabelPatch string = `[
{ "op": "add", "path": "/metadata/labels/added-label", "value": "yes" }
]`
)
// Add a label {"added-label": "yes"} to the object
func addLabel(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
obj := struct {
metav1.ObjectMeta
Data map[string]string
}{}
raw := ar.Request.Object.Raw
err := json.Unmarshal(raw, &obj)
if err != nil {
klog.Error(err)
return toAdmissionResponse(err)
}
reviewResponse := v1beta1.AdmissionResponse{}
reviewResponse.Allowed = true
if len(obj.ObjectMeta.Labels) == 0 {
reviewResponse.Patch = []byte(addFirstLabelPatch) // 這里最需要注意的就是修改時是通過patch的方式
} else {
reviewResponse.Patch = []byte(addAdditionalLabelPatch)
}
pt := v1beta1.PatchTypeJSONPatch
reviewResponse.PatchType = &pt
return &reviewResponse
}
把這個放到http handle里。
把這個HTTPS服務起一個service, 這樣apiserver就可以自動發現它。
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: <name of this configuration object>
webhooks:
- name: <webhook name, e.g., pod-policy.example.io>
rules: # 最好明確一下該hook關心哪些api,防止帶來不必要的額外開銷。
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: "Namespaced"
clientConfig:
service:
namespace: <namespace of the front-end service> # webhook server的namespace
name: <name of the front-end service> # service name
caBundle: <pem encoded ca cert that signs the server cert used by the webhook> # 因為需要通過https訪問,所以要給apiserver配置ca
admissionReviewVersions:
- v1beta1
timeoutSeconds: 1
adminssion control 是非常重要的APIserver擴展的方式,掌握了其開發很多地方就能以比較優雅的方式解決一些實際問題。是基于k8s開發PaaS平臺的利器
更多精彩: https://sealyun.com
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。