> ## Documentation Index
> Fetch the complete documentation index at: https://docs.neuraltrust.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# GCP — Hybrid deployment

> Complete walkthrough for deploying the NeuralTrust Data Plane on Google Kubernetes Engine with the Control Plane running on NeuralTrust SaaS. Covers cluster prep, full values overlay, ingress, certificates, GPU workers, enrollment, and verification.

This guide walks you end-to-end through a **hybrid deployment** on GKE — the Data Plane, TrustGate, and Firewall run in your cluster; the Control Plane UI, API, and Scheduler run on NeuralTrust SaaS.

If you want everything (including the UI) in your own cluster, see [GCP self-hosted](./self-hosted) instead.

## What you'll end up with

| Component                            | Location                       | Replicas (default) |
| ------------------------------------ | ------------------------------ | ------------------ |
| Data Plane API                       | Your GKE cluster               | 2                  |
| Data Plane worker                    | Your GKE cluster               | 1                  |
| Kafka Connect                        | Your GKE cluster               | 1                  |
| TrustGate admin / gateway / actions  | Your GKE cluster               | 2 each             |
| Firewall gateway + 5 workers         | Your GKE cluster               | 2 + 5              |
| ClickHouse, Kafka, PostgreSQL, Redis | Your GKE cluster (or external) | 1 each             |
| Control Plane API, UI, Scheduler     | **NeuralTrust SaaS**           | —                  |

For the full image inventory and resource baseline, see [Image catalog](../images).

## Prerequisites

| Resource                                | Recommended                                                                                                              |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| GKE version                             | 1.28+                                                                                                                    |
| CPU pool machine type                   | `e2-standard-8` (8 vCPU / 32 GiB)                                                                                        |
| Min CPU nodes                           | **≥ 4** across 3 zones (regional cluster). Drop to 3 if Firewall workers run on GPU nodes.                               |
| GPU pool *(optional, for GPU Firewall)* | `n1-standard-4` + 1 × T4 — 5 nodes (one per default Firewall worker)                                                     |
| Storage                                 | `pd-balanced` (default) or `pd-ssd` for ClickHouse                                                                       |
| Sizing baseline                         | \~20.5 vCPU / 58.5 GiB requests / 80 GiB PVC (defaults with CPU Firewall)                                                |
| DNS                                     | A control over a base domain (e.g. `platform.example.com`)                                                               |
| Image pull                              | `gcr-keys.json` from NeuralTrust                                                                                         |
| NeuralTrust tenant                      | A SaaS Control Plane tenant — request from [support@neuraltrust.ai](mailto:support@neuraltrust.ai) if you don't have one |

## Step 1 — Provision the GKE cluster

```bash theme={null}
gcloud container clusters create neuraltrust \
  --region <REGION> \
  --num-nodes 2 \
  --machine-type e2-standard-8 \
  --release-channel regular \
  --addons HorizontalPodAutoscaling,HttpLoadBalancing,GcePersistentDiskCsiDriver

gcloud container clusters get-credentials neuraltrust --region <REGION>
kubectl get nodes
```

`--num-nodes 2` is per-zone in a regional cluster → 6 worker nodes across 3 zones. This is sufficient for the hybrid CPU pool with HA. For tighter cost, move Firewall workers to a GPU pool and drop the CPU pool to `--num-nodes 1` (= 3 nodes) plus `--enable-autoscaling --min-nodes 1 --max-nodes 3`.

## Step 2 — Create the namespace and image pull secret

```bash theme={null}
kubectl create namespace neuraltrust

kubectl create secret docker-registry gcr-secret \
  --docker-server=europe-west1-docker.pkg.dev \
  --docker-username=_json_key \
  --docker-password="$(cat path/to/gcr-keys.json)" \
  --docker-email=admin@neuraltrust.ai \
  -n neuraltrust
```

## Step 3 — Write your values overlay

Save as `my-values.yaml`:

```yaml theme={null}
# Hybrid deployment on GKE
global:
  platform: "gcp"
  domain: "platform.example.com"
  storageClass: "pd-balanced"
  autoGenerateSecrets: true

# Control Plane disabled — runs on NeuralTrust SaaS
neuraltrust-control-plane:
  controlPlane:
    enabled: false
  infrastructure:
    postgresql:
      deploy: true        # for TrustGate admin metadata

# Data Plane in your cluster
neuraltrust-data-plane:
  dataPlane:
    enabled: true

# TrustGate (typical for hybrid)
trustgate:
  enabled: true
  global:
    env:
      SERVER_BASE_DOMAIN: "platform.example.com"

# Firewall in-cluster
neuraltrust-firewall:
  firewall:
    enabled: true

# Infrastructure
infrastructure:
  clickhouse:
    deploy: true
  kafka:
    deploy: true
```

