自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

K8S自定義Webhook實(shí)現(xiàn)認(rèn)證管理

運(yùn)維 系統(tǒng)運(yùn)維
在Kubernetes中,APIServer是整個(gè)集群的中樞神經(jīng),它不僅連接了各個(gè)模塊,更是為整個(gè)集群提供了訪問控制能力。這篇文章主要和大家討論認(rèn)證環(huán)節(jié)。

[[439204]]

大家好,我是喬克。

在Kubernetes中,APIServer是整個(gè)集群的中樞神經(jīng),它不僅連接了各個(gè)模塊,更是為整個(gè)集群提供了訪問控制能力。

Kubernetes API的每個(gè)請(qǐng)求都要經(jīng)過多階段的訪問控制才會(huì)被接受,包括認(rèn)證、授權(quán)、準(zhǔn)入,如下所示。

客戶端(普通賬戶、ServiceAccount等)想要訪問Kubernetes中的資源,需要通過經(jīng)過APIServer的三大步驟才能正常訪問,三大步驟如下:

  1. Authentication 認(rèn)證階段:判斷請(qǐng)求用戶是否為能夠訪問集群的合法用戶。如果用戶是個(gè)非法用戶,那 apiserver會(huì)返回一個(gè) 401 的狀態(tài)碼,并終止該請(qǐng)求;
  2. 如果用戶合法的話,我們的 apiserver 會(huì)進(jìn)入到訪問控制的第二階段 Authorization:授權(quán)階段。在該階段中apiserver 會(huì)判斷用戶是否有權(quán)限進(jìn)行請(qǐng)求中的操作。如果無權(quán)進(jìn)行操作,apiserver 會(huì)返回 403的狀態(tài)碼,并同樣終止該請(qǐng)求;
  3. 如果用戶有權(quán)進(jìn)行該操作的話,訪問控制會(huì)進(jìn)入到第三個(gè)階段:AdmissionControl。在該階段中 apiserver 的admission controller 會(huì)判斷請(qǐng)求是否是一個(gè)安全合規(guī)的請(qǐng)求。如果最終驗(yàn)證通過的話,訪問控制流程才會(huì)結(jié)束。

這篇文章主要和大家討論認(rèn)證環(huán)節(jié)。

認(rèn)證

Kubernetes中支持多種認(rèn)證機(jī)制,也支持多種認(rèn)證插件,在認(rèn)證過程中,只要一個(gè)通過則表示認(rèn)證通過。

常用的認(rèn)證插件有:

  • X509證書
  • 靜態(tài)Token
  • ServiceAccount
  • OpenID
  • Webhook
  • .....

這里不會(huì)把每種認(rèn)證插件都介紹一下,主要講講Webhook的使用場(chǎng)景。

在企業(yè)中,大部分都會(huì)有自己的賬戶中心,用于管理員工的賬戶以及權(quán)限,而在K8s集群中,也需要進(jìn)行賬戶管理,如果能直接使用現(xiàn)有的賬戶系統(tǒng)是不是會(huì)方便很多?

K8s的Webhook就可以實(shí)現(xiàn)這種需求,Webhook是一個(gè)HTTP回調(diào),通過一個(gè)條件觸發(fā)HTTP POST請(qǐng)求發(fā)送到Webhook 服務(wù)端,服務(wù)端根據(jù)請(qǐng)求數(shù)據(jù)進(jìn)行處理。

下面就帶大家從0到1開發(fā)一個(gè)認(rèn)證服務(wù)。

開發(fā)Webhook

簡(jiǎn)介

WebHook的功能主要是接收APIServer的認(rèn)證請(qǐng)求,然后調(diào)用不同的認(rèn)證服務(wù)進(jìn)行認(rèn)證,如下所示。

這里只是做一個(gè)Webhook的例子,目前主要實(shí)現(xiàn)了Github和LDAP認(rèn)證,當(dāng)然,認(rèn)證部分的功能比較單一,沒有考慮復(fù)雜的場(chǎng)景。

Webhook開發(fā)

開發(fā)環(huán)境

構(gòu)建符合規(guī)范的Webhook

在開發(fā)Webhook的時(shí)候,需要符合Kubernetes的規(guī)范,具體如下:

  • URL:https://auth.example.com/auth
  • Method:POST
  • Input參數(shù)
  1.   "apiVersion""authentication.k8s.io/v1beta1"
  2.   "kind""TokenReview"
  3.   "spec": { 
  4.     "token""<持有者令牌>" 
  5.   } 
  • Output參數(shù)

