首页 > 解决方案 > 使用 Mutate 准入控制器修改 deploymnet 中的 ImagePullPolicy

问题描述

我正在构建一个用于部署的 Mutate 准入控制器,以确保 Pod 上的 imagePullPolicy 设置为 Always 并带有相应的验证准入控制器。我注意到我可以在部署(创建时)或副本集上设置它。

代码如下所示:

package main

import (
    "net/http"
    "fmt"
    "io/ioutil"
    "encoding/json"
    "os"
//  "github.com/golang/glog"
    "strconv"
    "k8s.io/api/admission/v1"
//  corev1 "k8s.io/api/core/v1"
    appsv1 "k8s.io/api/apps/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    admissionv1 "k8s.io/api/admission/v1"
)

func isKubeNamespace(ns string) bool {
    return ns == metav1.NamespacePublic || ns == metav1.NamespaceSystem
}

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

func (mr *myServerHandler) mutserve(w http.ResponseWriter, r *http.Request) {

    var Body []byte
    if r.Body != nil {
        if data , err := ioutil.ReadAll(r.Body); err == nil {
            Body = data
        }
    }

    if len(Body) == 0 {
        fmt.Fprintf(os.Stderr, "Unable to retrieve Body from API")
        http.Error(w,"Empty Body", http.StatusBadRequest)
    }

    fmt.Fprintf(os.Stdout,"Received Request")

    if r.URL.Path != "/mutate" {
        fmt.Fprintf(os.Stderr, "Not a Validate URL Path")
        http.Error(w, "Not A Validate URL Path", http.StatusBadRequest)
    }

    // Read the Response from the Kubernetes API and place it in the Request 

    arRequest := &v1.AdmissionReview{}
    if err := json.Unmarshal(Body, arRequest); err != nil {
        fmt.Fprintf(os.Stderr, "Error Unmarsheling the Body request")
        http.Error(w, "Error Unmarsheling the Body request", http.StatusBadRequest)
        return
    }


//  if arRequest.Request.Resource.Resource != "pods" {
         
//          fmt.Fprintf(os.Stderr, "Handling the wrong resource")
//          http.Error(w, "Handling the wrong resource", http.StatusBadRequest)
//          return  
//  }

    raw := arRequest.Request.Object.Raw
    replicaset := appsv1.ReplicaSet{}

    if !isKubeNamespace(arRequest.Request.Namespace) {
        
        if err := json.Unmarshal(raw, &replicaset); err != nil {
            fmt.Fprintf(os.Stderr, "Error , unable to Deserializing Pod")
            http.Error(w,"Error , unable to Deserializing Pod", http.StatusBadRequest)
            return
        }
    } else {
            fmt.Fprintf(os.Stderr, "Error , unauthorized Namespace")
            http.Error(w,"Error , unauthorized Namespace", http.StatusBadRequest)
            return
    }

    containers := replicaset.Spec.Template.Spec.Containers

    

    arResponse := v1.AdmissionReview{
        Response: &v1.AdmissionResponse{
                UID: arRequest.Request.UID,
        },
    }

    var patches []patchOperation

    for i , container := range containers {
        fmt.Fprintf(os.Stdout, "container[%d]= %s imagePullPolicy=%s", i, container.Name , container.ImagePullPolicy)
        
        if containers[i].ImagePullPolicy != "Always" {

            if containers[i].ImagePullPolicy == "Never" || containers[i].ImagePullPolicy == "IfNotPresent"  {
                    
                patches = append(patches, patchOperation{
                            Op: "replace",
                            Path: "spec/template/spec/containers/[" + strconv.Itoa(i) + "]/ImagePullPolicy",
                            Value: "Always",
                })
                    
            } else {

                patches = append(patches, patchOperation{
                            Op: "Add",
                            Path: "/spec/template/spec/containers/[" + strconv.Itoa(i) + "]/ImagePullPolicy",
                            Value: "Always",
                })

                arResponse.Response.Allowed = true
            }
        }
    }
//    if pullPolicy != "Always" {

    patchBytes, err := json.Marshal(patches)

    if err != nil {
        fmt.Fprintf(os.Stderr, "Can't encode Patches: %v", err)
        http.Error(w, fmt.Sprintf("couldn't encode Patches: %v", err), http.StatusInternalServerError)
        return
    }

    v1JSONPatch := admissionv1.PatchTypeJSONPatch
    arResponse.APIVersion = "admission.k8s.io/v1"
    arResponse.Kind = arRequest.Kind
    arResponse.Response.Allowed = true
    arResponse.Response.Patch = patchBytes
    arResponse.Response.PatchType = &v1JSONPatch
    
    resp, rErr := json.Marshal(arResponse)

    if rErr != nil {
        fmt.Fprintf(os.Stderr, "Can't encode response: %v", rErr)
        http.Error(w, fmt.Sprintf("couldn't encode response: %v", rErr), http.StatusInternalServerError)
    }

    if _ , wErr := w.Write(resp); wErr != nil {
        fmt.Fprintf(os.Stderr, "Can't write response: %v", wErr)
        http.Error(w, fmt.Sprintf("cloud not write response: %v", wErr), http.StatusInternalServerError)
    }

}

如果我运行“添加”补丁,它最终会始终添加 imagePullPolicy,但如果我想替换它,我会收到以下错误:

“无法创建新的副本集“ubi-kuku-547654586”:发生内部错误:替换操作不适用:文档缺少路径:/spec/template/spec/containers/[0]/ImagePullPolicy:缺少值”

我在创建部署时尝试过它仍然是同样的错误

我尝试使用 core/v1 包为单个 pod(/spec/containers/[0]/ImagePullPolicy)使用相同的结构(不同的路径)并且它有效。

标签: gokuberneteskubernetes-podkubernetes-deployment

解决方案


推荐阅读