Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Horizontal Scaling #1048

Merged
merged 26 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
75074e9
Add env var GOOS to makefile
kate-osborn Aug 30, 2023
c179d66
Add leader election
kate-osborn Aug 30, 2023
ece0e64
Update helm README
kate-osborn Sep 8, 2023
04c60a5
Remove comment about leader election limitation
kate-osborn Sep 14, 2023
69c9683
ARCH -> GOARCH
kate-osborn Sep 14, 2023
ffd2a18
Remove unnecessary context var name
kate-osborn Sep 14, 2023
2a40805
Group flag values
kate-osborn Sep 14, 2023
047f6ea
Improve leader election lock name description
kate-osborn Sep 14, 2023
c61e65b
MY_* -> POD_*
kate-osborn Sep 14, 2023
baca3a6
LeaderElectorLogger
kate-osborn Sep 14, 2023
2437d29
Make leader elector runnable by the manager
kate-osborn Sep 14, 2023
7516e6b
Update architecture doc
kate-osborn Sep 14, 2023
47dc941
GO_ARCH -> GOARCH
kate-osborn Sep 14, 2023
e940333
Refactor status updater interface
kate-osborn Sep 15, 2023
de1af02
Add comment about default values
kate-osborn Sep 15, 2023
b30ce2d
Update architecture doc
kate-osborn Sep 15, 2023
29fc37b
Update cli-help doc
kate-osborn Sep 15, 2023
972b745
Add Status interface
kate-osborn Sep 18, 2023
2ca2c30
Update the lock desc in helm values and readme
kate-osborn Sep 18, 2023
536a6b4
Fix rebase error
kate-osborn Sep 18, 2023
07d4ce2
Be consistent with disable var names
kate-osborn Sep 18, 2023
d0fbca8
Fix another rebase error
kate-osborn Sep 18, 2023
89e9360
Lowercase
kate-osborn Sep 18, 2023
404d048
Update internal/mode/static/config/config.go
kate-osborn Sep 18, 2023
ff71d88
Update internal/mode/static/config/config.go
kate-osborn Sep 18, 2023
28cd3b1
Be consistent with leader logs
kate-osborn Sep 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ TAG ?= $(VERSION:v%=%)## The tag of the image. For example, 0.3.0
TARGET ?= local## The target of the build. Possible values: local and container
KIND_KUBE_CONFIG=$${HOME}/.kube/kind/config## The location of the kind kubeconfig
OUT_DIR ?= $(shell pwd)/build/out## The folder where the binary will be stored
ARCH ?= amd64## The architecture of the image and/or binary. For example: amd64 or arm64
GOARCH ?= amd64## The architecture of the image and/or binary. For example: amd64 or arm64
GOOS ?= linux## The OS of the image and/or binary. For example: linux or darwin
override HELM_TEMPLATE_COMMON_ARGS += --set creator=template --set nameOverride=nginx-gateway## The common options for the Helm template command.
override HELM_TEMPLATE_EXTRA_ARGS_FOR_ALL_MANIFESTS_FILE += --set service.create=false## The options to be passed to the full Helm templating command only.
override NGINX_DOCKER_BUILD_OPTIONS += --build-arg NJS_DIR=$(NJS_DIR) --build-arg NGINX_CONF_DIR=$(NGINX_CONF_DIR)
Expand All @@ -35,11 +36,11 @@ build-images: build-nkg-image build-nginx-image ## Build the NKG and nginx docke

.PHONY: build-nkg-image
build-nkg-image: check-for-docker build ## Build the NKG docker image
docker build --platform linux/$(ARCH) --target $(strip $(TARGET)) -f build/Dockerfile -t $(strip $(PREFIX)):$(strip $(TAG)) .
docker build --platform linux/$(GOARCH) --target $(strip $(TARGET)) -f build/Dockerfile -t $(strip $(PREFIX)):$(strip $(TAG)) .

.PHONY: build-nginx-image
build-nginx-image: check-for-docker ## Build the custom nginx image
docker build --platform linux/$(ARCH) $(strip $(NGINX_DOCKER_BUILD_OPTIONS)) -f build/Dockerfile.nginx -t $(strip $(NGINX_PREFIX)):$(strip $(TAG)) .
docker build --platform linux/$(GOARCH) $(strip $(NGINX_DOCKER_BUILD_OPTIONS)) -f build/Dockerfile.nginx -t $(strip $(NGINX_PREFIX)):$(strip $(TAG)) .

