This template offers a solution for deploying a Node.js server and a PostgreSQL database on Google Cloud Platform (GCP) using Terraform, an infrastructure as code tool. By leveraging Terraform's language (HCL), the infrastructure can be deployed across different environments like development, production, staging ensuring that the correct configuration is preserved.
Lumitech is a custom software development company providing professional services worldwide. We partner with technology businesses globally helping them to build successful engineering teams and create innovative software products. We’re a global team of software engineers, AI and ML specialists, product managers, and technology experts who have achieved a 600% growth rate since 2022. When a rocket launches toward the moon, it doesn’t stop halfway. Neither do we.
The infrastructure includes the following components:
- VPC Network: A Virtual Private Cloud network to securely connect your resources.
- Cloud Run: A fully managed environment for deploying and scaling containerized applications.
- Cloud SQL: A fully managed relational database service for PostgreSQL.
- IAM Roles: Identity and Access Management roles for handling migrations, deployment, and secrets access.
- CI/CD: Prisma database migration and deployment configurations triggered on branch updates.
Before you begin, ensure you have the following prerequisites:
- Terraform CLI: Install Terraform by following the installation guide.
- gcloud CLI: Install the Google Cloud SDK by following the installation guide.
- Basic Knowledge of Terraform: Familiarize yourself with Terraform by following this tutorial.
- GCP Project: Create a Google Cloud Platform project with billing enabled. Follow the creation guide and billing setup guide.
- IAM Roles: Ensure your IAM Principal has the following roles:
- Cloud Run Admin
- Editor
- Project IAM Admin
- Secret Manager Admin
- Service Account Admin
- Service Networking Admin
- gcloud Authentication: Authenticate to the gcloud CLI in your terminal -
gcloud auth login. A detailed guide you can find here. - GitHub Repository Connection: Connect your GitHub repository to GCP Cloud Build. Follow this guide.
- Copy Template Files: Copy the files from the template to your project directory. The following files are required:
migration-cloudbuild.yamlandcloudbuild.yaml.tfdirectory files withdevandmodulesfolders..gitignorewith necessary files to be ignored from Terraform.
- Input Variables: Update the
terraform.tfvarsfile inside thetf/devdirectory. Update the mock data with your project variables.- In this file, you provide the variables of the infrastructure to be created — service name, database name, GitHub repository, etc.
- If you are using VSCode, you can install the Terraform extension.
- Infrastructure Creation: Go to
tf/devdirectory in your terminal and apply the following commands:terraform init- Initialize the dependencies of your project.terraform apply- Create the infrastructure on GCP. You will be prompted to confirm the changes. This step takes approximately 20 minutes.terraform init -migrate-state- Migrate the state to GCP after the infrastructure creation. The state will be stored on Google Cloud Storage instead of in local files.
- Save Changes: Push the changes to your GitHub repository with
git push. This step will trigger first deployment and migration actions on Cloud Build. - Unset Temporary Image: Set the Cloud Run dummy image variable to false after the first successful deployment. You do not need to run terraform apply again, as the new image is already in use.
To provide a new secret environment variable to the Cloud Run container, proceed with the following steps:
- Create a new secret variable in the Secret Manager. You can follow the steps in the Secret Manager documentation.
- Add an environment prefix if the variable will be used only for the current environment. e.g.
dev-secret-name
- Add an environment prefix if the variable will be used only for the current environment. e.g.
- Copy the secret ID from the secret details page. Secret ID example:
projects/123456789101/secrets/dev-secret-name. - Create a Terraform variable with the secret ID as its value.
# tf/dev/variables.tf
variable "example_secret_for_cloud_run" {
type = string
}
# ... other variable declarations# tf/dev/terraform.tfvars
example_secret_for_cloud_run = "projects/123456789102/secrets/dev-some-secret"
# ... other variables- Pass the secret ID variable to the Cloud Run module.
# tf/dev/main.tf
module "cloud_run" {
...
secret_vars = {
SECRET_NAME = var.example_secret_for_cloud_run
}
...
}- Update the infrastructure on GCP -
terraform applyand confirm the changes.- This step passes the variables to the Cloud Run instance and creates an IAM role with access to the secret ID.
Each environment is defined as a root module with the same reusable submodules. To create another environment (production, staging, etc.), complete the following steps:
- Copy the
tf/devdirectory with the desired environment name (e.g.,tf/prodortf/staging). - Update the environment variables in
terraform.tfvarsto match the environment. - Proceed from step 6 in the Deployment Steps section.
This Terraform template is split into a root module (in tf/dev) and submodules (in tf/modules). By separating environment-specific settings from reusable infrastructure modules, you can quickly replicate environments (e.g., tf/prod, tf/staging) while keeping the same core logic in the submodules.
- Holds environment-level configurations and the main
.tfvarsfile for variables specific to this environment. - References the submodules to provision resources for your chosen environment.
- You can copy this entire directory to create another environment (e.g.,
tf/prod).
Each directory within tf/modules defines a reusable component of the infrastructure:
cloud-run/– Provisions and configures Cloud Run services.cloud-sql/– Manages a Cloud SQL PostgreSQL instance.network/– Sets up a VPC network.project-api/– Enables project-level APIs.secret/– Generate secrets in Secret Manager.
.
├── cloudbuild.yaml
├── Dockerfile
├── LICENSE
├── migration-cloudbuild.yaml
├── README.md
└── tf
├── dev
│ ├── main.tf
│ ├── outputs.tf
│ ├── terraform.tfvars
│ └── variables.tf
└── modules
├── cloud-run
│ ├── iam.tf
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── cloud-sql
│ ├── iam.tf
│ ├── main.tf
│ ├── migration.tf
│ ├── outputs.tf
│ ├── secrets.tf
│ └── variables.tf
├── network
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── project-api
│ └── main.tf
└── secret
├── main.tf
└── variables.tf
- General style and structure guidelines - Google Cloud best practices for Terraform configurations.
- Root modules - Google Cloud best practices for Root modules and Terraform structure.
