Terraform is a infrastructure as code (IaC) tool that makes it easier to provision the infrastructure resources for your application. In this guide we will look at how and why you might want to leverage Terraform with your Twilio Functions and Assets project.
You'll need the latest Terraform CLI installed on your system.
Additionally, make sure you have either have the following environment variables defined on your system:
TWILIO_ACCOUNT_SID
with the Account SID of the project you want to deploy toTWILIO_API_KEY
with a valid API KeyTWILIO_API_SECRET
with a valid secret for your API KeyMake sure you also have the latest version of the Serverless Toolkit installed. In this tutorial we'll be using the Twilio CLI plugin. Install the latest version of the Serverless Toolkit by running:
1twilio plugins:remove @twilio-labs/plugin-serverless2twilio plugins:install @twilio-labs/plugin-serverless@latest
You'll also need an existing Twilio Serverless project created with the Serverless Toolkit. If you don't have one you can follow the Getting Started guide.
Before we start with the work, there's a couple of things you need to understand about Terraform.
Terraform is primarily used to provision various resources but not for deploying applications. By default when you run twilio serverless:deploy
or twilio-run deploy
the Serverless Toolkit will handle both provisioning the respective Serverless Service and Environment and afterwards deploy your code to them.
Provisioning in this context is creating a Serverless Service/Environment resource but could also be any other Service you'd be creating using the CLI, API, or the Console. This can even be purchasing a new phone number. Deploying involves taking the respective code for your project and uploading it to those provisioned resources.
With Terraform we are splitting provisioning and deployment into distinct steps. Splitting these two steps has a couple of benefits:
An important aspect of Terraform is the fact that it maintains state of your resources. It does so by either creating a .tfstate
file on your system or by storing it in a backend of your choice. The Terraform state contains information such as the SIDs of the Twilio resources you might have created through Terraform. By sharing this Terraform state with your colleagues by using a shared backend (you generally don't want to check-in a .tfstate
file in your project) you can make sure you are all deploying to the right project.
Terraform providers are essentially integrations that can be used to teach Terraform how to create certain resources. We've released a Twilio provider for Terraform that we'll be using as part of this project. If you find any issues with it, don't hesitate to create a GitHub issue on the project.
In the Terraform Registry you can find a wide variety of providers for other platforms.
There are a few common Terraform commands that will likely use when working with Terraform.
terraform init
is used to set up your project. You'll need to run this for example if you clone your project or if you start using new providers.
terraform fmt
will make sure your Terraform file is formatted appropriately.
terraform validate
verifies that your file is correct including using the right resources available through the provider.
terraform plan
will compute the plan on how Terraform can move from the current state to the new state described in your Terraform file.
terraform apply
will handle the actual provisioning. It also runs terraform plan
under the hood if you didn't run it before.
Start by creating a main.tf
file at the root of your project.
All the following code has to be added to this main.tf
file in the order mentioned below. At the end of the section you can also find the full file if you want to copy and paste it.
To create the Twilio resources we'll be using the Twilio provider. In order to make sure you are using the latest version, head over to the Terraform Registry page. Click the "Use Provider" button and copy the content into your main.tf
file.
The result should look like this with possibly a different version.
1terraform {2required_providers {3twilio = {4source = "twilio/twilio"5version = "0.7.0"6}7}8}910provider "twilio" {11# Configuration options12}
From here we can define which resources we want to create with Terraform. You can find a list of all available Twilio resources on GitHub. In our case we'll create a twilio_serverless_services_v1
and a twilio_serverless_services_environments_v1
as both are required for our Serverless deployment.
Add the following lines to your main.tf
file:
1resource "twilio_serverless_services_v1" "service" {2friendly_name = "Terraform Example Service"3unique_name = "terraform-demo"4include_credentials = true5}67resource "twilio_serverless_services_environments_v1" "environment" {8service_sid = twilio_serverless_services_v1.service.sid9unique_name = "stage-environment"10domain_suffix = "stage"11}
The first resource we create is a Serverless Service with the name terraform-demo
and friendly name Terraform Example Service
. The second resource we create is a Serverless Environment with the domain suffix stage
and name stage-environment
. For this resource we are passing in the SID of the previously created Service.
This is one of the strengths of us using Terraform for the provisioning as we can immediately define the relationship between the resources.
We'll have to tell the Serverless Toolkit to deploy the code to the Service and Environment we provisioned with Terraform. To do this we have to output the SIDs for the Service and Environment from Terraform.
Add the following code to your main.tf
to output the relevant SIDs:
1output "serverlessService" {2value = twilio_serverless_services_v1.service.sid3sensitive = true4}56output "serverlessEnvironment" {7value = twilio_serverless_services_environments_v1.environment.sid8sensitive = true9}
This completes our main.tf
Terraform file that should look in total like this:
1terraform {2required_providers {3twilio = {4source = "twilio/twilio"5version = "0.7.0"6}7}8}910provider "twilio" {11# Configuration options12}1314resource "twilio_serverless_services_v1" "service" {15friendly_name = "Terraform Example Service"16unique_name = "terraform-demo"17include_credentials = true18}1920resource "twilio_serverless_services_environments_v1" "environment" {21service_sid = twilio_serverless_services_v1.service.sid22unique_name = "stage-environment"23domain_suffix = "stage"24}2526output "serverlessService" {27value = twilio_serverless_services_v1.service.sid28sensitive = true29}3031output "serverlessEnvironment" {32value = twilio_serverless_services_environments_v1.environment.sid33sensitive = true34}
Now that we have our completed Terraform file it's time to provision our resources.
First, if you have not done so yet, initialize your Terraform project by running:
terraform init
Next ensure that your main.tf
is valid by running:
1terraform fmt2terraform validate
If you want to get a preview of what will be provisioned run:
terraform plan
Now it's time to provision the resources by running:
terraform apply
Once you confirmed the provisioning with yes
all the resources will be created using the credentials in your environment variables.
You should also see the new service that was created in your Twilio Console.
Now that the resources have been provisioned we can deploy our code. For this we first have to retrieve the relevant SIDs from Terraform. We can use terraform output
for this.
We'll store them in temporary variables using:
1SERVERLESS_SID=$(terraform output -raw serverlessService)2ENVIRONMENT_SID=$(terraform output -raw serverlessEnvironment)
With this we can trigger the deployment by passing in the relevant SIDs using --service-sid
and --environment
:
1twilio serverless:deploy \2--service-sid "$SERVERLESS_SID" \3--environment "$ENVIRONMENT_SID" \4--username $TWILIO_API_KEY5--password $TWILIO_API_SECRET
This will kick of the same deployment that you are used to but it will explicitly deploy to the Service and Environment you have passed in.
As mentioned before we can use Terraform to provision a variety of Twilio resources. For example you can use it to provision a Verify service by adding:
1resource "twilio_verify_services_v2" "service" {2friendly_name = "Verify Demo"3}45output "verifyServiceSid" {6value = twilio_verify_services_v2.service.sid7sensitive = true8}
If you want to pass the Service SID to your Twilio Functions deployment you can do this using the Serverless Toolkit by running:
1VERIFY_SERVICE_SID=$(terraform output -raw verifyServiceSid)2twilio serverless:env:set --key VERIFY_SERVICE_SID --value "$VERIFY_SERVICE_SID"
Check out more examples on the Twilio Terraform Provider GitHub.
With all of this set up we can actually move this into a Continuous Integration / Continuous Delivery (CI/CD) system. How exactly you use Terraform depends on your the system you are using. Make sure to consult the Terraform docs for more information. You will also have to use some backend to store your Terraform state. To learn more on how to use the Serverless Toolkit from CI/CD environments check out our dedicated guide for it.