Get Started
Today, you bootstrap a new modular service with
common-template-copier,
GitLab’s standard project template. It scaffolds a three-layer service with LabKit v2
already wired in, a CI pipeline built on common-ci-tasks, and the Caproni and Runway
configuration needed for local development and production deployment.
Coming soon: we are automating more of this workflow with
bench, the CLI from the LabBench project. Until that lands, the copier flow below is the paved path.
Prerequisites
| Tool | Purpose | Install |
|---|---|---|
| copier | Project template generator | pip3 install --upgrade copier |
| mise | Task runner and tool versions | curl https://mise.run | sh |
Everything else — Go, Caproni, Fairway, helm, kubectl, and the rest — is pinned
in the generated project’s .tool-versions and installed for you by
scripts/prepare-dev-env.sh, so every contributor gets the same versions.
Scaffold a new service
Run copier against the template and follow the prompts:
copier copy https://gitlab.com/gitlab-com/gl-infra/common-template-copier.git my-service --trustThe questions that matter for a modular service:
| Question | Answer |
|---|---|
project_name | Lowercase project path slug (e.g. my-service) |
gitlab_namespace | Group path without the host (e.g. gitlab-org/ops) |
initial_codeowners | Your @gitlab_username |
golang | yes |
release_platform | yes — this selects the LabKit-based three-layer service |
three_layer_go | yes (the default) — scaffold the transport/domain/store example app |
Answering golang + release_platform + three_layer_go gives you the modular
service skeleton:
my-service/
├── main.go # LabKit v2 app + httpserver bootstrap
├── internal/
│ ├── transport/ # HTTP handlers and routes
│ ├── domain/ # Business logic
│ └── store/ # Data access layer
├── .gitlab-ci.yml # CI/CD pipeline (via common-ci-tasks)
├── .runway/fairway.yaml # Fairway chart configuration
├── caproni.yaml # This project's local Kubernetes rig
├── caproni.infra.yaml # Template-owned infra fragment (cert-manager, CNPG, dev CA)
├── caproni/ # Local-dev charts, values, and README
├── .tool-versions # Pinned tool versions, installed via mise
├── .mise.toml # Local task runner
├── go.mod
└── README.mdTo see a finished, deployed example of this exact layout, lean on the Go service template exemplar — a complete Theseus service running in staging and production that you can read alongside this tutorial.
LabKit is baked in
The generated main.go bootstraps a LabKit v2 application, so every service starts with:
- Structured logging in the format GitLab’s logging pipeline expects, enriched with build metadata (version, commit, date) injected at build time
- HTTP server component with access logging, tracing, correlation IDs, panic recovery, health endpoints, and graceful shutdown handled for you
- Three-layer architecture (transport → domain → store) enforced from day one, so every service looks the same and engineers can navigate any Theseus-managed service immediately
See the LabKit page for what the library layer provides.
Set up and push
From the generated project, initialise git before running the setup script — it installs pre-commit hooks, which need the repository to exist:
cd my-service
git init --initial-branch=main
scripts/prepare-dev-env.sh # installs pinned tools via mise + git hooks
git add -A && git commit -m "Initial commit"
git remote add origin git@gitlab.com:gitlab-org/ops/my-service.git
git push --set-upstream origin mainThe service builds and its tests pass before you write a line of domain code:
mise run testThen register the project with infra-mgmt so that branch protections, approval rules, and CI/CD tokens are managed through automation.
Run locally with Caproni
The generated project pins Caproni 4 in .tool-versions and includes a
caproni/README.md walkthrough. The first-time flow:
scripts/chart-gen.sh # render chart/ from .runway/fairway.yaml via Fairway
caproni up # provision k8s, deploy GitLab + my-service
sudo caproni update-etc-hosts # wire my-service.caproni.test into /etc/hosts
scripts/build.sh linux-arm64 # build the service binary (match your host arch)
scripts/container.sh # bake the :local image the chart expectsCaproni provisions a local Kubernetes cluster and deploys your service’s
Fairway-rendered chart alongside GitLab — the same images and charts used in
production. Until container.sh has built the :local image, the service pod
sits in ImagePullBackOff; that’s expected, not a bug. Edit mode
(caproni run) then rebuilds and restarts the in-cluster process on file save.
See caproni/README.md in your project and the
Caproni docs for the full walkthrough.
Since Caproni 4.0, nothing is composed implicitly — everything the rig depends on is declared across three files:
caproni.yaml— this project’s cluster, repositories, deployers, and reloaders. Yours to edit.caproni.infra.yaml— the infrastructure fragment (cert-manager, trust-manager, CloudNativePG, the dev CA). Template-owned:copier updatekeeps it current, so don’t edit it in place.caproni.local.yaml— optional machine-specific overrides, merged last. Keep it out of version control. For example, if your existing Caproni VM is smaller than the requested size:
# caproni.local.yaml
version: 2
cluster:
colima:
memory: 8GiBDeploy to production
.runway/fairway.yaml declares your service’s chart configuration, and the CI pipeline
generated by the template handles building, signing, and releasing. Once the project is
registered with the Release Platform, deployments flow through CI without manual
intervention. See
Runway for how binding and deployment work.
Keeping your service up to date
The template is versioned. Pull in template improvements at any time with:
copier update --trust --skip-answeredYour project’s current template version is recorded in .copier-answers.yml.
See
Update your service template
for conflict handling and migrations.
What’s next
- Set up typed configuration — give your new service protobuf-defined, validated config with LabKit
v2/config - Go service template exemplar — a complete, live reference service to lean on
- bench (LabBench) — CLI automation for this workflow, coming soon
- Caproni — local Kubernetes development
- Runway — production deployment
- LabKit — standard libraries for logging, metrics, and tracing