Any changes to the CRD API (api/v1alpha1/) must be agreed with the core team before implementation.
make test # Run unit/integration tests (no cluster needed)
make lint # Run golangci-lint
make lint-fix # Run golangci-lint with auto-fix
make fmt # Run go fmt
make vet # Run go vet
make build # Build the manager binary (runs manifests, generate, fmt, vet, lint)
make manifests # Regenerate CRD manifests and RBAC from controller-runtime markers
make generate # Regenerate DeepCopy methods
make test-e2e # Run end-to-end tests in a Kind cluster (creates one if needed, tears it down after)After modifying types in api/v1alpha1/, always run make manifests generate before testing.
Run a single test package (requires make test or make setup-envtest to have been run first):
KUBEBUILDER_ASSETS="$(./bin/setup-envtest use --bin-dir ./bin -p path)" go test ./internal/controller/... -vFilter to a specific Ginkgo spec with --ginkgo.focus:
KUBEBUILDER_ASSETS="$(./bin/setup-envtest use --bin-dir ./bin -p path)" go test ./internal/controller/... -v --ginkgo.focus "spec name"Run a specific e2e test by label:
TEST_LABELS="<label>" make test-e2e- Go v1.25.0+.
- Docker or Podman.
- kubectl v1.31+.
- Access to a Kubernetes v1.31+ cluster.
Build and push the operator image:
make docker-build docker-push IMG=<some-registry>/valkey-operator:tagInstall the CRDs into the cluster:
make installDeploy the operator to the cluster:
make deploy IMG=<some-registry>/valkey-operator:tagCreate a sample ValkeyCluster:
kubectl apply -f config/samples/v1alpha1_valkeycluster.yamlDelete the instances (CRs) from the cluster:
kubectl delete -f config/samples/v1alpha1_valkeycluster.yamlDelete the CRDs from the cluster:
make uninstallUndeploy the controller from the cluster:
⚠️ Warning:make undeployremoves all resources in the operator's namespace. Always deploy the operator in a dedicated namespace to avoid accidentally deleting unrelated workloads.
make undeployGenerate a single YAML file containing all resources (CRDs, RBAC, deployment):
make build-installer IMG=<some-registry>/valkey-operator:tagThis produces dist/install.yaml which can be applied with kubectl apply -f.
The kubebuilder scaffolding gives a build target make run which runs the operator process locally, but towards a K8s cluster.
Since neither Pod IPs are routable, nor Pod FQDNs are resolvable outside the cluster, any attempt by the operator to connect to a Valkey pod will fail.
Here is a procedure to make it work, but you might need to adapt depending on your setup.
- Linux and a distro using
systemd-resolvedfor DNS (like Ubuntu >= 22.04, Fedora >= 36). - K8s cluster via
minikube, with the Docker driver (default on Linux). - The domain name for your cluster is
cluster.local.
minikube start
make installminikube tunnelThis creates a network route on the host for the service CIDR using the minikube IP address as a gateway.
We will be able to connect to services locally.
See ip route showing 10.96.0.0/12 via 192.168.49.2 dev br-ea36a389b2f9.
for name cidr in $(kubectl get nodes -Ao jsonpath='{range .items[*]}{@.metadata.name}{" "}{@.spec.podCIDR}{"\n"}{end}'); do echo sudo ip route add $cidr via $(minikube ip -n $name); doneThis adds a similar route as in the previous step, but for Pod CIDR ranges. We get the podCIDR range for each node using kubectl, then route the range to the node IP.
Now the operator running outside the K8s cluster should be able to connect to a listener using the Pod IP.
Since we probably also want to access it using FQDN, like when accessing a pod in a headless service using
<pod-name>.<service-name>.<namespace>.svc.cluster.local, we also need to setup the DNS.
# Add kube-dns to the list of DNS servers
sudo resolvectl dns $(ip route | grep $(minikube ip) | awk '{print $NF}' | uniq) $(kubectl -n kube-system get svc kube-dns -o jsonpath='{.spec.clusterIP}')
# Forward request for cluster.local to the kube-dns
sudo resolvectl domain $(ip route | grep $(minikube ip) | awk '{print $NF}' | uniq) cluster.local
# Test
# Optionally run `resolvectl` to check the status.
dig kubernetes.default.svc.cluster.localSince we want the kube-dns in the cluster to resolve all queries ending with cluster.local we need to
configure our local DNS service to forward these request.
We first need to get the network bridge towards minikube, using ip route | grep $(minikube ip) | awk '{print $NF}',
then we also need the ServiceIP for the kube-dns service in the K8s cluster,
we get this using kubectl -n kube-system get svc kube-dns -o jsonpath='{.spec.clusterIP}'.
With this information we can configure the local DNS service using resolvectl.
make run
kubectl create -f config/samples/v1alpha1_valkeycluster.yamlThe operator should now be able to connect to Valkey containers in the minikube cluster.