Skip to content

Development Setup

This guide covers setting up a development environment for the Cloudflare Tunnel Gateway Controller.

Prerequisites

  • Go 1.25.4 or later
  • kubectl configured with cluster access
  • A Kubernetes cluster (kind, minikube, or remote)
  • Cloudflare account with a tunnel configured
  • golangci-lint (for linting)

Quick Start

# Clone the repository
git clone https://github.com/lexfrei/cloudflare-tunnel-gateway-controller.git
cd cloudflare-tunnel-gateway-controller

# Install dependencies
go mod download

# Build
go build -o bin/controller ./cmd/controller

# Run tests
go test -v ./...

# Run linter
golangci-lint run

Building

Binary

# Development build
go build -o bin/controller ./cmd/controller

# Production build with version info
VERSION=v0.1.0
GITSHA=$(git rev-parse HEAD)
go build -ldflags "-s -w -X main.Version=${VERSION} -X main.Gitsha=${GITSHA}" \
  -trimpath -o bin/controller ./cmd/controller

Container Image

# Build with podman
podman build --tag cloudflare-tunnel-gateway-controller:dev --file Containerfile .

# Build with docker
docker build --tag cloudflare-tunnel-gateway-controller:dev --file Containerfile .

# Multi-arch build
docker buildx build --platform linux/amd64,linux/arm64 \
  --tag ghcr.io/lexfrei/cloudflare-tunnel-gateway-controller:dev \
  --file Containerfile .

Running Locally

With kubeconfig

# Set required environment variables
export CF_TUNNEL_ID="your-tunnel-id"
export CF_API_TOKEN="your-api-token"

# Run controller
./bin/controller \
  --log-level=debug \
  --log-format=text \
  --gateway-class-name=cloudflare-tunnel

In Cluster (Development)

# Install Gateway API CRDs
kubectl apply --filename https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml

# Create namespace
kubectl create namespace cloudflare-tunnel-system

# Create secret with credentials
kubectl create secret generic cloudflare-credentials \
  --namespace=cloudflare-tunnel-system \
  --from-literal=api-token="${CF_API_TOKEN}"

# Apply RBAC
kubectl apply --filename deploy/rbac/

# Run controller locally against cluster
./bin/controller \
  --tunnel-id="${CF_TUNNEL_ID}" \
  --log-level=debug

Linting

The project uses golangci-lint with strict configuration:

# Run linter
golangci-lint run

# Run with timeout for CI
golangci-lint run --timeout=5m

# Auto-fix issues
golangci-lint run --fix

Key Linter Settings

Linter Setting Description
funlen max 60 Maximum function length
gocyclo max 15 Maximum cyclomatic complexity
gosec enabled Security checks
nolintlint enabled Requires //nolint explanations

Debugging

Enable Debug Logging

./bin/controller --log-level=debug --log-format=text

Inspect Controller State

# Check Gateway status
kubectl get gateway --all-namespaces --output yaml

# Check HTTPRoute status
kubectl get httproute --all-namespaces --output yaml

# Check controller logs
kubectl logs --namespace cloudflare-tunnel-system \
  deployment/cloudflare-tunnel-gateway-controller

# Check events
kubectl get events --namespace cloudflare-tunnel-system \
  --sort-by='.lastTimestamp'

Debug with Delve

# Install delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Run with debugger
dlv debug ./cmd/controller -- \
  --tunnel-id="${CF_TUNNEL_ID}" \
  --log-level=debug

IDE Setup

VS Code

Recommended extensions:

  • Go (golang.go)
  • YAML (redhat.vscode-yaml)
  • Kubernetes (ms-kubernetes-tools.vscode-kubernetes-tools)

Settings (.vscode/settings.json):

{
  "go.lintTool": "golangci-lint",
  "go.lintFlags": ["--fast"],
  "go.useLanguageServer": true,
  "gopls": {
    "ui.semanticTokens": true
  }
}

GoLand

  1. Enable golangci-lint integration:
  2. Settings → Go → Linters → Enable golangci-lint
  3. Configure run configuration:
  4. Add environment variables: CF_TUNNEL_ID, CF_API_TOKEN
  5. Set working directory to project root

Common Tasks

Add a New Flag

  1. Add flag in cmd/controller/cmd/root.go:

    rootCmd.Flags().String("my-flag", "default", "Description")
    
  2. Add viper binding and default:

    viper.SetDefault("my-flag", "default")
    
  3. Add to controller.Config struct in internal/controller/manager.go

  4. Pass value in runController() function

Update Dependencies

# Update all dependencies
go get -u ./...
go mod tidy

# Update specific dependency
go get -u github.com/cloudflare/cloudflare-go/v4@latest
go mod tidy

Helm Chart Versioning

Do Not Manually Bump Versions

Do not manually change version or appVersion in Chart.yaml. The release workflow automatically sets both values based on the release tag. Manual changes will cause conflicts.

Generate Godoc

godoc -http=:6060
# Open http://localhost:6060/pkg/github.com/lexfrei/cloudflare-tunnel-gateway-controller/