257 lines
8.7 KiB
Go
257 lines
8.7 KiB
Go
package options
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"flag"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/spf13/pflag"
|
||
"k8s.io/client-go/rest"
|
||
"k8s.io/client-go/tools/clientcmd"
|
||
"k8s.io/client-go/tools/leaderelection"
|
||
cliflag "k8s.io/component-base/cli/flag"
|
||
"k8s.io/klog/v2"
|
||
ctrl "sigs.k8s.io/controller-runtime"
|
||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
|
||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||
|
||
"code.gitea.io/gitea/modules/k8s/controller"
|
||
)
|
||
|
||
type ControllerManagerOptions struct {
|
||
KubeConfig string
|
||
Master string
|
||
MetricsAddr string
|
||
HealthProbeAddr string
|
||
|
||
LeaderElect bool
|
||
LeaderElection *leaderelection.LeaderElectionConfig
|
||
|
||
WebhookCertDir string
|
||
SecureMetrics bool
|
||
EnableHTTP2 bool
|
||
|
||
// ControllerGates is the list of controller gates to enable or disable controller.
|
||
// '*' means "all enabled by default controllers"
|
||
// 'foo' means "enable 'foo'"
|
||
// '-foo' means "disable 'foo'"
|
||
// first item for a particular name wins.
|
||
ControllerGates []string
|
||
|
||
DebugMode bool
|
||
}
|
||
|
||
func NewControllerManagerOptions() *ControllerManagerOptions {
|
||
return &ControllerManagerOptions{
|
||
KubeConfig: "",
|
||
Master: "",
|
||
MetricsAddr: ":8080",
|
||
HealthProbeAddr: ":8081",
|
||
LeaderElect: false,
|
||
LeaderElection: &leaderelection.LeaderElectionConfig{
|
||
LeaseDuration: 30 * time.Second,
|
||
RenewDeadline: 15 * time.Second,
|
||
RetryPeriod: 5 * time.Second,
|
||
},
|
||
WebhookCertDir: "",
|
||
SecureMetrics: true,
|
||
EnableHTTP2: false,
|
||
ControllerGates: []string{"*"},
|
||
DebugMode: false,
|
||
}
|
||
}
|
||
|
||
// Flags 返回一组命名的命令行标志集合
|
||
func (s *ControllerManagerOptions) Flags() cliflag.NamedFlagSets {
|
||
fss := cliflag.NamedFlagSets{}
|
||
|
||
// Kubernetes 相关选项
|
||
fs := fss.FlagSet("kubernetes")
|
||
fs.StringVar(&s.KubeConfig, "kubeconfig", s.KubeConfig, "Path to kubeconfig file with authorization and master location information.")
|
||
fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server.")
|
||
|
||
// 指标和健康检查
|
||
fs = fss.FlagSet("metrics")
|
||
fs.StringVar(&s.MetricsAddr, "metrics-bind-address", s.MetricsAddr, "The address the metric endpoint binds to. Use :8443 for HTTPS or :8080 for HTTP, or 0 to disable.")
|
||
fs.StringVar(&s.HealthProbeAddr, "health-probe-bind-address", s.HealthProbeAddr, "The address the probe endpoint binds to.")
|
||
fs.BoolVar(&s.SecureMetrics, "metrics-secure", s.SecureMetrics, "If set, metrics endpoint is served securely via HTTPS.")
|
||
|
||
// Leader 选举相关选项
|
||
fs = fss.FlagSet("leaderelection")
|
||
fs.BoolVar(&s.LeaderElect, "leader-elect", s.LeaderElect, "Whether to enable leader election. This field should be enabled when controller manager deployed with multiple replicas.")
|
||
s.bindLeaderElectionFlags(s.LeaderElection, fs)
|
||
|
||
// Webhook 相关选项
|
||
fs = fss.FlagSet("webhook")
|
||
fs.StringVar(&s.WebhookCertDir, "webhook-cert-dir", s.WebhookCertDir, "Certificate directory used to setup webhooks, need tls.crt and tls.key placed inside. If not set, webhook server would look up the server key and certificate in {TempDir}/k8s-webhook-server/serving-certs")
|
||
fs.BoolVar(&s.EnableHTTP2, "enable-http2", s.EnableHTTP2, "If set, HTTP/2 will be enabled for the metrics and webhook servers")
|
||
|
||
// 一般选项
|
||
fs = fss.FlagSet("generic")
|
||
fs.StringSliceVar(&s.ControllerGates, "controllers", s.ControllerGates, fmt.Sprintf("A list of controllers to enable. '*' enables all on-by-default controllers, 'foo' enables the controller named 'foo', '-foo' disables the controller named 'foo'.\nAll controllers: %s",
|
||
strings.Join(controller.GetAllControllers().List(), ", ")))
|
||
fs.BoolVar(&s.DebugMode, "debug", s.DebugMode, "Don't enable this if you don't know what it means.")
|
||
|
||
// klog 选项
|
||
kfs := fss.FlagSet("klog")
|
||
local := flag.NewFlagSet("klog", flag.ExitOnError)
|
||
klog.InitFlags(local)
|
||
local.VisitAll(func(fl *flag.Flag) {
|
||
fl.Name = strings.Replace(fl.Name, "_", "-", -1)
|
||
kfs.AddGoFlag(fl)
|
||
})
|
||
|
||
return fss
|
||
}
|
||
|
||
// 绑定 Leader 选举相关标志
|
||
func (s *ControllerManagerOptions) bindLeaderElectionFlags(l *leaderelection.LeaderElectionConfig, fs *pflag.FlagSet) {
|
||
fs.DurationVar(&l.LeaseDuration, "leader-elect-lease-duration", l.LeaseDuration, ""+
|
||
"The duration that non-leader candidates will wait after observing a leadership "+
|
||
"renewal until attempting to acquire leadership of a led but unrenewed leader "+
|
||
"slot. This is effectively the maximum duration that a leader can be stopped "+
|
||
"before it is replaced by another candidate. This is only applicable if leader "+
|
||
"election is enabled.")
|
||
fs.DurationVar(&l.RenewDeadline, "leader-elect-renew-deadline", l.RenewDeadline, ""+
|
||
"The interval between attempts by the acting master to renew a leadership slot "+
|
||
"before it stops leading. This must be less than or equal to the lease duration. "+
|
||
"This is only applicable if leader election is enabled.")
|
||
fs.DurationVar(&l.RetryPeriod, "leader-elect-retry-period", l.RetryPeriod, ""+
|
||
"The duration the clients should wait between attempting acquisition and renewal "+
|
||
"of a leadership. This is only applicable if leader election is enabled.")
|
||
}
|
||
|
||
// Validate 验证选项
|
||
func (s *ControllerManagerOptions) Validate() []error {
|
||
var errs []error
|
||
|
||
// 验证 ControllerGates
|
||
allControllersNameSet := controller.GetAllControllers()
|
||
for _, selector := range s.ControllerGates {
|
||
if selector == "*" {
|
||
continue
|
||
}
|
||
selector = strings.TrimPrefix(selector, "-")
|
||
if !allControllersNameSet.Has(selector) {
|
||
errs = append(errs, fmt.Errorf("%q is not in the list of known controllers", selector))
|
||
}
|
||
}
|
||
|
||
return errs
|
||
}
|
||
|
||
// IsControllerEnabled 检查指定的控制器是否启用
|
||
func (s *ControllerManagerOptions) IsControllerEnabled(name string) bool {
|
||
allowedAll := false
|
||
for _, controllerGate := range s.ControllerGates {
|
||
if controllerGate == name {
|
||
return true
|
||
}
|
||
if controllerGate == "-"+name {
|
||
return false
|
||
}
|
||
if controllerGate == "*" {
|
||
allowedAll = true
|
||
}
|
||
}
|
||
return allowedAll
|
||
}
|
||
|
||
// NewControllerManager 创建并返回一个新的控制器管理器
|
||
func (s *ControllerManagerOptions) NewControllerManager() (*controller.Manager, error) {
|
||
cm := &controller.Manager{}
|
||
|
||
// TLS 选项
|
||
tlsOpts := []func(*tls.Config){}
|
||
|
||
// 如果未启用 HTTP/2,则禁用它以防止 HTTP/2 流取消和快速重置 CVE 的漏洞
|
||
if !s.EnableHTTP2 {
|
||
disableHTTP2 := func(c *tls.Config) {
|
||
klog.V(4).Info("disabling http/2")
|
||
c.NextProtos = []string{"http/1.1"}
|
||
}
|
||
tlsOpts = append(tlsOpts, disableHTTP2)
|
||
}
|
||
|
||
// Webhook 服务器配置
|
||
webhookServer := webhook.NewServer(webhook.Options{
|
||
CertDir: s.WebhookCertDir,
|
||
TLSOpts: tlsOpts,
|
||
Port: 8443,
|
||
})
|
||
|
||
// 度量服务器配置
|
||
metricsServerOptions := metricsserver.Options{
|
||
BindAddress: s.MetricsAddr,
|
||
SecureServing: s.SecureMetrics,
|
||
TLSOpts: tlsOpts,
|
||
}
|
||
|
||
if s.SecureMetrics {
|
||
// 使用身份验证和授权来保护度量端点
|
||
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
|
||
}
|
||
|
||
// 设置控制器管理器选项
|
||
controllerOpts := ctrl.Options{
|
||
Scheme: controller.Scheme,
|
||
Metrics: metricsServerOptions,
|
||
WebhookServer: webhookServer,
|
||
HealthProbeBindAddress: s.HealthProbeAddr,
|
||
}
|
||
|
||
// 配置 Leader 选举
|
||
if s.LeaderElect {
|
||
controllerOpts.LeaderElection = s.LeaderElect
|
||
controllerOpts.LeaderElectionNamespace = "devstar-system"
|
||
controllerOpts.LeaderElectionID = "devstar-controller-manager-leader-election"
|
||
leaseDuration := s.LeaderElection.LeaseDuration
|
||
renewDeadline := s.LeaderElection.RenewDeadline
|
||
retryPeriod := s.LeaderElection.RetryPeriod
|
||
controllerOpts.LeaseDuration = &leaseDuration
|
||
controllerOpts.RenewDeadline = &renewDeadline
|
||
controllerOpts.RetryPeriod = &retryPeriod
|
||
}
|
||
|
||
// 创建 controller-runtime 管理器
|
||
klog.V(0).Info("setting up manager")
|
||
ctrl.SetLogger(klog.NewKlogr())
|
||
|
||
// 获取 Kubernetes 配置
|
||
var config *rest.Config
|
||
var err error
|
||
|
||
if s.KubeConfig != "" {
|
||
config, err = clientcmd.BuildConfigFromFlags(s.Master, s.KubeConfig)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("unable to get kubeconfig: %v", err)
|
||
}
|
||
} else {
|
||
config = ctrl.GetConfigOrDie()
|
||
}
|
||
|
||
// 创建管理器
|
||
mgr, err := ctrl.NewManager(config, controllerOpts)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("unable to set up overall controller manager: %v", err)
|
||
}
|
||
|
||
// 添加健康检查
|
||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||
return nil, fmt.Errorf("unable to set up health check: %v", err)
|
||
}
|
||
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
||
return nil, fmt.Errorf("unable to set up ready check: %v", err)
|
||
}
|
||
|
||
// 设置控制器管理器
|
||
cm.Manager = mgr
|
||
cm.IsControllerEnabled = s.IsControllerEnabled
|
||
|
||
return cm, nil
|
||
}
|