Deploying serverless applications has become increasingly popular due to its scalability, cost-efficiency, and ease of management. Amazon Web Services (AWS) Lambda provides a powerful serverless computing platform, while Go (Golang) offers a performant and statically typed programming language.
In this article, we will explore how to deploy Go-based applications to AWS Lambda using the seamless integration of GitHub Actions and Terraform. By combining these tools, developers can automate the deployment process, streamline version control, and ensure consistent infrastructure as code practices for their serverless projects.
Prerequisites
Before we begin, you will need to have the following prerequisites:
An AWS account
A GitHub account
AWS CLI installed and configured with your AWS credentials (see the AWS documentation for instructions)
// main.go
packagemainimport (
"github.com/aws/aws-lambda-go/events""github.com/aws/aws-lambda-go/lambda")
funchello() (events.APIGatewayProxyResponse, error) {
returnevents.APIGatewayProxyResponse{
Body: "Hello World!",
StatusCode: 200,
}, nil}
funcmain() {
// Make the handler available for Remote Procedure Call by AWS Lambda
lambda.Start(hello)
}
This file contains the minimal code required to create a Go application that can be deployed to AWS Lambda. It imports the events and lambda packages from the aws-lambda-go library and defines a hello function that returns a response that our API Gateway will return to the client. The main function is the entry point for our application and calls the hello function. The lambda.Start function starts the AWS Lambda handler1.
Step 4: Install dependencies
Next, install the dependencies for your Go application:
go get github.com/aws/aws-lambda-go/events
go get github.com/aws/aws-lambda-go/lambda
This will install aws-lambda-go/events, which contains the APIGatewayProxyResponse struct, and aws-lambda-go/lambda, which contains the lambda.Start function.
Step 5: Create the remote backend
We will use S3 as our remote backend for Terraform. This is necessary because we will be using GitHub Actions to deploy our code and we need to store the Terraform state in a remote location.
NOTE We will not be creating a DynamoDB table for state locking to keep things simple, but you should consider doing this if you are deploying to production. You can read more about this in the Terraform documentation.
To create the S3 bucket for our remote backend, we will use the following command:
Alternatively, you can create the bucket using the AWS Console following the instructions in the AWS documentation.
Step 6: Creating the Terraform configuration
Now that we have created our Go application and installed the dependencies, we can create the Terraform configuration. We will use the following Terraform configuration to deploy our Go application to AWS Lambda:
Step 7: Configure AWS credentials for GitHub Actions
To configure AWS credentials for GitHub Actions, we will use OIDC federation. This is a secure way to authenticate with AWS without having to store your AWS credentials in your GitHub repository.
We will need to follow the following steps to configure AWS credentials for GitHub Actions:
Open the AWS Console and navigate to the IAM service.
Click on “Identity providers” in the left navigation bar.
Click on “Add provider”.
Select “OpenID Connect” as the provider type.
For “Provider URL”, enter https://token.actions.githubusercontent.com2.
Next, we will need to create an IAM role for GitHub Actions. We will need to follow the following steps to create an IAM role for GitHub Actions:
Click on the provider you just created. It should be called “token.actions.githubusercontent.com”.
Click on “Assign role”.
Select “Create a new role” and click on “Next”.
For “Identity provider”, select “token.actions.githubusercontent.com”.
For Audience, enter sts.amazonaws.com.
Click on “Next: Permissions”.
Select “AmazonS3FullAccess”, “AWSLambdaFullAccess”, “IAMFullAccess”, and “AmazonAPIGatewayAdministrator” and click on “Next: Tags”.
Click on “Next: Review”.
For “Role name”, enter github-actions and click on “Create role”.
Search for the role you just created and click on it.
Copy the “ARN” (It should look something like arn:aws:iam::000000000000:role/github-actions). You will need this in the next step.
NOTE: You should consider using a more restrictive IAM policy for your GitHub Actions IAM role.
Step 8: Create the GitHub Actions workflow
Next, we will create the GitHub Actions workflow. We will use the following workflow to deploy our Go application to AWS Lambda:
Do not forget to replace <IAM_ROLE> with the IAM role ARN you created in the previous step.
# .github/workflows/deploy.ymlname: 'Deploy'on:
push:
branches: [ "main" ]
pull_request:
workflow_dispatch:
permissions:
id-token: writecontents: readjobs:
terraform:
name: 'Terraform'runs-on: ubuntu-latestenvironment: productiondefaults:
run:
shell: bashsteps:
# Checkout the repository to the GitHub Actions runner - name: Checkoutuses: actions/checkout@v3# Configure AWS Credentials# You will need to replace <IAM_ROLE> with the IAM role ARN you created in the previous step - name: Configure AWS Credentialsuses: aws-actions/configure-aws-credentials@v2with:
role-to-assume: <IAM_ROLE>aws-region: us-east-1 - name: Setup Terraformuses: hashicorp/setup-terraform@v1 - name: Setup Go environmentuses: actions/setup-go@v4.0.1# This step builds the Go application and creates a zip file containing the binary# It is important to note that the binary must be named "bootstrap" - name: Build Go applicationrun: | GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bootstrap main.go
zip lambda-handler.zip bootstrap# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. - name: Terraform Initrun: terraform init - name: Terraform Formatrun: terraform fmt -check - name: Terraform Planrun: terraform plan -input=false - name: Output ref and event_namerun: | echo ${{github.ref}}
echo ${{github.event_name}}# On push to "main", build or change infrastructure according to Terraform configuration files - name: Terraform Applyif: github.ref == 'refs/heads/main' && github.event_name == 'push'run: terraform apply -auto-approve -input=false - name: Output API Gateway invocation URLif: github.ref == 'refs/heads/main' && github.event_name == 'push'run: | terraform output api_endpoint
Step 9: Deploy the Go application to AWS Lambda
Now that we have created the GitHub Actions workflow, we can push our code to GitHub and let GitHub Actions deploy our Go application to AWS.
git add .
git commit -m "Deploy Go application to AWS Lambda"git push --set-upstream origin main
You can view the GitHub Actions workflow by going to the “Actions” tab in your GitHub repository.
Step 10: Test the API
Now that we have deployed our Go application to AWS Lambda, we can get the API Gateway invocation URL by going to the “Actions” tab in your GitHub repository and clicking on the latest workflow run. Then seeing the output of the “Output API Gateway invocation URL” step.
If we make a request to the API Gateway invocation URL, we should see the following response:
Conclusion
In this article, we explored how to deploy Go-based applications to AWS Lambda using GitHub Actions and Terraform. By combining these tools, developers can automate the deployment process, streamline version control, and ensure consistent infrastructure as code practices for their serverless projects.
You can find the source code for this article in the GitHub repository.