sentry的main函数入口

sentry 模块的入口在文件 cmd/sentry/main.go 中。

准备工作

读取命令行参数

const (
	defaultCredentialsPath = "/var/run/dapr/credentials"
	// defaultDaprSystemConfigName is the default resource object name for Dapr System Config.
	defaultDaprSystemConfigName = "daprsystem"

	healthzPort = 8080
)

func main() {
	configName := flag.String("config", defaultDaprSystemConfigName, "Path to config file, or name of a configuration object")
	credsPath := flag.String("issuer-credentials", defaultCredentialsPath, "Path to the credentials directory holding the issuer data")
	flag.StringVar(&credentials.RootCertFilename, "issuer-ca-filename", credentials.RootCertFilename, "Certificate Authority certificate filename")
	flag.StringVar(&credentials.IssuerCertFilename, "issuer-certificate-filename", credentials.IssuerCertFilename, "Issuer certificate filename")
	flag.StringVar(&credentials.IssuerKeyFilename, "issuer-key-filename", credentials.IssuerKeyFilename, "Issuer private key filename")
	trustDomain := flag.String("trust-domain", "localhost", "The CA trust domain")
	tokenAudience := flag.String("token-audience", "", "Expected audience for tokens; multiple values can be separated by a comma")
......
}

logger  和 metrics 的参数需要展开:

	loggerOptions := logger.DefaultOptions()
	loggerOptions.AttachCmdFlags(flag.StringVar, flag.BoolVar)

	metricsExporter := metrics.NewExporter(metrics.DefaultMetricNamespace)
	metricsExporter.Options().AttachCmdFlags(flag.StringVar, flag.BoolVar)

获取 k8s 的 配置文件路径:

	var kubeconfig *string
	if home := homedir.HomeDir(); home != "" {
    // 读取 home 路径
		kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
	} else {
    // 通过 `--kubeconfig` 传递完整的 kubeconfig 文件路径
		kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
	}

最后解析一把:

flag.Parse()

设置环境变量

将 kubeconfig 的值设置到 KUBE_CONFIG 环境变量:

var (
	KubeConfigVar = "KUBE_CONFIG"
)

if err := utils.SetEnvVariables(map[string]string{
		utils.KubeConfigVar: *kubeconfig,
	}); err != nil {
		log.Fatalf("error set env failed:  %s", err.Error())
	}

初始化

这行日志标记着初始化正式开始:

	log.Infof("starting sentry certificate authority -- version %s -- commit %s", buildinfo.Version(), buildinfo.Commit())
	log.Infof("log level set to: %s", loggerOptions.OutputLevel)

初始化metrics

// Initialize dapr metrics exporter
	if err := metricsExporter.Init(); err != nil {
		log.Fatal(err)
	}

初始化监控

	if err := monitoring.InitMetrics(); err != nil {
		log.Fatal(err)
	}

读取配置

  // 拼凑文件路径
  issuerCertPath := filepath.Join(*credsPath, credentials.IssuerCertFilename) //issuer.crt
	issuerKeyPath := filepath.Join(*credsPath, credentials.IssuerKeyFilename)   // issuer.key
	rootCertPath := filepath.Join(*credsPath, credentials.RootCertFilename)     // ca.crt

  // 读取 sentry 配置:
  config, err := config.FromConfigName(*configName)
	if err != nil {
		log.Warn(err)
	}

  // 保存证书相关的各个路径和参数
	config.IssuerCertPath = issuerCertPath
	config.IssuerKeyPath = issuerKeyPath
	config.RootCertPath = rootCertPath
	config.TrustDomain = *trustDomain
	if *tokenAudience != "" {
		config.TokenAudience = tokenAudience
	}

启动服务

启动sentry server

	ca := sentry.NewSentryCA()

	// Start the server in background
	err = ca.Start(runCtx, config)
	if err != nil {
		log.Fatalf("failed to restart sentry server: %s", err)
	}

启动 health server

	log.Infof("starting watch on filesystem directory: %s", watchDir)

// Start the health server in background
	go func() {
		healthzServer := health.NewServer(log)
		healthzServer.Ready()

		if innerErr := healthzServer.Run(runCtx, healthzPort); innerErr != nil {
			log.Fatalf("failed to start healthz server: %s", innerErr)
		}
	}()

监控目录变化

  issuerEvent := make(chan struct{})
  watchDir := filepath.Dir(config.IssuerCertPath)

  // Watch for changes in the watchDir
	// This also blocks until runCtx is canceled
	fswatcher.Watch(runCtx, watchDir, issuerEvent)

这个函数会一直阻塞直到 runCtx 被取消(这意味着要退出 sentry 进程)。

如果有文件更新,则 issuerEvent 会收到 event,issuerEvent 相关的处理代码:

	go func() {
		// Restart the server when the issuer credentials change
		var restart <-chan time.Time
		for {
			select {
			case <-issuerEvent:
				monitoring.IssuerCertChanged()
				log.Debug("received issuer credentials changed signal")
				// Batch all signals within 2s of each other
				if restart == nil {
          // issuerEvent 不会被直接处理,而是安排在 2 秒发一个 restart event
          // 2秒之内的各种 issuerEvent 都会被这个 restart event 集中处理
					restart = time.After(2 * time.Second)
				}
			case <-restart:
        // 收到 restart,意味着 issuerEvent 已经积攒了 2 秒钟,可以统一处理了
				log.Warn("issuer credentials changed; reloading")
				innerErr := ca.Restart(runCtx, config)
				if innerErr != nil {
					log.Fatalf("failed to restart sentry server: %s", innerErr)
				}
        // 重置 restart,恢复原样,以便处理 2 秒之后的后续 issuerEvent
				restart = nil
			}
		}
	}()

退出

	shutdownDuration := 5 * time.Second
	log.Infof("allowing %s for graceful shutdown to complete", shutdownDuration)
	<-time.After(shutdownDuration)

总结

去除非核心代码,sentry main 函数的主要功能是启动 sentry 的 ca server, 并监控目录,如果有变化则重启 ca server。