Terraform-EKS-GitLab

pbates | May 4, 2022, 1:17 a.m.

Terraform AWS EKS GitLab Agent CI/CD

  • [ ] Terraform
  • [ ] EKS
  • [ ] GitLab

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.

Infrastructure as Code IaC Terraform

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.


Providers

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.


State

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

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 Sources

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

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

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
}

Check those boxes!!

  • [X] Terraform
  • [X] EKS

Gitlab CI/CD

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: []

Check the last box!!

  • [X] GitLab