Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.2-750.1697534106
# OpenAPI generation stage
FROM openapitools/openapi-generator-cli:v7.16.0 AS openapi-gen

RUN \
microdnf install -y \
util-linux \
&& \
microdnf clean all
WORKDIR /local

COPY \
hyperfleet-api \
/usr/local/bin/
# Copy OpenAPI spec
COPY openapi/openapi.yaml /local/openapi/openapi.yaml

# Generate Go client/models from OpenAPI spec
RUN bash /usr/local/bin/docker-entrypoint.sh generate \
-i /local/openapi/openapi.yaml \
-g go \
-o /local/pkg/api/openapi && \
rm -f /local/pkg/api/openapi/go.mod /local/pkg/api/openapi/go.sum && \
rm -rf /local/pkg/api/openapi/test

# Build stage
FROM golang:1.24-alpine AS builder

WORKDIR /build

# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download

# Copy source code
COPY . .

# Copy generated OpenAPI code from openapi-gen stage
COPY --from=openapi-gen /local/pkg/api/openapi ./pkg/api/openapi

# Build binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o hyperfleet-api ./cmd/hyperfleet-api

# Runtime stage
FROM gcr.io/distroless/static-debian12:nonroot

WORKDIR /app

# Copy binary from builder
COPY --from=builder /build/hyperfleet-api /app/hyperfleet-api

# Copy OpenAPI schema for validation (uses the source spec, not the generated one)
COPY --from=builder /build/openapi/openapi.yaml /app/openapi/openapi.yaml

# Set default schema path (can be overridden by Helm for provider-specific schemas)
ENV OPENAPI_SCHEMA_PATH=/app/openapi/openapi.yaml

EXPOSE 8000

ENTRYPOINT ["/usr/local/bin/hyperfleet-api", "serve"]
ENTRYPOINT ["/app/hyperfleet-api"]
CMD ["serve"]

LABEL name="hyperfleet-api" \
vendor="Red Hat" \
version="0.0.1" \
summary="HyperFleet API" \
description="HyperFleet API"
summary="HyperFleet API - Cluster Lifecycle Management Service" \
description="HyperFleet API for cluster lifecycle management"
45 changes: 45 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ version:=$(shell date +%s)
# a tool for managing containers and images, etc. You can set it as docker
container_tool ?= podman

# Image configuration
IMAGE_REGISTRY ?= quay.io/openshift-hyperfleet
IMAGE_NAME ?= hyperfleet-api
IMAGE_TAG ?= latest

# Dev image configuration - set QUAY_USER to push to personal registry
# Usage: QUAY_USER=myuser make image-dev
QUAY_USER ?=
DEV_TAG ?= dev-$(git_sha)

# Database connection details
db_name:=hyperfleet
db_host=hyperfleet-db.$(namespace)
Expand Down Expand Up @@ -53,6 +63,9 @@ help:
@echo "make generate-mocks generate mock implementations for services"
@echo "make generate-all generate all code (openapi + mocks)"
@echo "make clean delete temporary generated files"
@echo "make image build container image"
@echo "make image-push build and push container image"
@echo "make image-dev build and push to personal Quay registry"
@echo "$(fake)"
.PHONY: help

Expand Down Expand Up @@ -283,3 +296,35 @@ db/login:
db/teardown:
$(container_tool) stop psql-hyperfleet
$(container_tool) rm psql-hyperfleet

# Build container image (multi-stage build, no local binary needed)
.PHONY: image
image:
@echo "Building container image $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)..."
$(container_tool) build -t $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG) .
@echo "✅ Image built: $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)"

# Build and push container image to registry
.PHONY: image-push
image-push: image
@echo "Pushing image $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)..."
$(container_tool) push $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
@echo "✅ Image pushed: $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)"

