github.com/chenbh/concourse/v6@v6.4.2/worker/workercmd/worker.go (about)

     1  package workercmd
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	"code.cloudfoundry.org/lager"
    11  	"github.com/concourse/baggageclaim/baggageclaimcmd"
    12  	bclient "github.com/concourse/baggageclaim/client"
    13  	"github.com/chenbh/concourse/v6"
    14  	"github.com/chenbh/concourse/v6/atc/worker/gclient"
    15  	concourseCmd "github.com/chenbh/concourse/v6/cmd"
    16  	"github.com/chenbh/concourse/v6/worker"
    17  	"github.com/concourse/flag"
    18  	"github.com/tedsuo/ifrit"
    19  	"github.com/tedsuo/ifrit/grouper"
    20  	"github.com/tedsuo/ifrit/http_server"
    21  	"github.com/tedsuo/ifrit/sigmon"
    22  )
    23  
    24  type WorkerCommand struct {
    25  	Worker WorkerConfig
    26  
    27  	TSA worker.TSAConfig `group:"TSA Configuration" namespace:"tsa"`
    28  
    29  	Certs Certs
    30  
    31  	WorkDir flag.Dir `long:"work-dir" required:"true" description:"Directory in which to place container data."`
    32  
    33  	BindIP   flag.IP `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
    34  	BindPort uint16  `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`
    35  
    36  	DebugBindIP   flag.IP `long:"debug-bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the pprof debugger endpoints."`
    37  	DebugBindPort uint16  `long:"debug-bind-port" default:"7776"      description:"Port on which to listen for the pprof debugger endpoints."`
    38  
    39  	HealthcheckBindIP   flag.IP       `long:"healthcheck-bind-ip"    default:"0.0.0.0"  description:"IP address on which to listen for health checking requests."`
    40  	HealthcheckBindPort uint16        `long:"healthcheck-bind-port"  default:"8888"     description:"Port on which to listen for health checking requests."`
    41  	HealthCheckTimeout  time.Duration `long:"healthcheck-timeout"    default:"5s"       description:"HTTP timeout for the full duration of health checking."`
    42  
    43  	SweepInterval               time.Duration `long:"sweep-interval" default:"30s" description:"Interval on which containers and volumes will be garbage collected from the worker."`
    44  	VolumeSweeperMaxInFlight    uint16        `long:"volume-sweeper-max-in-flight" default:"3" description:"Maximum number of volumes which can be swept in parallel."`
    45  	ContainerSweeperMaxInFlight uint16        `long:"container-sweeper-max-in-flight" default:"5" description:"Maximum number of containers which can be swept in parallel."`
    46  
    47  	RebalanceInterval time.Duration `long:"rebalance-interval" default:"4h" description:"Duration after which the registration should be swapped to another random SSH gateway."`
    48  
    49  	ConnectionDrainTimeout time.Duration `long:"connection-drain-timeout" default:"1h" description:"Duration after which a worker should give up draining forwarded connections on shutdown."`
    50  
    51  	RuntimeConfiguration `group:"Runtime Configuration"`
    52  
    53  	// This refers to flags relevant to the operation of the Guardian runtime.
    54  	// For historical reasons it is namespaced under "garden" i.e. CONCOURSE_GARDEN instead of "guardian" i.e. CONCOURSE_GUARDIAN
    55  	Guardian GuardianRuntime `group:"Guardian Configuration" namespace:"garden"`
    56  
    57  	Containerd ContainerdRuntime `group:"Containerd Configuration" namespace:"containerd"`
    58  
    59  	ExternalGardenURL flag.URL `long:"external-garden-url" description:"API endpoint of an externally managed Garden server to use instead of running the embedded Garden server."`
    60  
    61  	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`
    62  
    63  	ResourceTypes flag.Dir `long:"resource-types" description:"Path to directory containing resource types the worker should advertise."`
    64  
    65  	Logger flag.Lager
    66  }
    67  
    68  func (cmd *WorkerCommand) Execute(args []string) error {
    69  	runner, err := cmd.Runner(args)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
    75  }
    76  
    77  func (cmd *WorkerCommand) Runner(args []string) (ifrit.Runner, error) {
    78  	if cmd.ResourceTypes == "" {
    79  		cmd.ResourceTypes = flag.Dir(concourseCmd.DiscoverAsset("resource-types"))
    80  	}
    81  
    82  	logger, _ := cmd.Logger.Logger("worker")
    83  
    84  	atcWorker, gardenServerRunner, err := cmd.gardenServerRunner(logger.Session("garden"))
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	atcWorker.Version = concourse.WorkerVersion
    90  
    91  	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"))
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	healthChecker := worker.NewHealthChecker(
    97  		logger.Session("healthchecker"),
    98  		cmd.baggageclaimURL(),
    99  		cmd.gardenURL(),
   100  		cmd.HealthCheckTimeout,
   101  	)
   102  
   103  	tsaClient := cmd.TSA.Client(atcWorker)
   104  
   105  	beaconRunner := worker.NewBeaconRunner(
   106  		logger.Session("beacon-runner"),
   107  		tsaClient,
   108  		cmd.RebalanceInterval,
   109  		cmd.ConnectionDrainTimeout,
   110  		cmd.gardenAddr(),
   111  		cmd.baggageclaimAddr(),
   112  	)
   113  
   114  	gardenClient := gclient.BasicGardenClientWithRequestTimeout(
   115  		logger.Session("garden-connection"),
   116  		cmd.Guardian.RequestTimeout,
   117  		cmd.gardenURL(),
   118  	)
   119  
   120  	baggageclaimClient := bclient.NewWithHTTPClient(
   121  		cmd.baggageclaimURL(),
   122  
   123  		// ensure we don't use baggageclaim's default retryhttp client; all
   124  		// traffic should be local, so any failures are unlikely to be transient.
   125  		// we don't want a retry loop to block up sweeping and prevent the worker
   126  		// from existing.
   127  		&http.Client{
   128  			Transport: &http.Transport{
   129  				// don't let a slow (possibly stuck) baggageclaim server slow down
   130  				// sweeping too much
   131  				ResponseHeaderTimeout: 1 * time.Minute,
   132  			},
   133  			// we've seen destroy calls to baggageclaim hang and lock gc
   134  			// gc is periodic so we don't need to retry here, we can rely
   135  			// on the next sweeper tick.
   136  			Timeout: 5 * time.Minute,
   137  		},
   138  	)
   139  
   140  	containerSweeper := worker.NewContainerSweeper(
   141  		logger.Session("container-sweeper"),
   142  		cmd.SweepInterval,
   143  		tsaClient,
   144  		gardenClient,
   145  		cmd.ContainerSweeperMaxInFlight,
   146  	)
   147  
   148  	volumeSweeper := worker.NewVolumeSweeper(
   149  		logger.Session("volume-sweeper"),
   150  		cmd.SweepInterval,
   151  		tsaClient,
   152  		baggageclaimClient,
   153  		cmd.VolumeSweeperMaxInFlight,
   154  	)
   155  
   156  	var members grouper.Members
   157  
   158  	if !cmd.gardenServerIsExternal() {
   159  		members = append(members, grouper.Member{
   160  			Name:   "garden",
   161  			Runner: concourseCmd.NewLoggingRunner(logger.Session("garden-runner"), gardenServerRunner),
   162  		})
   163  	}
   164  
   165  	members = append(members, grouper.Members{
   166  		{
   167  			Name:   "baggageclaim",
   168  			Runner: concourseCmd.NewLoggingRunner(logger.Session("baggageclaim-runner"), baggageclaimRunner),
   169  		},
   170  		{
   171  			Name: "debug",
   172  			Runner: concourseCmd.NewLoggingRunner(
   173  				logger.Session("debug-runner"),
   174  				http_server.New(
   175  					fmt.Sprintf("%s:%d", cmd.DebugBindIP.IP, cmd.DebugBindPort),
   176  					http.DefaultServeMux,
   177  				),
   178  			),
   179  		},
   180  		{
   181  			Name: "healthcheck",
   182  			Runner: concourseCmd.NewLoggingRunner(
   183  				logger.Session("healthcheck-runner"),
   184  				http_server.New(
   185  					fmt.Sprintf("%s:%d", cmd.HealthcheckBindIP.IP, cmd.HealthcheckBindPort),
   186  					http.HandlerFunc(healthChecker.CheckHealth),
   187  				),
   188  			),
   189  		},
   190  		{
   191  			Name: "beacon",
   192  			Runner: concourseCmd.NewLoggingRunner(
   193  				logger.Session("beacon-runner"),
   194  				beaconRunner,
   195  			),
   196  		},
   197  		{
   198  			Name: "container-sweeper",
   199  			Runner: concourseCmd.NewLoggingRunner(
   200  				logger.Session("container-sweeper"),
   201  				containerSweeper,
   202  			),
   203  		},
   204  		{
   205  			Name: "volume-sweeper",
   206  			Runner: concourseCmd.NewLoggingRunner(
   207  				logger.Session("volume-sweeper"),
   208  				volumeSweeper,
   209  			),
   210  		},
   211  	}...)
   212  
   213  	return grouper.NewParallel(os.Interrupt, members), nil
   214  }
   215  
   216  func (cmd *WorkerCommand) gardenServerIsExternal() bool {
   217  	return cmd.ExternalGardenURL.URL != nil
   218  }
   219  
   220  func (cmd *WorkerCommand) gardenAddr() string {
   221  	if cmd.gardenServerIsExternal() {
   222  		return cmd.ExternalGardenURL.URL.Host
   223  	}
   224  
   225  	return fmt.Sprintf("%s:%d", cmd.BindIP, cmd.BindPort)
   226  }
   227  
   228  func (cmd *WorkerCommand) gardenURL() string {
   229  	return fmt.Sprintf("http://%s", cmd.gardenAddr())
   230  }
   231  
   232  func (cmd *WorkerCommand) baggageclaimAddr() string {
   233  	return fmt.Sprintf("%s:%d", cmd.Baggageclaim.BindIP, cmd.Baggageclaim.BindPort)
   234  }
   235  
   236  func (cmd *WorkerCommand) baggageclaimURL() string {
   237  	return fmt.Sprintf("http://%s", cmd.baggageclaimAddr())
   238  }
   239  
   240  func (cmd *WorkerCommand) workerName() (string, error) {
   241  	if cmd.Worker.Name != "" {
   242  		return cmd.Worker.Name, nil
   243  	}
   244  
   245  	return os.Hostname()
   246  }
   247  
   248  func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
   249  	volumesDir := filepath.Join(cmd.WorkDir.Path(), "volumes")
   250  
   251  	err := os.MkdirAll(volumesDir, 0755)
   252  	if err != nil {
   253  		return nil, err
   254  	}
   255  
   256  	cmd.Baggageclaim.VolumesDir = flag.Dir(volumesDir)
   257  
   258  	cmd.Baggageclaim.OverlaysDir = filepath.Join(cmd.WorkDir.Path(), "overlays")
   259  
   260  	return cmd.Baggageclaim.Runner(nil)
   261  }