DevOps Fest 2019. Mykyta Protsenko. Infrastructure-as-code: bridging the gap between Devs and Ops2. Who am I?
Mykyta Protsenko
Software developer @ Netflix
(Edge Developer Productivity)
Twitter: @mykyta_p
25. What tools do we need?
aws elb create-load-balancer
--load-balancer-name myELB
--listeners
"Protocol=HTTP,
LoadBalancerPort=80,
InstanceProtocol=HTTP,
InstancePort=80"
--subnets subnet-15aaab61
--security-groups sg-a61988c3
26. Imperative tools?
aws elb create-load-balancer
--load-balancer-name myELB
--listeners
"Protocol=HTTP,
LoadBalancerPort=80,
InstanceProtocol=HTTP,
InstancePort=80"
--subnets subnet-15aaab61
--security-groups sg-a61988c3
28. Cloudformation?
"MyDNSRecord": {
"Type": "AWS::Route53::RecordSet",
"Properties": { "HostedZoneName":
{"Fn::Join":
["", [{"Ref":"HostedZone"},
"."]]},
"Comment" : "DNS for inst.",
"Name" : {"Fn::Join":
["",[{"Ref":"EC2Instance"},
".",{"Ref": "AWS::Region"},
".", {"Ref:"HostedZone"},"."]]},
"Type" : "A",
"TTL" : "300",
"ResourceRecords":
[{"Fn::GetAtt" :
["EC2Instance", PublicIp"]}]}
}
35. Terraform FTW!
resource "aws_ecs_service" "hello-world" {
cluster = "${aws_ecs_cluster.main.id}"
task_definition =
"${aws_ecs_task_definition.hello-world.arn}"
desired_count = "2"
network_configuration {
subnets = ["${aws_subnet.sb_a.id}",...]
security_groups =
["${aws_security_group.web_ecs.id}"]
}
load_balancer {
target_group_arn =
"${aws_alb_target_group.hello-world.id}"
container_name = "helloworld"
container_port = "8080"
}
...
https://github.com/iac-demo
36. Terraform FTW!
resource "aws_ecs_service" "hello-world" {
cluster = "${aws_ecs_cluster.main.id}"
task_definition =
"${aws_ecs_task_definition.hello-world.arn}"
desired_count = "2"
network_configuration {
subnets = ["${aws_subnet.sb_a.id}",...]
security_groups =
["${aws_security_group.web_ecs.id}"]
}
load_balancer {
target_group_arn =
"${aws_alb_target_group.hello-world.id}"
container_name = "helloworld"
container_port = "8080"
}
...
https://github.com/iac-demo
37. Terraform FTW!
resource "aws_ecs_service" "hello-world" {
cluster = "${aws_ecs_cluster.main.id}"
task_definition =
"${aws_ecs_task_definition.hello-world.arn}"
desired_count = "2"
network_configuration {
subnets = ["${aws_subnet.sb_a.id}",...]
security_groups =
["${aws_security_group.web_ecs.id}"]
}
load_balancer {
target_group_arn =
"${aws_alb_target_group.hello-world.id}"
container_name = "helloworld"
container_port = "8080"
}
...
https://github.com/iac-demo
38. Terraform FTW!
resource "aws_alb" "hello-world" {
name = "hello-world"
subnets = [...]
security_groups = [...]
vpc_id = "${aws_vpc.iacdemo_vpc.id}"
}
https://github.com/iac-demo
40. Core Infrastructure
resource "aws_vpc" "iacdemo_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
}
resource "aws_internet_gateway"
"default" {
vpc_id = "${aws_vpc.iacdemo_vpc.id}"
}
...
https://github.com/iac-demo
41. Core Infrastructure
output "vpc_id" {
value = "${aws_vpc.iacdemo_vpc.id}"
}
terraform {
backend "s3" {
key = "iacdemo.tfstate"
region = "us-west-2"
bucket = "demobucket"
}
}
https://github.com/iac-demo
42. Project Infrastructuredata "terraform_remote_state" "core" {
backend = "s3"
config {
key = "iacdemo.tfstate"
region = "us-west-2"
bucket = "demobucket"
}
}
resource "aws_alb" "hello-world" {
name = "hello-world"
...
vpc_id =
"${data.
terraform_remote_state.core.vpc_id}"
}
https://github.com/iac-demo
43. Project Infrastructuredata "terraform_remote_state" "core" {
backend = "s3"
config {
key = "iacdemo.tfstate"
region = "us-west-2"
bucket = "demobucket"
}
}
resource "aws_alb" "hello-world" {
name = "hello-world"
...
vpc_id =
"${data.
terraform_remote_state.core.vpc_id}"
}
https://github.com/iac-demo
50. State of the world
terraform {
backend "s3" {
key = "iacdemo.tfstate"
region = "us-west-2"
bucket = "demobucket"
dynamodb_table =
"table_for_locking"
}
}
59. Terraform modules
variable "service_name" {}
variable "docker_image" {}
resource "aws_ecs_task_definition"
"service" {
family = "${var.service_name}"
container_definitions = <<DEF
[{
...
"image": "${var.docker_image}",
"name": "${var.service_name}"
...
}]DEF
}
61. Terraform modulesmodule "hello_world" {
source = "./microservice_module"
service_name = "helloworld1"
docker_image= "helloworld:latest"
}
module "another_hello_world" {
source = "./microservice_module"
service_name = "helloworld2"
docker_image= "helloworld:latest"
}
69. Create Before Destroy
resource "aws_alb" "hello-world" {
...
lifecycle {
create_before_destroy = "true"
}
}
resource "aws_ecs_service" "hello-world" {
...
lifecycle {
create_before_destroy = "true"
}
}
78. Declarative K8S
$ export DOCKER_IMAGE=hello:latest
$ export SERVICE_NAME=helloworld
$ k8s_template.yaml.sh |
kubectl apply -f -
79. Still Need Core Infra
provider "google" {
project = "breakme-europe"
region = "europe-west1"
}
resource "google_container_cluster"
"main" {
name = "k8s-cluster"
zone = "europe-west1-d"
initial_node_count = 4
node_config {
machine_type = "n1-standard-2"
...
}
...
}
92. Leverage Build System
build.gradle
buildscript {
dependencies {
classpath "com.roku:henka:1.0.0-RELEASE"
}
}
task terraformPlan(type: TerraformTask) {
description "Runs a terraform script"
tfDir = "${projectDir}/terraform"
tfAction = "plan -input=false"
terraformBaseDir = "/opt/terraform"
terraformVersion = "0.11.11"
}
// ...