Skip to main content
Version: Community Edition (1.0)

Google Cloud Kubernetes (GKE)

This page explains how to create a Kubernetes cluster using Google Cloud Kubernetes Engine (GKE) and install Semaphore Community Edition.

Overview

If this is your first time using Semaphore we suggest trying out Semaphore Cloud to see if the platform fits your needs. You can create a free trial account without a credit card and use every feature.

The self-hosted installation is recommended for users and teams familiar with Semaphore.

macOS users

There is a known issue that blocks Docker on macOS. If you have trouble running Helm and you're using macOS, check the following outstanding issue for a workaround.

Step 1 - Install dependencies

Install the following tools before starting the installation:

  • Google Cloud SDK: command line tools to create and manage your Google Cloud services
  • Certbot: to create TLS certificates for your domain

Step 2 - Set up Google project

It is recommended to create a Google Cloud Project for your Semaphore installation. Once you have created your project, take note of the Google Project ID.

Append the following lines to your configuration file. Adjust the values to match your Project ID and the zone where the Kubernetes cluster runs. We'll call this file google-config

google-config
export DOMAIN="<domain-to-install-semaphore>"
export GOOGLE_CLOUD_PROJECT_ID="<your-project-id>"
export GOOGLE_STATIC_IP_NAME="<id-for-semaphore-ip>"
export GOOGLE_CERTIFICATE_NAME="<your-tls-certificate-name>"
export GOOGLE_CLOUD_ZONE=<your-zone-id>
export GOOGLE_CLOUD_CLUSTER_NAME="<your-cluster-name>"
Important

We highly recommend installing Semaphore on a subdomain, e.g. semaphore.example.com. Installing Semaphore on your main domain is discouraged as its operation might interfere with other services running on the same domain.

For example, if your domain is example.com, consider installing Semaphore on semaphore.example.com. See the example below.

example of semaphore-config file
export DOMAIN="semaphore.example.com"
export IP_ADDRESS=1.2.3.4

Once you have modified the configuration file, you should have something like the following example:

export DOMAIN="semaphore.example.com"
export GOOGLE_CLOUD_PROJECT_ID="my-semaphore-443021"
export GOOGLE_CERTIFICATE_NAME="my-semaphore-certificates"
export GOOGLE_STATIC_IP_NAME="my-semahore-ip"
export GOOGLE_CLOUD_ZONE=us-central1-a
export GOOGLE_CLOUD_CLUSTER_NAME="my-semaphore-gke"

Load your Google config file with the following command:

Load configuration
source google-config

Authenticate with your Google Cloud account before continuing. The command opens a browser to log in to your account.

Login to GCP
gcloud auth login

Once logged in, activate to your Semaphore project on the terminal with the following commands:

Switch to your Semaphore project
gcloud config set project "${GOOGLE_CLOUD_PROJECT_ID}"

Step 3 - Reserve a public IP

Reserve a public IP address for the Kubernetes ingress with the following commands:

Reserve IP
gcloud compute addresses create "${GOOGLE_STATIC_IP_NAME}" \
--project "${GOOGLE_CLOUD_PROJECT_ID}" \
--global

Run the following command to access your assigned IP address:

Retrieve reserved IP
export IP_ADDRESS=$(gcloud compute addresses describe "${GOOGLE_STATIC_IP_NAME}" \
--project "${GOOGLE_CLOUD_PROJECT_ID}" \
--global \
--format='get(address)')
echo export IP_ADDRESS=$IP_ADDRESS >> google-config

Take note of the IP address as you'll need it later.

$ echo $IP_ADDRESS

34.25.122.100

Step 4 - Create TLS certificates

note

You may skip this section if you already have wildcard certificates, e.g. *.semaphore.example.com for the domain where you are installing Semaphore.

We can use certbot to create a free wildcard TLS certificate with the following command:

remote shell - create certificates with certbot
source google-config
mkdir -p certs
certbot certonly --manual --preferred-challenges=dns \
-d "*.${DOMAIN}" \
--register-unsafely-without-email \
--work-dir certs \
--config-dir certs \
--logs-dir certs

When you are prompted to create a DNS TXT record to verify domain ownership. For example:

Please deploy a DNS TXT record under the name:

_acme-challenge.semaphore.example.com.

with the following value:

EL545Zty7vUUvIHQRSkwxXTWsirldw91enasgB5uOHs

Create the DNS TXT record before continuing the certificate generation. Follow the instructions on the terminal.

tip

You can verify the creation of the TXT record in the Google Dig Tool. Type the challenge DNS TXT record and check if its value corresponds to the correct value.

Once done, you should get a message like this:

Successfully received certificate.
Certificate is saved at: certs/live/semaphore.example.com/fullchain.pem
Key is saved at: certs/live/semaphore.example.com/privkey.pem
This certificate expires on 2025-02-27.
These files will be updated when the certificate renews.

Check the existence of the certificate files on the following paths. You will require both files during the Semaphore installation.

  • Full chain certificate: ./certs/live/$DOMAIN/fullchain.pem
  • Private key certificate: ./certs/live/$DOMAIN/privkey.pem

You may delete the TXT record from your domain at this point. It's no longer needed.

Step 5 - Install TLS certificates

Install the TLS certificates created before using the following command:

Install certificates
gcloud compute ssl-certificates create "${GOOGLE_CERTIFICATE_NAME}" \
--certificate="certs/live/${DOMAIN}/fullchain.pem" \
--private-key="certs/live/${DOMAIN}/privkey.pem" \
--project="${GOOGLE_CLOUD_PROJECT_ID}"

Step 6 - Create DNS records

Configure your DNS by creating two A records that point to the reserved IP:

  1. Go to your domain provider's DNS settings

  2. Create root domain A record

    • Type: A
    • Name: semaphore (e.g. semaphore.example.com)
    • Value: the public IP address of your Linux machine
  3. Create a wildcard record

    • Type: A
    • Name: *.semaphore (e.g. *.semaphore.example.com)
    • Value: the public IP address of your Linux machine
  4. Wait for DNS propagation (typically a few minutes)

    You can verify the creation of the TXT record in the Online Dig Tool for:

    • semaphore.example.com
    • *.semaphore.example.com

Step 7 - Create Kubernetes Cluster

In this section, we create a 1-node cluster with the smallest machine that can run Semaphore with default parameters.

First, install the GKE plugin for the Google Cloud SDK:

Install plugins
gcloud components install gke-gcloud-auth-plugin

Next, enable the Kubernetes API for your project:

Enable Kubernetes API
gcloud services enable container.googleapis.com --project ${GOOGLE_CLOUD_PROJECT_ID}

Finally, create the cluster. You may adjust the commands if you want to create more nodes or use more powerful machines. The command might take several minutes to complete.

Create GKE instance
gcloud container clusters create "${GOOGLE_CLOUD_CLUSTER_NAME}" \
--project "${GOOGLE_CLOUD_PROJECT_ID}" \
--zone "${GOOGLE_CLOUD_ZONE}" \
--num-nodes 1 \
--machine-type e2-custom-8-16384 \
--network "default" \
--subnetwork "default" \
--enable-ip-alias \
--cluster-version latest \
--no-enable-master-authorized-networks

Once done, ensure you can access the cluster with:

kubectl get nodes

Step 8 - Install CRDs

Semaphore requires the [Emissary CRDs] to be installed on the cluster. Install the Custom Resource Definitions (CRDs) with the following commands:

Install CRDs
kubectl apply -f https://app.getambassador.io/yaml/emissary/3.9.1/emissary-crds.yaml
kubectl wait --timeout=90s --for=condition=available deployment emissary-apiext -n emissary-system

Step 9 - Install Semaphore

Sanity check that the environment is ready for the installation. The commands should not fail and return valid values:

source google-config
echo "DOMAIN=${DOMAIN}"
echo "IP_ADDRESS=${IP_ADDRESS}"
echo "GOOGLE_CERTIFICATE_NAME=${GOOGLE_CERTIFICATE_NAME}"
echo "GOOGLE_STATIC_IP_NAME=${GOOGLE_STATIC_IP_NAME}"
ls certs/live/${DOMAIN}/privkey.pem certs/live/${DOMAIN}/fullchain.pem