<Tip>
  Most fields above are chart defaults — the only required overrides are `global.platform`, `global.domain`, and `trustgate.global.env.SERVER_BASE_DOMAIN`. Everything else is shown for clarity.
</Tip>

### External infrastructure (optional)

To use Cloud SQL, ClickHouse Cloud, or Confluent Cloud instead of in-cluster, swap in:

```yaml theme={null}
infrastructure:
  clickhouse:
    deploy: false
    external:
      host: "your-clickhouse.cloud"
      port: "8443"
      user: "neuraltrust"
      password: ""        # inject via --set or pre-created secret
      database: "neuraltrust"
  kafka:
    deploy: false
    external:
      bootstrapServers: "pkc-xxxxx.gcp.confluent.cloud:9092"

neuraltrust-control-plane:
  infrastructure:
    postgresql:
      deploy: false
  controlPlane:
    components:
      postgresql:
        secrets:
          host: "10.x.x.x"          # Cloud SQL private IP
          port: "5432"
          user: "neuraltrust"
          password: ""
          database: "neuraltrust"
```

Full external-infra reference: [Configuration scenarios › External infrastructure](../configuration#external-infrastructure-only). For ClickHouse Cloud, see the [native-port caveat](../feature-flags#required-clickhouse-cloud-caveat) before installing.

## Step 4 — Install

```bash theme={null}
helm upgrade --install neuraltrust-platform \
  oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
  --version <VERSION> \
  --namespace neuraltrust \
  -f my-values.yaml
```

Replace `<VERSION>` with a chart version from the [release list](https://github.com/NeuralTrust/neuraltrust-platform/releases).

Initial install takes 3–5 minutes. Wait for all pods to be ready:

```bash theme={null}
kubectl get pods -n neuraltrust -w
```

## Step 5 — Wire up DNS and certificates

The chart creates GCE Ingresses for each component. Get the assigned IPs:

```bash theme={null}
kubectl get ingress -n neuraltrust -o wide
```

You'll see ingresses like:

| Host                                  | Component                                                                 |
| ------------------------------------- | ------------------------------------------------------------------------- |
| `data-plane-api.platform.example.com` | Data Plane API *(needed for SaaS Control Plane to reach your Data Plane)* |
| `admin.platform.example.com`          | TrustGate admin                                                           |
| `gateway.platform.example.com`        | TrustGate proxy                                                           |
| `actions.platform.example.com`        | TrustGate actions                                                         |

Create A records in Cloud DNS pointing each host at the load balancer's IP.

### Add Managed Certificates

Once DNS resolves, add a `ManagedCertificate` and a `FrontendConfig`, then reference them from the ingress:

```yaml theme={null}
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: platform-cert
  namespace: neuraltrust
spec:
  domains:
    - data-plane-api.platform.example.com
    - admin.platform.example.com
    - gateway.platform.example.com
    - actions.platform.example.com
---
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: platform-fc
  namespace: neuraltrust
spec:
  redirectToHttps:
    enabled: true
```

Then in `my-values.yaml`:

```yaml theme={null}
neuraltrust-data-plane:
  dataPlane:
    components:
      api:
        ingress:
          annotations:
            networking.gke.io/managed-certificates: "platform-cert"
            networking.gke.io/v1beta1.FrontendConfig: "platform-fc"

trustgate:
  ingress:
    controlPlane:
      annotations:
        networking.gke.io/managed-certificates: "platform-cert"
        networking.gke.io/v1beta1.FrontendConfig: "platform-fc"
    dataPlane:
      annotations:
        networking.gke.io/managed-certificates: "platform-cert"
        networking.gke.io/v1beta1.FrontendConfig: "platform-fc"
    actions:
      annotations:
        networking.gke.io/managed-certificates: "platform-cert"
        networking.gke.io/v1beta1.FrontendConfig: "platform-fc"
```

Re-run `helm upgrade …` to apply.

## Step 6 — Enroll the Data Plane with NeuralTrust SaaS

This is the **hybrid-specific step** that connects your in-cluster Data Plane to the NeuralTrust SaaS Control Plane.

<Steps>
  <Step title="Get the Data Plane JWT secret">
    The chart auto-generated this on first install:

    ```bash theme={null}
    kubectl get secret data-plane-jwt-secret -n neuraltrust \
      -o jsonpath='{.data.DATA_PLANE_JWT_SECRET}' | base64 -d
    ```

    Save it — you'll paste it into the portal.
  </Step>

  <Step title="Open the NeuralTrust portal">
    Log in to your tenant at the URL provided by NeuralTrust (typically `https://app.neuraltrust.ai`).
  </Step>

  <Step title="Connect the Data Plane">
    Navigate to **Team Settings → Advanced → Connect Data Plane** (see [Platform › Advanced](/platform/advanced) for the full UI walkthrough).

    Provide:

    | Field              | Value                                         |
    | ------------------ | --------------------------------------------- |
    | Data Plane API URL | `https://data-plane-api.platform.example.com` |
    | Data Plane JWT     | (the secret you copied above)                 |
    | Region             | Match the region of your GKE cluster          |
  </Step>

  <Step title="Verify connectivity">
    The portal will issue a health check against your Data Plane API. On success, you'll see your data plane listed as **Connected** and dashboards start populating within a few minutes of TrustGate traffic.
  </Step>
</Steps>

## Step 7 — Send traffic through TrustGate

Point your AI applications at the TrustGate gateway URL (`https://gateway.platform.example.com`). All telemetry will flow through the local Data Plane, into ClickHouse, and surface in the NeuralTrust SaaS dashboards.

For TrustGate gateway / route / plugin configuration, see [TrustGate › Getting started](/trustgate/overview).

## Verification

```bash theme={null}
# Pods
kubectl get pods -n neuraltrust

# Ingress addresses
kubectl get ingress -n neuraltrust -o wide

# Data Plane health
curl https://data-plane-api.platform.example.com/health

# TrustGate gateway health
curl https://gateway.platform.example.com/__health
```

In the NeuralTrust portal:

* **Data Plane status**: Connected
* **TrustGate**: receiving traffic, dashboards populating
* **Firewall**: classifying prompts (if enabled and routed)

## Upgrading

```bash theme={null}
helm upgrade neuraltrust-platform \
  oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
  --version <NEW_VERSION> \
  --namespace neuraltrust \
  -f my-values.yaml
```

Auto-generated secrets and PVCs are preserved. Always check the [release notes](https://github.com/NeuralTrust/neuraltrust-platform/releases) before upgrading.

## Migration to self-hosted

To bring the Control Plane in-house later, flip one flag and upgrade:

```yaml theme={null}
neuraltrust-control-plane:
  controlPlane:
    enabled: true
```

Then add DNS for `api.platform.example.com`, `app.platform.example.com`, `scheduler.platform.example.com`. The rest of the stack keeps running unchanged — see [Self-hosted on GKE](./self-hosted) for the full picture.

## Troubleshooting

| Symptom                                   | Likely cause                                                                                            | Fix                                                                                         |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Portal says "Data Plane unreachable"      | DNS not resolved, certificate provisioning incomplete, or firewall rule blocking the SaaS Control Plane | Confirm `curl https://data-plane-api.<domain>/health` succeeds from outside your VPC        |
| `ManagedCertificate` stays `Provisioning` | DNS not yet pointing at the load balancer                                                               | Confirm `dig <host>` returns the LB IP, then wait up to 60 minutes                          |
| `ImagePullBackOff`                        | Missing or wrong `gcr-secret`                                                                           | Recreate the secret with the JSON key from NeuralTrust                                      |
| Data Plane API restarts                   | ClickHouse not reachable, Kafka not reachable                                                           | Check `kubectl logs` on the API; verify dependency pods are `Running`                       |
| TrustGate can't reach the Firewall        | Service name mismatch                                                                                   | Default is `http://firewall:80` — verify `NEURAL_TRUST_FIREWALL_URL` in `trustgate-secrets` |

For deeper troubleshooting, see [Vanilla Kubernetes troubleshooting](../kubernetes/overview#common-issues).

## Related guides

* [Self-hosted deployment on GKE](./self-hosted) — Control Plane in your cluster
* [GCP overview](./overview) — cluster prerequisites and GCP-specific defaults
* [Deployment models](../deployment-models) — hybrid vs self-hosted comparison
* [Image catalog](../images) — what runs in hybrid mode
* [Secrets management](../secrets) — auto-generation, External Secrets Operator
* [Firewall deployment](../firewall) — GPU workers on GKE
