Mit Terraform dynamisch Server in AWS anlegen

Terraform ist eine “Infrastructure as code” Software der Firma Hashicorp. Es ermoeglicht Admins das Beschreiben von Datacenter Infrastrukture um diese wiederholt und schnell auf und abzubauen sowie zu erweitern oder umkonfigureren. Unterstuetzte Provider sind aktuell, OpenStack, AWS, Microsoft Azure, Google Cloud Platform, IBM Cloud (formerly Bluemix), Oracle Cloud Infrastructure, VMware vSphere und Scaleway.

Um sich Vorstellen zu koennen wie hilfreich die Software ist und das der anfaengliche Aufwand fuer die Implementierung Sinn macht, moechte ich ein Szenario skizzieren.
Stellen wir uns vor, wir bauen eine geclusterte Container Umgebung mit 17 Worker/Manager und Loadbalancer in AWS auf. Es gibt verschiedene Halbautomatisierte Loesungen um diese Server in AWS zu erstellen, mit Netzwerk und Security Groups zu verknuepfen und anschliessend via Ansible zu konfigurieren. Moechte man spaeter die Umgebung erweitern, bedeutet das wieder manueller Eingriff. Die gleiche Umgebung als Prod, QA und Dev Umgebung Aufzubauen erhoet den Aufwand noch einmal. Terraform gibt uns nun die Moeglichkeit, die Umgebung in einer Art Programmiersprache zu Beschreiben und so oft ausrollen wie wir es benoetigen. Checken wir die Terraform Scripte in git ein, koenntne wir sogar jederzeit zu einem aelteren Stand zurueckkehren. D.h. wenn z.B. unser 17Node Cluster ausgelastet ist und wir erweitern diesen ueber Weihnachten, koennten wir wenige Tage spaeter diese Erweiterung zuruecknehmen. Terraform bietet uns also die Moeglichkeit mit Infrastuktur hoch flexibel umzugeben. Fuer eine ordentliche Blue/Green Pipeline fast unersetzlich.

Nachfolgend moechte ich an einem Beispiel zeigen, wie man Netzwerk, SecurityGroup, DNS und die Server Ressource von ‘n’ Servern beschreibt. Als Beispiel hier HAProxy!

Variablen

Hier beschreiben wir Variablen die uns ermoeglichen recht schnell Konfiguration aendern.

variable "aws_region" {
  description = "Region for the VPC"
  default = "eu-central-1"
}

variable "vpc_cidr" {
  description = "CIDR for the VPC"
  default = "10.0.0.0/16"
}

variable "public_subnet_cidr" {
  description = "CIDR for the public subnet"
  default = "10.0.1.0/24"
}

variable "ami" {
  description = "CentOS"
  default = "ami-dd3c0f36"
}

variable "key_path" {
description = "SSH Public Key path"
  default = "~/.ssh/aws.pub"
}

variable "key_name" {
  default = "aws"
}

variable "haproxy_count" {
  default = "5"
}

variable "public_domain" {
  type = "string"
  description = "Public domain name"
  default = "example.com"
}

Security Group

resource "aws_security_group" "sg_public_haproxy" {
  name = "vpc_haproxy"
  description = "Allow HAPRoxy access"

  ingress {
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks =  ["0.0.0.0/0"]
  }
  ingress {
    from_port = 80
    to_port = 80
    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"]
  }
  ingress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["${var.public_subnet_cidr}"]
  }
  vpc_id="${aws_vpc.default.id}"
  tags {
    Name = "Public HAProxy"
  }
}

Resource

Dies ist die eigentliche Beschreibung des Servers inkl. DNS Eintrag.


resource "aws_instance" "haproxy" {
  count = "${var.haproxy_count}"
  ami  = "${var.ami}"
  instance_type = "t2.small"
  key_name = "${aws_key_pair.default.id}"
  subnet_id = "${aws_subnet.public-subnet.id}"
  vpc_security_group_ids = ["${aws_security_group.sg_public_haproxy.id}"]
  associate_public_ip_address = true
  source_dest_check = false

tags {
    Name = "haproxy${count.index}"
  }
}


# Create DNS record
resource "aws_route53_record" "haproxy" {
    count = "${var.haproxy_count}"
    zone_id = "${aws_route53_zone.public.zone_id}"
    name = "haproxy${count.index}.${aws_route53_zone.public.name}"
    type = "A"
    ttl = 60
    records = [
        "${aws_instance.haproxy.*.public_ip[count.index]}"
    ]
}