Best Practices to structure your Infrastructure Code.
April 26, 2023
What is Infrastructure as Code
The concept of Infrastructure as Code (IaC) entails managing and provisioning infrastructure through code, rather than manual configuration of components such as servers and networks. This methodology leverages tools such as CloudFormation, Terraform, and Ansible to define infrastructure as code, which can be version controlled, tested, and deployed like any other software code.
IaC has numerous benefits
Infrastructure can be managed efficiently
consistency across different environments
reliable infrastructure deployment
ability to quickly scale and replicate infrastructure in response to changing demands.
Adopting IaC can help organisations simplify their infrastructure management processes, minimise the risk of human error, and improve their agility and flexibility in operations.
Terraform is a popular open-source tool for managing infrastructure as code, developed by HashiCorp. With Terraform, developers can define and provision infrastructure resources across multiple cloud providers, including AWS, Azure, and Google Cloud Platform, as well as on-premises data centers. The tool uses a declarative configuration language to define infrastructure resources and their dependencies, which can then be version controlled, tested, and shared like any other code. Terraform offers a range of features, including support for modules, which allow for reusable infrastructure components, and the ability to plan and preview infrastructure changes before they are applied. With Terraform, organisations can automate the provisioning and management of their infrastructure, reducing the risk of manual errors and improving consistency and reliability.
Best Practices for Structuring Terraform Code
Structuring Terraform code in a way that separates core infrastructure and application infrastructure can help ensure consistency, reduce complexity, and facilitate management. One recommended best practice is to use a modular design, where infrastructure components are separated into reusable modules that can be shared across different projects.
To separate core infrastructure and application infrastructure, it's important to define a clear boundary between the two. Typically, core infrastructure refers to the foundational resources required to support the application, such as networks, security groups, and database clusters, while application infrastructure includes resources specific to the application, such as servers and load balancers.
One approach is to create separate directories for core infrastructure and application infrastructure, each with their own set of modules. The core infrastructure modules can be organised into a separate module group, which is shared across all applications. The application infrastructure modules can then be organised into separate module groups, each specific to an individual application.
Another recommended practice is to use naming conventions and tags to distinguish between core and application infrastructure. For example, resources related to core infrastructure could be prefixed with "core-", while resources related to application infrastructure could be prefixed with the application name.
By separating core infrastructure and application infrastructure, Terraform code can be structured in a way that is more modular, maintainable, and scalable, while also facilitating the reuse of infrastructure components across different projects.
Techwondoe's structure for one of its major clients...
For one of our client's projects, we selected Google Cloud Platform as the ideal solution, and to take advantage of its benefits, we opted to write Infrastructure as Code (IaC). However, we had to consider how to effectively manage this infrastructure code. Initially, we placed the infrastructure code alongside the application code in each application's repository using Terraform. Later, we moved all the infrastructure code to a separate repository that encompassed both core and application infrastructure. Finally, we decided to further separate the core and application infrastructures into their own dedicated repositories.
Our infra-core repository is structured like this
├── infra-core │ ├── database │ ├── main.tf │ ├── security │ ├── main.tf │ ├── secrets │ ├── main.tf │ ├── storage │ ├── main.tf │ ├── networking │ ├── main.tf │ ├── monitoring │ ├── main.tf │ ├── main.tf │ ├── variables.tf │ ├── dev.tfvars │ ├── prod.tfvars │ └── staging.tfvars
Our infra-application repository is structured like this. All the components used in this project are serverless components.
├── application │ ├── cloudrun │ ├── main.tf │ ├── lambda-bucket │ ├── main.tf │ ├── lambda-http-v2 │ ├── main.tf │ ├── lambda-schedule │ ├── main.tf │ ├── main.tf │ ├── variables.tf │ ├── dev.tfvars │ ├── prod.tfvars │ └── staging.tfvars
By separating the core and application infrastructure modules into their own dedicated repositories, we can ensure that changes to one do not unintentionally impact the other. This directory structure also makes it easier to manage infrastructure changes across different environments, as the
environment-specific.tfvars files are kept separate and can be modified independently.
It's always interesting to learn from different perspectives and approaches. So, I'd like to turn the question to you, the viewers:
How do you approach structuring your Terraform code for core and application infrastructure? Do you keep them in separate repositories, or do you keep them in a single repository? Share your experiences and thoughts in the comments below!