From 8c8038897282996f7d3c00df077d95c1ffa7bbe7 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Sun, 7 Jan 2024 15:40:27 -0600 Subject: [PATCH 1/3] Support specifying an alternate number of replicas for cloudflared Cloudflared should [support HA configurations out of the box](https://blog.cloudflare.com/highly-available-and-highly-scalable-cloudflare-tunnels/) with no extra work from the controller. This also means it should be possible to support a DaemonSet option for cloudflared. --- .../main.go | 22 +++++++++++++------ .../templates/deployment.yaml | 1 + .../values.yaml | 3 +++ .../controlled-cloudflared-connector.go | 8 +++---- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cmd/cloudflare-tunnel-ingress-controller/main.go b/cmd/cloudflare-tunnel-ingress-controller/main.go index 750bdb1..a6db248 100644 --- a/cmd/cloudflare-tunnel-ingress-controller/main.go +++ b/cmd/cloudflare-tunnel-ingress-controller/main.go @@ -21,12 +21,13 @@ type rootCmdFlags struct { // for annotation on Ingress ingressClass string // for IngressClass.spec.controller - controllerClass string - logLevel int - cloudflareAPIToken string - cloudflareAccountId string - cloudflareTunnelName string - namespace string + controllerClass string + logLevel int + cloudflareAPIToken string + cloudflareAccountId string + cloudflareTunnelName string + namespace string + cloudflaredReplicaCount int32 } func main() { @@ -99,7 +100,13 @@ func main() { case <-done: return case _ = <-ticker.C: - err := controller.CreateControlledCloudflaredIfNotExist(ctx, mgr.GetClient(), tunnelClient, options.namespace) + err := controller.CreateControlledCloudflaredIfNotExist( + ctx, + mgr.GetClient(), + tunnelClient, + options.namespace, + options.cloudflaredReplicaCount, + ) if err != nil { logger.WithName("controlled-cloudflared").Error(err, "create controlled cloudflared") } @@ -119,6 +126,7 @@ func main() { rootCommand.PersistentFlags().StringVar(&options.cloudflareAccountId, "cloudflare-account-id", options.cloudflareAccountId, "cloudflare account id") rootCommand.PersistentFlags().StringVar(&options.cloudflareTunnelName, "cloudflare-tunnel-name", options.cloudflareTunnelName, "cloudflare tunnel name") rootCommand.PersistentFlags().StringVar(&options.namespace, "namespace", options.namespace, "namespace to execute cloudflared connector") + rootCommand.PersistentFlags().Int32Var(&options.cloudflaredReplicaCount, "cloudflared-replica-count", options.cloudflaredReplicaCount, "namespace to execute cloudflared connector") err := rootCommand.Execute() if err != nil { diff --git a/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml b/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml index 5b0c659..5ca49d0 100644 --- a/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml +++ b/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml @@ -39,6 +39,7 @@ spec: - --cloudflare-account-id=$(CLOUDFLARE_ACCOUNT_ID) - --cloudflare-tunnel-name=$(CLOUDFLARE_TUNNEL_NAME) - --namespace=$(NAMESPACE) + - --cloudflared-replica-count={{ .Values.cloudflared.replicaCount }} env: - name: CLOUDFLARE_API_TOKEN valueFrom: diff --git a/helm/cloudflare-tunnel-ingress-controller/values.yaml b/helm/cloudflare-tunnel-ingress-controller/values.yaml index 03f88bc..d6f9683 100644 --- a/helm/cloudflare-tunnel-ingress-controller/values.yaml +++ b/helm/cloudflare-tunnel-ingress-controller/values.yaml @@ -21,6 +21,9 @@ ingressClass: replicaCount: 1 +cloudflared: + replicaCount: 1 + image: repository: ghcr.io/strrl/cloudflare-tunnel-ingress-controller pullPolicy: IfNotPresent diff --git a/pkg/controller/controlled-cloudflared-connector.go b/pkg/controller/controlled-cloudflared-connector.go index 26fd5e9..982fb97 100644 --- a/pkg/controller/controlled-cloudflared-connector.go +++ b/pkg/controller/controlled-cloudflared-connector.go @@ -10,7 +10,6 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -19,6 +18,7 @@ func CreateControlledCloudflaredIfNotExist( kubeClient client.Client, tunnelClient *cloudflarecontroller.TunnelClient, namespace string, + replicas int32, ) error { list := appsv1.DeploymentList{} err := kubeClient.List(ctx, &list, &client.ListOptions{ @@ -40,7 +40,7 @@ func CreateControlledCloudflaredIfNotExist( return errors.Wrap(err, "fetch tunnel token") } - deployment := cloudflaredConnectDeploymentTemplating(token, namespace) + deployment := cloudflaredConnectDeploymentTemplating(token, namespace, replicas) err = kubeClient.Create(ctx, deployment) if err != nil { return errors.Wrap(err, "create controlled-cloudflared-connector deployment") @@ -48,7 +48,7 @@ func CreateControlledCloudflaredIfNotExist( return nil } -func cloudflaredConnectDeploymentTemplating(token string, namespace string) *appsv1.Deployment { +func cloudflaredConnectDeploymentTemplating(token string, namespace string, replicas int32) *appsv1.Deployment { appName := "controlled-cloudflared-connector" image := os.Getenv("CLOUDFLARED_IMAGE") pullPolicy := os.Getenv("CLOUDFLARED_IMAGE_PULL_POLICY") @@ -62,7 +62,7 @@ func cloudflaredConnectDeploymentTemplating(token string, namespace string) *app }, }, Spec: appsv1.DeploymentSpec{ - Replicas: pointer.Int32(1), + Replicas: &replicas, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "app": appName, From 6de01f384a519fbd386fffeb3fb395cae0786a19 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Sun, 7 Jan 2024 21:01:52 -0600 Subject: [PATCH 2/3] Rebase conflict --- helm/cloudflare-tunnel-ingress-controller/values.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/helm/cloudflare-tunnel-ingress-controller/values.yaml b/helm/cloudflare-tunnel-ingress-controller/values.yaml index d6f9683..d388bf3 100644 --- a/helm/cloudflare-tunnel-ingress-controller/values.yaml +++ b/helm/cloudflare-tunnel-ingress-controller/values.yaml @@ -21,9 +21,6 @@ ingressClass: replicaCount: 1 -cloudflared: - replicaCount: 1 - image: repository: ghcr.io/strrl/cloudflare-tunnel-ingress-controller pullPolicy: IfNotPresent @@ -79,3 +76,4 @@ cloudflared: repository: cloudflare/cloudflared pullPolicy: IfNotPresent tag: latest + replicaCount: 1 From 1d19b9f6a81ad723ed21bc5527da0dbf16a085d2 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Sun, 7 Jan 2024 21:14:32 -0600 Subject: [PATCH 3/3] Refactor to pass count via env var I'm not sure if you prefer CLI args or env vars, but the env vars seem to require less "prop drilling" --- .../main.go | 22 ++++++------------- .../templates/deployment.yaml | 3 ++- .../controlled-cloudflared-connector.go | 10 +++++++-- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/cmd/cloudflare-tunnel-ingress-controller/main.go b/cmd/cloudflare-tunnel-ingress-controller/main.go index a6db248..750bdb1 100644 --- a/cmd/cloudflare-tunnel-ingress-controller/main.go +++ b/cmd/cloudflare-tunnel-ingress-controller/main.go @@ -21,13 +21,12 @@ type rootCmdFlags struct { // for annotation on Ingress ingressClass string // for IngressClass.spec.controller - controllerClass string - logLevel int - cloudflareAPIToken string - cloudflareAccountId string - cloudflareTunnelName string - namespace string - cloudflaredReplicaCount int32 + controllerClass string + logLevel int + cloudflareAPIToken string + cloudflareAccountId string + cloudflareTunnelName string + namespace string } func main() { @@ -100,13 +99,7 @@ func main() { case <-done: return case _ = <-ticker.C: - err := controller.CreateControlledCloudflaredIfNotExist( - ctx, - mgr.GetClient(), - tunnelClient, - options.namespace, - options.cloudflaredReplicaCount, - ) + err := controller.CreateControlledCloudflaredIfNotExist(ctx, mgr.GetClient(), tunnelClient, options.namespace) if err != nil { logger.WithName("controlled-cloudflared").Error(err, "create controlled cloudflared") } @@ -126,7 +119,6 @@ func main() { rootCommand.PersistentFlags().StringVar(&options.cloudflareAccountId, "cloudflare-account-id", options.cloudflareAccountId, "cloudflare account id") rootCommand.PersistentFlags().StringVar(&options.cloudflareTunnelName, "cloudflare-tunnel-name", options.cloudflareTunnelName, "cloudflare tunnel name") rootCommand.PersistentFlags().StringVar(&options.namespace, "namespace", options.namespace, "namespace to execute cloudflared connector") - rootCommand.PersistentFlags().Int32Var(&options.cloudflaredReplicaCount, "cloudflared-replica-count", options.cloudflaredReplicaCount, "namespace to execute cloudflared connector") err := rootCommand.Execute() if err != nil { diff --git a/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml b/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml index 5ca49d0..c303396 100644 --- a/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml +++ b/helm/cloudflare-tunnel-ingress-controller/templates/deployment.yaml @@ -39,7 +39,6 @@ spec: - --cloudflare-account-id=$(CLOUDFLARE_ACCOUNT_ID) - --cloudflare-tunnel-name=$(CLOUDFLARE_TUNNEL_NAME) - --namespace=$(NAMESPACE) - - --cloudflared-replica-count={{ .Values.cloudflared.replicaCount }} env: - name: CLOUDFLARE_API_TOKEN valueFrom: @@ -79,6 +78,8 @@ spec: value: "{{ .Values.cloudflared.image.repository }}:{{ .Values.cloudflared.image.tag }}" - name: CLOUDFLARED_IMAGE_PULL_POLICY value: {{ .Values.cloudflared.image.pullPolicy | quote }} + - name: CLOUDFLARED_REPLICA_COUNT + value: {{ .Values.cloudflared.replicaCount | quote }} resources: {{- toYaml .Values.resources | nindent 12 }} {{- with .Values.nodeSelector }} diff --git a/pkg/controller/controlled-cloudflared-connector.go b/pkg/controller/controlled-cloudflared-connector.go index 982fb97..4df0636 100644 --- a/pkg/controller/controlled-cloudflared-connector.go +++ b/pkg/controller/controlled-cloudflared-connector.go @@ -3,6 +3,7 @@ package controller import ( "context" "os" + "strconv" cloudflarecontroller "github.com/STRRL/cloudflare-tunnel-ingress-controller/pkg/cloudflare-controller" "github.com/pkg/errors" @@ -18,7 +19,6 @@ func CreateControlledCloudflaredIfNotExist( kubeClient client.Client, tunnelClient *cloudflarecontroller.TunnelClient, namespace string, - replicas int32, ) error { list := appsv1.DeploymentList{} err := kubeClient.List(ctx, &list, &client.ListOptions{ @@ -40,7 +40,12 @@ func CreateControlledCloudflaredIfNotExist( return errors.Wrap(err, "fetch tunnel token") } - deployment := cloudflaredConnectDeploymentTemplating(token, namespace, replicas) + replicas, err := strconv.ParseInt(os.Getenv("CLOUDFLARED_REPLICA_COUNT"), 10, 32) + if err != nil { + return errors.Wrap(err, "invalid replica count") + } + + deployment := cloudflaredConnectDeploymentTemplating(token, namespace, int32(replicas)) err = kubeClient.Create(ctx, deployment) if err != nil { return errors.Wrap(err, "create controlled-cloudflared-connector deployment") @@ -52,6 +57,7 @@ func cloudflaredConnectDeploymentTemplating(token string, namespace string, repl appName := "controlled-cloudflared-connector" image := os.Getenv("CLOUDFLARED_IMAGE") pullPolicy := os.Getenv("CLOUDFLARED_IMAGE_PULL_POLICY") + return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: appName,