Multi-cloud networking for Kubernetes, simplified.
Galactic connects Kubernetes workloads across multiple clouds and regions as if they were on a single, unified network. It provides secure, isolated Virtual Private Clouds (VPCs) that span cloud boundaries—without vendor lock-in or complex configuration.
Modern organizations run workloads everywhere: AWS, Azure, GCP, on-premises, and edge locations. Each environment brings its own networking model, APIs, and constraints. The result is fragmented networks, operational complexity, and cloud provider lock-in.
Galactic provides the SRv6 data plane that makes multi-cloud VPC connectivity work at the kernel level. It runs as a DaemonSet agent on every node, managing SRv6 routes and VRF isolation, and as a CNI plugin that attaches pods to the correct virtual network. VPC and VPCAttachment definitions are managed by a companion operator; Galactic acts on the identifiers that operator assigns.
Under the hood, Galactic uses Segment Routing over IPv6 (SRv6) for efficient, deterministic routing and Virtual Routing and Forwarding (VRF) for true network isolation at the kernel level. BGP is used to distribute SRv6 routes between agents across nodes and clusters.
For Developers — Attach to a VPC with a single annotation. No networking code, no cloud-specific APIs.
For Platform Teams — Manage multi-cloud networking from Kubernetes using GitOps workflows and standard tooling.
For Organizations — Move workloads between providers without network redesign. One networking model instead of N cloud-specific implementations.
A ContainerLab environment is available under deploy/containerlab/:
deploy/containerlab/— Three Kind clusters wired over an SRv6 transit mesh. The full GVPC multi-cluster environment with FRR underlay and GoBGP L3VPN overlay.
See the galactic DevContainer for development environment setup. On ARM64 / OrbStack, use the containerlab DevContainer to run ContainerLab via Docker-out-of-Docker.
Manifests for a real cluster live under config/, composed with Kustomize. One command deploys the galactic-system namespace (labeled pod-security.kubernetes.io/enforce: privileged — both DaemonSets need it, for hostPath volumes, hostNetwork, and elevated capabilities), the galactic-cni DaemonSet, and both galactic-router roles — tenant (per-node, runs everywhere except control-plane nodes) and tenant-control (BGP route reflector, opt-in — stays at zero replicas until nodes are labeled galactic.datumapis.com/node: control):
kubectl apply -k config/Each component can also be applied on its own, e.g. kubectl apply -k config/router for just the router (both roles) or kubectl apply -k config/router/tenant for just the per-node role.
-
Container images.
.github/workflows/publish.yamlbuildsghcr.io/datum-cloud/galactic-cniandghcr.io/datum-cloud/galactic-router(fromcontainers/galactic-cni/Dockerfileandcontainers/galactic-router/Dockerfilerespectively) on every push and release — but it never publishes a:latesttag, only date-stamped tags per push/release (e.g.v0.0.0-main-20260713-170924) and, for tagged releases, semver tags. Theimage:references committed inconfig/cni/daemonset.yamlandconfig/router/base/daemonset.yamlsay:latestonly as a placeholder that CI substitutes with a real published tag when it builds theghcr.io/datum-cloud/galactic-kustomizeOCI Kustomize bundle — that substitution never happens in the git checkout itself. Applyingconfig/directly from a clone will therefore fail to pull:latest. Before applying, resolve the current tag (check the package pages or the latest successful run ofpublish.yamlonmain) and pin it, e.g.:cd config/cni && kustomize edit set image ghcr.io/datum-cloud/galactic-cni=ghcr.io/datum-cloud/galactic-cni:<resolved-tag> cd config/router/base && kustomize edit set image ghcr.io/datum-cloud/galactic-router=ghcr.io/datum-cloud/galactic-router:<resolved-tag>
-
Talos: gRPC health port.
galactic-routerrunshostNetwork: trueand defaults to gRPC health checks on port5000, which collides with Talos's built-in dashboard (/sbin/dashboardpermanently binds127.0.0.1:5000on every Talos node).config/router/base/daemonset.yamlalready ships withGALACTIC_ROUTER_GRPC_HEALTH_PORT=5179(and matching probe/containerPort) to avoid this; if you rungalactic-routeroutside these manifests on Talos, setGALACTIC_ROUTER_GRPC_HEALTH_PORTto something other than5000yourself. -
galactic-routertenant mode: BGP local address. The node needs a global-unicast IPv6 address assigned tolo(typically by an underlay/fabric BGP daemon that starts beforegalactic-router), or you must setGALACTIC_ROUTER_BGP_LOCAL_ADDRESSexplicitly — this is required even whenGALACTIC_ROUTER_BGP_LISTEN_PORT=-1(no inbound listener), sincegalactic-routerstill needs a source address for outbound BGP connections. Without one of these, startup fails withGALACTIC_ROUTER_BGP_LOCAL_ADDRESS not set and no address could be detected on lo: no global-unicast IPv6 address found on lo. Seedocs/router/configuration.mdfor details.
See docs/router/configuration.md for the full galactic-router CLI flag / environment variable reference — note that env var names generally follow GALACTIC_ROUTER_<FLAG_NAME> but aren't always the naive uppercased guess (e.g. --mode is GALACTIC_ROUTER_ROUTER_MODE, not GALACTIC_ROUTER_MODE); the reference table has the exact name for every flag.
This project uses Task as its build tool. Build, test, and lint operations are defined in the root Taskfile.yaml.
# macOS
brew install go-task
# Linux (official installer)
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
# Go toolchain
go install github.com/go-task/task/v3/cmd/task@latestSee taskfile.dev/installation for the full list of options.
task # list available taskstask build # produces bin/galactic-cni and bin/galactic-router
task lint # golangci-lint + yamlfmt; lint-fix applies safe auto-fixes
task ci # full pipeline: lint → build → test:unit → test:e2eThere is no task docker-build — the shared production Dockerfile and release
workflow were removed (see Production Deployment above). containers/galactic-cni/Dockerfile
exists only to support task test:e2e below.
task test # run unit tests then e2e tests (requires Docker + Kind)
task test:unit # unit tests only — race detector, coverage output
task test:e2e # full e2e lifecycle — spins up a Kind cluster, builds and
# loads the image, then tears the cluster down on exittask test:unit is the fast path for development; it runs the same command as the CI test-unit job. task test:e2e requires Docker and Kind and mirrors the CI test-e2e job exactly, including automatic cluster cleanup via a trap on exit.
Run task ci before opening a pull request.
The lab environment has its own Taskfile.yaml; run task from deploy/containerlab/ to see available tasks.
See AGENTS.md for the contributor guide (development workflow, code standards, architecture pointers) and docs/agents/ARCHITECTURE.md for the full architecture reference.
See LICENSE for details.
Galactic is developed by Datum.