GCP Cloud Workstations provides number of pre-configured base images that include most of the common tools. You can extend these base images, or you can crete a custom image that has the minimal configuration for your specific use-case, and nothing else.
This repo demonstrates how to create and use an optimized image for Go development in VS Code, with automatic Cloud Workstations configuration update. You can add your own tools in Dockerfile, or provide additional user-specific options for new users in setup for things like VS Code default settings and git configuration. This pipeline includes new image build and workstation configuration update with that image.
For brevity, these setup will skip the details for common steps, the assumption is you already are familiar with Cloud Build builds and Cloud Workstation configuration. A Terraform setup is coming soon for more automated deployment process.
export PROJECT_ID="proj-demo" # GCP project ID
export REGION="us-west1" # GCP region where you want to run the scans
export AR_REPO="ws-images" # Artifact Registry name (us-west1-docker.pkg.dev/$PROJECT_ID/ws-images)
export WS_NAME="demo" # Cloud Workstations prefix (helpful with multiple workstations)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')Next, create a service account which will be used to run the workstation:
gcloud iam service-accounts create workstation-runnerExport accounts:
export RUNNER_SA="workstation-runner@$PROJECT_ID.iam.gserviceaccount.com"
export BUILDER_SA="$PROJECT_NUMBER@cloudbuild.gserviceaccount.com"
export COMPUTE_SA="$PROJECT_NUMBER[email protected]"At minimum, the runner account has to have these roles. Depending on what you will do with this workstation, you may want to add additional roles.
Complete list of rights included in each one these roles is available here
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$RUNNER_SA" \
--role="roles/workstations.workstationCreator" \
--condition=None
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$RUNNER_SA" \
--role="roles/workstations.operationViewer" \
--condition=None
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$RUNNER_SA" \
--role="roles/artifactregistry.reader" \
--condition=None
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$BUILDER_SA" \
--role="roles/workstations.admin" \
--condition=None
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$COMPUTE_SA" \
--role="roles/workstations.admin" \
--condition=NoneCreate Artifact Registry repository:
gcloud artifacts repositories create $AR_REPO \
--location=$REGION \
--repository-format=dockerCreate a VPC network and subnet for the workstation cluster:
# Create VPC network
gcloud compute networks create $WS_NAME-network \
--project=$PROJECT_ID \
--subnet-mode=custom \
--bgp-routing-mode=regional
# Create subnet in the specified region
gcloud compute networks subnets create $WS_NAME-subnet \
--project=$PROJECT_ID \
--region=$REGION \
--network=$WS_NAME-network \
--range=10.0.0.0/24Export the network and subnet names for use in subsequent commands:
export NETWORK="$WS_NAME-network"
export SUBNET="$WS_NAME-subnet"Cloud Workstations automatically creates the necessary firewall rules for the control plane.
Create a workstation cluster in the network you just created:
More info on the parameters available in this command here
gcloud workstations clusters create $WS_NAME-cluster \
--project=$PROJECT_ID \
--region=$REGION \
--network="projects/$PROJECT_ID/global/networks/$NETWORK" \
--subnetwork="projects/$PROJECT_ID/regions/$REGION/subnetworks/$SUBNET" \
--asyncYou only have to run this once, but this process can take as much as 20 min. Use the describe command to check on its status:
gcloud workstations clusters describe $WS_NAME-cluster \
--project=$PROJECT_ID \
--region=$REGIONThe presence of "reconciling": true indicates that the cluster is still being provisioned. When complete, the response of the above command will look something like this (notice network is now populated):
{
"createTime": "2023-04-08T22:34:52.290190289Z",
"name": "projects/my-project/locations/us-west1/workstationClusters/dev-cluster",
"network": "projects/project/global/networks/default",
"subnetwork": "projects/project/regions/us-west1/subnetworks/default",
"updateTime": "2023-04-08T22:49:16.878931635Z"
}Once the cluster is configured and the above describe command returns confirmation with network information, create the workstation configuration with a base image. This initial configuration will be updated later by the Cloud Build pipeline.
We're using the official Code OSS base image from Google as a starting point. The Cloud Build pipeline will update this configuration with your custom image after the build completes.
Note: If you encounter an
enableAuditAgenterror with the stablegcloudcommand, update your gcloud CLI:gcloud components update
gcloud workstations configs create $WS_NAME-config \
--project=$PROJECT_ID \
--region=$REGION \
--cluster=$WS_NAME-cluster \
--container-custom-image=us-central1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest \
--service-account=$RUNNER_SA \
--machine-type=n2-standard-8 \
--pd-disk-type=pd-ssd \
--pd-disk-size=200 \
--idle-timeout=3600 \
--running-timeout=43200Timeout settings: workstation stops after 1 hour of inactivity (
idle-timeout=3600), but can run for up to 12 hours (running-timeout=43200) with active use (maximum allowed).
Now build and deploy your custom image. The Cloud Build pipeline will automatically update the workstation configuration created above.
gcloud builds submit \
--region=$REGION \
--substitutions=_REGION=$REGION,_REPO=$AR_REPO,_CLUSTER=$WS_NAME-cluster,_CONFIG=$WS_NAME-configAfter the build completes, the workstation configuration will be updated with your custom image.
With the cluster and configuration created, create the actual workstation:
gcloud workstations create $WS_NAME-workstation \
--project=$PROJECT_ID \
--region=$REGION \
--cluster=$WS_NAME-cluster \
--config=$WS_NAME-configYou can now start and launch your workstation:
open https://console.cloud.google.com/workstations/list?project=$PROJECT_IDThe workstation image includes setup scripts in /setup/ to help configure your personal development environment:
To configure Git with your GitHub credentials and set up SSH keys:
/setup/git -u <github-username> -e <email>This script will:
- Configure Git with your username and email
- Set nano as the default Git editor
- Generate an ED25519 SSH key
- Display your public key for adding to GitHub
- Test the SSH connection to GitHub
Example:
/setup/git -u johndoe -e [email protected]To apply pre-configured VS Code settings optimized for Go development:
/setup/codeThis script will:
- Copy default VS Code settings to your user profile
- Configure editor preferences (minimap, git, YAML formatting, etc.)
- Set up GitHub Copilot settings (if you have access)
- Configure Go language tooling
The settings include:
- Smart Git commits and sync
- Disabled minimap (can be re-enabled)
- YAML formatting with 2-space indentation
- Docker and Kubernetes development helpers
- Custom spell-check dictionary
Note: After running either setup script, close and re-launch your workstation for all changes to take effect.
To customize the default settings:
- Edit
/setup/profile/settings.jsonin the repository before building your image - Rebuild and deploy the image using the Cloud Build pipeline
- Run
/setup/codein your workstation to apply the new settings
Alternatively, you can manually edit ~/.local/share/code-server/User/settings.json directly in your workstation for immediate changes (these will persist on the workstation's persistent disk).
To update your custom image, simply submit a new build. The Cloud Build pipeline will automatically update the workstation configuration with the new image.
gcloud builds submit \
--region=$REGION \
--substitutions=_REGION=$REGION,_REPO=$AR_REPO,_CLUSTER=$WS_NAME-cluster,_CONFIG=$WS_NAME-configNote: If the workstation is running, you must stop and start it again for the new image to take effect.
If you want to monitor or debug this process, start by navigating to the Cloud Build history tab and check on the status of your build. Both, build and deploy steps have to be green.
open https://console.cloud.google.com/cloud-build/builds;region=$REGION?project=$PROJECT_IDNext, check whether the image is in the Artifact registry. You should see there a tag that equals to what was in version during the last tag.
open https://console.cloud.google.com/artifacts/docker/$PROJECT_ID/$REGION/$AR_REPO/ws-go-code?project=$PROJECT_IDFinally, check the Configurations section of Cloud Workstations to see if the config was updated with the digest of the last built image that corresponds to the tag:
open https://console.cloud.google.com/workstations/configurations?project=$PROJECT_IDThis is my personal project and it does not represent my employer. While I do my best to ensure that everything works, I take no responsibility for issues caused by this code.