What we will do

  • Create new VPC
  • Create an Internet Gateway and a NAT gateway
  • Define subnets
  • Create security group
  • Create EC2 instance
  • Integration with gitlab CI

Define terraform file

We will create few .tf files:

  1. backend.tf for integration with gitlab CI, we need save state file on AWS S3 bucket, otherwise Terraform will create resources every time we run CI pipeline.
terraform {
  backend "s3" {
    key     = "terraform-pipeline/terraform.tfstate"
    region  = "cn-north-1"
    bucket  = "dev-terraform-state"
    profile = "prod-bj-profile"
  }
}
  1. provider.tf define terraform provider, aws for this article
provider "aws" {
  access_key = "aws-access-key"
  secret_key = "aws-secret-key"
  region     = "cn-north-1"
}
  1. vpc.tf define resources we need to create here, including VPC, EC2, security group etc.
resource "aws_vpc" "DEMO-BJ-VPC" {
  cidr_block           = "192.168.0.0/16"
  enable_dns_hostnames = "true"
  tags = {
    Name = "DEMO-BJ-VPC"
  }
}
resource "aws_internet_gateway" "DEMO-BJ-GW" {
  vpc_id = aws_vpc.DEMO-BJ-VPC.id
  tags = {
    Name = "demo-bj-gw"
  }
}

resource "aws_subnet" "DEMO-BJ-public-a-1" {
  vpc_id            = aws_vpc.DEMO-BJ-VPC.id
  cidr_block        = "192.168.0.0/24"
  availability_zone = "cn-north-1a"
  tags = {
    Name = "DEMO-BJ-public-a-1"
  }
}
resource "aws_subnet" "DEMO-BJ-public-a-2" {
  vpc_id            = aws_vpc.DEMO-BJ-VPC.id
  cidr_block        = "192.168.1.0/24"
  availability_zone = "cn-north-1a"
  tags = {
    Name = "DEMO-BJ-public-a-2"
  }
}

resource "aws_route_table" "cn-north-1a-demo" {
  vpc_id = aws_vpc.DEMO-BJ-VPC.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.DEMO-BJ-GW.id
  }
  tags = {
    Name = "cn-north-1a-demo"
  }
}

resource "aws_main_route_table_association" "cn-north-1a-demo-public" {
  vpc_id = aws_vpc.DEMO-BJ-VPC.id
  route_table_id = aws_route_table.cn-north-1a-demo.id
}

resource "aws_security_group" "demo-bj-ec2-security-group" {
  name        = "demo-bj-ec2-security-group"
  description = "Allow incoming HTTP connections."

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = "demo-bj-ec2-security-group"
  }
  vpc_id = aws_vpc.DEMO-BJ-VPC.id
}

resource "aws_eip" "demo-bj-ec2-eip-1" {
  instance = aws_instance.DEMO-BJ-WEB-SERVER.id
  vpc      = true
  tags = {
    Name = "demo-bj-eip"
  }
}

resource "aws_instance" "DEMO-BJ-WEB-SERVER" {
  ami                         = "ami-xxxxxxxxxx"
  availability_zone           = "cn-north-1a"
  instance_type               = "r5.large"
  key_name                    = "DEMO-BJ-WEB_KeyPair"
  vpc_security_group_ids      = ["${aws_security_group.demo-bj-ec2-security-group.id}"]
  subnet_id                   = aws_subnet.DEMO-BJ-public-a-1.id
  associate_public_ip_address = true
  source_dest_check           = true
  iam_instance_profile        = "AmazonSSMRoleForInstancesQuickSetup"
  tags = {
    Name = "DEMO-BJ-WEB-SERVER"
  }
}

for most of AWS resources, define resource name via tag “Name”

  1. vars.tf define variables, like region
variable "AWS_REGION" {
  default = "cn-north-1"
}

Define gitlab CI file

edit gitlab-ci.yml file, content:

stages:
 - apply

APPLY:
  stage: apply 
  script:
    - terraform init
    - terraform plan -out main.tf
    - terraform apply "main.tf"

conclusion

Terraform is an awesome tool for managing resources on cloud platform, now you can run gitlab CI job to deploy vpc and EC2 instance in AWS.