Running infrastructure at any scale almost always guarantees a dizzying array of components and configurations. To further complicate things, different teams within an organization may have the need for similar infrastructures with slight variations. That infrastructure may be spread over multiple topographies, from on-premise to one or more cloud vendors.
While it is possible to use infrastructure providers’ user or command line interfaces to spin up and configure components one at a time, the end result is typically hard to organize and maintain in a simple and straightforward way.
At Fairwinds, we build Kubernetes infrastructure for clients that is scalable, secure, and reliable. Along with running applications with Kubernetes, our work includes configuring networking, compute resources, storage, as well as supporting components like monitoring. To ensure that best practices for building infrastructure are maintained for all our clients, we use common patterns for our clients that provide both consistency and customization where needed.
Terraform is our tool of choice to manage the entire lifecycle of infrastructure using infrastructure as code. That means declaring infrastructure components in configuration files that are then used by Terraform to provision, adjust and tear down infrastructure in various cloud providers.
For example, say you are working in AWS and would like to spin up several EC2 instances of a specific type. You would define the type and number of instances in a configuration file, and Terraform would use that to communicate with the AWS API to create those instances. The same file could then be used to adjust the configuration, for example increasing or decreasing the number of instances.
Because infrastructure typically includes many more components than just compute instances, we use a Terraform feature called modules to combine multiple infrastructure components into large, reusable, and shareable chunks.
For the remainder of this post, we will set the stage by diving into some of Terraform’s core elements. If you have never used Terraform and are looking for more hands on experience, the tutorials at Hashicorp’s site are useful.
Let’s talk a little bit about Terraform providers. Terraform has more than 100 cloud providers it serves. At Fairwinds we use Terraform for three - AWS, GCP, and Azure. The provider is what enables interfacing with the specific API and exposes whatever resource you have defined. HCL, or HashiCorp Language is the common language used to define a resource, no matter what provider is being used.
The first resource that will need to be defined in any project using Terraform is the provider, as this is what gives you access to the API you will be interacting with to create resources. Once the provider has been configured and authenticated, a vast amount of resources are now available to be created. Each cloud provider has their own set of resources; a few examples are an
google_dns_record_set, and an
azuread_application. Resources, according to Terraform, are “the most important element in the Terraform language”. This is where you describe the piece of infrastructure to be created; and this can range from a compute instance to defining specific permissions and much more.
In most cases, you will want more configuration than what the basic examples show in the Terraform docs, and the terraform vpc resource for AWS provides in detail the argument references that are required and optional; as well as what attributes you will have access to within this resource. Using the docs, you could spin up many resources with Terraform that would likely meet all the needs you have.
Now that we’ve outlined how Terraform interacts with various providers to create and manage resources, let’s talk about best practices for maintaining and organizing projects.
Terraform offers a great way to package and reuse common code in the form of modules. Terraform modules are comparable to functions or methods in scripting or programming languages. They present a standard interface for creating resources by providing inputs and returning outputs. Modules also simplify projects by increasing readability and allowing teams to organize infrastructure in logical blocks. Modules can be easily shared and sourced into any Terraform project.
Modules are generally used as a simpler interface for creating and managing multiple resources. This greatly cuts down on the amount of duplicate code in a project. It can be tedious copying and pasting sections of code around while only changing a few parameters. For example, if tasked with creating multiple VPCs for different environments - one could invoke a single VPC module multiple times, rather than creating each individual resource necessary for a fully functioning VPC.
Input variables are used to customize the behavior of a module, and potentially, how the resources will be named. Some modules can be very flexible about how, and if, a resource will be created. For example, our Google Cloud VPC module can change behavior based on what inputs are declared. If a user sets
enable_cloud_nat = true the module will then create additional Cloud NAT resources. Check out the official documentation for more information on Input Variables.
Similar to functions, Terraform modules can also return output. This output can be used as input into another module or resource.
State management is a key component to any long term Terraform project. The Terraform state file keeps track of all changes in an environment. State files can also serve as a data source that can be imported by other Terraform projects. By default, the state file is stored on the filesystem. However, it is important to keep the state file safe, secure, and backed up - which generally means keeping it in highly available object storage. By leveraging this remote storage, teams can safely share and interact with a single state that is always current. For additional information, check out the Terraform documentation on remote states, here.
In the following blogs, we will dive deeper into these topics as we demonstrate how to use Terraform to build Kubernetes infrastructure in different cloud providers. Check out our getting started guides for the major cloud providers: