瀏覽代碼

dockerversion: DockerUserAgent(): use sync.Once to construct User-Agent

The User-Agent includes the kernel version, which involves making a syscall
(and parsing the results) on Linux, and reading (plus parsing) the registry
on Windows. These operations are relatively costly, and we should not perform
those on every request that uses the User-Agent.

This patch adds a sync.Once so that we only perform these actions once for
the lifetime of the daemon's process.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 2 年之前
父節點
當前提交
66dfc0169f
共有 1 個文件被更改,包括 36 次插入15 次删除
  1. 36 15
      dockerversion/useragent.go

+ 36 - 15
dockerversion/useragent.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"runtime"
+	"sync"
 
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/useragent"
@@ -17,23 +18,43 @@ type UAStringKey struct{}
 //
 //	[docker client's UA] UpstreamClient([upstream client's UA])
 func DockerUserAgent(ctx context.Context) string {
-	httpVersion := make([]useragent.VersionInfo, 0, 6)
-	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: Version})
-	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()})
-	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "git-commit", Version: GitCommit})
-	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
-		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "kernel", Version: kernelVersion.String()})
+	daemonUA := getDaemonUserAgent()
+	if upstreamUA := getUserAgentFromContext(ctx); len(upstreamUA) > 0 {
+		return insertUpstreamUserAgent(upstreamUA, daemonUA)
 	}
-	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "os", Version: runtime.GOOS})
-	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH})
+	return daemonUA
+}
 
-	dockerUA := useragent.AppendVersions("", httpVersion...)
-	upstreamUA := getUserAgentFromContext(ctx)
-	if len(upstreamUA) > 0 {
-		ret := insertUpstreamUserAgent(upstreamUA, dockerUA)
-		return ret
-	}
-	return dockerUA
+var (
+	daemonUAOnce sync.Once
+	daemonUA     string
+)
+
+// getUserAgentFromContext returns the user-agent to use for requests made by
+// the daemon.
+//
+// It includes;
+//
+// - the docker version
+// - go version
+// - git-commit
+// - kernel version
+// - os
+// - architecture
+func getDaemonUserAgent() string {
+	daemonUAOnce.Do(func() {
+		httpVersion := make([]useragent.VersionInfo, 0, 6)
+		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: Version})
+		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()})
+		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "git-commit", Version: GitCommit})
+		if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
+			httpVersion = append(httpVersion, useragent.VersionInfo{Name: "kernel", Version: kernelVersion.String()})
+		}
+		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "os", Version: runtime.GOOS})
+		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH})
+		daemonUA = useragent.AppendVersions("", httpVersion...)
+	})
+	return daemonUA
 }
 
 // getUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists