Purple white and red flowers.
Our garden is growing. We've raised a Series A funding round.
Read more here

Run pull requests in preview environments with Kubernetes

Borys Generalov
Borys Generalov
March 30, 2023

To ensure your product functions correctly, you need to conduct thorough tests. However, testing in a local development environment or a staging environment is vastly different from the production environment where the product will eventually live. Preview environments are a much better option for testing because you can have a realistic production-like environment at your fingertips. Testing in this type of environment increases the likelihood of identifying problems and bugs before the product goes live.

What is a preview environment?

A preview environment is a safe, temporary, fully functional instance of a live (or production) environment that can be created or destroyed as needed. It improves collaboration between development and operations teams and reduces the risk of introducing bugs or breaking changes to the production environment. This type of environment makes it easy to preview pull request (PR) changes in a real-world setting before merging. In addition, provisioning preview environments on demand removes the bottlenecks caused by manual provisioning.

An ideal preview environment should be lightweight, easy to manage, and should not require any complex setup. However, in practice, achieving the above with Kubernetes can be difficult. This is where Garden helps to make preview environments a breeze to set up and use.

In this article, you'll learn how to integrate Garden with GitHub Actions, a continuous integration, continuous delivery (CI/CD) platform, to deploy preview environments on a Kubernetes cluster.

Using Garden to manage preview environments

As a modern, open source DevOps platform, Garden helps you build, deploy, and manage containerized applications running on a Kubernetes cluster. It provides a simple, intuitive, and efficient way for developers to manage their projects, regardless of the size or complexity of the application. It also integrates with popular tools and services, including Kubernetes, Docker, and Helm, making it easy to leverage your existing infrastructure.

With Garden, you can easily create and manage multiple preview environments for your different branches using infrastructure as code (IaC). To do so, you define your infrastructure using a YAML file. When you store this infrastructure code in a version control system, like Git, you can easily track changes, collaborate with other team members, and audit your environment to ensure security and regulatory requirements have been met.

The following diagram depicts how Garden deploys a preview environment on a Kubernetes cluster:

