# GCP Self Hosting (GKE)

This section explains how to setup and create resources for self-hosting Zerve on a pre-existing GKE cluster in a Google Cloud Platform project.

***

## General Infrastructure

At this time, GCP Self-Hosting is possible only with an existing GKE cluster.

<figure><img src="/files/5amLDSQzpPOel857862N" alt=""><figcaption></figcaption></figure>

### GCS Bucket

Zerves requires block storage in order to store block state and user files.  We recommend creating a bucket for this purpose using the installation steps below.

### Artifact Registry

Zerve needs a repository in the [Artifact Registry](https://cloud.google.com/artifact-registry) to store Docker images.

### IAM Identities

**Application Service Account**

An identity that represents Zerve application in your GCP project.

Zerve will use [Service Account Impersonation](https://cloud.google.com/iam/docs/service-account-impersonation) to obtain short-lived credentials to perform operations within your GCP project, such as scheduling compute jobs or managing canvas storage.

**Execution Service Account**

An identity for compute jobs that Zerve schedules to execute code blocks.

This service account can be used to grant users' code blocks access to other GCP resources in your organization.

**Build Service Account**

An identity for build jobs.

This service account will be used to grant build jobs access to the GCS bucket and docker repository.

### Google Kubernetes Engine

Zerve can use your existing GKE cluster to schedule build and compute jobs. This cluster does not have to be in the same project with the rest of Zerve's infrastructure.

Cluster requirements:

* Version 1.28 or higher.
* Enabled [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
* DNS-based control plane endpoint

***

### Setup Instructions

#### Cloud infrastructure

You can use `gcloud` CLI to provision the necessary infrastructure. You can do it in a separate GCP project within your organization.

Set some common env vars, used throughout the guide:&#x20;

<pre class="language-sh"><code class="lang-sh"><a data-footnote-ref href="#user-content-fn-1">export PROJECT_ID=</a>
<a data-footnote-ref href="#user-content-fn-2">export ZERVE_ORG_ID=</a>
<a data-footnote-ref href="#user-content-fn-3">export REGION=europe-west2</a>
export BUCKET_NAME="zerve-$ZERVE_ORG_ID"
</code></pre>

If using [GKE](#google-kubernetes-engine) for compute, set env vars for the project ID and node identity of the GKE cluster:

```bash
export COMPUTE_PROJECT_ID=
export COMPUTE_NODES_SA=
```

Point your `gcloud` CLI to the [general infrastructure](#general-infrastructure) project:

```bash
gcloud config set project "$PROJECT_ID"
```

Set up [service accounts](#iam-identities):

```bash
gcloud iam service-accounts create zerve-app-sa --display-name "Zerve application service account"
```

```bash
gcloud iam service-accounts create zerve-execution-sa --display-name "Zerve execution service account"
```

```bash
gcloud iam service-accounts create zerve-build-sa --display-name "Zerve build service account"
```

```bash
gcloud iam service-accounts add-iam-policy-binding "zerve-app-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --member "serviceAccount:zerve-sa@zerve-14458.iam.gserviceaccount.com" \
  --role roles/iam.serviceAccountTokenCreator
```

Set up the [bucket](#gcs-bucket):

```bash
gcloud storage buckets create "gs://$BUCKET_NAME" \
  --location "$REGION" \
  --public-access-prevention \
  --uniform-bucket-level-access \
  --enable-hierarchical-namespace
```

```bash
gcloud storage buckets update "gs://$BUCKET_NAME" --cors-file /dev/stdin <<- EOF
    [
      {
        "origin": ["https://app.zerve.ai"],
        "responseHeader": ["*"],
        "method": ["GET", "PUT", "POST"],
        "maxAgeSeconds": 3600
      }
    ]
EOF
```

```bash
gcloud storage buckets add-iam-policy-binding "gs://$BUCKET_NAME" \
  --member "serviceAccount:zerve-app-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/storage.objectAdmin"
```

```bash
gcloud storage managed-folders create "gs://$BUCKET_NAME/build"
```

```bash
gcloud storage managed-folders add-iam-policy-binding "gs://$BUCKET_NAME/build" \
  --member "serviceAccount:zerve-build-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role roles/storage.objectViewer
```

```bash
gcloud storage managed-folders create "gs://$BUCKET_NAME/canvases"
```

```bash
gcloud storage managed-folders add-iam-policy-binding "gs://$BUCKET_NAME/canvases" \
  --member "serviceAccount:zerve-execution-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role roles/storage.objectAdmin
```

Set up the [docker repository](#artifact-registry):

```bash
gcloud artifacts repositories create zerve \
  --location "$REGION" \
  --repository-format docker \
  --mode standard-repository
```

```bash
gcloud artifacts repositories add-iam-policy-binding zerve \
  --location "$REGION" \
  --member "serviceAccount:zerve-build-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/artifactregistry.repoAdmin"
```

Setup logging permissions:

```bash
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member "serviceAccount:zerve-execution-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/logging.logWriter"
```

```bash
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member "serviceAccount:zerve-build-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/logging.logWriter"
```

```bash
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member "serviceAccount:zerve-app-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/logging.viewer"
```

If using [GKE](#google-kubernetes-engine) for compute:

* Allow k8s service accounts to impersonate Zerve's [IAM service accounts](#iam-identities):

  ```bash
  gcloud iam service-accounts add-iam-policy-binding "zerve-execution-sa@$PROJECT_ID.iam.gserviceaccount.com" \
    --member "serviceAccount:$COMPUTE_PROJECT_ID.svc.id.goog[zerve/executor]" \
    --role roles/iam.workloadIdentityUser
  ```

  ```bash
  gcloud iam service-accounts add-iam-policy-binding "zerve-build-sa@$PROJECT_ID.iam.gserviceaccount.com" \
    --member "serviceAccount:$COMPUTE_PROJECT_ID.svc.id.goog[zerve/builder]" \
    --role roles/iam.workloadIdentityUser
  ```

* Allow k8s nodes to pull images from the [docker repository](#artifact-registry):

  ```bash
  gcloud artifacts repositories add-iam-policy-binding zerve \
    --location "$REGION" \
    --member "serviceAccount:$COMPUTE_NODES_SA" \
    --role "roles/artifactregistry.reader"
  ```

* Allow Zerve to connect to your EKS cluster:

  ```bash
  gcloud iam roles create ClustersConnect \
    --project "$COMPUTE_PROJECT_ID" \
    --title "Clusters connect role" \
    --description "Allow connecting to clusters" \
    --permissions "container.clusters.connect"
  ```

  ```bash
  gcloud projects add-iam-policy-binding "$COMPUTE_PROJECT_ID" \
    --member "serviceAccount:zerve-app-sa@$PROJECT_ID.iam.gserviceaccount.com" \
    --role "projects/$COMPUTE_PROJECT_ID/roles/ClustersConnect"
  ```

* Setup RBAC in your cluster by installing our helm chart:

  ```bash
  cat <<- EOF > /tmp/values.yaml
    builder:
      # Associate "builder" k8s SA with the corresponding IAM SA
      serviceAccount:
        annotations:
          iam.gke.io/gcp-service-account: zerve-build-sa@$PROJECT_ID.iam.gserviceaccount.com
    executor:
      # Associate "executor" k8s SA with the corresponding IAM SA
      serviceAccount:
        annotations:
          iam.gke.io/gcp-service-account: zerve-execution-sa@$PROJECT_ID.iam.gserviceaccount.com
    scheduler:
      # Grant Zerve application full access to the namespace
      user:
        enabled: true
        name: zerve-app-sa@$PROJECT_ID.iam.gserviceaccount.com
        
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: admin
  EOF
  ```

  ```bash
  helm install zerve oci://public.ecr.aws/x8w6c8k3/helm/zerve -n zerve -f /tmp/values.yaml --create-namespace
  ```

***

#### Zerve Organization Self-Hosting Settings

Navigate to your organization's self-hosting settings in Zerve app.

Fill out the form with the following values:

* **Project ID**: the project ID where Zerve's [general infrastructure](#general-infrastructure) resides, e.g. `flying-banana-412312-r9`.
* **Region**: the region where Zerve's [general infrastructure](#general-infrastructure) resides, e.g. `europe-west2`
* **Bucket Name**: the name of the [GCS bucket](#gcs-bucket) , e.g. `zerve`.
* **Service Account**: the email of the [application service account](#iam-identities), e.g. `zerve-app-sa@flying-banana-412312-r9.iam.gserviceaccount.com`.
* **Docker Repository**: the address of the [docker repository](#artifact-registry), e.g. `europe-west2-docker.pkg.dev/flying-banana-412312-r9/zerve`.

If using [GKE](#google-kubernetes-engine) for compute, check the `Kubernetes` box under `Compute options` and fill out the following values:

* **Namespace**: the namespace where Zerve's [helm chart](#google-kubernetes-engine) was installed, e.g. `zerve`.
* **Endpoint**: DNS-based control plane endpoint of the GKE cluster, e.g. `https://gke-723981544496.europe-west2.gke.goog`
  * To find it using `gcloud` CLI, run the following command:

    ```bash
    gcloud container clusters describe CLUSTER_NAME \
      --location "$REGION" \
      --format 'value(controlPlaneEndpointsConfig.dnsEndpointConfig.endpoint)'
    ```
* **Service Account Token**: leave empty
* **Certificate Authority Data**: leave empty

[^1]: GCP project ID

[^2]: ID of your organization in Zerve app

[^3]: Region for GCS bucket and docker repo. For best performance, use the region of your GKE cluster


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.zerve.ai/guide/integrations/cloud/gcp-self-hosting-gke.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
