Skip to content

Latest commit

 

History

History
518 lines (406 loc) · 18.7 KB

File metadata and controls

518 lines (406 loc) · 18.7 KB

Deployment Guide

This guide covers deploying HyperFleet API to a Kubernetes cluster via Helm chart.

For running the binary directly on your machine (development, debugging), see the Development Guide.


Prerequisites

Before deploying, ensure you have:

  • Kubernetes cluster (1.25+)
  • Helm 3 CLI
  • PostgreSQL database — either:
    • An external managed instance (Cloud SQL, RDS, Azure Database) for production, or
    • The chart's built-in PostgreSQL pod for evaluation and testing
  • Container image — a released hyperfleet-api image, a pre-built image from your registry, or build your own:
    make image \
      IMAGE_REGISTRY=quay.io/yourorg \
      IMAGE_TAG=v1.0.0
    
    podman push quay.io/yourorg/hyperfleet-api:v1.0.0

Quick Start

The fastest path to a running deployment. This uses the chart's built-in PostgreSQL and no authentication — suitable for evaluation and testing.

Three values are required (they have no usable defaults):

Value What to set Example
image.registry Container registry domain quay.io
image.repository Organization and image name openshift-hyperfleet/hyperfleet-api
image.tag Image version v1.0.0

Deploy:

helm install hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --create-namespace \
  --set image.registry=quay.io \
  --set image.repository=openshift-hyperfleet/hyperfleet-api \
  --set image.tag=v1.0.0

Verify:

kubectl get pods --namespace hyperfleet-system
kubectl port-forward svc/hyperfleet-api 8000:8000 --namespace hyperfleet-system
curl http://localhost:8000/api/hyperfleet/v1/clusters

This creates a HyperFleet API deployment, a PostgreSQL StatefulSet, and the necessary Services, ConfigMaps, and Secrets.


Production Deployment

For production, use an external managed database and store credentials in a Kubernetes Secret.

Step 1: Create database secret

kubectl create secret generic hyperfleet-db-external \
  --namespace hyperfleet-system \
  --from-literal=db.host=<your-db-host> \
  --from-literal=db.port=5432 \
  --from-literal=db.name=hyperfleet \
  --from-literal=db.user=hyperfleet \
  --from-literal=db.password=<your-password>

Step 2: Deploy with external database

helm install hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --create-namespace \
  --set image.registry=quay.io \
  --set image.repository=openshift-hyperfleet/hyperfleet-api \
  --set image.tag=v1.0.0 \
  --set database.postgresql.enabled=false \
  --set database.external.enabled=true \
  --set database.external.secretName=hyperfleet-db-external

The chart injects database credentials as environment variables using secretKeyRef — credentials are never exposed in ConfigMaps or pod specs.

How configuration flows in Kubernetes (click to expand)
┌─────────────────────────────────────────────────────────────┐
│                       Helm Chart                            │
│                                                             │
│  values.yaml                                                │
│    ├─ server.port, logging.level, etc.                      │
│    └─ database.external.secretName                          │
└──────────────────┬──────────────────────────────────────────┘
                   │
                   ├─────────────────┬────────────────────────┐
                   ▼                 ▼                        ▼
         ┌──────────────────┐ ┌─────────────┐     ┌───────────────┐
         │    ConfigMap     │ │   Secret    │     │  Deployment   │
         │                  │ │             │     │               │
         │ Non-sensitive:   │ │ Sensitive:  │     │ Env vars:     │
         │ - server.host    │ │ - db.host   │     │ - HYPERFLEET  │
         │ - server.port    │ │ - db.user   │     │   _CONFIG     │
         │ - logging.level  │ │ - db.pass   │     │ - secretKeyRef│
         └──────┬───────────┘ └──────┬──────┘     └───────┬───────┘
                │                    │                    │
                └────────────────────┴────────────────────┘
                                     │
                                     ▼
                    ┌─────────────────────────────────────┐
                    │              Pod                    │
                    │                                     │
                    │  Volume Mounts:                     │
                    │  - /etc/hyperfleet/config.yaml      │
                    │    (from ConfigMap)                 │
                    │                                     │
                    │  Environment Variables:             │
                    │  - HYPERFLEET_CONFIG=               │
                    │    /etc/hyperfleet/config.yaml      │
                    │  - HYPERFLEET_DATABASE_HOST=        │
                    │    (from Secret via secretKeyRef)   │
                    │  - HYPERFLEET_DATABASE_PASSWORD=    │
                    │    (from Secret via secretKeyRef)   │
                    └─────────────┬───────────────────────┘
                                  │
                                  ▼
                    ┌─────────────────────────────────────┐
                    │         Application                 │
                    │                                     │
                    │  1. Load config from file           │
                    │     (/etc/hyperfleet/config.yaml)   │
                    │  2. Apply environment variables     │
                    │  3. Apply CLI flags (if any)        │
                    │                                     │
                    │  Priority: Flags > Env Vars >       │
                    │    ConfigMap > Defaults             │
                    └─────────────────────────────────────┘

Configuring Authentication

