Skip to content

Bootstrap coder-k8s repository scaffolding#1

Merged
ThomasK33 merged 1 commit into
mainfrom
k8s-bootstrap-vcs3
Feb 9, 2026
Merged

Bootstrap coder-k8s repository scaffolding#1
ThomasK33 merged 1 commit into
mainfrom
k8s-bootstrap-vcs3

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Bootstrap the repository with an initial Go/Kubernetes-oriented scaffold.

Summary

  • initialize github.com/coder/coder-k8s as a Go module with a minimal executable and unit test
  • add a vendoring-first Makefile workflow (vendor, test, build, verify-vendor, codegen)
  • add Nix flake dev shell and direnv integration
  • add Goreleaser config + release Dockerfile for binary and GHCR image publishing
  • add GitHub Actions workflows for PR CI and release publishing
  • bootstrap baseline Kubernetes dependencies and commit vendored modules for future operator/API work

Validation

  • make test
  • make build
  • make verify-vendor
  • goreleaser check

📋 Implementation Plan

Plan: Bootstrap github.com/coder/coder-k8s

Context / Why

You want a clean bootstrap for a single Go module that can later host three major pieces in one repo: a Kubernetes Operator, an aggregated API server, and an MCP server. The immediate goal is to establish a reproducible dev environment, CI/CD, and a minimal executable/testable baseline without Kubebuilder/Operator SDK.

This plan focuses on creating the smallest viable foundation that compiles, tests in CI, vendors dependencies, and produces release assets (binary + container image) via Goreleaser.

Evidence

  • Repository root currently contains only:
    • README.md
    • .git worktree pointer file
  • README.md currently has only:
    • # coder-k8s

Why this is sufficient: there is no existing Go/Nix/CI scaffold to preserve, so we can define the bootstrap structure directly.

Implementation details

1) Initialize module + minimal app that compiles and is testable

Create a single module with one go mod init and minimal source layout.

Files to add/edit

  • go.mod (created via go mod init github.com/coder/coder-k8s)
  • main.go
  • main_test.go

Shape of code

package main

import "fmt"

func helloMessage() string {
	return "hello world"
}

func main() {
	fmt.Println(helloMessage())
}
package main

import "testing"

func TestHelloMessage(t *testing.T) {
	t.Helper()
	if got, want := helloMessage(), "hello world"; got != want {
		t.Fatalf("unexpected hello message: got %q want %q", got, want)
	}
}

Notes:

  • Keep the first milestone intentionally small; the test avoids flaky stdout capture and still validates behavior.

2) Configure vendoring-first Go workflow (including future K8s codegen path)

Set project defaults and task automation around vendored deps and non-Kubebuilder code generation.

Files to add/edit

  • Makefile (chosen over Justfile for zero extra tool dependency)
  • .gitignore

Make targets

  • vendor/.modules.stamp: file target that depends on go.mod (and go.sum) and runs go mod tidy && go mod vendor
  • vendor: convenience target that depends on the stamp
  • test: depends on the stamp, then runs GOFLAGS=-mod=vendor go test ./...
  • build: depends on the stamp, then runs GOFLAGS=-mod=vendor go build ./...
  • verify-vendor: rerun tidy/vendor and fail on dirty tree
  • codegen: wrapper target for vendor-based Kubernetes code-generator scripts (placeholder args now, ready for real API groups later)

This guarantees go mod tidy and go mod vendor are automatically re-run when go.mod changes (and also when go.sum changes).

Shape of Makefile core

GOFLAGS ?= -mod=vendor
VENDOR_STAMP := vendor/.modules.stamp

.PHONY: vendor test build verify-vendor codegen

$(VENDOR_STAMP): go.mod go.sum
	go mod tidy
	go mod vendor
	@touch $(VENDOR_STAMP)

vendor: $(VENDOR_STAMP)

test: $(VENDOR_STAMP)
	GOFLAGS=$(GOFLAGS) go test ./...

build: $(VENDOR_STAMP)
	GOFLAGS=$(GOFLAGS) go build ./...

verify-vendor:
	go mod tidy
	go mod vendor
	git diff --exit-code -- go.mod go.sum vendor/

codegen: $(VENDOR_STAMP)
	@echo "Run k8s.io/code-generator scripts from ./vendor once API packages exist"

