Install onto a single k3s node
Get Marshal running on one Linux node: fill in five values, run one apply, and open the URL. The installer brings its own Postgres and Redis on the node, so there is nothing else to set up first. It is the fastest way to evaluate Marshal, and with a managed Postgres it serves a small team well.
What you can do with it
- Evaluate on a spare VM. Install k3s on any Linux machine, point the installer at it, and claim your owner account the same day.
- Run a demo node on Google Cloud. Let the installer create a private GCE VM with k3s for you, or one with its own public address for a demo.
- Serve a small team. Keep the single node and move Postgres to a managed database for durable data and backups.
What you need
- The Prerequisites: onboarding values and local tools (Terraform 1.5 or newer, Helm 3.14 or newer, kubectl).
- A Linux node running k3s 1.27 or newer, and a kubeconfig for it. k3s ships the Traefik
ingress and the
local-pathstorage class, which is all this path needs. When the installer creates the node for you, it uses ane2-standard-4VM (4 vCPU, 16 GB) by default.
Install k3s and get a kubeconfig
curl -sfL https://get.k3s.io | sh -
# Optional, and recommended for large tool images:
# --kubelet-arg=registry-qps=0 --kubelet-arg=serialize-image-pulls=falseThe admin kubeconfig on the node is /etc/rancher/k3s/k3s.yaml. Copy it to your workstation
and change the server address:
scp node:/etc/rancher/k3s/k3s.yaml ~/.kube/marshal-k3s.yaml
perl -pi -e 's#https://127\.0\.0\.1:6443#https://<NODE-IP>:6443#' ~/.kube/marshal-k3s.yaml
export KUBECONFIG=~/.kube/marshal-k3s.yaml # or set kubeconfig_path in tfvarsInstall
Get the installer
git clone --branch v<chart_version> https://github.com/marshal-org/marshal-install.git
cd marshal-install/single-node-k3sSee Get the installer for the tag scheme.
Fill in terraform.tfvars
cp ../examples/single-node-k3s.tfvars.example terraform.tfvars
$EDITOR terraform.tfvarsFive values are required: installation_jwt, deployment_id, registry_pull_token,
chart_version and ingress_host. Everything else has a default.
No domain? Use sslip.io with the node’s IP, written with dashes:
ingress_host = "marshal.203-0-113-5.sslip.io".
Apply
terraform init
terraform applyCheck the install
terraform output next_steps # verify commands and the app URL
kubectl get pods -n marshalWhat you should see
Every pod in the marshal namespace is Running, and terraform output app_url prints your
address. HTTPS is on by default with a self-signed placeholder certificate, labeled
“Marshal Platform Temp Cert”, so your browser shows a warning until you add a real certificate.
Claim your owner account
Read the setup token
kubectl get secret marshal-app-secrets -n marshal -o jsonpath='{.data.SETUP_TOKEN}' | base64 -dThe token works only until the first owner exists.
Open /setup
Go to your address with /setup at the end, for example https://marshal.acme.com/setup.
Paste the token, enter your email and a password, and select Claim instance.
You are signed in as the owner. Next, follow Getting started as an owner to invite your team, then run your first task.
Datastores
By default the installer runs postgres:16-alpine on a local-path volume and redis:7-alpine
on the node, and connects Marshal to both. The node is fully self-contained, and Postgres has no
high availability or backups. For durable data, turn off the in-cluster pair and give the
installer both connection strings:
provision_datastores = false
database_url = "postgres://marshal:PW@10.0.0.5:5432/marshal?sslmode=require"
redis_url = "redis://10.0.0.6:6379"See Datastore options.
TLS
tls_mode decides how the ingress serves traffic:
tls_mode | Result |
|---|---|
self_signed (default) | HTTPS with a generated placeholder certificate. Browsers warn. |
inline | HTTPS with your certificate, from tls_cert_pem and tls_key_pem |
secret | HTTPS with a TLS Secret you manage, named by tls_secret_name |
none | Plain HTTP |
To use cert-manager, install it with a ClusterIssuer, set ingress_annotations (for example
{ "cert-manager.io/cluster-issuer" = "letsencrypt" }) and ingress_tls, and point the host’s
DNS A record at the node.
Images
Nodes pull directly from registry.marshal.codes with your pull token by default. To use a
mirror you run, set image_cache_registry and registry_auth_mode. See
Registry options.
Let the installer create the node
Set deploy_cluster = true with project_id, zone and admin_source_ranges, and Terraform
creates a private GCE VM with Cloud NAT and installs k3s on it. The new node’s API is private, so
the install runs in two steps:
Create the node
terraform apply -var deploy_cluster=true -var project_id=acme-prod \
-var zone=europe-west1-b -var 'admin_source_ranges=["10.8.0.0/24"]'Fetch its kubeconfig over IAP, then install
gcloud compute ssh marshal-k3s --zone europe-west1-b --tunnel-through-iap \
--command 'sudo cat /etc/rancher/k3s/k3s.yaml' > k3s.yaml
# change https://127.0.0.1:6443 to the node's internal IP
terraform apply -var deploy_cluster=false -var kubeconfig_path=./k3s.yamlterraform output next_steps prints these exact commands after the first step. Run Terraform
from inside the VPC (a bastion, VPN or IAP tunnel): the k3s API on port 6443 accepts only
admin_source_ranges.
For a demo node that serves the app from its own address, set public_ip = true. Terraform
reserves a static external IP and opens ports 80 and 443 to public_http_source_ranges (the
whole internet by default). SSH and the k3s API stay on IAP and admin_source_ranges.
terraform output k3s_external_ip prints the address for your DNS record.
Upgrades
Check out the installer tag for the new version, bump chart_version in terraform.tfvars
to match, and run terraform apply. See Day-2.