[A screenshot showing how Garden creates a preview environment.
How Garden creates preview environments

As you can see, the Garden CLI is installed on a GitHub agent that is running the workflow. Once a new pull request is created, GitHub Actions calls the Garden CLI command to provision a preview environment. In turn, Garden reads the environment details from a project config file (<span class="p-color-bg">project.garden.yml</span>), builds Docker containers, and pushes them into the container registry. Finally, it uses kubectl to communicate with the remote Kubernetes API server to deploy the resources as needed.

Implementing on-demand preview environments

In this tutorial, you'll learn how to spin up a Kubernetes preview environment after creating a pull request in GitHub. Then you'll set up a Garden project and create GitHub Actions that automatically provision the preview environment when there is a push to the branch with a PR on it.

Before you begin, you'll need the following:

Create a demo project

To begin, you need to clone the demo project and navigate to its base directory:


```bash
git clone https://github.com/garden-io/garden.git
cd garden/examples/demo-project

Make sure you have a single-zone Kubernetes cluster provisioned and ready to operate. You also need to install and configure kubectl to interact with your cluster and store the kubectl context in <span class="p-color-bg">kubeconfig</span>. For more information on how to do this, check out this documentation from Google.

In addition, you need to set up your container registry and enable in-cluster building with the Google Container Registry (GCR). If you need help with this step, this documentation from Garden is a great resource.

Lastly, you need to create a GKE service account so that GitHub Actions can deploy to GKE.

Please note: You need to give the service account the proper permissions. The example code for this article uses a service account named "sa-deploy" with the roles "Kubernetes Engine Developer" and "Storage Admin". If you encounter any issues with this, you can read through this GitHub article to help troubleshoot.

Set up the Garden environment

After cloning your project, you need to update it and add a preview environment to your project config file.

Garden's environments are a software deployment space where the source code will be deployed and executed. For the purpose of this tutorial, a preview environment will be deployed within a separate namespace in the same GKE cluster.

To define your preview environment configuration, navigate back to the demo project base directory and open the <span class="p-color-bg">garden.yml</span> file with the text editor of your choice.

Find the <span class="p-color-bg">environments</span> section:


```yaml
environments:
- name: local
- name: remote
	defaultNamespace: ${var.userId}
```

The <span class="p-color-bg">local</span> environment can be used to deploy your work-in-progress code to a local Kubernetes cluster. However, for the purpose of this preview environment, replace the existing <span class="p-color-bg">remote</span> environment with the <span class="p-color-bg">preview</span> environment configuration. For full customization, refer to the official documentation. Otherwise, the following configuration can be used as a starting point:


```yaml
kind: Project
name: demo-project-start
environments:
  - name: preview
    defaultNamespace: '${local.env.USER}-${local.env.PR_NUMBER}-preview'
providers:
  - name: kubernetes
	# replace the context with your kubectl context
	context: gke_preview-env-demo_europe-north1-a_demo-cluster
    environments:
      - preview
    namespace: '${environment.namespace}'
	deploymentRegistry:
	# set the hostname according to the region your cluster runs in
	hostname: eu.gcr.io
	# set the namespace to the project ID of the target cluster
	namespace: preview-env-demo
    imagePullSecrets:
      - name: gcr-config
        namespace: default
```

Here, you describe a <span class="p-color-bg">preview</span> environment that corresponds to a new namespace in the GKE cluster. GCR is utilized to store the container images.

To simplify the setup, you can remove the ingress configuration from both the backend and frontend services. To do so, open the <span class="p-color-bg">garden.yml</span> file for each service and delete the <span class="p-color-bg">ingresses</span> section, as shown here:


```yaml
ingresses:
  - path: /hello-frontend
	port: http
  - path: /call-backend
	port: http
```

At this point, you need to run a few Garden commands locally to verify that everything is working:


```bash
export USER="local"
export PR_NUMBER="pr1"
# set env variable using PowerShell: 
#$env:USER="local"
#$env:PR_NUMBER="pr1"

```

Then run the following commands to verify the setup is correct:


```bash
garden deploy
garden get status
```

The <span class="p-color-bg">garden deploy</span> command deploys an environment and builds any necessary modules and dependencies. While this is very useful in a CI/CD context, you can also use the <span class="p-color-bg">garden dev</span> command when running locally. The <span class="p-color-bg">garden dev</span> command launches the Garden dev console, which builds, deploys, and tests all your modules and services, and then rebuilds, redeploys, and retests as you modify the code.

The <span class="p-color-bg">garden get status</span> command outputs the full status of your environment.

Next, run the dev console and navigate to the Garden dashboard to view the setup:


```bash
garden dev
```

You can access the dashboard by opening the URL that can be found in your terminal:

A screenshot showing the Garden CLI
Garden CLI

The dashboard should display the status of both the backend and frontend services as "Ready":

A screenshot showing the Garden dashboard
Garden dashboard

Now, it's time to create a GitHub workflow.

Create a GitHub workflow

In this section, you'll create a workflow file to run your GitHub Actions.

First, create a GitHub workflow file under the folder <span class="p-color-bg">.github/workflows</span> and name it <span class="p-color-bg">pr-preview-env.yml</span>:


```bash
mkdir .github/workflows
cd .github/workflows
touch pr-preview-env.yml
```

Open the file in your preferred text editor and insert the content of the GitHub Garden workflow. The most important steps are highlighted here:


```yml

 # Install Garden CLI tool
 - name: Set up Garden
   run: |-
     curl -sL https://get.garden.io/install.sh | bash
     export PATH=$PATH:$HOME/.garden/bin
     chmod u+x $HOME/.garden
     echo "PATH=$HOME/.garden/bin:$PATH" >> $GITHUB_ENV

 # Deploy the preview environment to the GKE cluster
 - name: Deploy
   if: github.event.pull_request.merged == false
   run: |-
     cd ./demo-project-start
     garden --version
     garden --env=preview plugins kubernetes cluster-init
     garden deploy
     garden get status

 # Destroy the preview environment once a pull request is merged
 - name: Destroy
   if: github.event.pull_request.merged == true
   run: |-
     cd ./demo-project-start
     garden delete environment --env=preview
```

In the first portion of this code, you install the Garden CLI tool. Then you use the Garden CLI to deploy/destroy a preview environment as needed. For more information on the Garden commands, check out the official docs.

This workflow should authenticate to the GKE cluster using the service account you created previously. This example uses authentication as workload identity federation, which is a recommended way to authenticate to GKE clusters in Google Cloud.

Create a pull request

Now that you've created a GitHub workflow, you need to create a pull request to see the preview environment in action.

Create a new repository on GitHub and push the changes from the <span class="p-color-bg">demo-project-start</span> that you modified previously. If you experience any problems, check out this GitHub documentation to help troubleshoot.

Create a new branch (*ie* <span class="p-color-bg">feature/feature1</span>) and copy and paste a <span class="p-color-bg">backend</span> folder to simulate the introduction of a new service. Rename the folder to <span class="p-color-bg">backend2</span> and update the <span class="p-color-bg">garden.yml</span> file with the following:


```yaml
kind: Module
type: container
name: backend2
dockerfile: Dockerfile
services:
  - name: backend2
    ports:
      - name: http
        containerPort: 8080
        servicePort: 80
```

Commit and push your changes; then navigate to your GitHub repository and make a new pull request.

Preview the changes

In the previous section, you created a pull request, which automatically triggers the creation of a preview environment on the Kubernetes cluster. To test the workflow, you need to verify that the deployment has been successfully applied to the Kubernetes cluster by checking that it exists in the correct namespace. Then, you need to make local changes and push them to the repository. At that point, the preview environment will be automatically updated by the GitHub Actions workflow.

To see the workflow run, navigate to GitHub Actions and click on the job **Deploy to Preview**:

A screenshot showing the GitHub workflow running
GitHub workflow

View the results of the **Deploy** step, and it should contain detailed logs from <span class="p-color-bg">Garden</span>:

A screenshot showing the details of the **Deploy** step
Deploy result details

The **Deploy** step logs display information about the deployment process, including the Kubernetes namespace that corresponds to your preview environment.

Next, navigate to your Kubernetes cluster and verify that there are services and pods running in the namespace <span class="p-color-bg">runner-pr1-preview</span>:

A screenshot showing services on the GKE cluster
Services on the GKE cluster

If you see multiple sets of frontend and backend services deployed into distinct Kubernetes namespaces, well done! The workflow you created works as expected and deploys a distinct preview environment when raising a pull request.

You can also use port forwarding to send API requests from your local machine. To set up port forwarding, select the service **backend**, scroll down to **Ports**, select **PORT FORWARDING**, and follow the instructions:

A screenshot showing the GKE **Port Forwarding** button
GKE Port forwarding

You should get a URL that looks like this:

"https://ssh.cloud.google.com/devshell/proxy?port=8080". This URL will help you access your service. Open the URL in your browser and append the API endpoint <span class="p-color-bg">/hello-backend</span>. You should see the response message <span class="p-color-bg">Hello from Go!</span>:

A screenshot showing the response from backend service
Backend service response

You can push more changes in your pull request to see that the preview environment has been updated. To finish, complete the pull request and ensure the preview environment has been deleted.

Use One-Click Preview Environments

Garden Cloud simplifies the deployment process further by allowing you to connect to your Git repository and use one-click preview environments. One-click preview environments are branch-specific namespaces that are created from the Garden Cloud UI to avoid creating a GitHub workflow file, which Garden Cloud creates automatically.

One-click preview environments also come with a web dashboard that provides a comprehensive overview of all preview environments, including the status, health, and resources of each environment. This makes it easy for developers to keep track of preview environments and quickly spin them up for applications.

A preview environment for every pull request

Preview environments provide a safe, controlled environment for testing and help you get feedback quickly. Having a preview environment that is automatically created upon making a pull request ensures the quality of the final product and increases the velocity of the development process.

In this article, you learned about the importance of preview environments in software development and how to use Garden to deploy a preview environment on a Kubernetes cluster.

Garden is designed to simplify the management and testing of cloud-native applications running on Kubernetes. It helps to improve the developer experience and speed up the software delivery cycle by automating the deployment process and reducing time wasted while switching between tasks.

previous arrow
Previous
Next
newt arrow