.PHONY: check-for-docker
check-for-docker: ## Check if Docker is installed
Expand All @@ -49,13 +50,13 @@ check-for-docker: ## Check if Docker is installed
build: ## Build the binary
ifeq (${TARGET},local)
@go version || (code=$$?; printf "\033[0;31mError\033[0m: unable to build locally\n"; exit $$code)
CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -trimpath -a -ldflags "$(GO_LINKER_FLAGS)" $(ADDITIONAL_GO_BUILD_FLAGS) -o $(OUT_DIR)/gateway github.com/nginxinc/nginx-kubernetes-gateway/cmd/gateway
CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -trimpath -a -ldflags "$(GO_LINKER_FLAGS)" $(ADDITIONAL_GO_BUILD_FLAGS) -o $(OUT_DIR)/gateway github.com/nginxinc/nginx-kubernetes-gateway/cmd/gateway
endif

.PHONY: build-goreleaser
build-goreleaser: ## Build the binary using GoReleaser
@goreleaser -v || (code=$$?; printf "\033[0;31mError\033[0m: there was a problem with GoReleaser. Follow the docs to install it https://goreleaser.com/install\n"; exit $$code)
GOOS=linux GOPATH=$(shell go env GOPATH) GOARCH=$(ARCH) goreleaser build --clean --snapshot --single-target
GOOS=linux GOPATH=$(shell go env GOPATH) GOARCH=$(GOARCH) goreleaser build --clean --snapshot --single-target

.PHONY: generate
generate: ## Run go generate
Expand Down
117 changes: 80 additions & 37 deletions cmd/gateway/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const (
gatewayCtrlNameFlag = "gateway-ctlr-name"
gatewayCtrlNameUsageFmt = `The name of the Gateway controller. ` +
`The controller name must be of the form: DOMAIN/PATH. The controller's domain is '%s'`
gatewayFlag = "gateway"
)

