Skip to content

Install & deploy

The UpCloud provider is one process per zone. You run it next to BigFleet, point it at an OS template, give it an UpCloud API sub-account and an SSH key pair, and BigFleet dials its --addr. This page covers the container image, the Helm chart, the flags you actually need, mTLS, and the Secret wiring.

Everything below is for a real account.

Container image

The binary is a single static Go binary; the image is built from deploy/Dockerfile (distroless, non-root, no shell). Build and push it from the repository root (the providers/upcloud module’s replace => ../.. needs the whole repo in context to resolve the providerkit root module):

Terminal window
docker build -t ghcr.io/intunderflow/bigfleet-upcloud:0.1.0 \
-f providers/upcloud/deploy/Dockerfile .
docker push ghcr.io/intunderflow/bigfleet-upcloud:0.1.0

The entrypoint is the provider binary, so you pass flags as container args. A bare smoke test (fake backend, no credentials) confirms the image runs:

Terminal window
docker run --rm -p 9000:9000 -p 9090:9090 \
ghcr.io/intunderflow/bigfleet-upcloud:0.1.0 \
--seed-count 32 --addr :9000 --metrics-addr :9090
# then: curl localhost:9090/healthz -> ok
# curl localhost:9090/readyz -> ready

The container exposes two ports, for BigFleet and Prometheus:

PortFlagServes
9000--addrgRPC CapacityProvider + grpc.health.v1 + reflection
9090--metrics-addrHTTP /metrics, /healthz (liveness), /readyz (readiness)

Helm chart

The chart lives at deploy/helm/. It renders a Deployment (single replica — one process per zone, owns its --state), a Service exposing the gRPC + metrics ports (with Prometheus scrape annotations), a ServiceAccount, and — when enabled — a ConfigMap for the offerings and a PersistentVolumeClaim for durable state. It consumes the UPCLOUD_USERNAME / UPCLOUD_PASSWORD Secret you create in Credentials.

Install one release per zone, with a values file per zone:

Terminal window
helm install bigfleet-upcloud-fi-hel1 providers/upcloud/deploy/helm \
-n bigfleet --create-namespace \
-f fi-hel1.values.yaml

A minimal fi-hel1.values.yaml:

image:
repository: ghcr.io/intunderflow/bigfleet-upcloud
tag: 0.1.0
# One process per zone. `zone` sets the zone this process serves and `provider`
# is the label stamped on every HostRef.
zone: fi-hel1
provider: upcloud-fi-hel1
# The server settings.
upcloud:
template: 01000000-0000-4000-8000-000030240200 # OS template storage UUID to clone
eurUSD: 1.08 # EUR->USD conversion for the pinned price table
# The API sub-account Secret (keys: username, password) -> UPCLOUD_USERNAME / UPCLOUD_PASSWORD.
credentials:
secretName: bigfleet-upcloud-credentials
# SSH delivery of the per-cluster bootstrap blob. The private key authenticates
# the provider; the public key is injected into each server at create.
ssh:
user: root
privateKeySecretName: bigfleet-upcloud-ssh # key: id (PEM private key)
publicKey: "ssh-ed25519 AAAA... bigfleet-upcloud"
# Durable state on a PersistentVolume: fence marks, the idempotency map, and
# bindings survive restarts. Without it the provider is in-memory only.
state:
enabled: true
persistence:
enabled: true
size: 1Gi

The offerings JSON is delivered through offerings.content: set it and the chart renders the JSON into a ConfigMap, mounts it at /etc/bigfleet/offerings/offerings.json, and passes --offerings. Use --set-file so you keep the file out of your values:

Terminal window
helm install bigfleet-upcloud-fi-hel1 providers/upcloud/deploy/helm \
-n bigfleet --create-namespace \
-f fi-hel1.values.yaml \
--set-file offerings.content=offerings.fi-hel1.json

The offerings shape is documented in Configuration. Always enable durable state on a PersistentVolume in production — without it the provider is in-memory and cannot recover bindings on restart.

Flags

Every flag the binary accepts, grouped by what you touch first. The full reference (defaults, semantics, the create-then-bootstrap model) is in Configuration.

Core

FlagDefaultMeaning
--addr:9000gRPC listen address
--providerupcloudLabel stamped on HostRef.provider (e.g. upcloud-fi-hel1)
--upcloud-backendautoupcloud | fake | auto (auto = upcloud when credentials and --zone are set, else fake)
--username / --password(empty)UpCloud API sub-account credentials (or set UPCLOUD_USERNAME / UPCLOUD_PASSWORD)
--zone(empty)UpCloud zone id this process serves (e.g. fi-hel1). Required for the upcloud backend
--state(empty)Durable state file; empty = in-memory only

Launch parameters (upcloud backend)

FlagDefaultMeaning
--template(empty)OS template storage UUID to clone at create. Required for the upcloud backend
--base-user-data(empty)File with the generic pre-binding cloud-init baked in at create (installs the on-host hook only — never the secret)
--bootstrap-hook/opt/bigfleet/bootstrapImage path that applies the delivered bootstrap blob

SSH delivery (upcloud backend)

FlagDefaultMeaning
--ssh-key(empty)SSH private key (PEM) used for Configure/Drain delivery
--ssh-pubkey(empty)Authorized public key injected into servers at create (so --ssh-key can authenticate)
--ssh-userrootSSH user for Configure/Drain delivery

Offerings & pricing

FlagDefaultMeaning
--offerings(empty)JSON offerings file (else a built-in mix sized by --seed-count)
--seed-count32Speculative slots for the default offerings
--zone-a / --zone-bfi-hel1 / de-fra1Zones for the default offerings
--eur-usd1.08EUR→USD rate applied to the pinned price table

Background, observability & TLS

FlagDefaultMeaning
--reconcile-interval2mBackground UpCloud→inventory reconcile interval (0 = off)
--metrics-addr:9090Address for /metrics, /healthz, /readyz (empty = disabled)
--reflectiontrueRegister gRPC server reflection (for grpcurl/debugging)
--tls-cert / --tls-key(empty)gRPC server certificate + key (PEM); enables TLS
--tls-ca(empty)gRPC client CA bundle (PEM); enables mTLS

mTLS

With no --tls-cert/--tls-key the provider serves insecure gRPC — fine only for trusted in-cluster traffic. For production, terminate mTLS in the provider itself:

  • --tls-cert + --tls-key enable TLS (TLS 1.3 minimum).
  • adding --tls-ca (a client CA bundle) enables mTLS: the provider then requires and verifies a client certificate on every connection.

--tls-ca without --tls-cert/--tls-key is rejected, and supplying only one of cert/key is rejected — so a half-configured TLS setup fails fast at startup rather than silently serving plaintext. The chart mounts a standard Kubernetes TLS Secret at /etc/bigfleet/tls and wires the flags for you:

tls:
enabled: true
mtls: true # mount ca.crt and require a verified client cert
secretName: bigfleet-upcloud-tls # Secret keys: tls.crt, tls.key, ca.crt

The full trust model is in Security.

Bringing it up

Terminal window
helm install bigfleet-upcloud-fi-hel1 providers/upcloud/deploy/helm \
-n bigfleet -f fi-hel1.values.yaml
kubectl -n bigfleet logs deploy/bigfleet-upcloud-fi-hel1 | grep 'serving CapacityProvider'
kubectl -n bigfleet port-forward deploy/bigfleet-upcloud-fi-hel1 9090:9090 &
curl localhost:9090/readyz # -> ready once gRPC is serving

The pod reports /readyz green only after the gRPC server is serving, so wire it to a readiness probe and let BigFleet dial the Service once the probe passes.