Skip to content

Allow for provisioning NGINX as DaemonSet #3397

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

Merged
merged 7 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 24 additions & 2 deletions apis/v1alpha2/nginxproxy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,22 @@ const (
)

// KubernetesSpec contains the configuration for the NGINX Deployment and Service Kubernetes objects.
//
// +kubebuilder:validation:XValidation:message="only one of deployment or daemonSet can be set",rule="(!has(self.deployment) && !has(self.daemonSet)) || ((has(self.deployment) && !has(self.daemonSet)) || (!has(self.deployment) && has(self.daemonSet)))"
//
//nolint:lll
type KubernetesSpec struct {
// Deployment is the configuration for the NGINX Deployment.
// This is the default deployment option.
//
// +optional
Deployment *DeploymentSpec `json:"deployment,omitempty"`

// DaemonSet is the configuration for the NGINX DaemonSet.
//
// +optional
DaemonSet *DaemonSetSpec `json:"daemonSet,omitempty"`

// Service is the configuration for the NGINX Service.
//
// +optional
Expand All @@ -382,12 +391,25 @@ type DeploymentSpec struct {
// Pod defines Pod-specific fields.
//
// +optional
Pod PodSpec `json:"pod,omitempty"`
Pod PodSpec `json:"pod"`

// Container defines container fields for the NGINX container.
//
// +optional
Container ContainerSpec `json:"container"`
}

// DaemonSet is the configuration for the NGINX DaemonSet.
type DaemonSetSpec struct {
// Pod defines Pod-specific fields.
//
// +optional
Pod PodSpec `json:"pod"`

// Container defines container fields for the NGINX container.
//
// +optional
Container ContainerSpec `json:"container,omitempty"`
Container ContainerSpec `json:"container"`
}

// PodSpec defines Pod-specific fields.
Expand Down
22 changes: 22 additions & 0 deletions apis/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions charts/nginx-gateway-fabric/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
16 changes: 16 additions & 0 deletions charts/nginx-gateway-fabric/templates/nginxproxy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@ spec:
debug: {{ .Values.nginx.debug }}
{{- end }}
{{- end }}
{{- if eq .Values.nginx.kind "daemonSet" }}
daemonSet:
{{- if .Values.nginx.pod }}
pod:
{{- toYaml .Values.nginx.pod | nindent 8 }}
{{- end }}
container:
{{- if .Values.nginx.container }}
{{- toYaml .Values.nginx.container | nindent 8 }}
{{- end }}
image:
{{- toYaml .Values.nginx.image | nindent 10 }}
{{- if .Values.nginx.debug }}
debug: {{ .Values.nginx.debug }}
{{- end }}
{{- end }}
{{- if .Values.nginx.service }}
service:
{{- with .Values.nginx.service }}
Expand Down
3 changes: 2 additions & 1 deletion charts/nginx-gateway-fabric/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@
"default": "deployment",
"description": "The kind of NGINX deployment.",
"enum": [
"deployment"
"deployment",
"daemonSet"
],
"required": [],
"title": "kind"
Expand Down
1 change: 1 addition & 0 deletions charts/nginx-gateway-fabric/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ nginx:
# @schema
# enum:
# - deployment
# - daemonSet
# @schema
# -- The kind of NGINX deployment.
kind: deployment
Expand Down
3,388 changes: 3,388 additions & 0 deletions config/crd/bases/gateway.nginx.org_nginxproxies.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions deploy/azure/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
3,388 changes: 3,388 additions & 0 deletions deploy/crds.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions deploy/default/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/experimental-nginx-plus/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/experimental/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/nginx-plus/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/nodeport/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/openshift/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/snippets-filters-nginx-plus/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
1 change: 1 addition & 0 deletions deploy/snippets-filters/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rules:
- serviceaccounts
- services
- deployments
- daemonsets
verbs:
- create
- update
Expand Down
11 changes: 0 additions & 11 deletions internal/framework/controller/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,10 @@ package controller

import (
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

// CreateNginxResourceName creates the base resource name for all nginx resources
// created by the control plane.
func CreateNginxResourceName(prefix, suffix string) string {
return fmt.Sprintf("%s-%s", prefix, suffix)
}

// ObjectMetaToNamespacedName converts ObjectMeta to NamespacedName.
func ObjectMetaToNamespacedName(meta metav1.ObjectMeta) types.NamespacedName {
return types.NamespacedName{
Namespace: meta.Namespace,
Name: meta.Name,
}
}
8 changes: 6 additions & 2 deletions internal/mode/static/nginx/agent/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,15 @@ func (cs *commandService) getPodOwner(podName string) (types.NamespacedName, err
return types.NamespacedName{}, fmt.Errorf("expected one owner reference of the nginx Pod, got %d", len(podOwnerRefs))
}

if podOwnerRefs[0].Kind != "ReplicaSet" {
err := fmt.Errorf("expected pod owner reference to be ReplicaSet, got %s", podOwnerRefs[0].Kind)
if podOwnerRefs[0].Kind != "ReplicaSet" && podOwnerRefs[0].Kind != "DaemonSet" {
err := fmt.Errorf("expected pod owner reference to be ReplicaSet or DaemonSet, got %s", podOwnerRefs[0].Kind)
return types.NamespacedName{}, err
}

if podOwnerRefs[0].Kind == "DaemonSet" {
return types.NamespacedName{Namespace: pod.Namespace, Name: podOwnerRefs[0].Name}, nil
}

var replicaSet appsv1.ReplicaSet
var replicaSetErr error
if err := wait.PollUntilContextCancel(
Expand Down
31 changes: 28 additions & 3 deletions internal/mode/static/nginx/agent/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ func TestGetPodOwner(t *testing.T) {
expected types.NamespacedName
}{
{
name: "successfully gets pod owner",
name: "successfully gets pod owner; ReplicaSet",
podName: "nginx-pod",
podList: &v1.PodList{
Items: []v1.Pod{
Expand Down Expand Up @@ -725,6 +725,31 @@ func TestGetPodOwner(t *testing.T) {
Name: "nginx-deployment",
},
},
{
name: "successfully gets pod owner; DaemonSet",
podName: "nginx-pod",
podList: &v1.PodList{
Items: []v1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx-pod",
Namespace: "test",
OwnerReferences: []metav1.OwnerReference{
{
Kind: "DaemonSet",
Name: "nginx-daemonset",
},
},
},
},
},
},
replicaSet: &appsv1.ReplicaSet{},
expected: types.NamespacedName{
Namespace: "test",
Name: "nginx-daemonset",
},
},
{
name: "error listing pods",
podName: "nginx-pod",
Expand All @@ -745,7 +770,7 @@ func TestGetPodOwner(t *testing.T) {
errString: "should only be one pod with name",
},
{
name: "pod owner reference is not ReplicaSet",
name: "pod owner reference is not ReplicaSet or DaemonSet",
podName: "nginx-pod",
podList: &v1.PodList{
Items: []v1.Pod{
Expand All @@ -763,7 +788,7 @@ func TestGetPodOwner(t *testing.T) {
},
},
replicaSet: &appsv1.ReplicaSet{},
errString: "expected pod owner reference to be ReplicaSet",
errString: "expected pod owner reference to be ReplicaSet or DaemonSet",
},
{
name: "pod has multiple owners",
Expand Down
12 changes: 12 additions & 0 deletions internal/mode/static/provisioner/eventloop.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ func newEventLoop(
),
},
},
{
objectType: &appsv1.DaemonSet{},
options: []controller.Option{
controller.WithK8sPredicate(
k8spredicate.And(
k8spredicate.GenerationChangedPredicate{},
nginxResourceLabelPredicate,
predicate.RestartDeploymentAnnotationPredicate{},
),
),
},
},
{
objectType: &corev1.Service{},
options: []controller.Option{
Expand Down
30 changes: 8 additions & 22 deletions internal/mode/static/provisioner/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ func (h *eventHandler) HandleEventBatch(ctx context.Context, logger logr.Logger,
switch obj := e.Resource.(type) {
case *gatewayv1.Gateway:
h.store.updateGateway(obj)
case *appsv1.Deployment, *corev1.ServiceAccount, *corev1.ConfigMap, *rbacv1.Role, *rbacv1.RoleBinding:
case *appsv1.Deployment, *appsv1.DaemonSet, *corev1.ServiceAccount,
*corev1.ConfigMap, *rbacv1.Role, *rbacv1.RoleBinding:
objLabels := labels.Set(obj.GetLabels())
if h.labelSelector.Matches(objLabels) {
gatewayName := objLabels.Get(controller.GatewayLabel)
Expand Down Expand Up @@ -116,7 +117,7 @@ func (h *eventHandler) HandleEventBatch(ctx context.Context, logger logr.Logger,
logger.Error(err, "error deprovisioning nginx resources")
}
h.store.deleteGateway(e.NamespacedName)
case *appsv1.Deployment, *corev1.Service, *corev1.ServiceAccount,
case *appsv1.Deployment, *appsv1.DaemonSet, *corev1.Service, *corev1.ServiceAccount,
*corev1.ConfigMap, *rbacv1.Role, *rbacv1.RoleBinding:
if err := h.reprovisionResources(ctx, e); err != nil {
logger.Error(err, "error re-provisioning nginx resources")
Expand Down Expand Up @@ -267,40 +268,25 @@ func (h *eventHandler) deprovisionSecretsForAllGateways(ctx context.Context, sec

switch {
case strings.HasSuffix(resources.AgentTLSSecret.Name, secret):
if err := h.provisioner.deleteSecret(
ctx,
controller.ObjectMetaToNamespacedName(resources.AgentTLSSecret),
); err != nil {
if err := h.provisioner.deleteObject(ctx, &corev1.Secret{ObjectMeta: resources.AgentTLSSecret}); err != nil {
allErrs = append(allErrs, err)
}
case strings.HasSuffix(resources.PlusJWTSecret.Name, secret):
if err := h.provisioner.deleteSecret(
ctx,
controller.ObjectMetaToNamespacedName(resources.PlusJWTSecret),
); err != nil {
if err := h.provisioner.deleteObject(ctx, &corev1.Secret{ObjectMeta: resources.PlusJWTSecret}); err != nil {
allErrs = append(allErrs, err)
}
case strings.HasSuffix(resources.PlusCASecret.Name, secret):
if err := h.provisioner.deleteSecret(
ctx,
controller.ObjectMetaToNamespacedName(resources.PlusCASecret),
); err != nil {
if err := h.provisioner.deleteObject(ctx, &corev1.Secret{ObjectMeta: resources.PlusCASecret}); err != nil {
allErrs = append(allErrs, err)
}
case strings.HasSuffix(resources.PlusClientSSLSecret.Name, secret):
if err := h.provisioner.deleteSecret(
ctx,
controller.ObjectMetaToNamespacedName(resources.PlusClientSSLSecret),
); err != nil {
if err := h.provisioner.deleteObject(ctx, &corev1.Secret{ObjectMeta: resources.PlusClientSSLSecret}); err != nil {
allErrs = append(allErrs, err)
}
default:
for _, dockerSecret := range resources.DockerSecrets {
if strings.HasSuffix(dockerSecret.Name, secret) {
if err := h.provisioner.deleteSecret(
ctx,
controller.ObjectMetaToNamespacedName(dockerSecret),
); err != nil {
if err := h.provisioner.deleteObject(ctx, &corev1.Secret{ObjectMeta: dockerSecret}); err != nil {
allErrs = append(allErrs, err)
}
}
Expand Down
Loading
Loading