var (
Expand All @@ -38,25 +37,6 @@ var (
gatewayClassName = stringValidatingValue{
validator: validateResourceName,
}

// Backing values for static subcommand cli flags.
updateGCStatus bool
disableMetrics bool
metricsSecure bool
disableHealth bool

metricsListenPort = intValidatingValue{
validator: validatePort,
value: 9113,
}
healthListenPort = intValidatingValue{
validator: validatePort,
value: 8081,
}
gateway = namespacedNameValue{}
configName = stringValidatingValue{
validator: validateResourceName,
}
)

func createRootCommand() *cobra.Command {
Expand Down Expand Up @@ -85,6 +65,46 @@ func createRootCommand() *cobra.Command {
}

func createStaticModeCommand() *cobra.Command {
// flag names
const (
gatewayFlag = "gateway"
configFlag = "config"
updateGCStatusFlag = "update-gatewayclass-status"
metricsDisableFlag = "metrics-disable"
metricsSecureFlag = "metrics-secure-serving"
metricsPortFlag = "metrics-port"
healthDisableFlag = "health-disable"
healthPortFlag = "health-port"
leaderElectionDisableFlag = "leader-election-disable"
leaderElectionLockNameFlag = "leader-election-lock-name"
)

// flag values
var (
updateGCStatus bool
gateway = namespacedNameValue{}
configName = stringValidatingValue{
validator: validateResourceName,
}
disableMetrics bool
metricsSecure bool
metricsListenPort = intValidatingValue{
pleshakov marked this conversation as resolved.
Show resolved Hide resolved
validator: validatePort,
value: 9113,
}
disableHealth bool
healthListenPort = intValidatingValue{
validator: validatePort,
value: 8081,
}

disableLeaderElection bool
leaderElectionLockName = stringValidatingValue{
validator: validateResourceName,
value: "nginx-gateway-leader-election-lock",
}
)

cmd := &cobra.Command{
Use: "static-mode",
Short: "Configure NGINX in the scope of a single Gateway resource",
Expand All @@ -109,23 +129,21 @@ func createStaticModeCommand() *cobra.Command {
return fmt.Errorf("error validating POD_IP environment variable: %w", err)
}

namespace := os.Getenv("MY_NAMESPACE")
namespace := os.Getenv("POD_NAMESPACE")
if namespace == "" {
return errors.New("MY_NAMESPACE environment variable must be set")
return errors.New("POD_NAMESPACE environment variable must be set")
}

podName := os.Getenv("POD_NAME")
if podName == "" {
return errors.New("POD_NAME environment variable must be set")
}

var gwNsName *types.NamespacedName
if cmd.Flags().Changed(gatewayFlag) {
gwNsName = &gateway.value
}

metricsConfig := config.MetricsConfig{}
if !disableMetrics {
metricsConfig.Enabled = true
metricsConfig.Port = metricsListenPort.value
metricsConfig.Secure = metricsSecure
}

conf := config.Config{
GatewayCtlrName: gatewayCtlrName.value,
ConfigName: configName.String(),
Expand All @@ -136,11 +154,20 @@ func createStaticModeCommand() *cobra.Command {
Namespace: namespace,
GatewayNsName: gwNsName,
UpdateGatewayClassStatus: updateGCStatus,
MetricsConfig: metricsConfig,
HealthConfig: config.HealthConfig{
Enabled: !disableHealth,
Port: healthListenPort.value,
},
MetricsConfig: config.MetricsConfig{
Enabled: !disableMetrics,
Port: metricsListenPort.value,
Secure: metricsSecure,
},
LeaderElection: config.LeaderElection{
Enabled: !disableLeaderElection,
LockName: leaderElectionLockName.String(),
Identity: podName,
},
}

if err := static.StartManager(conf); err != nil {
Expand All @@ -163,53 +190,69 @@ func createStaticModeCommand() *cobra.Command {

cmd.Flags().VarP(
&configName,
"config",
configFlag,
"c",
`The name of the NginxGateway resource to be used for this controller's dynamic configuration.`+
` Lives in the same Namespace as the controller.`,
)

cmd.Flags().BoolVar(
&updateGCStatus,
"update-gatewayclass-status",
updateGCStatusFlag,
true,
"Update the status of the GatewayClass resource.",
)

cmd.Flags().BoolVar(
&disableMetrics,
"metrics-disable",
metricsDisableFlag,
false,
"Disable exposing metrics in the Prometheus format.",
)

cmd.Flags().Var(
&metricsListenPort,
"metrics-port",
metricsPortFlag,
"Set the port where the metrics are exposed. Format: [1024 - 65535]",
)

cmd.Flags().BoolVar(
&metricsSecure,
"metrics-secure-serving",
metricsSecureFlag,
false,
"Enable serving metrics via https. By default metrics are served via http."+
" Please note that this endpoint will be secured with a self-signed certificate.",
)

cmd.Flags().BoolVar(
&disableHealth,
"health-disable",
healthDisableFlag,
false,
"Disable running the health probe server.",
)

cmd.Flags().Var(
&healthListenPort,
"health-port",
healthPortFlag,
"Set the port where the health probe server is exposed. Format: [1024 - 65535]",
)

cmd.Flags().BoolVar(
&disableLeaderElection,
leaderElectionDisableFlag,
false,
"Disable leader election. Leader election is used to avoid multiple replicas of the NGINX Kubernetes Gateway"+
" reporting the status of the Gateway API resources. If disabled, "+
"all replicas of NGINX Kubernetes Gateway will update the statuses of the Gateway API resources.",
)

cmd.Flags().Var(
&leaderElectionLockName,
leaderElectionLockNameFlag,
"The name of the leader election lock. "+
"A Lease object with this name will be created in the same Namespace as the controller.",
kate-osborn marked this conversation as resolved.
Show resolved Hide resolved
)

return cmd
}

Expand Down
18 changes: 18 additions & 0 deletions cmd/gateway/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ func TestStaticModeCmdFlagValidation(t *testing.T) {
"--metrics-secure-serving",
"--health-port=8081",
"--health-disable",
"--leader-election-lock-name=my-lock",
"--leader-election-disable=false",
},
wantErr: false,
},
Expand Down Expand Up @@ -243,6 +245,22 @@ func TestStaticModeCmdFlagValidation(t *testing.T) {
expectedErrPrefix: `invalid argument "999" for "--health-disable" flag: strconv.ParseBool:` +
` parsing "999": invalid syntax`,
},
{
name: "leader-election-lock-name is set to invalid string",
args: []string{
"--leader-election-lock-name=!@#$",
},
wantErr: true,
expectedErrPrefix: `invalid argument "!@#$" for "--leader-election-lock-name" flag: invalid format`,
},
{
name: "leader-election-disable is set to empty string",
args: []string{
"--leader-election-disable=",
},
wantErr: true,
expectedErrPrefix: `invalid argument "" for "--leader-election-disable" flag: strconv.ParseBool`,
},
}

for _, test := range tests {
Expand Down
8 changes: 6 additions & 2 deletions conformance/provisioner/static-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ metadata:
app.kubernetes.io/instance: nginx-gateway
app.kubernetes.io/version: "edge"
spec:
# We only support a single replica for now
replicas: 1
selector:
matchLabels:
Expand All @@ -30,15 +29,20 @@ spec:
- --config=nginx-gateway-config
- --metrics-disable
- --health-port=8081
- --leader-election-lock-name=nginx-gateway-leader-election
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_NAMESPACE
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
image: ghcr.io/nginxinc/nginx-kubernetes-gateway:edge
imagePullPolicy: Always
name: nginx-gateway
Expand Down
Loading
Loading