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
90 changes: 90 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Release

# Tag-driven: the tag IS the version. Nothing in the repo pins a release version, so a release
# needs no prior bump commit -- the tag is stamped into the images, the binary (VERSION ->
# pkg/version) and dist/install.yaml below. workflow_dispatch exists to re-publish a tag whose
# first run failed halfway, without moving the tag.
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: Existing tag to publish
required: true

permissions:
contents: read

env:
CONTROLLER_IMAGE: inftyai/nebula-controller
VERSION: ${{ inputs.version || github.ref_name }}

jobs:
# Both images ship under the same tag. Their names are repeated here rather than taken from env
# because the matrix is evaluated before env exists.
images:
name: Push ${{ matrix.image }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- image: inftyai/nebula-controller
dir: .
target: docker-buildx
- image: inftyai/nebula-logship
dir: components/logship
target: docker-push
steps:
- name: Clone the code
uses: actions/checkout@v5

# PLATFORMS carries linux/arm64, which an amd64 runner can only build under emulation.
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

# VERSION is passed explicitly: its default is `git describe`, which needs the tag history
# that checkout does not fetch, and would silently stamp a bare commit instead.
- name: Build and push
working-directory: ${{ matrix.dir }}
run: make ${{ matrix.target }} IMG=${{ matrix.image }}:${{ env.VERSION }} VERSION=${{ env.VERSION }}

release:
name: Publish release
runs-on: ubuntu-latest
needs: images
permissions:
contents: write
steps:
- name: Clone the code
uses: actions/checkout@v5

# build-installer runs controller-gen and kustomize through `go install`.
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod

# Pins the released tag into the manifest, so applying it cannot drift onto a different
# image than the release it came from.
- name: Generate install manifest
run: make build-installer IMG=${{ env.CONTROLLER_IMAGE }}:${{ env.VERSION }}

# Runs after the images so a published release never points at a tag nobody can pull.
# A pre-release suffix (v0.2.0-rc.1) must not become the repo's "latest" release.
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
prerelease=""
case "$VERSION" in *-*) prerelease="--prerelease" ;; esac
gh release create "$VERSION" dist/install.yaml \
--title "$VERSION" --generate-notes $prerelease
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ components/*/bin/
# exactly the kind of thing that sneaks into a commit unnoticed.
/manager

# `make build-installer` output, the release artifact — generated, never reviewed.
/dist

# Test binary, build with `go test -c`
*.test

Expand Down
23 changes: 17 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and
# the catalog pass LoadRestrictionsNone.
KUSTOMIZE_BUILD_FLAGS ?= --load-restrictor=LoadRestrictionsNone

# render-manifests builds an overlay with the manager image pinned to IMG.
#
# `kustomize build` has no image-override flag, so pinning it means EDITING
# config/manager/kustomization.yaml, whose newTag is committed. The trap restores the file
# however the shell exits, so a local deploy leaves no stray version diff to commit by
# accident. One shell for the whole body, or the trap would fire on the first line.
KUSTOMIZATION := $(CURDIR)/config/manager/kustomization.yaml
define render-manifests
cp $(KUSTOMIZATION) $(KUSTOMIZATION).bak && \
trap 'mv $(KUSTOMIZATION).bak $(KUSTOMIZATION)' EXIT && \
(cd $(CURDIR)/config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)) && \
$(KUSTOMIZE) build $(KUSTOMIZE_BUILD_FLAGS) $(1)
endef

.PHONY: verify-catalog
verify-catalog: kustomize ## Verify the price catalog CSVs parse and the catalog ConfigMap renders.
go test ./pkg/provider/catalog/...
Expand Down Expand Up @@ -205,8 +219,7 @@ docker-buildx: buildx-builder ## Build and push docker image for the manager for
.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build $(KUSTOMIZE_BUILD_FLAGS) config/default > dist/install.yaml
$(call render-manifests,config/default) > dist/install.yaml

##@ Deployment

Expand All @@ -224,13 +237,11 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build $(KUSTOMIZE_BUILD_FLAGS) config/default | $(KUBECTL) apply -f -
$(call render-manifests,config/default) | $(KUBECTL) apply -f -

.PHONY: deploy-e2e
deploy-e2e: manifests kustomize ## Deploy for e2e: config/default plus the fake-provider env var (baked in at deploy time, not via a post-deploy rollout).
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build $(KUSTOMIZE_BUILD_FLAGS) config/e2e | $(KUBECTL) apply -f -
$(call render-manifests,config/e2e) | $(KUBECTL) apply -f -

.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
Expand Down
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,31 @@ the standard `nvidia.com/gpu` resource limit, so scheduling and provisioning rea
the same number. Do not set `nodeName` or a provider `nodeSelector` yourself — the
placement controller owns those.

## Getting started
## Quick start

```bash
# 1. Namespace and provider credentials. Create them first — the manager reads them as env
# on startup. MODAL_ENVIRONMENT is optional; see docs/deploy.md for the other providers.
kubectl create namespace nebula-system
kubectl create secret generic nebula-modal-credentials -n nebula-system \
--from-literal=MODAL_TOKEN_ID=ak-... \
--from-literal=MODAL_TOKEN_SECRET=as-...

# 2. CRDs, manager and webhook. Server-side apply, because the CRDs are too large for the
# last-applied annotation. The manager provisions its own webhook cert — no cert-manager.
kubectl apply --server-side -f https://github.com/InftyAI/Nebula/releases/download/v0.1.0/install.yaml
```

One virtual node appears per provider whose credentials are present:

```bash
kubectl get nodes -l nebula.inftyai.com/provider
```

Then define a [NodePool](#defining-a-nodepool) and [opt a workload in](#opting-a-workload-in).

See [docs](docs/README.md) for an overview of Nebula.
To build and deploy from source instead, see [docs/deploy.md](docs/deploy.md). The
[docs](docs/README.md) cover the rest.

## License

Expand Down
2 changes: 1 addition & 1 deletion config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ kind: Kustomization
images:
- name: controller
newName: inftyai/nebula-controller
newTag: latest
newTag: v0.1.0
7 changes: 5 additions & 2 deletions docs/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This guide covers building and deploying the Nebula manager to a Kubernetes
cluster, including wiring provider credentials.

- [Quick start](#quick-start)
- [From source](#from-source)
- [How credentials are handled](#how-credentials-are-handled)
- [Webhook TLS (no cert-manager)](#webhook-tls-no-cert-manager)
- [What `deploy-all` does](#what-deploy-all-does)
Expand All @@ -15,7 +15,10 @@ cluster, including wiring provider credentials.

---

## Quick start
## From source

To install a release instead of building, see the quick start in the
[README](../README.md#quick-start).

```bash
# 1. Put provider credentials in .env (secrets only — gitignored).
Expand Down
Loading