pbates | May 4, 2022, 1:17 a.m.
The full life cycle of a declarative, scalable, and secure manged container service.
IaC allows for the managing and provisioning of our infrastructure through code. Scaling
is an important functionality of any infrastructure. The ability to scale up during peak
demand or down to save finances is a critical for business. Using a single source of Truth
to store the configuration and state will allow for a full GitOps workflow.
Terraform is an infrastructure as code tool which can create
and manage resources on several cloud platforms. Terraform code which is written in HCL a
low-level syntax language and all files end in the .tf
extension. The language is primarily
made of arguments and blocks, see code below.
versions.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
kubernetes = {
source = "hashicorp/kubernetes"
}
}
}
provider "aws" {
region = var.region
}
The “Providers” plugin allows Terraform to interact with AWS. This file declares which providers
Terraform will use when initialized. Provider arguments are added to the required_providers
block.
An additional version constraint be added below the source declaration such as version = "~> 14.0.2"
.
Additionally, with the aws provider the region and credentials need to be provided. Later we will use
GitLab to store the creds. For now the region we stored as a variable with the var.nameOfVar
convention.
backend.tf
terraform {
backend "http" {
}
}
The backend configuration will provide the definition for where the state of the infrastructure
will be stored. The state allows Terraform to track the resources and specifically the configuration.
The created manifests will be added to our GitLab repository. By adding the "http"
backend the state
will be securely stored and managed by GitLab.
variables.tf
variable "region" {
default = "us-east-1"
description = "AWS region"
}
variable "cluster_name" {
default = "your cluster name"
description = "EKS Cluster name"
}
variable "cluster_version" {
default = "1.22"
description = "Kubernetes version"
}
variable "instance_type" {
default = "t2.medium"
description = "EKS node instance type"
}
variable "instance_count" {
default = 2
description = "EKS node count"
}
variable "max_instance_count" {
default = 5
description = "EKS node group max scaling"
}
The variables file allows the customization of the Terraform modules from a single file.
This style allows for variables to be shared across multiple terraform modules.
data.tf
data "aws_availability_zones" "available" {}
To create resources with information defined outside of Terraform data resources need to be
declared. The data
block in the above example tells Terraform to read from aws the
available zones within the region declared.
vpc.tf
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = var.cluster_name
cidr = "10.20.0.0/16"
azs = data.aws_availability_zones.available.names
private_subnets = ["10.20.1.0/24", "10.20.2.0/24", "10.20.3.0/24"]
public_subnets = ["10.20.101.0/24", "10.20.102.0/24", "10.20.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
private_subnet_tags = {
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
"kubernetes.io/role/internal-elb" = "1"
}
public_subnet_tags = {
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
"kubernetes.io/role/elb" = "1"
}
}
The VPC configuration has several required inputs for more information see the offical docs
here. This
file uses information from both previously created variable and data files. With the declarations
above Terraform will request several resources such as subnets, routing tables, internet gateways,
and NATs. Also declared are special tags on subnets that will allow for Load Balancer communication.
eks.tf
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_name = var.cluster_name
cluster_version = var.cluster_version
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_group_defaults = {
tags = {
Name = "A Special Name"
Environment = "Staging"
Terraform = "true"
}
}
eks_managed_node_groups = {
staging_mymfg_node = {
min_size = 1
max_size = var.max_instance_count
desired_size = var.instance_count
instance_types = [var.instance_type]
create_launch_template = false
launch_template_name = ""
disk_size = 50
}
}
}
Just as the vpc source the eks has its own set of required inputs which can be found here.
For more information specifically to AWS managed note groups see the following docs.
A Quick modification to the data.tf
file to gather cluster information.
data.tf
data "aws_availability_zones" "available" {}
data "aws_eks_cluster" "cluster" {
name = module.eks.cluster_id
}
data "aws_eks_cluster_auth" "cluster" {
name = module.eks.cluster_id
}
GitLab
is a one-stop shop for the DevOps and GitOps world. Building on top of technologies created
by GitLab we can extend simple templates to use our IaC docs.
The five stages of our pipeline consist are:
- initialization “init”
- validation “validate”
- build “plan”
- deployment “apply”
- clean-up. “destroy”
Above in quotes you can see each stage with its related terraform command. The deployment/apply stage only applies
to the default branch.
.gitlab-ci.yml
include:
- template: Terraform.gitlab-ci.yml
variables:
TF_STATE_NAME: default
stages:
- init
- validate
- build
- deploy
- cleanup
destroy:
extends: .destroy
needs: []