github.com/projectcontour/contour@v1.28.2/cmd/contour/gatewayprovisioner.go (about)

     1  // Copyright Project Contour Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package main
    15  
    16  import (
    17  	"fmt"
    18  	"os"
    19  
    20  	"github.com/projectcontour/contour/internal/k8s"
    21  	"github.com/projectcontour/contour/internal/provisioner"
    22  	"github.com/projectcontour/contour/internal/provisioner/controller"
    23  	"github.com/projectcontour/contour/pkg/config"
    24  
    25  	"github.com/alecthomas/kingpin/v2"
    26  	"github.com/distribution/reference"
    27  	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
    28  	"k8s.io/client-go/rest"
    29  	ctrl "sigs.k8s.io/controller-runtime"
    30  	"sigs.k8s.io/controller-runtime/pkg/manager"
    31  	controller_runtime_metrics_server "sigs.k8s.io/controller-runtime/pkg/metrics/server"
    32  )
    33  
    34  func registerGatewayProvisioner(app *kingpin.Application) (*kingpin.CmdClause, *gatewayProvisionerConfig) {
    35  	cmd := app.Command("gateway-provisioner", "Run contour gateway provisioner.")
    36  
    37  	provisionerConfig := &gatewayProvisionerConfig{
    38  		contourImage:          "ghcr.io/projectcontour/contour:v1.28.2",
    39  		envoyImage:            "docker.io/envoyproxy/envoy:v1.29.2",
    40  		metricsBindAddress:    ":8080",
    41  		leaderElection:        false,
    42  		leaderElectionID:      "0d879e31.projectcontour.io",
    43  		gatewayControllerName: "projectcontour.io/gateway-controller",
    44  	}
    45  
    46  	cmd.Flag("contour-image", "The container image used for the managed Contour.").
    47  		Default(provisionerConfig.contourImage).
    48  		StringVar(&provisionerConfig.contourImage)
    49  
    50  	cmd.Flag("enable-leader-election", "Enable leader election for the gateway provisioner.").
    51  		BoolVar(&provisionerConfig.leaderElection)
    52  
    53  	cmd.Flag("envoy-image", "The container image used for the managed Envoy.").
    54  		Default(provisionerConfig.envoyImage).
    55  		StringVar(&provisionerConfig.envoyImage)
    56  
    57  	cmd.Flag("gateway-controller-name", "The controller string to process GatewayClasses and Gateways for.").
    58  		Default(provisionerConfig.gatewayControllerName).
    59  		StringVar(&provisionerConfig.gatewayControllerName)
    60  
    61  	cmd.Flag("incluster", "Use in cluster configuration.").
    62  		Default("true").
    63  		BoolVar(&provisionerConfig.inCluster)
    64  	cmd.Flag("kubeconfig", "Path to kubeconfig (if not in running inside a cluster).").
    65  		PlaceHolder("/path/to/file").
    66  		StringVar(&provisionerConfig.kubeconfig)
    67  
    68  	cmd.Flag("leader-election-namespace", "The namespace in which the leader election resource will be created.").
    69  		Default(config.GetenvOr("CONTOUR_PROVISIONER_NAMESPACE", "projectcontour")).
    70  		StringVar(&provisionerConfig.leaderElectionNamespace)
    71  
    72  	cmd.Flag("metrics-addr", "The address the metric endpoint binds to. It can be set to 0 to disable serving metrics.").
    73  		Default(provisionerConfig.metricsBindAddress).
    74  		StringVar(&provisionerConfig.metricsBindAddress)
    75  
    76  	return cmd, provisionerConfig
    77  }
    78  
    79  type gatewayProvisionerConfig struct {
    80  	// contourImage is the container image for the Contour container(s) managed
    81  	// by the gateway provisioner.
    82  	contourImage string
    83  
    84  	// envoyImage is the container image for the Envoy container(s) managed
    85  	// by the gateway provisioner.
    86  	envoyImage string
    87  
    88  	// metricsBindAddress is the TCP address that the gateway provisioner should bind to for
    89  	// serving prometheus metrics. It can be set to "0" to disable the metrics serving.
    90  	metricsBindAddress string
    91  
    92  	// leaderElection determines whether or not to use leader election when starting
    93  	// the gateway provisioner.
    94  	leaderElection bool
    95  
    96  	// leaderElectionID determines the name of the configmap that leader election will
    97  	// use for holding the leader lock.
    98  	leaderElectionID string
    99  
   100  	// leaderElectionNamespace determines the namespace in which the leader
   101  	// election resource will be created.
   102  	leaderElectionNamespace string
   103  
   104  	// gatewayControllerName defines the controller string that this gateway provisioner instance
   105  	// will process GatewayClasses and Gateways for.
   106  	gatewayControllerName string
   107  
   108  	// Kubernetes client parameters.
   109  	inCluster  bool
   110  	kubeconfig string
   111  }
   112  
   113  func runGatewayProvisioner(config *gatewayProvisionerConfig) {
   114  	setupLog := ctrl.Log.WithName("setup")
   115  
   116  	for _, image := range []string{config.contourImage, config.envoyImage} {
   117  		// Parse will not handle short digests.
   118  		if _, err := reference.Parse(image); err != nil {
   119  			setupLog.Error(err, "invalid image reference", "value", image)
   120  			os.Exit(1)
   121  		}
   122  	}
   123  
   124  	setupLog.Info("using contour", "image", config.contourImage)
   125  	setupLog.Info("using envoy", "image", config.envoyImage)
   126  
   127  	// Establish k8s core client connection.
   128  	restConfig, err := k8s.NewRestConfig(config.kubeconfig, config.inCluster)
   129  	if err != nil {
   130  		setupLog.Error(err, "failed to create REST config for Kubernetes clients")
   131  		os.Exit(1)
   132  	}
   133  
   134  	mgr, err := createManager(restConfig, config)
   135  	if err != nil {
   136  		setupLog.Error(err, "failed to create contour gateway provisioner")
   137  		os.Exit(1)
   138  	}
   139  
   140  	setupLog.Info("starting contour gateway provisioner")
   141  	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
   142  		setupLog.Error(err, "failed to start contour gateway provisioner")
   143  		os.Exit(1)
   144  	}
   145  }
   146  
   147  // createManager creates a new manager from restConfig and provisionerConfig.
   148  func createManager(restConfig *rest.Config, provisionerConfig *gatewayProvisionerConfig) (manager.Manager, error) {
   149  	scheme, err := provisioner.CreateScheme()
   150  	if err != nil {
   151  		return nil, fmt.Errorf("error creating runtime scheme: %w", err)
   152  	}
   153  
   154  	mgr, err := ctrl.NewManager(restConfig, manager.Options{
   155  		Scheme:                        scheme,
   156  		LeaderElection:                provisionerConfig.leaderElection,
   157  		LeaderElectionResourceLock:    "leases",
   158  		LeaderElectionID:              provisionerConfig.leaderElectionID,
   159  		LeaderElectionNamespace:       provisionerConfig.leaderElectionNamespace,
   160  		LeaderElectionReleaseOnCancel: true,
   161  		Metrics: controller_runtime_metrics_server.Options{
   162  			BindAddress: provisionerConfig.metricsBindAddress,
   163  		},
   164  		Logger: ctrl.Log.WithName("contour-gateway-provisioner"),
   165  	})
   166  	if err != nil {
   167  		return nil, fmt.Errorf("failed to create manager: %w", err)
   168  	}
   169  
   170  	// Create and register the controllers with the manager.
   171  	if _, err := controller.NewGatewayClassController(mgr, provisionerConfig.gatewayControllerName); err != nil {
   172  		return nil, fmt.Errorf("failed to create gatewayclass controller: %w", err)
   173  	}
   174  	if _, err := controller.NewGatewayController(mgr, provisionerConfig.gatewayControllerName, provisionerConfig.contourImage, provisionerConfig.envoyImage); err != nil {
   175  		return nil, fmt.Errorf("failed to create gateway controller: %w", err)
   176  	}
   177  	return mgr, nil
   178  }