info.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "runtime"
  7. "strings"
  8. "time"
  9. "github.com/containerd/containerd/log"
  10. "github.com/docker/docker/api"
  11. "github.com/docker/docker/api/types"
  12. "github.com/docker/docker/api/types/system"
  13. "github.com/docker/docker/cli/debug"
  14. "github.com/docker/docker/daemon/config"
  15. "github.com/docker/docker/daemon/logger"
  16. "github.com/docker/docker/dockerversion"
  17. "github.com/docker/docker/pkg/fileutils"
  18. "github.com/docker/docker/pkg/meminfo"
  19. "github.com/docker/docker/pkg/parsers/kernel"
  20. "github.com/docker/docker/pkg/parsers/operatingsystem"
  21. "github.com/docker/docker/pkg/platform"
  22. "github.com/docker/docker/pkg/sysinfo"
  23. "github.com/docker/docker/registry"
  24. metrics "github.com/docker/go-metrics"
  25. "github.com/opencontainers/selinux/go-selinux"
  26. )
  27. // SystemInfo returns information about the host server the daemon is running on.
  28. func (daemon *Daemon) SystemInfo() *system.Info {
  29. defer metrics.StartTimer(hostInfoFunctions.WithValues("system_info"))()
  30. sysInfo := daemon.RawSysInfo()
  31. cfg := daemon.config()
  32. v := &system.Info{
  33. ID: daemon.id,
  34. Images: daemon.imageService.CountImages(),
  35. IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled,
  36. BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled,
  37. BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled,
  38. Name: hostName(),
  39. SystemTime: time.Now().Format(time.RFC3339Nano),
  40. LoggingDriver: daemon.defaultLogConfig.Type,
  41. KernelVersion: kernelVersion(),
  42. OperatingSystem: operatingSystem(),
  43. OSVersion: osVersion(),
  44. IndexServerAddress: registry.IndexServer,
  45. OSType: runtime.GOOS,
  46. Architecture: platform.Architecture,
  47. RegistryConfig: daemon.registryService.ServiceConfig(),
  48. NCPU: sysinfo.NumCPU(),
  49. MemTotal: memInfo().MemTotal,
  50. GenericResources: daemon.genericResources,
  51. DockerRootDir: cfg.Root,
  52. Labels: cfg.Labels,
  53. ExperimentalBuild: cfg.Experimental,
  54. ServerVersion: dockerversion.Version,
  55. HTTPProxy: config.MaskCredentials(getConfigOrEnv(cfg.HTTPProxy, "HTTP_PROXY", "http_proxy")),
  56. HTTPSProxy: config.MaskCredentials(getConfigOrEnv(cfg.HTTPSProxy, "HTTPS_PROXY", "https_proxy")),
  57. NoProxy: getConfigOrEnv(cfg.NoProxy, "NO_PROXY", "no_proxy"),
  58. LiveRestoreEnabled: cfg.LiveRestoreEnabled,
  59. Isolation: daemon.defaultIsolation,
  60. }
  61. daemon.fillContainerStates(v)
  62. daemon.fillDebugInfo(v)
  63. daemon.fillAPIInfo(v, &cfg.Config)
  64. // Retrieve platform specific info
  65. daemon.fillPlatformInfo(v, sysInfo, cfg)
  66. daemon.fillDriverInfo(v)
  67. daemon.fillPluginsInfo(v, &cfg.Config)
  68. daemon.fillSecurityOptions(v, sysInfo, &cfg.Config)
  69. daemon.fillLicense(v)
  70. daemon.fillDefaultAddressPools(v, &cfg.Config)
  71. return v
  72. }
  73. // SystemVersion returns version information about the daemon.
  74. func (daemon *Daemon) SystemVersion() types.Version {
  75. defer metrics.StartTimer(hostInfoFunctions.WithValues("system_version"))()
  76. kernelVersion := kernelVersion()
  77. cfg := daemon.config()
  78. v := types.Version{
  79. Components: []types.ComponentVersion{
  80. {
  81. Name: "Engine",
  82. Version: dockerversion.Version,
  83. Details: map[string]string{
  84. "GitCommit": dockerversion.GitCommit,
  85. "ApiVersion": api.DefaultVersion,
  86. "MinAPIVersion": api.MinVersion,
  87. "GoVersion": runtime.Version(),
  88. "Os": runtime.GOOS,
  89. "Arch": runtime.GOARCH,
  90. "BuildTime": dockerversion.BuildTime,
  91. "KernelVersion": kernelVersion,
  92. "Experimental": fmt.Sprintf("%t", cfg.Experimental),
  93. },
  94. },
  95. },
  96. // Populate deprecated fields for older clients
  97. Version: dockerversion.Version,
  98. GitCommit: dockerversion.GitCommit,
  99. APIVersion: api.DefaultVersion,
  100. MinAPIVersion: api.MinVersion,
  101. GoVersion: runtime.Version(),
  102. Os: runtime.GOOS,
  103. Arch: runtime.GOARCH,
  104. BuildTime: dockerversion.BuildTime,
  105. KernelVersion: kernelVersion,
  106. Experimental: cfg.Experimental,
  107. }
  108. v.Platform.Name = dockerversion.PlatformName
  109. daemon.fillPlatformVersion(&v, cfg)
  110. return v
  111. }
  112. func (daemon *Daemon) fillDriverInfo(v *system.Info) {
  113. v.Driver = daemon.imageService.StorageDriver()
  114. v.DriverStatus = daemon.imageService.LayerStoreStatus()
  115. const warnMsg = `
  116. WARNING: The %s storage-driver is deprecated, and will be removed in a future release.
  117. Refer to the documentation for more information: https://docs.docker.com/go/storage-driver/`
  118. switch v.Driver {
  119. case "overlay":
  120. v.Warnings = append(v.Warnings, fmt.Sprintf(warnMsg, v.Driver))
  121. }
  122. fillDriverWarnings(v)
  123. }
  124. func (daemon *Daemon) fillPluginsInfo(v *system.Info, cfg *config.Config) {
  125. v.Plugins = system.PluginsInfo{
  126. Volume: daemon.volumes.GetDriverList(),
  127. Network: daemon.GetNetworkDriverList(),
  128. // The authorization plugins are returned in the order they are
  129. // used as they constitute a request/response modification chain.
  130. Authorization: cfg.AuthorizationPlugins,
  131. Log: logger.ListDrivers(),
  132. }
  133. }
  134. func (daemon *Daemon) fillSecurityOptions(v *system.Info, sysInfo *sysinfo.SysInfo, cfg *config.Config) {
  135. var securityOptions []string
  136. if sysInfo.AppArmor {
  137. securityOptions = append(securityOptions, "name=apparmor")
  138. }
  139. if sysInfo.Seccomp && supportsSeccomp {
  140. if daemon.seccompProfilePath != config.SeccompProfileDefault {
  141. v.Warnings = append(v.Warnings, "WARNING: daemon is not using the default seccomp profile")
  142. }
  143. securityOptions = append(securityOptions, "name=seccomp,profile="+daemon.seccompProfilePath)
  144. }
  145. if selinux.GetEnabled() {
  146. securityOptions = append(securityOptions, "name=selinux")
  147. }
  148. if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
  149. securityOptions = append(securityOptions, "name=userns")
  150. }
  151. if Rootless(cfg) {
  152. securityOptions = append(securityOptions, "name=rootless")
  153. }
  154. if cgroupNamespacesEnabled(sysInfo, cfg) {
  155. securityOptions = append(securityOptions, "name=cgroupns")
  156. }
  157. if noNewPrivileges(cfg) {
  158. securityOptions = append(securityOptions, "name=no-new-privileges")
  159. }
  160. v.SecurityOptions = securityOptions
  161. }
  162. func (daemon *Daemon) fillContainerStates(v *system.Info) {
  163. cRunning, cPaused, cStopped := stateCtr.get()
  164. v.Containers = cRunning + cPaused + cStopped
  165. v.ContainersPaused = cPaused
  166. v.ContainersRunning = cRunning
  167. v.ContainersStopped = cStopped
  168. }
  169. // fillDebugInfo sets the current debugging state of the daemon, and additional
  170. // debugging information, such as the number of Go-routines, and file descriptors.
  171. //
  172. // Note that this currently always collects the information, but the CLI only
  173. // prints it if the daemon has debug enabled. We should consider to either make
  174. // this information optional (cli to request "with debugging information"), or
  175. // only collect it if the daemon has debug enabled. For the CLI code, see
  176. // https://github.com/docker/cli/blob/v20.10.12/cli/command/system/info.go#L239-L244
  177. func (daemon *Daemon) fillDebugInfo(v *system.Info) {
  178. v.Debug = debug.IsEnabled()
  179. v.NFd = fileutils.GetTotalUsedFds()
  180. v.NGoroutines = runtime.NumGoroutine()
  181. v.NEventsListener = daemon.EventsService.SubscribersCount()
  182. }
  183. func (daemon *Daemon) fillAPIInfo(v *system.Info, cfg *config.Config) {
  184. const warn string = `
  185. Access to the remote API is equivalent to root access on the host. Refer
  186. to the 'Docker daemon attack surface' section in the documentation for
  187. more information: https://docs.docker.com/go/attack-surface/`
  188. for _, host := range cfg.Hosts {
  189. // cnf.Hosts is normalized during startup, so should always have a scheme/proto
  190. proto, addr, _ := strings.Cut(host, "://")
  191. if proto != "tcp" {
  192. continue
  193. }
  194. if cfg.TLS == nil || !*cfg.TLS {
  195. v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on http://%s without encryption.%s", addr, warn))
  196. continue
  197. }
  198. if cfg.TLSVerify == nil || !*cfg.TLSVerify {
  199. v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on https://%s without TLS client verification.%s", addr, warn))
  200. continue
  201. }
  202. }
  203. }
  204. func (daemon *Daemon) fillDefaultAddressPools(v *system.Info, cfg *config.Config) {
  205. for _, pool := range cfg.DefaultAddressPools.Value() {
  206. v.DefaultAddressPools = append(v.DefaultAddressPools, system.NetworkAddressPool{
  207. Base: pool.Base,
  208. Size: pool.Size,
  209. })
  210. }
  211. }
  212. func hostName() string {
  213. hostname := ""
  214. if hn, err := os.Hostname(); err != nil {
  215. log.G(context.TODO()).Warnf("Could not get hostname: %v", err)
  216. } else {
  217. hostname = hn
  218. }
  219. return hostname
  220. }
  221. func kernelVersion() string {
  222. var kernelVersion string
  223. if kv, err := kernel.GetKernelVersion(); err != nil {
  224. log.G(context.TODO()).Warnf("Could not get kernel version: %v", err)
  225. } else {
  226. kernelVersion = kv.String()
  227. }
  228. return kernelVersion
  229. }
  230. func memInfo() *meminfo.Memory {
  231. memInfo, err := meminfo.Read()
  232. if err != nil {
  233. log.G(context.TODO()).Errorf("Could not read system memory info: %v", err)
  234. memInfo = &meminfo.Memory{}
  235. }
  236. return memInfo
  237. }
  238. func operatingSystem() (operatingSystem string) {
  239. defer metrics.StartTimer(hostInfoFunctions.WithValues("operating_system"))()
  240. if s, err := operatingsystem.GetOperatingSystem(); err != nil {
  241. log.G(context.TODO()).Warnf("Could not get operating system name: %v", err)
  242. } else {
  243. operatingSystem = s
  244. }
  245. if inContainer, err := operatingsystem.IsContainerized(); err != nil {
  246. log.G(context.TODO()).Errorf("Could not determine if daemon is containerized: %v", err)
  247. operatingSystem += " (error determining if containerized)"
  248. } else if inContainer {
  249. operatingSystem += " (containerized)"
  250. }
  251. return operatingSystem
  252. }
  253. func osVersion() (version string) {
  254. defer metrics.StartTimer(hostInfoFunctions.WithValues("os_version"))()
  255. version, err := operatingsystem.GetOperatingSystemVersion()
  256. if err != nil {
  257. log.G(context.TODO()).Warnf("Could not get operating system version: %v", err)
  258. }
  259. return version
  260. }
  261. func getEnvAny(names ...string) string {
  262. for _, n := range names {
  263. if val := os.Getenv(n); val != "" {
  264. return val
  265. }
  266. }
  267. return ""
  268. }
  269. func getConfigOrEnv(config string, env ...string) string {
  270. if config != "" {
  271. return config
  272. }
  273. return getEnvAny(env...)
  274. }