JWT authentication is disabled by default in the Helm chart. To enable it, set the config.server.jwt.* properties, like so:

helm install hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --set image.registry=quay.io \
  --set image.repository=openshift-hyperfleet/hyperfleet-api \
  --set image.tag=v1.0.0 \
  --set config.server.jwt.enabled=true \
  --set config.server.jwt.issuer_url=https://your-idp.example.com/auth/realms/your-realm \
  --set config.server.jwk.cert_url=https://your-idp.example.com/auth/realms/your-realm/protocol/openid-connect/certs
Value Required when JWT enabled Description
config.server.jwt.enabled Yes Set to true
config.server.jwt.issuer_url Yes Expected JWT issuer URL for token validation
config.server.jwk.cert_url Yes (unless cert_file is set) URL to fetch JWK signing keys
config.server.jwt.audience No Expected JWT audience claim
config.server.jwt.identity_claim No JWT claim used as caller identity (default: email)

See Authentication for full reference including identity header configuration and caller identity details.


Configuring Required Adapters

Adapters are external components (validation, DNS, pull-secret, HyperShift) that report status back to HyperFleet API. The required adapter lists define which adapters must report "ready" before a resource is considered Reconciled.

By default, no adapters are required ([]). For production, configure the adapters your deployment uses:

--set 'config.adapters.required.cluster={validation,dns,pullsecret,hypershift}' \
--set 'config.adapters.required.nodepool={validation,hypershift}'

Or in a values file:

config:
  adapters:
    required:
      cluster:
        - validation
        - dns
        - pullsecret
        - hypershift
      nodepool:
        - validation
        - hypershift

Configuring Schema Validation

The API can validate cluster and nodepool spec fields against a custom OpenAPI schema on every create/update request. This is disabled by default.

Inline schema

Provide the schema content directly in your values file:

validationSchema:
  enabled: true
  content: |
    openapi: 3.0.0
    info:
      title: My Validation Schema
      version: 1.0.0
    paths: {}
    components:
      schemas:
        ClusterSpec:
          type: object
          required: [region]
          properties:
            region:
              type: string
        NodePoolSpec:
          type: object
          required: [machine_type]
          properties:
            machine_type:
              type: string

Existing ConfigMap

Reference a ConfigMap that already exists in the namespace (must contain an openapi.yaml key):

validationSchema:
  enabled: true
  existingConfigMap: my-validation-schema

When enabled, the chart creates (or references) a ConfigMap with the schema, mounts it into the container, and configures the API to validate against it. The API will fail to start if the schema is invalid.


Managing the Deployment

Upgrade

helm upgrade hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --set image.tag=v1.1.0

During upgrade, in case schema changes have occurred in the new version, a DB migration will be handled automatically. See Migration.

Uninstall

helm uninstall hyperfleet-api --namespace hyperfleet-system

Custom Values File

For repeatable deployments, create a values.yaml file:

image:
  registry: quay.io
  repository: openshift-hyperfleet/hyperfleet-api
  tag: v1.0.0

config:
  server:
    jwt:
      enabled: true
      issuer_url: https://your-idp.example.com/auth/realms/your-realm
    jwk:
      cert_url: https://your-idp.example.com/auth/realms/your-realm/protocol/openid-connect/certs

  adapters:
    required:
      cluster:
        - validation
        - dns
        - pullsecret
        - hypershift
      nodepool:
        - validation
        - hypershift

database:
  postgresql:
    enabled: false
  external:
    enabled: true
    secretName: hyperfleet-db-external

replicaCount: 3

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi
helm install hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --values values.yaml

Helm Values Reference

Parameter Description Default
image.registry Container registry CHANGE_ME (must be set)
image.repository Image repository CHANGE_ME (must be set)
image.tag Image tag "" (must be set)
image.pullPolicy Image pull policy Always
config.server.jwt.enabled Enable JWT authentication false
config.adapters.required.cluster Cluster adapters required for Reconciled state []
config.adapters.required.nodepool Nodepool adapters required for Reconciled state []
database.postgresql.enabled Enable built-in PostgreSQL true
database.external.enabled Use external database false
database.external.secretName Secret containing database credentials ""
validationSchema.enabled Enable spec validation schema false
replicaCount Number of API replicas 1
resources.limits.cpu CPU limit 500m
resources.limits.memory Memory limit 512Mi
podDisruptionBudget.enabled Enable PodDisruptionBudget false
podDisruptionBudget.minAvailable Minimum available pods during disruption 1
serviceMonitor.enabled Enable Prometheus Operator ServiceMonitor false
serviceMonitor.interval Metrics scrape interval 30s
serviceMonitor.scrapeTimeout Metrics scrape timeout 10s
serviceMonitor.labels Additional labels for Prometheus selector {}
serviceMonitor.namespace Namespace for ServiceMonitor (if different) ""

See Configuration Guide for the complete application configuration reference and charts/values.yaml for all Helm-specific settings.


Operations

Check Deployment Status

helm status hyperfleet-api --namespace hyperfleet-system
helm list --namespace hyperfleet-system
kubectl get pods --namespace hyperfleet-system
kubectl get svc --namespace hyperfleet-system

