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  }