如果你是一名 Kubernetes Operator 的開發者,你曾經是否面臨過這樣一個棘手的問題:如何在本地環境中高效地調試 Webhook,尤其是在涉及有效證書回調的情況下。這篇文章旨在提供一種清晰的指南,幫助你克服這一挑戰,優化本地開發和測試流程。
當我們初步涉足 Kubernetes Webhook 時,面對的首個挑戰通常是 Validation Webhook。對于這種驗證型 Webhook 來說,我們可以通過編寫自動化測試來驗證其功能。
這不僅確保了我的 Webhook 按預期工作,還允許我在日常開發中臨時禁用它,從而加快了整個開發過程。這種方法讓我能夠巧妙地避免復雜的調試問題,而不對整體功能造成任何影響。
if os.Getenv("ENABLE_WEBHOOKS") != "false" { if err = (&webappv1.Guestbook{}).SetupWebhookWithManager(mgr); err != nil { setupLog.Error(err, "unable to create webhook", "webhook", "Guestbook") os.Exit(1) }}
然而,對于 Mutating Webhook 來說,情況就變得有點復雜了。這類 Webhook 通常負責埋點的行為甚至更深層次的集群操作,比如注入 sidecar,這時候單靠自動化測試顯然是不夠的。我們需要一個更加高效的本地測試和調試方法。
在我們團隊中,有同事采用 Kind 來部署和測試服務,這種方法非常值得稱贊。它完全符合 K8s 的操作模式,為我們提供了一個接近生產環境的本地測試平臺。但是,大家可能也注意到了,這種方式存在一個效率瓶頸:每次進行代碼更改后,都需要重新構建 Docker 鏡像并部署到集群中,這一過程既耗時又影響開發流程的連貫性。
作為開發工程師,我們渴望的是一個極速的內部開發循環,一個不再需要頻繁的 docker build、docker push 或繁瑣的部署流程,即使這些已經完全自動化。
我們希望能夠使用本地熟悉的開發工具,如 VS Code 或者 IntelliJ IDEA 進行本地調試,而不是先部署到集群環境,再通過日志來分析錯誤這種遠程調試模式。
在不禁用 Webhook 的情況下,我們在本地啟動 controller 后會有如下錯誤。這個比較好處理,我們只要使用自簽證書,注入到 WebhookServer 即可,在前面的文章中我介紹過很多次,這里不再贅述。
2023-11-26T12:55:17+08:00 INFO Stopping and waiting for webhooks...2023-11-26T12:55:17+08:00 INFO Wait completed, proceeding to shutdown the manager2023-11-26T12:55:17+08:00 ERROR setup problem running manager {"error": "open /var/folders/hn/v2s5bx...00000gn/T/k8s-webhook-server/serving-certs/tls.crt: no such file or directory"}...
我們來運行一個示例,想必下面這個錯誤大家都非常熟悉吧,這個是因為 Webhook 注冊的地址'不對',它是集群內的地址。
? kubectl apply -f ./config/samplesError from server (InternalError): error when creating "config/samples/webapp_v1_guestbook.yaml": Internal error occurred: failed calling webhook "vguestbook.kb.io": failed to call webhook: Post "https://testing-webhooks-webhook-service.testing-webhooks-system.svc:443/validate-webapp-foobar-ai-v1-guestbook?timeout=10s": no endpoints available for service "testing-webhooks-webhook-service"
我們再來看下 ValidatingWebhookConfiguration 的配置。
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingWebhookConfigurationmetadata: name: testing-webhooks-validating-webhook-configurationwebhooks:- admissionReviewVersions: - v1 clientConfig: service: name: testing-webhooks-webhook-service namespace: testing-webhooks-system path: /validate-webapp-foobar-ai-v1-guestbook port: 443 failurePolicy: Fail matchPolicy: Equivalent name: vguestbook.kb.io rules: - ... ...
在這個配置中,webhooks 字段定義了一個或多個要注冊的 Webhook。每個 Webhook 通過 clientConfig 配置與 Kubernetes API 服務器的連接方式。
正如大家所看到的 https://testing-webhooks-webhook-service.testing-webhooks-system.svc:443/validate-webapp-foobar-ai-v1-guestbook,這個默認地址其實就是 K8s 集群內部的地址。這恰是 K8s 中處理 Webhook 的常規方法,其中 service 字段指向集群內運行的特定服務。
然而,在本地開發環境中,我們只在本地運行了我們的 Operator,直接使用內部服務是不大可能的,因為它要求 Webhook 服務必須部署在 K8s 集群中。
當我們在 K8s 中配置 Webhook 時,了解其配置細節是非常重要的。kubectl explain 是一個非常實用的小工具,它可以幫助我們深入理解 K8s 資源的各個屬性。
以 ValidatingWebhookConfiguration.webhooks.clientConfig 為例:
? kubectl explain ValidatingWebhookConfiguration.webhooks.clientConfigGROUP: admissionregistration.k8s.ioKIND: ValidatingWebhookConfigurationVERSION: v1FIELD: clientConfig <WebhookClientConfig>:DESCRIPTION:FIELDS: caBundle <string> `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate. If unspecified, system trust roots on the apiserver are used. service <ServiceReference> `service` is a reference to the service for this webhook. Either `service` or `url` must be specified. If the webhook is running within the cluster, then you should use `service`. url <string> `url` gives the location of the webhook, in standard URL form (`scheme://host:port/path`). Exactly one of `url` or `service` must be specified.
通過以上提供的詳細信息,不難發現 clientConfig 它除了通過定義 Service 讓 API 服務器連接到 WebhookServer 外,還有另外一種方式,那就是直接通過 URL 連接。
為了解決這個問題,我們可以將 Webhook 的配置從服務轉變為直接使用 URL。
通過將 clientConfig 中的 service 字段替換為 url 字段,我們可以指定 Webhook 服務的外部 URL。這樣一來,開發者可以在本地運行 Webhook 服務,并通過公開的 URL 使其可被 Kubernetes API 服務器訪問。
例如:
webhooks:- admissionReviewVersions: - v1 clientConfig: url: https://testing-webhooks.loca.lt/validate-webapp-foobar-ai-v1-guestbook
這種方法使得在本地開發環境中調試 Webhook 變得更加靈活和便捷。開發者可以使用本地服務器或通過隧道(如 ngrok[1] 或 localtunnel[2])暴露的服務,從而實現在本地環境中的有效調試。
事實上,我最初的首選是 ngrok,因為這玩意確實好用,它還有個 localhost:4040 非常的實用,但遺憾的是,它的 tls 能力是付費的。幸好,有很多平替工具可以選擇,比如 localtunnel,用起來也非常的方便。
步驟 1: 在我們的 main.go 需要接收一個證書路徑
...var certDir stringflag.StringVar(&certDir, "webhook-cert-dir", "/tmp/k8s-webhook-server/serving-certs", "Admission webhook cert/key dir.")...mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, Metrics: metricsserver.Options{BindAddress: metricsAddr}, HealthProbeBindAddress: probeAddr, WebhookServer: webhook.NewServer(webhook.Options{ CertDir: certDir, Port: 9443, }), LeaderElection: enableLeaderElection, LeaderElectionID: "dcc993a0.foobar.ai",})...
步驟 2:調整 Makefile,并啟動我們的程序
修改 Makefile 文件,讓其可以接收證書目錄:
.PHONY: runrun: manifests generate fmt vet ## Run a controller from your host. go run ./cmd/main.go --webhook-cert-dir ./config/certs
啟動程序:
? make run...go run ./cmd/main.go --webhook-cert-dir ./config/certs2023-11-26T11:18:42+08:00 INFO controller-runtime.builder Registering a mutating webhook {"GVK": "webapp.foobar.ai/v1, Kind=Guestbook", "path": "/mutate-webapp-foobar-ai-v1-guestbook"}2023-11-26T11:18:42+08:00 INFO controller-runtime.webhook Registering webhook {"path": "/mutate-webapp-foobar-ai-v1-guestbook"}2023-11-26T11:18:42+08:00 INFO controller-runtime.builder Registering a validating webhook {"GVK": "webapp.foobar.ai/v1, Kind=Guestbook", "path": "/validate-webapp-foobar-ai-v1-guestbook"}2023-11-26T11:18:42+08:00 INFO controller-runtime.webhook Registering webhook {"path": "/validate-webapp-foobar-ai-v1-guestbook"}...2023-11-26T11:18:42+08:00 INFO controller-runtime.webhook Starting webhook server...2023-11-26T11:18:42+08:00 INFO controller-runtime.webhook Serving webhook server {"host": "", "port": 9443}...
步驟 3:將本地主機服務器通過隧道公開
# 安裝npm install -g localtunnel# 使用 lt 命令啟動隧道lt --port 9443 / --local-https / --local-ca $(pwd)/certs/ca.crt / --local-cert $(pwd)/certs/tls.crt / --local-key $(pwd)/certs/tls.key / --subdomain testing-webhooksyour url is: https://testing-webhooks.loca.lt
步驟 4:修改 ValidatingWebhookConfiguration 配置
我們將默認的 service 服務。
webhooks:- admissionReviewVersions: - v1 clientConfig: service: name: testing-webhooks-webhook-service namespace: testing-webhooks-system path: /validate-webapp-foobar-ai-v1-guestbook port: 443...
替換換成 url 直連模式
webhooks:- admissionReviewVersions: - v1 clientConfig: url: https://testing-webhooks.loca.lt/validate-webapp-foobar-ai-v1-guestbook...
以上僅以 ValidatingWebhookConfiguration 為例,如果你的 controller 同時使用了 MutatingWebhookConfiguration,別忘了,處理方式是一樣的。
步驟 5:看看實際效果如何
最后,我們再執行同樣一個用例,就可以被當前的 ValidatingWebhook 攔截到了。
? kubectl apply -f ./config/samples/webapp_v1_guestbook.yamlThe Guestbook "guestbook-sample" is invalid: metadata.name: Invalid value: "guestbook-sample": Guestbook name must be no more than 5 characters for test purposes
本文鏈接:http://www.www897cc.com/showinfo-26-34633-0.html云原生小技巧 : 如何在本地調試 Kubernetes Webhook?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 四種消息隊列,如何選型?