# Build and push to personal Quay registry (requires QUAY_USER)
.PHONY: image-dev
image-dev:
ifndef QUAY_USER
@echo "❌ ERROR: QUAY_USER is not set"
@echo ""
@echo "Usage: QUAY_USER=myuser make image-dev"
@echo ""
@echo "This will build and push to: quay.io/$$QUAY_USER/$(IMAGE_NAME):$(DEV_TAG)"
@exit 1
endif
@echo "Building dev image quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG)..."
$(container_tool) build -t quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG) .
@echo "Pushing dev image..."
$(container_tool) push quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG)
@echo ""
@echo "✅ Dev image pushed: quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG)"
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,90 @@ make db/teardown # Remove PostgreSQL container
make db/login # Connect to database shell
```

## Container Image

Build and push container images using the multi-stage Dockerfile:

```bash
# Build container image
make image

# Build with custom tag
make image IMAGE_TAG=v1.0.0

# Build and push to default registry
make image-push

# Build and push to personal Quay registry (for development)
QUAY_USER=myuser make image-dev
```

Default image: `quay.io/openshift-hyperfleet/hyperfleet-api:latest`

## Kubernetes Deployment

### Using Helm Chart

The project includes a Helm chart for Kubernetes deployment with configurable PostgreSQL support.

**Development deployment (with built-in PostgreSQL):**
```bash
helm install hyperfleet-api ./charts/ \
--namespace hyperfleet-system \
--create-namespace
```

**Production deployment (with external database like GCP Cloud SQL):**
```bash
# First, create a secret with database credentials
kubectl create secret generic hyperfleet-db-external \
--namespace hyperfleet-system \
--from-literal=db.host=<your-cloudsql-ip> \
--from-literal=db.port=5432 \
--from-literal=db.name=hyperfleet \
--from-literal=db.user=hyperfleet \
--from-literal=db.password=<your-password>

# Deploy with external database
helm install hyperfleet-api ./charts/ \
--namespace hyperfleet-system \
--set database.postgresql.enabled=false \
--set database.external.enabled=true \
--set database.external.secretName=hyperfleet-db-external
```

**Custom image deployment:**
```bash
helm install hyperfleet-api ./charts/ \
--namespace hyperfleet-system \
--set image.registry=quay.io/myuser \
--set image.repository=hyperfleet-api \
--set image.tag=v1.0.0
```

**Upgrade deployment:**
```bash
helm upgrade hyperfleet-api ./charts/ --namespace hyperfleet-system
```

**Uninstall:**
```bash
helm uninstall hyperfleet-api --namespace hyperfleet-system
```

### Helm Values

| Parameter | Description | Default |
|-----------|-------------|---------|
| `image.registry` | Container registry | `quay.io/openshift-hyperfleet` |
| `image.repository` | Image repository | `hyperfleet-api` |
| `image.tag` | Image tag | `latest` |
| `database.postgresql.enabled` | Deploy built-in PostgreSQL | `true` |
| `database.external.enabled` | Use external database | `false` |
| `database.external.secretName` | Secret with db credentials | `""` |
| `auth.enableJwt` | Enable JWT authentication | `true` |
| `auth.enableAuthz` | Enable authorization | `true` |

## API Authentication

**Development mode (no auth):**
Expand Down
26 changes: 26 additions & 0 deletions charts/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# Parent directory patterns
../.git/
../../.git/
15 changes: 15 additions & 0 deletions charts/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v2
name: hyperfleet-api
description: HyperFleet API - Cluster Lifecycle Management Service
type: application
version: 1.0.0
appVersion: "1.0.0"
maintainers:
- name: HyperFleet Team
email: hyperfleet-team@redhat.com
keywords:
- hyperfleet
- api
- kubernetes
- cluster-management
home: https://github.com/openshift-hyperfleet/hyperfleet-api
63 changes: 63 additions & 0 deletions charts/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "hyperfleet-api.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "hyperfleet-api.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "hyperfleet-api.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "hyperfleet-api.labels" -}}
helm.sh/chart: {{ include "hyperfleet-api.chart" . }}
{{ include "hyperfleet-api.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "hyperfleet-api.selectorLabels" -}}
app.kubernetes.io/name: {{ include "hyperfleet-api.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: api
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "hyperfleet-api.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "hyperfleet-api.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Loading