View Logs

kubectl logs -f deployment/hyperfleet-api --namespace hyperfleet-system
kubectl logs -f -l app=hyperfleet-api --namespace hyperfleet-system

# PostgreSQL logs (if using built-in)
kubectl logs -f statefulset/hyperfleet-postgresql --namespace hyperfleet-system

Troubleshooting

kubectl describe pod <pod-name> --namespace hyperfleet-system
kubectl get events --namespace hyperfleet-system --sort-by='.lastTimestamp'
kubectl exec -it deployment/hyperfleet-api --namespace hyperfleet-system -- /bin/sh
kubectl get secrets --namespace hyperfleet-system
kubectl get configmaps --namespace hyperfleet-system

Health Checks

The deployment includes:

  • Liveness probe: GET /healthz (port 8080) — returns 200 if the process is alive
  • Readiness probe: GET /readyz (port 8080) — returns 200 when ready to receive traffic, 503 during startup/shutdown
  • Metrics: GET /metrics (port 9090) — Prometheus metrics endpoint

Scaling

# Manual scaling
kubectl scale deployment hyperfleet-api --replicas=3 --namespace hyperfleet-system

# Via Helm
helm upgrade hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --set replicaCount=3

Enable autoscaling via Helm values (autoscaling.enabled=true).

Monitoring

Prometheus metrics are available at http://<service>:9090/metrics.

Prometheus Operator Integration

# Enable ServiceMonitor
helm install hyperfleet-api ./charts/ \
  --namespace hyperfleet-system \
  --set image.registry=quay.io \
  --set image.repository=openshift-hyperfleet/hyperfleet-api \
  --set image.tag=v1.0.0 \
  --set serviceMonitor.enabled=true

# With custom Prometheus selector labels
--set serviceMonitor.labels.release=prometheus

# ServiceMonitor in a different namespace
--set serviceMonitor.namespace=monitoring

Production Checklist

Before deploying to production, ensure:

  • Image: Specific version tag set (not latest or empty)
  • Database: External managed database configured (Cloud SQL, RDS, Azure Database)
  • Secrets: Database credentials stored in a Secret (not ConfigMap)
  • Authentication: JWT enabled with issuer and JWK URL configured
  • Adapters: Required adapters specified for cluster and nodepool
  • Config file permissions: Config files (--config / HYPERFLEET_CONFIG) must be operator-trusted — see below
  • Resources: CPU/memory limits and requests set
  • Replicas: Multiple replicas configured (replicaCount >= 2)
  • Disruption: PodDisruptionBudget enabled (podDisruptionBudget.enabled=true)
  • Monitoring: ServiceMonitor enabled if using Prometheus Operator

Configuration File Security

The configuration file path — set via --config or HYPERFLEET_CONFIG — is a trust boundary. The API validates configuration content on startup (unknown fields are rejected, required values are enforced, TLS/JWT/timeout settings are checked) and will refuse to start with an invalid configuration. However, path and permission safety is the operator's responsibility. The API reads whatever file the process can access at the given path without checking permissions or ownership.

Ensure configuration files are:

  • Owned by the service account running the API (e.g., root:root or a dedicated user)
  • Mode 0600 (owner read/write only) or 0640 if group-readable access is needed
  • Never world-writable

In Helm deployments, the chart mounts the configuration as a ConfigMap volume at /etc/hyperfleet/config.yaml with default Kubernetes permissions, which satisfies these requirements. This guidance applies primarily to bare-metal or VM deployments where config files are managed directly on disk.


Complete Example: GKE Deployment

# 1. Build and push image
export QUAY_USER=myuser
podman login quay.io
make image-dev

# 2. Get GKE credentials
gcloud container clusters get-credentials my-cluster \
  --zone=us-central1-a \
  --project=my-project

# 3. Create namespace
kubectl create namespace hyperfleet-system
kubectl config set-context --current --namespace=hyperfleet-system

# 4. Create database secret
kubectl create secret generic hyperfleet-db-external \
  --from-literal=db.host=10.10.10.10 \
  --from-literal=db.port=5432 \
  --from-literal=db.name=hyperfleet \
  --from-literal=db.user=hyperfleet \
  --from-literal=db.password=secretpassword

# 5. Deploy with Helm
helm install hyperfleet-api ./charts/ \
  --set image.registry=quay.io \
  --set image.repository=myuser/hyperfleet-api \
  --set image.tag=dev-abc123 \
  --set config.server.jwt.enabled=false \
  --set database.postgresql.enabled=false \
  --set database.external.enabled=true \
  --set database.external.secretName=hyperfleet-db-external \
  --set 'config.adapters.required.cluster={validation,dns,pullsecret,hypershift}' \
  --set 'config.adapters.required.nodepool={validation,hypershift}'

# 6. Verify deployment
kubectl get pods
kubectl logs -f deployment/hyperfleet-api

# 7. Access API (port-forward for testing)
kubectl port-forward svc/hyperfleet-api 8000:8000
curl http://localhost:8000/api/hyperfleet/v1/clusters

Related Documentation