tare install
Install the complete TARS dataplane in a single command.
Synopsis
tare install <identity-file> [flags]
Description
tare install performs the full operator workflow:
- Load and validate the identity (service-account) file
- Optionally sync pinned images and the
serve-helmOCI chart to a private registry (--image-sync) - Optionally create a Kubernetes
dockerconfigjsonpull secret (--image-pull-secret-stdin) - Generate Helm values
helm upgrade --installthe TARS dataplane chart- Optionally wait for pods to be ready (
--wait)
helm and kubectl are downloaded automatically on first run into
~/.tare/tools/ and reused on subsequent runs.
By default (--ha=true, since ADR 041) the data-plane Envoy proxy +
sidecar'd ExtProc deploy with HA-safe values: HPA minReplicas: 2,
PDB minAvailable: 1, and EnvoyProxy.spec.shutdown.drainTimeout: 300s
for graceful drain of in-flight LLM streams. If the target cluster has
no metrics.k8s.io APIService (metrics-server absent), tare install
prints a non-fatal warning: the install-time floor of 2 still applies
but the HPA cannot autoscale beyond it. Pass --ha=false for
single-replica installs (lab / CI).
--serve-url is the customer-facing gateway URL for the data plane being
installed. It is optional: if omitted, the helm chart leaves
tars-config[proxy-url] unrendered and the CLI does not register a URL with
the management plane. Admins can configure the URL later via the management
plane (which fires a PROXY_URL configuration event that updates the running
data plane's tars-config).
When supplied, tare install calls the management plane's
ConfiguratorService.SetDataplaneURL before running helm upgrade --install
so the URL is persisted in system_settings.dataplane-url:<workspaceId> for
the data plane's workspace (looked up from the identity-file SA's
workspaceId). The chart then seeds tars-config[proxy-url] from
global.serveUrl at install. No TriggerUpdate is fired: the value will
be re-pushed via the standard event flow if an admin later edits it.
Usage
Basic install
tare install identity.json --serve-url https://proxy.acme.com
--serve-url sets the data plane's customer-facing gateway URL. It flows
into global.serveUrl in helm values; the controller-helm chart seeds
tars-config[proxy-url] from that value at install. (The separate
controller.config.proxyUrl value no longer exists: the controller and
worker pods read the URL from tars-config[proxy-url] at runtime, not from
a PROXY_URL env var.)
Deploys using the embedded Helm chart with defaults:
| Setting | Default |
|---|---|
| Release name | tars |
| System namespace | tars-system |
| Dataplane namespace | tars-dataplane |
| Customer | inferred from identity file |
Print Helm values
Print the generated Helm values to stdout without touching the cluster:
tare install identity.json --serve-url https://proxy.acme.com --print-helm-values
Useful for inspecting values or piping into GitOps tooling.
--dry-run is accepted as a hidden alias.
Image sync
Sync all pinned images and the serve-helm OCI chart from the source
registry to a private registry before installing:
tare install identity.json --serve-url https://proxy.acme.com \
--image-sync myregistry.example.com
- The SA JWT token is used to authenticate to the source registry.
- After the sync,
--image-registry(the Helmglobal.imageRegistry) points at the sync destination so the cluster pulls from where the images now live. - Source registry priority:
--image-registry(when--image-syncis also set) →REGISTRY_URLenv →registry.tetrate.ai(default). - The
serve-helmchart is mirrored as an OCI artifact alongside the images (e.g.myregistry.example.com/serve-helm:0.1.0-rc.4_<sha>). The tag encodes a SemVer build identifier: the+build metadata is normalized to_because OCI tags forbid+. The counter lives in the prerelease segment (rc.4,alpha.347) so versions are orderable;tare versions list --channel rcfinds the newest release candidate (ADR 048 /tetrateio/fraser#4395).tare installitself still uses the chart embedded in the CLI binary; the mirrored chart exists so downstreamhelm upgrade oci://myregistry.example.com/serve-helmworkflows succeed without reaching back toregistry.tetrate.ai. - For release-tagged
tarebuilds the chart also gets an extra tag equal to the running CLI version (e.g.myregistry.example.com/serve-helm:v1.2.3) so a downstreamhelm install --version <tare-version>resolves to the chart that shipped with that CLI. Dev / dirty builds skip the extra tag to keep the mirror free of ambiguous tags.
Sync only (no deploy), --serve-url is not required:
tare install identity.json \
--image-sync myregistry.example.com --sync-only
Mirror-to-mirror sync: pull from an existing private registry and push to a
new one in a single invocation. When paired with --image-sync,
--image-registry is interpreted as the source registry to pull from;
without --image-sync it keeps its original meaning of "set the Helm
global.imageRegistry".
tare install identity.json \
--image-registry acme.registry.example.com \
--image-sync acme1.registry.example.com \
--sync-only
Print the image list without copying, --serve-url is not required:
# Just the source references
tare install identity.json --print-images
# Source → destination pairs (requires --image-sync)
tare install identity.json \
--image-sync myregistry.example.com --print-images
Apply CRDs only
Apply the chart's CRDs to the cluster and exit before namespaces, pull
secret, and Helm install. --serve-url is not required. Useful for three
operational patterns:
- Cluster-admin handoff: a privileged operator pre-applies CRDs (which
are cluster-scoped), then a less-privileged operator runs the rest of
tare installagainst a namespace they own. - Race-free upgrades: apply CRDs first so subsequent
helm upgraderuns render against the new schema with no chicken-and-egg ordering. - Raw
helm installworkflows: operators who drive Helm directly (GitOps, Argo CD, custom CI) hand the CRD lifecycle totareand let Helm own only the workload resources.
tare install identity.json --crds-only
After the CRDs land, re-run without --crds-only (and with --serve-url)
to complete the install. --crds-only cannot be combined with
--sync-only, --image-sync, --image-pull-secret-stdin, or any
--print-* flag.
Followed by a raw helm install
If you intend to skip tare install for the workload step and run Helm
directly, you must tell Helm not to render or adopt the CRDs that tare
already applied via server-side apply. Two flags are needed:
# Step 1: apply CRDs with tare (kubectl server-side apply; no Helm ownership labels)
tare install identity.json --crds-only
# Step 2: install the workload with helm, skipping CRDs in both places they live
helm install tars oci://<registry>/serve-helm \
--version "<version>" \
-f values.yaml -n tars-system \
--skip-crds \
--set ai-gateway-crds.enabled=false
--skip-crdstells Helm to skip CRDs in the chart'scrds/directory.--set ai-gateway-crds.enabled=falsedisables theai-gateway-crdssubchart, which renders CRDs as templates (not ascrds/files) and would otherwise fail Helm's ownership-adoption check against the kubectl-applied CRDs.
Without both flags, Helm errors with:
CustomResourceDefinition "aigatewayroutes.aigateway.envoyproxy.io" ...
exists and cannot be imported into the current release: invalid ownership
metadata; label validation error: missing key "app.kubernetes.io/managed-by"
This split (tare owns CRDs, Helm owns the workload) is the
recommended pattern for GitOps and raw-Helm consumers. CRDs survive
helm uninstall tars because Helm does not manage them, so customer data
(Gateways, AIGatewayRoutes, MCPRoutes, …) is preserved.
Pull secret
Create a Kubernetes dockerconfigjson secret from credentials read on stdin:
echo "user:password" | tare install identity.json \
--serve-url https://proxy.acme.com \
--image-sync myregistry.example.com \
--image-pull-secret-stdin
- The secret is created (or updated) in both
tars-systemandtars-dataplanenamespaces. - Re-runs are idempotent (
kubectl applyunder the hood). - Default secret name:
tars-image-pull-secret. Override with--image-pull-secret-name.
To reference a pre-existing secret without creating one:
tare install identity.json --serve-url https://proxy.acme.com \
--image-pull-secret-name my-existing-secret
Full workflow
echo "user:password" | tare install identity.json \
--serve-url https://proxy.acme.com \
--image-sync myregistry.example.com \
--image-pull-secret-stdin \
--wait
With guardrails
Include llm-guard-api and envoy-dm images and enable guardrails
configuration:
echo "user:password" | tare install identity.json \
--serve-url https://proxy.acme.com \
--image-sync myregistry.example.com \
--image-pull-secret-stdin \
--enable-guardrails \
--wait
The guardrails container (llm-guard-api) requires a node with sufficient
memory and CPU. Use --guardrails-config to pin it to the right node pool:
# guardrails.yaml
# nodeSelector:
# node-type: gpu-large
#
# tolerations:
# - key: large-node
# operator: Exists
# effect: NoSchedule
echo "user:password" | tare install identity.json \
--serve-url https://proxy.acme.com \
--image-sync myregistry.example.com \
--image-pull-secret-stdin \
--enable-guardrails \
--guardrails-config guardrails.yaml \
--wait
The config file uses natural Kubernetes YAML, no escaped JSON strings:
# guardrails.yaml
nodeSelector:
node-type: gpu-large
tolerations:
- key: large-node
operator: Exists
effect: NoSchedule
# Optional: full affinity rules
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cloud.google.com/gke-nodepool
operator: In
values: [llm-guard-pool]
Pass --guardrails-config - to read the config from stdin instead of a file
(follows the kubectl/helm convention):
cat <<'EOF' | tare install identity.json \
--serve-url https://proxy.acme.com \
--enable-guardrails \
--guardrails-config - \
--wait
nodeSelector:
node-type: gpu-large
tolerations:
- key: large-node
operator: Exists
effect: NoSchedule
EOF
Note:
--guardrails-config -and--image-pull-secret-stdinboth read stdin; use a file when combining both.
Print Kubernetes resources (GitOps)
Print namespace and pull-secret manifests without touching the cluster.
--serve-url is not required:
echo "user:password" | tare install identity.json \
--image-sync myregistry.example.com \
--image-pull-secret-stdin \
--print-resources
Pipe directly into kubectl apply or commit to a GitOps repo.
Flags
Main
| Flag | Default | Description |
|---|---|---|
--serve-url <URL> | optional | Data plane gateway URL; sets global.serveUrl (which seeds tars-config[proxy-url]) and registers the URL with the management plane. Omit to defer URL configuration to the dashboard. |
--ha | true | HA-safe defaults for the data-plane Envoy proxy: HPA minReplicas: 2, PDB minAvailable: 1. Pass --ha=false for single-replica lab/CI installs. |
--drain-timeout-seconds | 300 | EnvoyProxy.spec.shutdown.drainTimeout (seconds). Maximum time Envoy waits for in-flight LLM streams to finish before SIGKILL. The Envoy Gateway controller propagates this into the data-plane Pod's terminationGracePeriodSeconds. |
--enable-guardrails | false | Include guardrails images and configuration |
--guardrails-config <file|-> | none | YAML file with Guardrails pod scheduling constraints (nodeSelector, affinity, tolerations), or - to read from stdin; requires --enable-guardrails |
--wait | false | Wait for pods ready after deploy |
Registry
| Flag | Default | Description |
|---|---|---|
--image-sync <REG> | none | Sync images and the serve-helm OCI chart to <REG> before install; sets --image-registry to <REG> after the sync (unless --image-registry was used to override the source) |
--image-pull-secret-stdin | false | Read user:password from stdin and create a pull secret |
--image-pull-secret-name <NAME> | tars-image-pull-secret | Name of the pull secret to create or reference |
--sync-only | false | Sync images then exit without deploying (requires --image-sync) |
Inspect
| Flag | Default | Description |
|---|---|---|
--print-helm-values | false | Print generated Helm values to stdout without deploying |
--print-resources | false | Print Kubernetes manifests (namespaces, pull secret) to stdout without applying |
--print-images | false | Print image list and exit (add --image-sync for src→dst pairs) |
--crds-only | false | Apply CRDs to the cluster and exit; skip namespaces, pull secret, Helm install, and wait. Incompatible with --sync-only, --image-sync, --image-pull-secret-stdin, and any --print-* flag. |
Advanced / hidden
These flags are hidden from --help but accepted for advanced use.
| Flag | Default | Description |
|---|---|---|
--dry-run | false | Alias for --print-helm-values |
--release-name | tars | Helm release name |
--system-namespace | tars-system | Kubernetes system namespace |
--dataplane-namespace | tars-dataplane | Kubernetes dataplane namespace |
--chart-path | embedded | Path or OCI/HTTP reference to Helm chart |
--chart-version | none | Chart version (required for remote/OCI charts) |
--image-registry | none | Container image registry. Without --image-sync: sets Helm global.imageRegistry. With --image-sync: source registry to pull from (push destination is --image-sync). Falls back to REGISTRY_URL env, then registry.tetrate.ai |
--image-tag | none | Image tag override |
--helm-values | none | Additional Helm values file to merge |
--deployment-mode | enterprise | enterprise or saas |
--environment | none | Environment label |
--customer | from identity | Customer label override |
--redis-type | cluster | cluster or hosted |
--rate-limiting | true | Enable rate limiting |
--timeout | 5m | Timeout for --wait |
--guardrails-node-selector | none | Node selector for Guardrails pods as key=value pairs (repeatable); prefer --guardrails-config |
--guardrails-affinity | none | Affinity rules for Guardrails pods as a JSON object; prefer --guardrails-config |
--guardrails-tolerations | none | Tolerations for Guardrails pods as a JSON array; prefer --guardrails-config |
Examples
Production deployment with private registry
# 1. Sync images (run once per release upgrade)
tare install identity.json \
--image-sync gcr.io/acme/tars \
--sync-only
# 2. Install (or upgrade)
echo "user:password" | tare install identity.json \
--serve-url https://proxy.acme.com \
--image-sync gcr.io/acme/tars \
--image-pull-secret-stdin \
--release-name acme-serve \
--wait
GitOps: generate values only
tare install identity.json \
--serve-url https://proxy.acme.com \
--image-registry gcr.io/acme/tars \
--image-pull-secret-name acme-pull-secret \
--guardrails-config guardrails.yaml \
--enable-guardrails \
--print-helm-values > helm/tars-values.yaml
Commit helm/tars-values.yaml and apply separately:
helm upgrade --install tars charts/valet/serve \
--namespace tars-system --create-namespace \
-f helm/tars-values.yaml
Preview images before syncing
tare install identity.json \
--image-sync myregistry.example.com \
--enable-guardrails \
--print-images
Output:
registry.tetrate.ai/gateway:v1.6.5 → myregistry.example.com/gateway:v1.6.5
registry.tetrate.ai/ratelimit:v1.6.5 → myregistry.example.com/ratelimit:v1.6.5
...
registry.tetrate.ai/llm-guard-api:v0.3.1 → myregistry.example.com/llm-guard-api:v0.3.1
registry.tetrate.ai/envoy-dm:v0.3.1 → myregistry.example.com/envoy-dm:v0.3.1
registry.tetrate.ai/serve-helm:0.1.0-rc.4_abcd123 → myregistry.example.com/serve-helm:0.1.0-rc.4_abcd123
Output
All progress is written to stderr; only --print-helm-values, --print-images,
and --print-resources write to stdout, making them safe to redirect:
Syncing images registry.tetrate.ai → myregistry.example.com
Copying registry.tetrate.ai/gateway:v1.6.5 → myregistry.example.com/gateway:v1.6.5
2009/11/10 23:00:00 existing blob: sha256:abc123...
...
Image sync complete.
Creating pull secret "tars-image-pull-secret" in namespace tars-system...
pull secret "tars-image-pull-secret" ok
Creating pull secret "tars-image-pull-secret" in namespace tars-dataplane...
pull secret "tars-image-pull-secret" ok
Installing TARS dataplane...
release: tars
system namespace: tars-system
dataplane namespace: tars-dataplane
Creating Kubernetes namespaces...
namespace tars-system: ok
namespace tars-dataplane: ok
Deploying with Helm...
Helm deployment complete
Installation complete.
Next steps:
kubectl get pods -n tars-system
kubectl logs -n tars-system -l app=tars
Verification
kubectl get pods -n tars-system
kubectl get pods -n tars-dataplane
kubectl logs -n tars-system -l app=tars
Management-plane event reporting
After the install completes, the CLI writes a ConfigMap labelled
tars.io/component=install-event to tars-system. The
tare-doctor CronJob (deployed with this chart) forwards that ConfigMap to
the management plane on its next tick (default: every 5 minutes) so the
workspace's deployment history reflects the new install. On a successful
forward the ConfigMap is deleted; on a 5xx / network failure it is retained
for the next tick; on a 4xx it is dropped (the same payload would re-reject).
If you install the chart without going through the tare CLI (raw helm install, ArgoCD / Flux, customer GitOps), the same dashboard row appears via
the tare-doctor reconciler which observes the helm release secret and emits an event with source: tare-doctor-poll. Operator attribution is empty on the non-CLI path
(rendered as a dash in the timeline).
Rollback and uninstall
# View history
helm history tars -n tars-system
# Rollback
helm rollback tars -n tars-system
# Uninstall
helm uninstall tars -n tars-system
kubectl delete namespace tars-system tars-dataplane
Where to go next