Notes:

  • This aligns with your requirement to use plain controller-runtime / client-go and vendor-hosted scripts rather than Kubebuilder/Operator SDK scaffolding.
  • Later, once API packages are present, codegen will call scripts like generate-groups.sh from ./vendor/k8s.io/code-generator/....

3) Add Nix flake dev shell + direnv integration

Create a reproducible dev environment and auto-activation via nix-direnv.

Files to add/edit

  • flake.nix
  • .envrc

Dev shell contents (minimum)

  • Go toolchain
  • gnumake
  • git
  • goreleaser
  • optional helpers (golangci-lint, docker, kubectl) can be added later as needs become concrete

Shape of .envrc

use flake

Shape of flake.nix (core, cross-platform via supportedSystems)

{
  description = "coder-k8s development environment";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

  outputs = { self, nixpkgs }:
    let
      supportedSystems = [
        "x86_64-linux"
        "aarch64-linux"
        "x86_64-darwin"
        "aarch64-darwin"
      ];
      forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
    in {
      devShells = forAllSystems (system:
        let
          pkgs = import nixpkgs { inherit system; };
        in {
          default = pkgs.mkShell {
            packages = with pkgs; [ go gnumake git goreleaser ];
          };
        }
      );
    };
}

4) Add Goreleaser config for binary + OCI image

Define release packaging once, and let GitHub Actions invoke it.

Files to add/edit

  • .goreleaser.yaml
  • Dockerfile.goreleaser (minimal runtime image recipe)

Key config points

  • Build Linux binary(ies) from module root
  • Archive artifacts and upload to GitHub release
  • Build/push image to ghcr.io/coder/coder-k8s
  • Tag image with {{ .Version }} to match release version

Shape of goreleaser docker section

dockers:
  - image_templates:
      - "ghcr.io/coder/coder-k8s:{{ .Version }}"
    dockerfile: Dockerfile.goreleaser
    use: buildx

5) Add CI workflow for PR validation

Run minimal but meaningful checks on every pull request.

Files to add/edit

  • .github/workflows/ci.yaml

Workflow behavior

  • Trigger: pull_request
  • Steps:
    • checkout
    • setup Go
    • run go mod tidy, go mod vendor, and fail if diff exists
    • run go test ./...
    • run go build ./...

This ensures the hello-world baseline remains compilable/tested and vendoring is enforced.

6) Add release workflow for Goreleaser publish

Run Goreleaser when a GitHub release is created and publish both binary artifacts and container image.

Files to add/edit

  • .github/workflows/release.yaml

Workflow behavior

  • Trigger: release with types: [created]
  • Permissions: contents: write, packages: write
  • Steps:
    • checkout with full history (fetch-depth: 0)
    • setup Go
    • setup Docker Buildx
    • login to GHCR using ${{ secrets.GITHUB_TOKEN }}
    • run Goreleaser action (goreleaser/goreleaser-action) with release --clean

Core image destination

  • ghcr.io/coder/coder-k8s:<release version>

7) Initial dependency bootstrap to support future Operator/API work

Add (and vendor) baseline dependencies so future work can proceed without toolchain rework.

Commands/tasks to run during implementation

  • go get sigs.k8s.io/controller-runtime
  • go get k8s.io/client-go
  • go get k8s.io/apimachinery
  • go get k8s.io/code-generator
  • make vendor

This keeps the bootstrap aligned with your explicit non-Kubebuilder direction and prepares vendor-based codegen scripts.

Validation checklist (implementation phase)

  • go test ./... passes locally
  • go build ./... succeeds
  • go mod vendor succeeds and vendor/ is committed
  • goreleaser check passes
  • act/dry-run equivalent optional for workflow sanity (if available)
Why Makefile (not Justfile) in this bootstrap

make is typically already available (and will be provided in the Nix shell), so it reduces initial tooling friction. If you later want nicer ergonomics, converting targets to just is straightforward once task surface area grows.


Generated with mux • Model: openai:gpt-5.3-codex • Thinking: xhigh

Add initial Go module/app, vendoring workflow, Nix dev shell, Goreleaser config, GitHub Actions CI/release workflows, and vendored Kubernetes bootstrap dependencies.\n\n---\n_Generated with [`mux`](https://github.com/coder/mux) • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh`_
@ThomasK33 ThomasK33 merged commit 3574aac into main Feb 9, 2026
1 check passed
@ThomasK33

Copy link
Copy Markdown
Member Author

@ThomasK33 ThomasK33 deleted the k8s-bootstrap-vcs3 branch February 9, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant