A Production Ready EKS Deployment with IaC & GitOps - Part 3 - Backend & Provider Configuration
In this part of the series, we will provision an AWS EKS Cluster using Terraform. To maintain infrastructure as code (IaC), we are using Terraform to define and manage the EKS cluster and related resources in an automated and repeatable manner. Before diving into the actual cluster provisioning, let’s go through the file structure and the Terraform backend & provider configurations that will be used throughout this guide. Terraform File Structure Our initial Terraform setup is structured as follows: ├── terraform.tf ├── main.tf ├── variables.tf We will add more terraform files here for other components such as vpc, eks etc.. terraform.tf: The Foundation The terraform.tf file serves as the foundational configuration file for our Terraform project. It contains two critical sections: Backend Configuration backend "s3" { bucket = "opsninja-tf-state-prod" region = "us-east-1" key = "opsninja/v1/terraform-prod.tfstate" dynamodb_table = "opsninja-tf-state-prod" } In Part 2 of this article series we provisioned the S3 bucket and the DynamoDB table. You should use the same table name and bucket name here. This configuration specifies where Terraform should store its state file. Using an S3 bucket with DynamoDB for state locking is a common practice in production environments, ensuring safe concurrent access to the infrastructure state. Here's what each property does: bucket - The name of the S3 bucket where Terraform will store the state file region - The AWS region where the S3 bucket is located key - The path within the S3 bucket where the state file will be stored. In your case: opsninja/v1/terraform-prod.tfstate represents the full path to the state file dynamodb_table - The name of the DynamoDB table used for state locking. This prevents multiple users from modifying the infrastructure at the same time This configuration ensures your Terraform state is stored remotely and can be accessed securely by team members while preventing concurrent modifications. Provider Requirements required_providers { aws = { source = "hashicorp/aws" version = "5.76.0" } # Additional providers... } This section defines all the providers needed for our infrastructure and their specific versions, ensuring consistency across team members and environments. main.tf: Provider Configuration The main.tf file focuses on configuring the providers declared in terraform.tf. It contains the specific settings and authentication methods for each provider. Key aspects include: AWS Provider Configuration provider "aws" { region = var.region profile = var.profile default_tags { tags = { application_name = var.app application_env = var.env terraform = "true" managed_by = "Terraform" } } } This configuration sets up AWS-specific settings, including default tags that will be applied to all resources. Kubernetes-Related Providers The file also includes configurations for kubectl, kubernetes, and helm providers, all necessary for managing Kubernetes resources. variables.tf: Variable Definitions The variables.tf file defines all the variables used across our Terraform configuration: variable "app" { description = "Application name" type = string default = "opsninja" } This file makes our configuration more flexible and reusable across different environments. Now that we have a clear idea about what our project structure is, you can add the following files to your terraform project. terraform.tf terraform { backend "s3"{ bucket = "opsninja-tf-state-prod" region = "us-east-1" key = "opsninja/v1/terraform-prod.tfstate" dynamodb_table = "opsninja-tf-state-prod" } required_providers { aws = { source = "hashicorp/aws" version = "5.76.0" } random = { source = "hashicorp/random" version = "~> 3.5.1" } tls = { source = "hashicorp/tls" version = "~> 4.0.4" } cloudinit = { source = "hashicorp/cloudinit" version = "~> 2.3.2" } helm = { source = "hashicorp/helm" version = "~> 2.11.0" } kubectl = { source = "alekc/kubectl" version = ">= 2.0.0" } } required_version = "~> 1.3" } main.tf provider "aws" { region = var.region profile = var.profile default_tags { tags = { application_name = var.app application_env = var.env terraform = "true" managed_by = "Terraform" } } } provider "kubectl" { apply_retry_count = 15 host = module.eks.cluster_endpoint cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) load_config_file = false exec {
In this part of the series, we will provision an AWS EKS Cluster using Terraform. To maintain infrastructure as code (IaC), we are using Terraform to define and manage the EKS cluster and related resources in an automated and repeatable manner.
Before diving into the actual cluster provisioning, let’s go through the file structure and the Terraform backend & provider configurations that will be used throughout this guide.
Terraform File Structure
Our initial Terraform setup is structured as follows:
├── terraform.tf
├── main.tf
├── variables.tf
We will add more terraform files here for other components such as vpc, eks etc..
terraform.tf: The Foundation
The terraform.tf
file serves as the foundational configuration file for our Terraform project. It contains two critical sections:
- Backend Configuration
backend "s3" {
bucket = "opsninja-tf-state-prod"
region = "us-east-1"
key = "opsninja/v1/terraform-prod.tfstate"
dynamodb_table = "opsninja-tf-state-prod"
}
In Part 2 of this article series we provisioned the S3 bucket and the DynamoDB table. You should use the same table name and bucket name here.
This configuration specifies where Terraform should store its state file. Using an S3 bucket with DynamoDB for state locking is a common practice in production environments, ensuring safe concurrent access to the infrastructure state.
Here's what each property does:
bucket
- The name of the S3 bucket where Terraform will store the state fileregion
- The AWS region where the S3 bucket is located-
key
- The path within the S3 bucket where the state file will be stored. In your case:-
opsninja/v1/terraform-prod.tfstate
represents the full path to the state file
-
dynamodb_table
- The name of the DynamoDB table used for state locking. This prevents multiple users from modifying the infrastructure at the same time
This configuration ensures your Terraform state is stored remotely and can be accessed securely by team members while preventing concurrent modifications.
- Provider Requirements
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.76.0"
}
# Additional providers...
}
This section defines all the providers needed for our infrastructure and their specific versions, ensuring consistency across team members and environments.
main.tf: Provider Configuration
The main.tf
file focuses on configuring the providers declared in terraform.tf
. It contains the specific settings and authentication methods for each provider. Key aspects include:
- AWS Provider Configuration
provider "aws" {
region = var.region
profile = var.profile
default_tags {
tags = {
application_name = var.app
application_env = var.env
terraform = "true"
managed_by = "Terraform"
}
}
}
This configuration sets up AWS-specific settings, including default tags that will be applied to all resources.
- Kubernetes-Related Providers The file also includes configurations for kubectl, kubernetes, and helm providers, all necessary for managing Kubernetes resources.
variables.tf: Variable Definitions
The variables.tf
file defines all the variables used across our Terraform configuration:
variable "app" {
description = "Application name"
type = string
default = "opsninja"
}
This file makes our configuration more flexible and reusable across different environments.
Now that we have a clear idea about what our project structure is, you can add the following files to your terraform project.
terraform.tf
terraform {
backend "s3"{
bucket = "opsninja-tf-state-prod"
region = "us-east-1"
key = "opsninja/v1/terraform-prod.tfstate"
dynamodb_table = "opsninja-tf-state-prod"
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.76.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.5.1"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0.4"
}
cloudinit = {
source = "hashicorp/cloudinit"
version = "~> 2.3.2"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.11.0"
}
kubectl = {
source = "alekc/kubectl"
version = ">= 2.0.0"
}
}
required_version = "~> 1.3"
}
main.tf
provider "aws" {
region = var.region
profile = var.profile
default_tags {
tags = {
application_name = var.app
application_env = var.env
terraform = "true"
managed_by = "Terraform"
}
}
}
provider "kubectl" {
apply_retry_count = 15
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
load_config_file = false
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
}
}
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
}
}
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
command = "aws"
}
}
}
variables.tf
##### Globals #####
variable "app" {
description = "Application name. Used as a prefix to most resources created (Ex: Policies)"
type = string
default = "opsninja"
}
variable "env" {
description = "Environment. Used to prefix most resources to identify resources environment-wise"
type = string
default = "prod"
}
variable "region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "profile" {
description = "AWS Profile. Used to provision resources"
type = string
default = "terraform"
}