Proof-of-Value Reference Architecture

⚠️ Gitpod Self-hosted has been replaced with Gitpod Dedicated, a self-hosted, single-tenant managed service that runs in your private cloud account but is managed by us.
Try out Gitpod Dedicated.

Status:
Alpha
Intended for: Trying out Gitpod in a representative way but with only the minimum of infrastructure required
Limitations: - Not intended for long-term, production usage
- Higher risk of data loss due to in-cluster dependencies - if you lose your cluster, you may lose your data
- Data is not carried over when moving to the Single Cluster Reference Architecture for production purposes

Overview

This reference architecture provides you with a setup where all components that are needed to operate Gitpod are deployed within the Kubernetes cluster. In contrast to a production-oriented setup, this means that the required database, object storage, well as a registry are deployed for you within the cluster. All cluster services and workspaces are deployed on a single autoscaling node group.

If you are looking for a scalable and reliable way to run Gitpod, please take a look at our Single Cluster Reference Architecture.

Cloud Provider Preparations

You need to prepare your workstation and your cloud provider (e.g. creating a project and preparing service accounts) to be able to replicate this reference architecture.

Independent of the cloud provider you are using, you need to have kubectl installed on your workstation and configured to access your cluster after creation.

Cloud provider specific instructions
  • GCP
  • AWS
  • Azure

In order to deploy Gitpod on the Google Kubernetes Engine (GKE) of the Google Cloud Platform (GCP), you need to create and configure a project for your installation. In this guide, we give you examples of how to create the needed resources by using the command line tool gcloud. To follow these examples make sure you have installed the gcloud CLI and logged in to your Google Cloud account. You can also use the GCP Console or the API instead. In that case, please refer to the linked Google docs.

First, create a GCP project and enable billing (you have to enable billing to enable GKE). You can freely choose a name for your project (hereinafter referred to as environment variable PROJECT_NAME). You also need the billing account ID (referred to as BILLING_ACCOUNT). To see available lDs, run gcloud alpha billing accounts list.

language icon language: 
bash
PROJECT_NAME=gitpod
gcloud projects create "${PROJECT_NAME}" --set-as-default

BILLING_ACCOUNT=0X0X0X-0X0X0X-0X0X0X
gcloud alpha billing projects link "${PROJECT_NAME}" \
    --billing-account "${BILLING_ACCOUNT}"

You can verify that the proper project has been set as default with this command:

language icon language: 
bash
gcloud config get-value project

After you created your project, you need to enable the following services in this project:

Services
cloudbilling.googleapis.com Google Billing API Billing is required to set up a GKE cluster.
containerregistry.googleapis.com Docker container images registry Enable this service such that Gitpod can push workspace images to that repository.
iam.googleapis.com Identity and Access Management (IAM) API To create and use service accounts for the setup.
compute.googleapis.com Google Compute Engine API The Google Compute Engine empowers to run virtual machines (VMs) for the Kubernetes cluster.
container.googleapis.com Kubernetes Engine API The Kubernetes engine is where we will deploy Gitpod to.
dns.googleapis.com Cloud DNS Cloud DNS is used in this reference architecture so set up the domain name resolution.
sqladmin.googleapis.com Cloud SQL Admin API Cloud SQL for MySQL is used as database service in this reference architecture.

Run these commands to enable the services:

language icon language: 
bash
gcloud services enable cloudbilling.googleapis.com
gcloud services enable containerregistry.googleapis.com
gcloud services enable iam.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable container.googleapis.com
gcloud services enable dns.googleapis.com
gcloud services enable sqladmin.googleapis.com

Now, you are prepared to create your Kubernetes cluster.

Kubernetes Cluster

The heart of this reference architecture is a Kubernetes cluster where all components are deployed to. This cluster has a single node pool that needs to have all of the following labels:

  • gitpod.io/workload_meta=true
  • gitpod.io/workload_ide=true
  • gitpod.io/workload_workspace_services=true
  • gitpod.io/workload_workspace_regular=true
  • gitpod.io/workload_workspace_headless=true

The following table gives an overview of the node types for the different cloud providers that are used by this reference architecture.

GCP AWS
Gitpod Node Pool n2d-standard-16 m6i.4xlarge
Cloud provider specific instructions
  • GCP
  • AWS

First, we create a service account for the cluster. The service account needs to have the following roles:

Roles
roles/logging.logWriter
roles/monitoring.metricWriter
roles/container.admin

Run the following commands to create the service account:

language icon language: 
bash
GKE_SA=gitpod-gke
GKE_SA_EMAIL="${GKE_SA}"@"${PROJECT_NAME}".iam.gserviceaccount.com
gcloud iam service-accounts create "${GKE_SA}" --display-name "${GKE_SA}"
gcloud projects add-iam-policy-binding "${PROJECT_NAME}" --member serviceAccount:"${GKE_SA_EMAIL}" --role="roles/logging.logWriter"
gcloud projects add-iam-policy-binding "${PROJECT_NAME}" --member serviceAccount:"${GKE_SA_EMAIL}" --role="roles/monitoring.metricWriter"
gcloud projects add-iam-policy-binding "${PROJECT_NAME}" --member serviceAccount:"${GKE_SA_EMAIL}" --role="roles/container.admin"

After that, we create a Kubernetes cluster.

Image Type UBUNTU_CONTAINERD
Machine Type n2d-standard-16
Cluster Version Choose latest from regular channel
Enable Autoscaling,
Autorepair,
IP Alias,
Network Policy
Disable Autoupgrade
metadata=disable-legacy-endpoints=true
Create Subnetwork gitpod-${CLUSTER_NAME}
Number of nodes 1
Min Nodes 1
Max Nodes 50
Max Pods per Node 110
Addons HorizontalPodAutoscaling,
NodeLocalDNS,
NetworkPolicy
Scopes gke-default,
https://www.googleapis.com/auth/ndev.clouddns.readwrite
Region Choose your region and zones
Node Labels gitpod.io/workload_meta=true,
gitpod.io/workload_ide=true,
gitpod.io/workload_workspace_services=true,
gitpod.io/workload_workspace_regular=true,
gitpod.io/workload_workspace_headless=true
language icon language: 
bash
CLUSTER_NAME=gitpod
REGION=us-central1-b
GKE_VERSION=1.21.12

gcloud container clusters \
    create "${CLUSTER_NAME}" \
    --disk-type="pd-ssd" \
    --disk-size="100GB" \
    --image-type="UBUNTU_CONTAINERD" \
    --machine-type="n2d-standard-16" \
    --cluster-version="${GKE_VERSION}" \
    --zone="${ZONE}" \
    --service-account "${GKE_SA_EMAIL}" \
    --num-nodes=1 \
    --no-enable-basic-auth \
    --enable-autoscaling \
    --enable-autorepair \
    --no-enable-autoupgrade \
    --enable-ip-alias \
    --enable-network-policy \
    --create-subnetwork name="gitpod-${CLUSTER_NAME}" \
    --metadata=disable-legacy-endpoints=true \
    --scopes="gke-default,https://www.googleapis.com/auth/ndev.clouddns.readwrite" \
    --node-labels="gitpod.io/workload_meta=true,gitpod.io/workload_ide=true,gitpod.io/workload_workspace_services=true,gitpod.io/workload_workspace_regular=true,gitpod.io/workload_workspace_headless=true" \
    --min-nodes=1 \
    --max-nodes=50 \
    --addons=HorizontalPodAutoscaling,NodeLocalDNS,NetworkPolicy

Now, you can connect kubectl to your newly created cluster.

language icon language: 
bash
gcloud container clusters get-credentials --zone="${ZONE}" "${CLUSTER_NAME}"

After that, you need to create cluster role bindings to allow the current user to create new RBAC rules.

language icon language: 
bash
kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole=cluster-admin \
    --user="$(gcloud config get-value core/account)"

Networking

For each Gitpod installation, you need a domain. In this guide, we use gitpod.example.com as a placeholder for your domain. Gitpod also uses different subdomains for some components as well as dynamically for the running workspaces. That’s why you need to configure your DNS server and your TLS certificates for your Gitpod domain with the following wildcards:

gitpod.example.com
*.gitpod.example.com
*.ws.gitpod.example.com

Cluster ports

The entry point for all traffic is the proxy component which has a service of type LoadBalancer that allows inbound traffic on ports 80 (HTTP) and 443 (HTTPS) as well as port 22 (SSH access to the workspaces).

SSH access is required to work with desktop IDEs, such as VS Code Desktop and JetBrains via JetBrains Gateway. To enable SSH, your load balancer needs to be capable of working with L4 protocols.

Cloud provider specific instructions
  • GCP
  • AWS
  • Azure

In this guide, we use load balancing through a standalone network endpoint group (NEG). For this, the Gitpod proxy service will get the following annotation by default:

language icon language: 
bash
cloud.google.com/neg: '{"exposed_ports": {"80":{},"443": {}}}'

For Gitpod, we support Calico as CNI only. You need to make sure that you DO NOT use GKE Dataplan V2. That means, do not add the --enable-dataplane-v2 flag during the cluster creation.

External DNS

You also need to configure your DNS server. If you have your own DNS server for your domain, make sure the domain with all wildcards points to your load balancer.

Creating a dedicated DNS zone is recommended when using cert-manager or external-dns but is not required. A pre-existing DNS zone may be used as long as the cert-manager and/or external-dns services are authorized to manage DNS records within that zone. If you are providing your own TLS certificates and will manually create A records pointing to Gitpod’s public load balancer IP addresses then creating a zone is unnecessary.

Cloud provider specific instructions
  • GCP
  • AWS
  • Azure

In this reference architecture, we use Google Cloud DNS for domain name resolution. To automatically configure Cloud DNS, we use External DNS for Kubernetes.

First, we need a service account with role roles/dns.admin. This service account is needed by cert-manager to alter the DNS settings for the DNS-01 resolution.

