Create preview environments with Terraform, GitHub Actions, and Vercel
Continuous integration and delivery (CI/CD) lets you release more frequently by automating testing and other tasks, so you can ship improvements to your services sooner. Preview environments are temporary environments that your CI pipelines can create for new pull requests to demonstrate feature changes. This helps your team (developers, product, QA) discover bugs faster, and experiment with the latest features without manually checking-out the branch and running the application locally.
Vercel is a platform that deploys frontend frameworks and static websites instantaneously, scales them automatically, and generates preview environments. While you can use Vercel's Git integration to create preview environments with serverless backends, Terraform lets you handle more complex preview environment setups that use Vercel for the frontend and other services for the backend. This creates fully-featured applications that you can share with your stakeholders for review and testing.
In this tutorial, you will build a workflow for deploying preview environments, and test changes to HashiCups, a fictional coffee-shop application. To build the preview workflow, you will create reusable HCP Terraform variable sets for your AWS and Vercel API credentials, setup and deploy the preview environments' shared resources, and set up the frontend preview environments repository. Then, you will test the workflow — which creates and destroys preview environments — by opening, merging, and closing pull requests.
Introduction to HashiCups
HashiCups is a demo application that lets you view and order customized HashiCorp branded coffee. The HashiCups application consists of a frontend React application and multiple backend services.
The HashiCups backend consists of a GraphQL backend, products API, a Postgres database, and a payments API. This tutorial uses a Docker compose file to bootstrap the backend services on an EC2 instance. The frontend application, running on Vercel, expects an HTTP-secured public API.
Prerequisites
The tutorial assumes that you are familiar with the Terraform and HCP Terraform plan and apply workflows. If you are new to Terraform itself, refer first to the Get Started tutorials. If you are new to HCP Terraform, refer to the Get Started - HCP Terraform tutorials.
For this tutorial, you will need:
- the Terraform 1.1.4+ CLI installed locally.
- an AWS account with AWS Credentials configured for use with Terraform.
- an HCP Terraform account
- a GitHub account
- a Vercel account
Create Vercel API token
The Terraform Vercel provider requires a personal account token for authentication. On the Vercel Token page, create a Vercel API token named learn-terraform
.
Save this token in a safe place as Vercel will only display it once. You will create an HCP Terraform variable set for this API token in the next step.
Set up HCP Terraform
Next, you need to configure HCP Terraform so that it can securely interact with GitHub, Vercel, and AWS on your behalf. This involves generating an HCP Terraform token to give to GitHub, which it will use to trigger builds, and adding your Vercel token and AWS credentials to your HCP Terraform workspace.
Create HCP Terraform team
In order for GitHub Actions to interact with HCP Terraform, you must create an HCP Terraform API token. While you could use your personal API token, it will have the same permissions as your user, which may span multiple organizations and workspaces. HCP Terraform teams enable your organization to properly scope permissions.
Note
HCP Terraform teams is a paid feature. If you do not have a paid account, create a personal API token by going to the Tokens page.
Visit your HCP Terraform organization's Teams page, found under Settings > Teams in the HCP Terraform UI.
Create a new team named learn-tf-preview-env
.
Then, grant the learn-tf-preview-env
team permission to manage workspaces. Click Update team organization access to confirm your changes.
Create HCP Terraform team API token
Click on the API tokens option in the left navigation, and then choose the Team Tokens tab.
Click Create a team token. Under Team, choose your learn-tf-preview-env
team and choose an Expiration of 30 days. Click Create.
Click Copy token to copy the token string. Save this token in a safe place as HCP Terraform will only display it once. You will add it to GitHub as a secret later in this tutorial.
Add the following to your Terraform configuration file, replacing TOKEN
with your HCP Terraform team API Token. This will let the Terraform CLI use your new team API token and use HCP Terraform.
Create HCP Terraform variable sets
Each pull request will create a new HCP Terraform workspace to launch your preview environment. The easiest way to allow each of these workspaces to authenticate to AWS and Vercel is through HCP Terraform’s reusable variable sets. HCP Terraform variable sets let you centrally manage provider credentials and reuse them across workspaces.
Since GitHub Actions dynamically generates the HCP Terraform workspaces for the preview environments, these variable sets must apply to all workspaces in the organization.
Note
HCP Terraform applies global variable sets to every workspace, which may lead to credential leakage. Be mindful if you include credentials in global variables.
Create AWS Credentials variable sets
If you do not have a variable set containing your AWS credentials, follow the steps in the Create and Use a Variable Set tutorial to create one. Select Apply to all workspaces in this organization for the variable set scope.
Tip
If you have temporary AWS credentials, you must also add your AWS_SESSION_TOKEN
as an environment variable to the variable set.
Create Vercel Credentials variable sets
Create a new variable set named Vercel Credentials
. Select Apply to all workspaces in this organization for the variable set scope.
Create an environment variable named VERCEL_API_TOKEN
and set it to your Vercel API token. Mark this variable as sensitive.
Click Add variable and Create variable set to create your Vercel variable set.
Setup and deploy shared resources
The setup for this tutorial relies on two sets of resources across two repositories: one for the shared resources and the other for the temporary preview environments . Each temporary preview environment will share the same VPC, security group, TLS certificate, and Vercel project. The shared resources repository manages these resources.
Fork the Learn Terraform Preview Environments Shared repository.
Clone your fork of the learn-terraform-preview-environment-shared
repository,
replacing USERNAME
with your own Github username.
Navigate to the cloned repository.
Review shared resources
This repository contains Terraform configuration to deploy shared resources that your preview environments will use:
The
vpc
module deploys a VPC and subnets. Terraform will provision your backend preview environments in this VPC.The
aws_security_group.hashicups-backend
allows ingress traffic on ports:443
and:8080
, and allows all egress traffic for access to the HashiCups backend preview environment.main.tfThe
tls_private_key
,tls_self-signed_cert
, andaws_acm_certificate
resources generate and upload a self-signed certificate to AWS. The HashiCups frontend expects an HTTPS-secured backend. This self signed certificate enables the load balancer for each backend preview environment to serve traffic through HTTPS.The
vercel_project
resource creates a Vercel project namedhashicups
. This project is preconfigured to use the React framework.main.tf
The outputs.tf
file defines outputs for these resources. This allows the preview environment workspaces to reference them through the terraform_remote_state
data source.
Update shared resources configuration
Before you can use this configuration, you must update it to point to your HCP Terraform organization.
In terraform.tf
, replace hashicorp-training
with your HCP Terraform organization name. Terraform will create a new workspace named hcup-be-shared
in HCP Terraform and use it to create and manage your shared sources.
Initialize shared resources
Initialize the Terraform configuration.
Navigate to HCP Terraform and filter on hcup-
to find your newly created workspace.
Deploy shared resources
Apply the configuration. Respond yes
to the prompt to deploy the shared resources.
Enable remote state sharing
Your preview environments need to access the hcup-be-shared
workspace's state to reference its outputs.
Navigate to the hcup-be-shared
workspace, then select Settings > General.
In the Remote state sharing section, select Share with all workspaces in this organization. Click Save settings.
Note
Terraform will enable any workspace in the organization to access this workspace's state. Be mindful when you enable this option since it may expose sensitive state.
Set up preview environment repository
Fork the Learn Terraform Preview Environments repository.
Since this repository will use GitHub actions with HCP Terraform to deploy preview environments, you must create repository action secrets and enable GitHub actions.
Create repository action secrets
In your forked repository, navigate to Settings. In the Secrets menu on the left sidebar, select Actions. Create a repository secret named TFC_API_TOKEN
and set it to the HCP Terraform team API token you created in the previous step.
Enable GitHub Actions
Navigate to the "Actions" tab and enable the pre-configured workflow by clicking "I understand my workflows, go ahead and enable them."
Clone forked preview environment repository
Clone your fork of the learn-terraform-preview-environment
repository,
replacing USERNAME
with your own Github username.
Navigate to the cloned repository.
Review preview environment repository
The learn-terraform-preview-environment
repository contains:
- The HashiCups frontend application.
- The HashiCups preview environment backend Terraform configuration.
- The GitHub Action that triggers the preview environment creation during pull requests.
This section will primarily focus on the Terraform configuration and the GitHub Action.
Review Terraform resources
The main.tf
file contains the terraform
block, which specifies the HCP Terraform organization to run in. The workspaces
block is a placeholder — the GitHub Action will replace this with a new workspace name for each run's preview environment and operations.
This file also defines the preview-env
Terraform module, which contains the configuration to deploy the EC2 instance, load balancers, and Vercel deployment associated with your preview environment.
The module takes one input: is_prod
. If is_prod
is set to true, Terraform will not deploy the backend preview environment resources and instead update the production Vercel deployment.
This configuration also returns two outputs: the lb_dns_name
, which corresponds to the backend URL, and the preview_url
, which corresponds to the Vercel deployment.
Next, navigate to the preview-env
directory, which contains the following:
The
main.tf
file definesaws_instance.hashicups-backend
, the EC2 instance containing the HashiCups backend. This EC2 instance references the subnets and security groups fromhcup-be-shared
, the shared resources workspace.preview-env/main.tfNotice the
count
meta-argument. Terraform will not create an EC2 instance containing the HashiCups backend ifis_prod
is true.Tip
The
setup-hashicups.yaml
file contains the user data script to provision the EC2 instance with the HashiCups backend.The
loadbalancer.tf
file defines an application load balancer and directs traffic to the EC2 instance. Since the HashiCups backend must run on HTTPS, it uses a self-signed certificate sourced from thehcup-be-shared
workspace. The resources in this file useterraform.workspace
as a name so you can more easily determine which workspace manages them. AWS uses the load balancer name as part of its URL, so the endpoint will contain the HCP Terraform workspace name.The
vercel.tf
file defines the Vercel deployment. Thevercel_project_directory.frontend
resource packages everything in the current directory to send to Vercel. Thepublic_api_url
local value returns the backend API url if the load balancer exists.The
vercel_deployment
resource creates the Vercel frontend deployment. This resource defines an environment variable namedNEXT_PUBLIC_PUBLIC_API_URL
and sets it to the preview environment backend. Vercel will build the HashiCups frontend with this environment variable, connecting the frontend to the preview environment backend.preview-env/vercel.tfThe
outputs.tf
file defines three outputs. Thelb_dns_name
andpublic_ip
point to the HashiCups backend. Thepreview_url
is the deployment URL containing the HashiCups frontend.
Review GitHub Actions
GitHub Actions add continuous integration to your repository, enabling you to automate your processes. A GitHub Action workflow is an automated process consisting of multiple steps.
Open .github/workflows/vercel.yml
, which defines a GitHub Action workflow for building and destroying preview environments.
This workflow only runs when you push to the main
branch, or if someone creates or closes a pull request.
This workflow defines a preview-environment
job with two environment variables and eight steps.
The
tfcWorkspaceName
environment variable is set to the branch name prefixed byhcup-be
. The GitHub Action will update the Terraform configuration to use this workspace name.The
tfcOrg
environment variable defaults tohashicorp-training
– you will update this to your HCP Terraform organization in the next step. Thedestroy
step uses this environment variable to destroy the HCP Terraform workspace once you close the pull request.
The steps define all actions in the workflow. This workflow takes one of three paths depending on the GitHub event that triggered it. As a result, each trigger will not run every step in the action.
When someone creates a new pull request, this GitHub Action will create the preview environment by running the steps in the diagram below.
When someone closes a pull request, the GitHub Action will delete the existing preview environment by running the steps in the diagram below.
When someone merges the pull request into the
main
branch, this GitHub Action will build and deploy the frontend into production by running the steps in the diagram below.
The GitHub Action job defines the following steps:
Checkout checks out the current commit.
.github/workflows/vercel.ymlSetup Terraform uses
setup-terraform
to retrieve the Terraform CLI and loads theTFC_API_TOKEN
as an environment variable, enabling the Terraform CLI to authenticate to HCP Terraform..github/workflows/vercel.ymlTerraform Init, create TFC workspace updates
main.tf
to use the workspace name defined bytfcWorkspaceName
(which contains your Git branch name). It then initializes the configuration, creating the HCP Terraform workspace. This step only runs during pull requests..github/workflows/vercel.ymlBuild and deploy preview environment applies the configuration, building and deploying both the backend and frontend preview environments. This step only runs during open pull requests.
.github/workflows/vercel.ymlTerraform output returns the outputs of the previous run. This output contains the URL for the backend API and the Vercel deployment. This step only runs during open pull requests.
.github/workflows/vercel.ymlCreate comment with Terraform output creates a comment in the pull request with the Terraform output. This makes it easier for you to navigate to the backend and frontend URL. This step only runs during open pull requests.
.github/workflows/vercel.ymlDestroy preview environment destroys the resources in the HCP Terraform workspace, then ndestroys the workspace itself using the HCP Terraform API. This step only runs when someone closes the pull request, which includes merging a pull request.
.github/workflows/vercel.yml
Build and deploy Prod Environment updates the HCP Terraform workspace in
main.tf
tohcup-frontend-vercel
. Then, it initializes the configuration and applies the configuration with theis_prod
variable set to true. This step only runs when someone pushes to themain
branch. This includes merging a pull request intomain
..github/workflows/vercel.yml
Update configuration
Before you can use this configuration, you must update the configuration in three places to point to your HCP Terraform organization and Vercel project.
In
main.tf
, replacehashicorp-training
with your HCP Terraform organization name.main.tfIn
preview-env/main.tf
, replacehashicorp-training
with your HCP Terraform organization name.preview-env/main.tfIn
.github/workflows/vercel.yml
, replacehashicorp-training
with your HCP Terraform organization name..github/workflows/vercel.yml
You must commit and push your changes to version control.
First, add your configuration changes.
Next, commit your changes.
Finally, push your changes.
Since you are pushing directly to the main
branch, the GitHub Action will trigger to build and deploy the production frontend in Vercel.
Create preview environment
In this step, you will create a pull request that contains a change to the frontend. This will trigger the GitHub action to create a preview environment.
In src/components/Header.js
, on line 62, add <h1 class="font-bold py-4">HashiCups</h1>
before </header>
. This will render HashiCups
after the HashiCorp logo in the frontend.
Now, you will push your changes in a new branch to create a pull request. This emulates the development workflow.
Create a new branch named update-frontend
for your changes.
Add the configuration changes.
Then, commit the changes.
Finally, push the changes.
Next, generate a pull request from the update-frontend
branch. From the base repository
drop-down, choose your forked repository and main
branch. Click Create pull request.
The pull request automatically triggers the GitHub action. Click on Details to follow the GitHub Action.
When GitHub Action runs the build step, it displays an HCP Terraform link so you can access the run from HCP Terraform.
Once the HCP Terraform run completes, the GitHub action will add a comment to the pull request containing the Terraform outputs.
Notice that the load balancer DNS name contains the branch name, update-frontend
.
Verify preview environment
First, go to lb_dns_name
, the backend URL, and accept the self-signed certificate. You must accept the self-signed certificate for the HashiCups frontend to successfully communicate with the backend.
Then, navigate to the Vercel deployment URL. Notice that "HashiCups" appears in the header, reflecting the changes you made in the pull request.
Open the developer tools console. You will find the frontend displays the API it's connected to.
Merge pull request
When you merge a pull request, you want to build and deploy the latest version into production and destroy the preview environment associated with the pull request.
Navigate to your pull request for update-frontend
then click Merge pull request to merge your changes into the main
branch.
Click on the Actions tab. Notice that merging the pull request triggers two GitHub Action runs.
- The run for
update-frontend
deletes the preview environment resources and workspace associated with the pull request. - The run for
main
builds the frontend for production and deploys it to Vercel.
Create another preview environment
In this section, you will open another pull request with new changes to create a second, isolated preview environment.
In src/components/Header.js
, on line 62, add <h1 class="font-bold py-4">HashiCups #2</h1>
before </header>
.
Create a new branch named update-frontend-2
for your changes.
Add your configuration changes.
Then, commit your changes.
Finally, push your changes.
Next, create a pull request from the update-frontend-2
branch. From the base repository
drop-down, choose your forked repository and main
branch. Click Create pull request.
Once the GitHub Action completes, it will post the outputs for your new preview environment in a comment on your pull request.
Notice that the load balancer DNS name contains the branch name, update-frontend-2
. Accept the backend API's self-signed certificate before navigating to the preview URL.
Your UI will reflect the changes in your update-frontend-2
branch. This preview environment is completely isolated and independent. Changes to this preview environment will not affect other preview environments.
Close pull request
When you close a pull request, you no longer need to review its preview environments. Close the pull request for your update-frontend-2
branch.
Click on Actions, then on the latest run.
Notice that the GitHub Action runs the destroy workflow, deleting the resources in the preview workspace and the workspace itself.
Clean up your infrastructure
Before moving on, destroy the resources and HCP Terraform workspaces you created for this tutorial. The resources and HCP Terraform workspaces associated with the pull requests were deleted in the Close pull request and Merge pull request sections.
In HCP Terraform, go to the hcup-be-shared
and hcup-frontend-vercel
workspaces, queue a destroy plan, and apply it. Then, delete the workspaces from HCP Terraform.
For more detailed guidance on destroying resources in HCP Terraform, reference the Destroy Resources and Workspaces tutorial.
Next steps
Over the course of this tutorial, you set up, created, and destroyed preview environments for HashiCups. In the process, you learned how to automate dynamic Terraform workspace runs in your CI/CD pipelines with HCP Terraform and HCP Terraform variable sets.
For more information on topics covered in this tutorial, check out the following resources.
- Learn how to automate HCP Terraform workspaces, variables, run triggers and more in the Automate HCP Terraform Workflow tutorial.
- Learn how to release applications in a rolling upgrade with near-zero downtime in the Use Application Load Balancers for Blue-Green and Canary Deployments
- Learn how to deploy an application to Kubernetes with TypeScript in the Deploy Applications with CDK for Terraform