Run the following to install Semaphore:

Install Semaphore
helm upgrade --install --debug semaphore oci://ghcr.io/semaphoreio/semaphore \
--version v1.0.0-rc.1 \
--timeout 20m \
--set global.domain.ip=${IP_ADDRESS} \
--set global.domain.name="${DOMAIN}" \
--set ingress.staticIpName="${GOOGLE_STATIC_IP_NAME}" \
--set ingress.enabled=true \
--set ingress.ssl.enabled=true \
--set ingress.ssl.certName="${GOOGLE_CERTIFICATE_NAME}" \
--set ingress.ssl.type="google"

Once the installation is done, you the following command should appear in the terminal:

=============================================================================================
Congratulations, Semaphore has been installed successfully!

To start using the app, go to https://id.semaphore.example.com/login

You can fetch credentials for the login by running this command:

echo "Email: $(kubectl get secret user-creds -n default -o jsonpath='{.data.email}' | base64 -d)"; echo "Password: $(kubectl get secret user-creds -n default -o jsonpath='{.data.password}' | base64 -d)"
=============================================================================================

Execute the shown command to retrieve the login credentials.

remote shell - get login credentials
$ echo "Email: $(kubectl get secret user-creds -n default -o jsonpath='{.data.email}' | base64 -d)"; echo "Password: $(kubectl get secret user-creds -n default -o jsonpath='{.data.password}' | base64 -d)"

Email: root@example.com
Password: AhGg_2v6uHuy7hqvNmeLw0O4RqI=
API Token: nQjnaPKQvW6TqXtpTNSx

Verify installation

You can check that for possible installation issues by following these steps:

  1. Ensure all pods are running. All pods should be in Running state with READY status showing all containers ready (e.g., 2/2).

    kubectl get pods
  2. Verify ingress configuration. The ingress should show the IP address you configured and no error messages.

    kubectl get ingress semaphore
  3. Verify SSL certificate. The certificate should be in ACTIVE state.

    gcloud compute ssl-certificates describe "${GOOGLE_CERTIFICATE_NAME}"

Step 10 - First login

note

On new installations, the system may take up to 30 minutes to finish all setup tasks. If you cannot login right away, wait a few minutes and try again.

Open a browser and navigate to the domain to id.<your-domain>/login. For example: id.example.com/login

Fill in the username and password obtained at the end of step 7.

Log in screen for Semaphore

Once logged in, select the Semaphore organization to continue.

Select your organization screen

You should be greeted with the onboarding guide.

Onboarding guide screen

Post installation tasks

Once your have Semaphore up and running, check out the following pages to finish setting up:

  • Connect with GitHub: connect your instance with GitHub to access your repositories
  • Invite users: invite users to your instance so they can start working on projects
  • Guided tour: complete the guided tour to get familiarized with Semaphore Community Edition
  • Add self-hosted agents: add more machines to scale up the capacity of your CI/CD platform

How to Uninstall Semaphore from GKE

If you want to completely uninstall Semaphore, follow these steps.

danger

If you uninstall Semaphore you will lose access to all your projects, workflows and logs. You cannot undo this action.

First, uninstall Semaphore with the following command:

Uninstall Semaphore
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
helm uninstall semaphore

Delete the persistent volume claims:

kubectl delete pvc \
minio-artifacts-storage-minio-artifacts-0 \
minio-cache-storage-minio-cache-0 \
minio-logs-storage-minio-logs-0 \
postgres-storage-postgres-0 \
rabbitmq-storage-rabbitmq-0 \
redis-data-redis-0

Next, release the IP address and remove the TLS certificate:

source google-config
gcloud compute addresses delete "${GOOGLE_STATIC_IP_NAME}" --global
gcloud compute ssl-certificates delete "${GOOGLE_CERTIFICATE_NAME}"

Finally, if you are no longer using the Kubernetes cluster, you may delete it with the following command. This completely destroys the Kubernetes cluster with any other things you might be running there.

source google-config
gcloud container clusters delete --zone "${GOOGLE_CLOUD_ZONE}" "${GOOGLE_CLOUD_CLUSTER_NAME}"

See also