language icon language: 
bash
DNS_SA=gitpod-dns01-solver
DNS_SA_EMAIL="${DNS_SA}"@"${PROJECT_NAME}".iam.gserviceaccount.com
gcloud iam service-accounts create "${DNS_SA}" --display-name "${DNS_SA}"
gcloud projects add-iam-policy-binding "${PROJECT_NAME}" \
    --member serviceAccount:"${DNS_SA_EMAIL}" --role="roles/dns.admin"

Save the service account key to the file ./dns-credentials.json:

language icon language: 
bash
gcloud iam service-accounts keys create --iam-account "${DNS_SA_EMAIL}" \
    ./dns-credentials.json

After that, we create a managed zone.

language icon language: 
bash
DOMAIN=gitpod.example.com
gcloud dns managed-zones create "${CLUSTER_NAME}" \
    --dns-name "${DOMAIN}." \
    --description "Automatically managed zone by kubernetes.io/external-dns"

Now we are ready to install External DNS. Please refer to the External DNS GKE docs.

Example on how to install External DNS with helm
language icon language: 
bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm upgrade \
    --atomic \
    --cleanup-on-fail \
    --create-namespace \
    --install \
    --namespace external-dns \
    --reset-values \
    --set provider=google \
    --set google.project="${PROJECT_NAME}" \
    --set logFormat=json \
    --set google.serviceAccountSecretKey=dns-credentials.json \
    --wait \
    external-dns \
    bitnami/external-dns

Depending on what your DNS setup for your domain looks like, you most probably want to configure the nameservers for your domain. Run the following command to get a list of nameservers used by your Cloud DNS setup:

language icon language: 
bash
gcloud dns managed-zones describe ${CLUSTER_NAME} --format json | jq '.nameServers'

cert-manager

Gitpod uses TLS secure external traffic bound for Gitpod as well as identifying, authorizing, and securing internal traffic between Gitpod’s internal components. While you can provide your own TLS certificate for securing external connections to Gitpod, cert-manager is required to generate internal TLS certificates.

Refer to the cert-manager DNS01 docs for more information.

Cloud provider specific instructions
  • GCP
  • AWS
  • Azure

Example on how to install cert-manager on GCP:

language icon language: 
bash
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm upgrade \
    --atomic \
    --cleanup-on-fail \
    --create-namespace \
    --install \
    --namespace cert-manager \
    --reset-values \
    --set installCRDs=true \
    --set 'extraArgs={--dns01-recursive-nameservers-only=true,--dns01-recursive-nameservers=8.8.8.8:53\,1.1.1.1:53}' \
    --wait \
    cert-manager \
    jetstack/cert-manager

TLS certificate

In this reference architecture, we use cert-manager to also create TLS certificates for the Gitpod domain. Since we need wildcard certificates for the subdomains, you must use the DNS-01 challenge.

Using a certificate issued by Let’s Encrypt is recommended as it minimizes overhead involving TLS certificates and managing CA certificate trust, but is not required. If you already have TLS certificates for your Gitpod installation with suitable DNS names you can skip this step and use your own certificates during the installation.

Cloud provider specific instructions
  • GCP
  • AWS
  • Azure

Now, we are configuring Google Cloud DNS for the DNS-01 challenge. For this, we need to create a secret that contains the key for the DNS service account:

language icon language: 
bash
CLOUD_DNS_SECRET=clouddns-dns01-solver
kubectl create secret generic "${CLOUD_DNS_SECRET}" \
    --namespace=cert-manager \
    --from-file=key.json="./dns-credentials.json"

After that, we are telling cert-manager which service account it should use:

language icon language: 
bash
kubectl annotate serviceaccount --namespace=cert-manager cert-manager \
    --overwrite "iam.gke.io/gcp-service-account=${DNS_SA_EMAIL}"

The next step is to create an issuer. In this guide, we create a cluster issuer. Create a file issuer.yaml like this:

language icon language: 
yml
# Replace $LETSENCRYPT_EMAIL with your email and $PROJECT_NAME with your GCP project name
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
    name: gitpod-issuer
spec:
    acme:
        email: $LETSENCRYPT_EMAIL
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
            name: issuer-account-key
        solvers:
            - dns01:
                  cloudDNS:
                      project: $PROJECT_NAME

… and run:

language icon language: 
bash
kubectl apply -f issuer.yaml

Install Gitpod

Congratulations. You have set up your cluster. Now, you are ready to install Gitpod. Follow the instructions of the installation guide.

If you followed the steps to create your infrastructure of this guide, you need to use the following config settings for your Gitpod installation:

General settings
Domain name value of $DOMAIN

Keep cert-manager selected for the TLS certificates options.

TLS certificates                                                              
Self-signed TLS certificate no
cert-manager yes
Issuer name gitpod-issuer
Issuer type Select “cluster issuer”
Additional features                                                                                                                                                                                 
Allow login to your workspace via SSH (if you wish to use desktop IDEs)

Was this helpful?