github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/cmd/swarmd/main.go (about) 1 package main 2 3 import ( 4 "context" 5 _ "expvar" 6 "fmt" 7 "net" 8 "net/http" 9 _ "net/http/pprof" 10 "os" 11 "os/signal" 12 13 engineapi "github.com/docker/docker/client" 14 "github.com/docker/swarmkit/agent/exec/dockerapi" 15 "github.com/docker/swarmkit/api" 16 "github.com/docker/swarmkit/api/genericresource" 17 "github.com/docker/swarmkit/cli" 18 "github.com/docker/swarmkit/cmd/swarmd/defaults" 19 "github.com/docker/swarmkit/log" 20 "github.com/docker/swarmkit/manager/encryption" 21 "github.com/docker/swarmkit/node" 22 "github.com/docker/swarmkit/version" 23 grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" 24 "github.com/prometheus/client_golang/prometheus" 25 "github.com/sirupsen/logrus" 26 "github.com/spf13/cobra" 27 ) 28 29 var externalCAOpt cli.ExternalCAOpt 30 31 func main() { 32 if err := mainCmd.Execute(); err != nil { 33 log.L.Fatal(err) 34 } 35 } 36 37 var ( 38 mainCmd = &cobra.Command{ 39 Use: os.Args[0], 40 Short: "Run a swarm control process", 41 SilenceUsage: true, 42 PersistentPreRun: func(cmd *cobra.Command, _ []string) { 43 logrus.SetOutput(os.Stderr) 44 flag, err := cmd.Flags().GetString("log-level") 45 if err != nil { 46 log.L.Fatal(err) 47 } 48 level, err := logrus.ParseLevel(flag) 49 if err != nil { 50 log.L.Fatal(err) 51 } 52 logrus.SetLevel(level) 53 54 v, err := cmd.Flags().GetBool("version") 55 if err != nil { 56 log.L.Fatal(err) 57 } 58 if v { 59 version.PrintVersion() 60 os.Exit(0) 61 } 62 }, 63 RunE: func(cmd *cobra.Command, args []string) error { 64 ctx := context.Background() 65 hostname, err := cmd.Flags().GetString("hostname") 66 if err != nil { 67 return err 68 } 69 70 advertiseAddr, err := cmd.Flags().GetString("advertise-remote-api") 71 if err != nil { 72 return err 73 } 74 75 addr, err := cmd.Flags().GetString("listen-remote-api") 76 if err != nil { 77 return err 78 } 79 addrHost, _, err := net.SplitHostPort(addr) 80 if err == nil { 81 ip := net.ParseIP(addrHost) 82 if ip != nil && (ip.IsUnspecified() || ip.IsLoopback()) { 83 fmt.Println("Warning: Specifying a valid address with --listen-remote-api may be necessary for other managers to reach this one.") 84 } 85 } 86 87 unix, err := cmd.Flags().GetString("listen-control-api") 88 if err != nil { 89 return err 90 } 91 92 metricsAddr, err := cmd.Flags().GetString("listen-metrics") 93 if err != nil { 94 return err 95 } 96 97 debugAddr, err := cmd.Flags().GetString("listen-debug") 98 if err != nil { 99 return err 100 } 101 102 managerAddr, err := cmd.Flags().GetString("join-addr") 103 if err != nil { 104 return err 105 } 106 107 forceNewCluster, err := cmd.Flags().GetBool("force-new-cluster") 108 if err != nil { 109 return err 110 } 111 112 hb, err := cmd.Flags().GetUint32("heartbeat-tick") 113 if err != nil { 114 return err 115 } 116 117 election, err := cmd.Flags().GetUint32("election-tick") 118 if err != nil { 119 return err 120 } 121 122 stateDir, err := cmd.Flags().GetString("state-dir") 123 if err != nil { 124 return err 125 } 126 127 joinToken, err := cmd.Flags().GetString("join-token") 128 if err != nil { 129 return err 130 } 131 132 engineAddr, err := cmd.Flags().GetString("engine-addr") 133 if err != nil { 134 return err 135 } 136 137 autolockManagers, err := cmd.Flags().GetBool("autolock") 138 if err != nil { 139 return err 140 } 141 142 var unlockKey []byte 143 if cmd.Flags().Changed("unlock-key") { 144 unlockKeyString, err := cmd.Flags().GetString("unlock-key") 145 if err != nil { 146 return err 147 } 148 unlockKey, err = encryption.ParseHumanReadableKey(unlockKeyString) 149 if err != nil { 150 return err 151 } 152 } 153 154 var resources []*api.GenericResource 155 if cmd.Flags().Changed("generic-node-resources") { 156 genericResources, err := cmd.Flags().GetString("generic-node-resources") 157 if err != nil { 158 return err 159 } 160 resources, err = genericresource.ParseCmd(genericResources) 161 if err != nil { 162 return err 163 } 164 } 165 166 // Create a cancellable context for our GRPC call 167 ctx, cancel := context.WithCancel(ctx) 168 defer cancel() 169 170 if err := os.MkdirAll(stateDir, 0700); err != nil { 171 return err 172 } 173 174 client, err := engineapi.NewClient(engineAddr, "", nil, nil) 175 if err != nil { 176 return err 177 } 178 179 executor := dockerapi.NewExecutor(client, resources) 180 181 if debugAddr != "" { 182 go func() { 183 // setup listening to give access to pprof, expvar, etc. 184 if err := http.ListenAndServe(debugAddr, nil); err != nil { 185 panic(err) 186 } 187 }() 188 } 189 190 if metricsAddr != "" { 191 // This allows to measure latency distribution. 192 grpc_prometheus.EnableHandlingTimeHistogram() 193 194 l, err := net.Listen("tcp", metricsAddr) 195 if err != nil { 196 panic(err) 197 } 198 mux := http.NewServeMux() 199 mux.Handle("/metrics", prometheus.Handler()) 200 201 go func() { 202 if err := http.Serve(l, mux); err != nil { 203 logrus.Errorf("serve metrics api: %s", err) 204 } 205 }() 206 } 207 208 n, err := node.New(&node.Config{ 209 Hostname: hostname, 210 ForceNewCluster: forceNewCluster, 211 ListenControlAPI: unix, 212 ListenRemoteAPI: addr, 213 AdvertiseRemoteAPI: advertiseAddr, 214 JoinAddr: managerAddr, 215 StateDir: stateDir, 216 JoinToken: joinToken, 217 ExternalCAs: externalCAOpt.Value(), 218 Executor: executor, 219 HeartbeatTick: hb, 220 ElectionTick: election, 221 AutoLockManagers: autolockManagers, 222 UnlockKey: unlockKey, 223 }) 224 if err != nil { 225 return err 226 } 227 228 if err := n.Start(ctx); err != nil { 229 return err 230 } 231 232 c := make(chan os.Signal, 1) 233 signal.Notify(c, os.Interrupt) 234 go func() { 235 <-c 236 n.Stop(ctx) 237 }() 238 239 go func() { 240 select { 241 case <-n.Ready(): 242 case <-ctx.Done(): 243 } 244 if ctx.Err() == nil { 245 logrus.Info("node is ready") 246 } 247 }() 248 249 return n.Err(ctx) 250 }, 251 } 252 ) 253 254 func init() { 255 mainCmd.Flags().BoolP("version", "v", false, "Display the version and exit") 256 mainCmd.Flags().StringP("log-level", "l", "info", "Log level (options \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"panic\")") 257 mainCmd.Flags().StringP("state-dir", "d", defaults.StateDir, "State directory") 258 mainCmd.Flags().StringP("join-token", "", "", "Specifies the secret token required to join the cluster") 259 mainCmd.Flags().String("engine-addr", defaults.EngineAddr, "Address of engine instance of agent.") 260 mainCmd.Flags().String("hostname", "", "Override reported agent hostname") 261 mainCmd.Flags().String("advertise-remote-api", "", "Advertise address for remote API") 262 mainCmd.Flags().String("listen-remote-api", "0.0.0.0:4242", "Listen address for remote API") 263 mainCmd.Flags().String("listen-control-api", defaults.ControlAPISocket, "Listen socket for control API") 264 mainCmd.Flags().String("listen-debug", "", "Bind the Go debug server on the provided address") 265 mainCmd.Flags().String("listen-metrics", "", "Listen address for metrics") 266 mainCmd.Flags().String("join-addr", "", "Join cluster with a node at this address") 267 mainCmd.Flags().String("generic-node-resources", "", "user defined resources (e.g. fpga=2,gpu=UUID1,gpu=UUID2,gpu=UUID3)") 268 mainCmd.Flags().Bool("force-new-cluster", false, "Force the creation of a new cluster from data directory") 269 mainCmd.Flags().Uint32("heartbeat-tick", 1, "Defines the heartbeat interval (in seconds) for raft member health-check") 270 mainCmd.Flags().Uint32("election-tick", 10, "Defines the amount of ticks (in seconds) needed without a Leader to trigger a new election") 271 mainCmd.Flags().Var(&externalCAOpt, "external-ca", "Specifications of one or more certificate signing endpoints") 272 mainCmd.Flags().Bool("autolock", false, "Require an unlock key in order to start a manager once it's been stopped") 273 mainCmd.Flags().String("unlock-key", "", "Unlock this manager using this key") 274 }