(setup-k8s-beamline)=
# Create a Kubernetes Beamline
:::{warning}
**DLS users:** beamlines and accelerators are set up through the internal
developer guide at , not these
public cluster steps. Follow along on your own test cluster only.
:::
So far the tutorials have deployed IOCs to the local podman instance on your
workstation with `docker compose`. This tutorial creates a **services
repository** that deploys into a Kubernetes cluster instead, using Helm.
By the end you will have:
- a services repo, `t02-services`, generated from
[`services-template-helm`](https://github.com/epics-containers/services-template-helm);
- the shared beamline services `t02-epics-pvcs` and `t02-epics-opis` running in
your cluster;
- the `ec` CLI configured to deploy and manage services in your namespace.
The worked example uses the domain **`t02`** (beamline **`bl02t`**) and the
namespace **`t02-beamline`** created in {any}`setup-kubernetes`. Substitute your
own names throughout.
:::{note}
A Helm/Kubernetes services repo has the same shape as the `docker compose` one
from {any}`create-beamline`: a `services/` folder with one deployable unit per
subfolder. The difference is that each unit is a **Helm chart** (a `Chart.yaml`
plus a `values.yaml`) rather than a `compose.yaml`, and `services/values.yaml`
holds the defaults shared by every chart.
:::
## Prerequisites
- A Kubernetes cluster with a namespace for your beamline.
{any}`setup-kubernetes` sets up a single-node k3s cluster plus the
`t02-beamline` namespace and context.
- A workstation with `ec`, `copier`, `git` and `kubectl` (see
{any}`setup_workstation`).
## Scaffold the services repo
Generate the repo from the template with `copier` (the flow mirrors
{any}`create-beamline`):
```bash
copier copy https://github.com/epics-containers/services-template-helm t02-services
```
Answer the prompts as follows for a local k3s cluster:
| Prompt | Worked-example answer |
|---|---|
| `domain` | `t02` |
| `description` | *(accept default — `t02 IOC Instances and Services`)* |
| `location` | `bl02t` |
| `cluster_name` | `local` *(any lower-case name for your cluster)* |
| `cluster_namespace` | `t02-beamline` |
| `git_platform` | `github.com` |
| `gateway` | `No` *(k3s uses host networking — see below)* |
| `athena_services` | *(leave blank)* |
| `logging_url` | `Skip` |
:::{note}
The template defines copier **migration scripts** that run when you later bring
the repo up to a newer template version with `copier update`. Those scripts
require the `--trust` flag, i.e. `copier update --trust`.
:::
Create the repo on GitHub () named `t02-services`, then
commit and push:
```bash
cd t02-services
git init -b main
git add .
git commit -m "initial commit"
git remote add origin https://github.com//t02-services
git push -u origin main
```
## Configure the ec CLI
`ec` wraps `helm` and `kubectl` to deploy and manage services. Install it if you
do not have it already, then source the generated `environment.sh` from inside
the repo:
```bash
# install ec if needed (see the workstation setup)
uv tool install edge-containers-cli
# from inside the t02-services directory:
source ./environment.sh
```
`environment.sh` configures `ec` for this repo by exporting:
```bash
export EC_CLI_BACKEND=K8S # deploy with Helm/kubectl
export EC_TARGET=t02-beamline # your namespace
export EC_SERVICES_REPO=https://github.com//t02-services
export EC_LOG_URL= # central log server (blank)
```
It also checks that `ec` is installed and enables shell completion. For the full
command and environment-variable reference see {any}`edge-containers-cli`.
## Deploy the shared services
Every beamline namespace needs two shared services, both generated by the
template:
- **`t02-epics-pvcs`** — persistent volumes where IOCs store autosave files,
generated GUIs and other data.
- **`t02-epics-opis`** — an nginx server that serves those GUI files.
`ec` deploys a service at a **git tag** of the repo, so tag the current state
first:
```bash
git tag 2026.7.1
git push origin 2026.7.1
```
Then deploy each service at that tag (`-v` prints the underlying helm/kubectl
commands):
```bash
ec -v deploy t02-epics-pvcs 2026.7.1
ec -v deploy t02-epics-opis 2026.7.1
```
:::{note}
On a local k3s cluster the template sets `hostNetwork: true` (in
`services/values.yaml`), so Channel Access reaches your workstation directly and
no gateway is needed. Clusters that forbid host networking — including DLS
personal namespaces — instead run a Channel Access gateway; answer **Yes** to the
`gateway` prompt to have the template generate one.
:::
## Check the deployment
List what is running in your namespace:
```bash
ec ps
```
```text
name label version ready deployed
t02-epics-pvcs service 2026.7.1 True 2026-07-01T09:10:00Z
t02-epics-opis service 2026.7.1 True 2026-07-01T09:11:00Z
```
Run `ec --help` to explore the other commands (`ec logs`, `ec exec`,
`ec monitor`, `ec stop`/`start`/`delete`).
:::{note}
When something will not start, inspect the underlying resources with
`kubectl describe pod `, or browse them in the Kubernetes dashboard (see
{any}`k8s-dashboard` for the local-cluster install).
:::
## Next steps
- {any}`add_k8s_ioc` — add your own IOC instance to this beamline.
- {any}`deploy-argocd` — drive a services repo through ArgoCD (GitOps continuous
deployment) instead of deploying by hand.
- {any}`helm` — the pure-Helm reference for what `ec deploy` runs under the hood.