如果成功會(huì)返回:

  1.   "apiVersion""authentication.k8s.io/v1beta1"
  2.   "kind""TokenReview"
  3.   "status": { 
  4.     "authenticated"true
  5.     "user": { 
  6.       "username""janedoe@example.com"
  7.       "uid""42"
  8.       "groups": [ 
  9.         "developers"
  10.         "qa" 
  11.       ], 
  12.       "extra": { 
  13.         "extrafield1": [ 
  14.           "extravalue1"
  15.           "extravalue2" 
  16.         ] 
  17.       } 
  18.     } 
  19.   } 

如果不成功,會(huì)返回:

  1.   "apiVersion""authentication.k8s.io/v1beta1"
  2.   "kind""TokenReview"
  3.   "status": { 
  4.     "authenticated"false 
  5.   } 

遠(yuǎn)程服務(wù)應(yīng)該會(huì)填充請(qǐng)求的 status 字段,以標(biāo)明登錄操作是否成功。

開發(fā)認(rèn)證服務(wù)

(1)創(chuàng)建項(xiàng)目并初始化go mod

  1. # mkdir kubernetes-auth-webhook 
  2. # cd kubernetes-auth-webhook 
  3. # go mod init 

(2)在項(xiàng)目根目錄下創(chuàng)建webhook.go,寫入如下內(nèi)容

  1. package main 
  2.  
  3. import ( 
  4.  "encoding/json" 
  5.  "github.com/golang/glog" 
  6.  authentication "k8s.io/api/authentication/v1beta1" 
  7.  "k8s.io/klog/v2" 
  8.  "net/http" 
  9.  "strings" 
  10.  
  11. type WebHookServer struct { 
  12.  server *http.Server 
  13.  
  14. func (ctx *WebHookServer) serve(w http.ResponseWriter, r *http.Request) { 
  15.  // 從APIServer中取出body 
  16.  // 將body進(jìn)行拆分, 取出type 
  17.  // 根據(jù)type, 取出不同的認(rèn)證數(shù)據(jù) 
  18.  var req authentication.TokenReview 
  19.  decoder := json.NewDecoder(r.Body) 
  20.  err := decoder.Decode(&req) 
  21.  if err != nil { 
  22.   klog.Error(err, "decoder request body error."
  23.   req.Status = authentication.TokenReviewStatus{Authenticated: false
  24.   w.WriteHeader(http.StatusUnauthorized) 
  25.   _ = json.NewEncoder(w).Encode(req) 
  26.   return 
  27.  } 
  28.  // 判斷token是否包含':' 
  29.  // 如果不包含,則返回認(rèn)證失敗 
  30.  if !(strings.Contains(req.Spec.Token, ":")) { 
  31.   klog.Error(err, "token invalied."
  32.   req.Status = authentication.TokenReviewStatus{Authenticated: false
  33.   //req.Status = map[string]interface{}{"authenticated"false
  34.   w.WriteHeader(http.StatusUnauthorized) 
  35.   _ = json.NewEncoder(w).Encode(req) 
  36.   return 
  37.  } 
  38.  // split token, 獲取type 
  39.  tokenSlice := strings.SplitN(req.Spec.Token, ":", -1) 
  40.  glog.Infof("tokenSlice: ", tokenSlice) 
  41.  hookType := tokenSlice[0] 
  42.  switch hookType { 
  43.  case "github"
  44.   githubToken := tokenSlice[1] 
  45.   err := authByGithub(githubToken) 
  46.   if err != nil { 
  47.    klog.Error(err, "auth by github error"
  48.    req.Status = authentication.TokenReviewStatus{Authenticated: false
  49.    w.WriteHeader(http.StatusUnauthorized) 
  50.    _ = json.NewEncoder(w).Encode(req) 
  51.    return 
  52.   } 
  53.   klog.Info("auth by github success"
  54.   req.Status = authentication.TokenReviewStatus{Authenticated: true
  55.   w.WriteHeader(http.StatusOK) 
  56.   _ = json.NewEncoder(w).Encode(req) 
  57.   return 
  58.  case "ldap"
  59.   username := tokenSlice[1] 
  60.   password := tokenSlice[2] 
  61.   err := authByLdap(username, password
  62.   if err != nil { 
  63.    klog.Error(err, "auth by ldap error"
  64.    req.Status = authentication.TokenReviewStatus{Authenticated: false
  65.    //req.Status = map[string]interface{}{"authenticated"false
  66.    w.WriteHeader(http.StatusUnauthorized) 
  67.    _ = json.NewEncoder(w).Encode(req) 
  68.    return 
  69.   } 
  70.   klog.Info("auth by ldap success"
  71.   req.Status = authentication.TokenReviewStatus{Authenticated: true
  72.   //req.Status = map[string]interface{}{"authenticated"true
  73.   w.WriteHeader(http.StatusOK) 
  74.   _ = json.NewEncoder(w).Encode(req) 
  75.   return 
  76.  } 

主要是解析認(rèn)證的請(qǐng)求Token,然后將Token進(jìn)行拆分判斷是需要什么認(rèn)證,Token的樣例如下:

  • Github認(rèn)證:github:
  • LDAP認(rèn)證:ldap::

這樣就可以獲取到用戶想用哪種認(rèn)證,再掉具體的認(rèn)證服務(wù)進(jìn)行處理。

(3)創(chuàng)建github.go,提供github認(rèn)證方法

  1. package main 
  2.  
  3. import ( 
  4.  "context" 
  5.  "github.com/golang/glog" 
  6.  "github.com/google/go-github/github" 
  7.  "golang.org/x/oauth2" 
  8.  
  9. func authByGithub(token string) (err error) { 
  10.  glog.V(2).Info("start auth by github......"
  11.  tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}) 
  12.  tokenClient := oauth2.NewClient(context.Background(), tokenSource) 
  13.  githubClient := github.NewClient(tokenClient) 
  14.  _, _, err = githubClient.Users.Get(context.Background(), ""
  15.  if err != nil { 
  16.   return err 
  17.  } 
  18.  return nil 

可以看到,這里僅僅做了一個(gè)簡(jiǎn)單的Token認(rèn)證,認(rèn)證的結(jié)果比較粗暴,如果err=nil,則表示認(rèn)證成功。

(4)創(chuàng)建ldap.go,提供ldap認(rèn)證

  1. package main 
  2.  
  3. import ( 
  4.  "crypto/tls" 
  5.  "errors" 
  6.  "fmt" 
  7.  "github.com/go-ldap/ldap/v3" 
  8.  "github.com/golang/glog" 
  9.  "k8s.io/klog/v2" 
  10.  "strings" 
  11.  
  12. var ( 
  13.  ldapUrl = "ldap://" + "192.168.100.179:389" 
  14.  
  15. func authByLdap(username, password string) error { 
  16.  groups, err := getLdapGroups(username, password
  17.  if err != nil { 
  18.   return err 
  19.  } 
  20.  if len(groups) > 0 { 
  21.   return nil 
  22.  } 
  23.  
  24.  return fmt.Errorf("No matching group or user attribute. Authentication rejected, Username: %s", username) 
  25.  
  26. // 獲取user的groups 
  27. func getLdapGroups(username, password string) ([]string, error) { 
  28.  glog.Info("username:password", username, ":"password
  29.  var groups []string 
  30.  
  31.  config := &tls.Config{InsecureSkipVerify: true
  32.  ldapConn, err := ldap.DialURL(ldapUrl, ldap.DialWithTLSConfig(config)) 
  33.  if err != nil { 
  34.   glog.V(4).Info("dial ldap failed, err: ", err) 
  35.   return groups, err 
  36.  } 
  37.  defer ldapConn.Close() 
  38.  
  39.  binduser := fmt.Sprintf("CN=%s,ou=People,dc=demo,dc=com", username) 
  40.  
  41.  err = ldapConn.Bind(binduser, password
  42.  if err != nil { 
  43.   klog.V(4).ErrorS(err, "bind user to ldap error"
  44.   return groups, err 
  45.  } 
  46.  
  47.  // 查詢用戶成員 
  48.  searchString := fmt.Sprintf("(&(objectClass=person)(cn=%s))", username) 
  49.  memberSearchAttribute := "memberOf" 
  50.  searchRequest := ldap.NewSearchRequest( 
  51.   "dc=demo,dc=com"
  52.   ldap.ScopeWholeSubtree, 
  53.   ldap.NeverDerefAliases, 
  54.   0, 
  55.   0, 
  56.   false
  57.   searchString, 
  58.   []string{memberSearchAttribute}, 
  59.   nil, 
  60.  ) 
  61.  searchResult, err := ldapConn.Search(searchRequest) 
  62.  if err != nil { 
  63.   klog.V(4).ErrorS(err, "search user properties error"
  64.   return groups, err 
  65.  } 
  66.  // 如果沒有查到結(jié)果,返回失敗 
  67.  if len(searchResult.Entries[0].Attributes) < 1 { 
  68.   return groups, errors.New("no user in ldap"
  69.  } 
  70.  entry := searchResult.Entries[0] 
  71.  for _, e := range entry.Attributes { 
  72.   for _, attr := range e.Values { 
  73.    groupList := strings.Split(attr, ","
  74.    for _, g := range groupList { 
  75.     if strings.HasPrefix(g, "cn=") { 
  76.      group := strings.Split(g, "="
  77.      groups = append(groups, group[1]) 
  78.     } 
  79.    } 
  80.   } 
  81.  } 
  82.  return groups, nil 

這里的用戶名是固定了的,所以不適合其他場(chǎng)景。

(5)創(chuàng)建main.go入口函數(shù)

  1. package main 
  2.  
  3. import ( 
  4.  "context" 
  5.  "flag" 
  6.  "fmt" 
  7.  "github.com/golang/glog" 
  8.  "net/http" 
  9.  "os" 
  10.  "os/signal" 
  11.  "syscall" 
  12.  
  13. var port string 
  14.  
  15. func main() { 
  16.  flag.StringVar(&port, "port""9999""http server port"
  17.  flag.Parse() 
  18.  // 啟動(dòng)httpserver 
  19.  wbsrv := WebHookServer{server: &http.Server{ 
  20.   Addr: fmt.Sprintf(":%v", port), 
  21.  }} 
  22.  mux := http.NewServeMux() 
  23.  mux.HandleFunc("/auth", wbsrv.serve) 
  24.  wbsrv.server.Handler = mux 
  25.  
  26.  // 啟動(dòng)協(xié)程來處理 
  27.  go func() { 
  28.   if err := wbsrv.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { 
  29.    glog.Errorf("Failed to listen and serve webhook server: %v", err) 
  30.   } 
  31.  }() 
  32.  
  33.  glog.Info("Server started"
  34.  
  35.  // 優(yōu)雅退出 
  36.  signalChan := make(chan os.Signal, 1) 
  37.  signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) 
  38.  <-signalChan 
  39.  
  40.  glog.Infof("Got OS shutdown signal, shutting down webhook server gracefully..."
  41.  _ = wbsrv.server.Shutdown(context.Background()) 

到此整個(gè)認(rèn)證服務(wù)就開發(fā)完畢了,是不是很簡(jiǎn)單?

Webhook測(cè)試

APIServer添加認(rèn)證服務(wù)

使用Webhook進(jìn)行認(rèn)證,需要在kube-apiserver里開啟,參數(shù)如下:

  • --authentication-token-webhook-config-file 指向一個(gè)配置文件,其中描述 如何訪問遠(yuǎn)程的 Webhook 服務(wù)
  • --authentication-token-webhook-config-file 指向一個(gè)配置文件,其中描述 如何訪問遠(yuǎn)程的 Webhook 服務(wù)

配置文件使用 kubeconfig 文件的格式。文件中,clusters 指代遠(yuǎn)程服務(wù),users 指代遠(yuǎn)程 API 服務(wù) Webhook。配置如下:

(1)、將配置文件放到相應(yīng)的目錄

  1. # mkdir /etc/kubernetes/webhook 
  2. # cat >> webhook-config.json <EOF 
  3.   "kind""Config"
  4.   "apiVersion""v1"
  5.   "preferences": {}, 
  6.   "clusters": [ 
  7.     { 
  8.       "name""github-authn"
  9.       "cluster": { 
  10.         "server""http://10.0.4.9:9999/auth" 
  11.       } 
  12.     } 
  13.   ], 
  14.   "users": [ 
  15.     { 
  16.       "name""authn-apiserver"
  17.       "user": { 
  18.         "token""secret" 
  19.       } 
  20.     } 
  21.   ], 
  22.   "contexts": [ 
  23.     { 
  24.       "name""webhook"
  25.       "context": { 
  26.         "cluster""github-authn"
  27.         "user""authn-apiserver" 
  28.       } 
  29.     } 
  30.   ], 
  31.   "current-context""webhook" 
  32. EOF 

 (2)在kube-apiserver中添加配置參數(shù)

  1. # mkdir /etc/kubernetes/backup 
  2. # cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/backup/kube-apiserver.yaml 
  3. # cd /etc/kubernetes/manifests/ 
  4. # cat kube-apiserver.yaml 
  5. apiVersion: v1 
  6. kind: Pod 
  7. metadata: 
  8.   annotations: 
  9.     kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.0.4.9:6443 
  10.   creationTimestamp: null 
  11.   labels: 
  12.     component: kube-apiserver 
  13.     tier: control-plane 
  14.   name: kube-apiserver 
  15.   namespace: kube-system 
  16. spec: 
  17.   containers: 
  18.   - command: 
  19.     - kube-apiserver 
  20.     - ...... 
  21.     - --authentication-token-webhook-config-file=/etc/config/webhook-config.json 
  22.     image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.22.0 
  23.     imagePullPolicy: IfNotPresent 
  24.     ...... 
  25.     volumeMounts: 
  26.     ...... 
  27.     - name: webhook-config 
  28.       mountPath: /etc/config 
  29.       readOnly: true 
  30.   hostNetwork: true 
  31.   priorityClassName: system-node-critical 
  32.   securityContext: 
  33.     seccompProfile: 
  34.       type: RuntimeDefault 
  35.   volumes: 
  36.   ...... 
  37.   - hostPath: 
  38.       path: /etc/kubernetes/webhook 
  39.       type: DirectoryOrCreate 
  40.     name: webhook-config 
  41. status: {} 

ps: 為了節(jié)約篇幅,上面省略了部分配置。

當(dāng)修改完過后,kube-apiserver會(huì)自動(dòng)重啟。

測(cè)試Github認(rèn)證

(1)在github上獲取Token,操作如圖所示

(2)配置kubeconfig,添加user

  1. # cat ~/.kube/config  
  2. apiVersion: v1 
  3. ...... 
  4. users: 
  5. name: joker 
  6.   user
  7.     token: github:ghp_jevHquU4g43m46nczWS0ojxxxxxxxxx 

(3)用Joker用戶進(jìn)行訪問

返回結(jié)果如下,至于報(bào)錯(cuò)是因?yàn)橛脩舻臋?quán)限不足。

  1. # kubectl get po --user=joker 
  2. Error from server (Forbidden): pods is forbidden: User "" cannot list resource "pods" in API group "" in the namespace "default" 

可以在webhook上看到日志信息,如下:

  1. # ./kubernetes-auth-webhook  
  2. I1207 15:37:29.531502   21959 webhook.go:55] auth by github success 

從日志和結(jié)果可以看到,使用Github認(rèn)證是OK的。

測(cè)試LDAP認(rèn)證

LDAP簡(jiǎn)介

LDAP是協(xié)議,不是軟件。

LDAP是輕量目錄訪問協(xié)議,英文全稱是Lightweight Directory Access Protocol,一般都簡(jiǎn)稱為L(zhǎng)DAP。按照我們對(duì)文件目錄的理解,ldap可以看成一個(gè)文件系統(tǒng),類似目錄和文件樹。

OpenLDAP是常用的服務(wù)之一,也是我們本次測(cè)試的認(rèn)證服務(wù)。

安裝OpenLDAP

OpenLDAP的安裝方式有很多,可以使用容器部署,也可以直接安裝在裸機(jī)上,這里采用后者。

  1. # yum install -y openldap openldap-clients openldap-servers  
  2. # systemctl start slapd 
  3. # systemctl enable slapd 

默認(rèn)配置文件,位于/etc/openldap/slapd.d, 文件格式為L(zhǎng)DAP Input Format (LDIF), ldap目錄特定的格式。這里不對(duì)配置文件做太多的介紹,有興趣可以自己去學(xué)習(xí)學(xué)習(xí)【1】。

在LDAP上配置用戶

(1)導(dǎo)入模板

  1. ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif  
  2. ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif  
  3. ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif  

(2)創(chuàng)建base組織

  1. # cat base.ldif 
  2. dn: dc=demo,dc=com 
  3. objectClass: top 
  4. objectClass: dcObject 
  5. objectClass: organization 
  6. o: ldap測(cè)試組織 
  7. dc: demo 
  8.  
  9. dn: cn=Manager,dc=demo,dc=com 
  10. objectClass: organizationalRole 
  11. cn: Manager 
  12. description: 組織管理人 
  13.  
  14. dn: ou=People,dc=demo,dc=com 
  15. objectClass: organizationalUnit 
  16. ou: People 
  17.  
  18. dn: ou=Group,dc=demo,dc=com 
  19. objectClass: organizationalUnit 
  20. ou: Group 

使用ldapadd添加base。

  1. ldapadd -x -D cn=admin,dc=demo,dc=com -w admin -f base.ldif  

(3)添加成員

  1. # cat adduser.ldif 
  2. dn: cn=jack,ou=People,dc=demo,dc=com 
  3. changetype: add 
  4. objectClass: inetOrgPerson 
  5. cn: jack 
  6. departmentNumber: 1 
  7. title: 大牛 
  8. userPassword: 123456 
  9. sn: Bai 
  10. mail: jack@demo.com 
  11. displayName: 中文名 

使用ldapadd執(zhí)行添加。

  1. ldapadd -x -D cn=admin,dc=demo,dc=com -w admin -f adduser.ldif 

(4)將用戶添加到組

  1. # cat add_member_group.ldif  
  2. dn: cn=g-admin,ou=Group,dc=demo,dc=com 
  3. changetype: modify 
  4. add: member 
  5. member: cn=jack,ou=People,dc=demo,dc=com 

使用ldapadd執(zhí)行添加。

  1. ldapadd -x -D cn=admin,dc=demo,dc=com -w admin -f add_member_group.ldif 

配置kubeconfig,進(jìn)行l(wèi)dap認(rèn)證測(cè)試

(1)修改~/.kube/config配置文件

  1. # cat ~/.kube/config  
  2. apiVersion: v1 
  3. ...... 
  4. users: 
  5. name: joker 
  6.   user
  7.     token: github:ghp_jevHquU4g43m46nczWS0oxxxxxxxx 
  8. name: jack 
  9.   user
  10.     token: ldap:jack:123456 

(2)使用kubectl進(jìn)行測(cè)試

  1. # kubectl get po --user=jack 
  2. Error from server (Forbidden): pods is forbidden: User "" cannot list resource "pods" in API group "" in the namespace "default" 

webhook服務(wù)日志如下:

  1. # ./kubernetes-auth-webhook  
  2. I1207 16:09:09.292067    7605 webhook.go:72] auth by ldap success 

通過測(cè)試結(jié)果可以看到使用LDAP認(rèn)證測(cè)試成功。

總結(jié)

使用Webhook可以很靈活的將K8S的租戶和企業(yè)內(nèi)部賬戶系統(tǒng)進(jìn)行打通,這樣可以方便管理用戶賬戶。

不過上面開發(fā)的Webhook只是一個(gè)簡(jiǎn)單的例子,驗(yàn)證方式和手法都比較粗暴,CoreOS開源的Dex【2】是比較不錯(cuò)的產(chǎn)品,可以直接使用。

本文轉(zhuǎn)載自微信公眾號(hào)「運(yùn)維開發(fā)故事」

 

責(zé)任編輯:姜華 來源: 運(yùn)維開發(fā)故事
相關(guān)推薦

2025-03-19 08:01:10

Kubernetes集群源碼

2022-04-22 13:32:01

K8s容器引擎架構(gòu)

2015-02-12 15:33:43

微信SDK

2023-03-31 07:17:16

2023-11-06 07:16:22

WasmK8s模塊

2015-02-12 15:38:26

微信SDK

2021-02-03 14:04:52

k8spermissionm管理工具

2022-04-29 10:40:38

技術(shù)服務(wù)端K8s

2023-09-06 08:12:04

k8s云原生

2023-01-04 17:42:22

KubernetesK8s

2022-09-07 15:57:41

KubernetesCRD

2023-09-11 14:21:00

2024-01-26 14:35:03

鑒權(quán)K8sNode

2020-05-12 10:20:39

K8s kubernetes中間件

2022-09-05 08:26:29

Kubernetes標(biāo)簽

2025-04-01 00:06:50

JavaK8sSpring

2009-09-07 22:00:15

LINQ自定義

2025-04-09 07:58:15

2023-08-03 08:36:30

Service服務(wù)架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)