Share
Embed
Build, provision & deploy in the Cloud with Packer, Ansible & Terraform – Confoo 2018
See https://feryn.eu/speaking/build-provision-deploy-cloud-packer-ansible-terraform-confoo-2018/ for more information
Thijs Feryn PRO
March 08, 2018
Transcript
103 slides
-
By Thijs Feryn Build, provision & deploy in the Cloud
with Packer, Ansible & Terraform -
✓ Less lock-in ✓ Faster deployments ✓ Better scalability ✓
Better reproducibility ✓ Less human error ✓ Lower cost ✓ Operational stability Goals -
✓ Alicloud ECS ✓ Amazon EC2 ✓ Azure ✓ CloudStack
✓ DigitalOcean ✓ Docker ✓ File ✓ Google Cloud ✓ Hyper-V ✓ LXC ✓ LXD ✓ Null ✓ 1&1 ✓ OpenStack ✓ Oracle OCI ✓ Parallels ✓ ProfitBricks ✓ QEMU ✓ Triton ✓ VirtualBox ✓ VMware ✓ Custom Packer builders -
{ "builders": [ { "type": "amazon-ebs", "access_key": "", "secret_key": "",
"region": "eu-west-2", "instance_type": "t2.micro", "ssh_username": "admin", "associate_public_ip_address": true, "subnet_id": “subnet-11d3d56a", "source_ami": "ami-e1e8f085", "ami_name": "thijsferyn_{{isotime \"2006_01_02__03_04_05\"}}" } ], "provisioners": [ { "type": "shell", "inline": ["apt-get update","apt-get install -y nginx"] } ] } -
$ aws ec2 describe-images --owners=self --query "Images[*]. {ID:ImageId,Name:Name,Status:State}" --output=table +--------------+-----------------------------------+-------------+
| ID | Name | Status | +--------------+-----------------------------------+-------------+ | ami-82ccd6e6| thijsferyn_2018_01_31__02_26_27 | available | +--------------+-----------------------------------+-------------+ -
✓ Written in Python ✓ Agentless ✓ Standalone ✓ SSH-based
✓ Runs playbook (yml files) ✓ Groups playbook in roles ✓ Install software ✓ Configure your server Ansible -
--- - hosts: all vars: code_folders: - "web" become: true
tasks: - name: update apt cache apt: update_cache=yes cache_valid_time=86400 - name: install required packages apt: name={{ item }} state=present with_items: - vim - curl - nginx - php7.0-fpm - rsync - name: create /var/www/html/ folder file: path: /var/www/html/ state: directory mode: 0755 owner: www-data playbook.yml -
- name: create /var/www/html/ folder file: path: /var/www/html/ state: directory
mode: 0755 owner: www-data - name: Copy code synchronize: src: ../{{ item }} dest: /var/www/html delete: yes recursive: yes group: no owner: no perms: no with_items: "{{code_folders}}" - name: Chown code to www-data file: path: /var/www/html/{{ item }} group: www-data owner: www-data mode: u=rwx,g=r,o=r recurse: yes playbook.yml -
. !"" files # $"" db.sql !"" host_vars # $""
default.yml !"" group_vars # $"" all.yml !"" inventory !"" playbook.yml !"" roles # $"" my-role # !"" defaults # # $"" main.yml # !"" handlers # # $"" main.yml # !"" meta # # $"" main.yml # !"" tasks # # $"" main.yml # !"" templates # # $"" template.j2 # $"" vars # $"" vars.yml !"" tasks # !"" task1.yml # !"" task2.yml $"" templates $"" template.j2 -
--- - hosts: all tasks: - include_tasks: task1.yml - include_tasks:
task2.yml roles: - my-role -
{ "builders": [ { "type": "openstack", "identity_endpoint": "https://osp.combell.com:5000/v3", "tenant_name": "18324-1",
"username": "18324", "password": "", "image_name": "MyBuild-{{isotime \"2006-01-02 03:04:05\"}}", "source_image": "1b9fe43e-4cf2-4986-b7f2-51f5706b120b", "ssh_username": "debian", "domain_name" : "default", "flavor": "m1.medium", "networks": ["a1175c54-cb12-436d-ac7b-d327499dc39b"], "floating_ip_pool" : "public" } ], "provisioners": [ { "type": "ansible", "playbook_file": "./ansible/playbook.yml" } ] } -
"image_name": "MyBuild-{{isotime \"2006-01-02 03:04:05\"}}", "source_image": "1b9fe43e-4cf2-4986-b7f2-51f5706b120b", "ssh_username": "debian", "domain_name" :
"default", "flavor": "m1.medium", "networks": ["a1175c54-cb12-436d-ac7b-d327499dc39b"], "floating_ip_pool" : "public" } ], "provisioners": [ { "type": "ansible", "playbook_file": "./ansible/playbook.yml" } ], "post-processors": [ { "type": "manifest", "output": "manifest.json" } ] } -
{ "builds": [ { "name": "amazon-ebs", "builder_type": "amazon-ebs", "build_time": 1517408990,
"files": null, "artifact_id": "eu-west-2:ami-82ccd6e6", "packer_run_uuid": "ba98283c-08ca-a9fc-ab10-e49502ce4ab6" }, { "name": "openstack", "builder_type": "openstack", "build_time": 1509053610, "files": null, "artifact_id": "ef90ad1c-ed64-4ae0-8283-e446e95c33e6", "packer_run_uuid": "b6000539-f3e6-85dd-2733-9fb3ae443e9f" } ], "last_run_uuid": "b6000539-f3e6-85dd-2733-9fb3ae443e9f" } -
✓ Launch virtual network ✓ Boot up webservers ✓ Configure
firewalls ✓ Assign loadbalancers ✓ Create DNS-records ✓ Assign SSH keys ✓ Create autoscaling group Orchestration -
✓ CloudFormation (AWS) ✓ Heat (OpenStack) ✓ Resource manager (Azure)
Vendor-specific orchestration tools -
✓ Infrastructure As Code ✓ Plan, graph, execute ✓ State
management ✓ Multiple providers ✓ Incremental changes ✓ Interacts with Cloud vendor APIs Terraform -
✓ Alicloud ✓ Archive ✓ Arukas ✓ AWS ✓ Bitbucket
✓ CenturyLinkCloud ✓ Chef ✓ Circonus ✓ Cloudflare ✓ CloudStack ✓ Cobbler ✓ Consul ✓ Datadog ✓ DigitalOcean ✓ DNS ✓ DNSMadeEasy ✓ DNSimple ✓ Docker ✓ Dyn ✓ External ✓ Fastly ✓ GitHub ✓ Gitlab ✓ Google Cloud ✓ Grafana ✓ Heroku ✓ HTTP ✓ Icinga2 ✓ Ignition ✓ InfluxDB ✓ Kubernetes ✓ Librato ✓ Local ✓ Logentries ✓ LogicMonitor ✓ Mailgun ✓ Microsoft Azure ✓ Microsoft Azure (Legacy ASM) ✓ MySQL ✓ New Relic ✓ Nomad ✓ NS1 ✓ 1&1 ✓ Oracle Public Cloud ✓ OpenStack ✓ OpsGenie ✓ OVH ✓ Packet ✓ PagerDuty ✓ PostgreSQL ✓ PowerDNS ✓ ProfitBricks ✓ RabbitMQ ✓ Rancher ✓ Random ✓ Rundeck ✓ Scaleway ✓ SoftLayer ✓ StatusCake ✓ Spotinst ✓ Template ✓ Terraform ✓ Terraform Enterprise ✓ TLS ✓ Triton ✓ UltraDNS ✓ Vault ✓ VMware vCloud Director ✓ VMware vSphere Terraform providers -
variable "ami" { type = "string" default = "ami-e1e8f085" #Stock
Debian Stretch } resource "aws_instance" "web" { ami = "${var.ami}" instance_type = "t2.micro" security_groups = ["Web"] tags { Name = "web" } } data "aws_route53_zone" "web" { name = "aws.combell.com." } resource "aws_route53_record" "web" { zone_id = "${data.aws_route53_zone.web.zone_id}" name = "thijsferyn-web.${data.aws_route53_zone.web.name}" type = "A" ttl = "60" records = ["${aws_instance.web.public_ip}"] } output "public_ip" { value = "${aws_instance.web.public_ip}" } output "hostname" { value = "${aws_route53_record.web.name}" } -
$ terraform init Initializing provider plugins... - Checking for available
provider plugins on https://releases.hashicorp.com... - Downloading plugin for provider "aws" (1.8.0)... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 1.8" Terraform has been successfully initialized! -
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: + aws_instance.web id: <computed> ami: "ami-e1e8f085" associate_public_ip_address: <computed> availability_zone: <computed> ebs_block_device.#: <computed> ephemeral_block_device.#: <computed> instance_state: <computed> instance_type: "t2.micro" ipv6_address_count: <computed> ipv6_addresses.#: <computed> key_name: <computed> network_interface.#: <computed> network_interface_id: <computed> placement_group: <computed> primary_network_interface_id: <computed> private_dns: <computed> private_ip: <computed> public_dns: <computed> public_ip: <computed> root_block_device.#: <computed> security_groups.#: "1" security_groups.2661672386: "Web" source_dest_check: "true" subnet_id: <computed> tags.%: "1" tags.Name: "web" tenancy: <computed> volume_tags.%: <computed> vpc_security_group_ids.#: <computed> -
+ aws_route53_record.web id: <computed> fqdn: <computed> name: "thijsferyn-web.aws.combell.com" records.#: <computed>
ttl: "60" type: "A" zone_id: "Z3K2HG3W48B0MR" Plan: 2 to add, 0 to change, 0 to destroy. -
$ terraform output -json { "hostname": { "sensitive": false, "type":
"string", "value": "thijsferyn-web.aws.combell.com" }, "public_ip": { "sensitive": false, "type": "string", "value": "35.178.38.182" } } -
$ terraform show aws_instance.web: id = i-0333e97ea6bdbc5ae ami = ami-e1e8f085
associate_public_ip_address = true availability_zone = eu-west-2a disable_api_termination = false ebs_block_device.# = 0 ebs_optimized = false ephemeral_block_device.# = 0 iam_instance_profile = instance_state = running instance_type = t2.micro ipv6_addresses.# = 0 key_name = monitoring = false network_interface.# = 0 network_interface_id = eni-c62e7193 placement_group = primary_network_interface_id = eni-c62e7193 private_dns = ip-172-31-19-7.eu-west-2.compute.internal -
network_interface_id = eni-c62e7193 placement_group = primary_network_interface_id = eni-c62e7193 private_dns =
ip-172-31-19-7.eu-west-2.compute.internal private_ip = 172.31.19.7 public_dns = ec2-35-178-38-182.eu-west-2.compute.amazonaws.com public_ip = 35.178.38.182 root_block_device.# = 1 root_block_device.0.delete_on_termination = true root_block_device.0.iops = 100 root_block_device.0.volume_id = vol-0b9364527ec09549e root_block_device.0.volume_size = 8 root_block_device.0.volume_type = gp2 security_groups.# = 1 security_groups.763657905 = Web source_dest_check = true subnet_id = subnet-11d3d56a tags.% = 1 tags.Name = web tenancy = default volume_tags.% = 0 vpc_security_group_ids.# = 0 -
aws_route53_record.web: id = Z3K2HG3W48B0MR_thijsferyn-web.aws.combell.com._A fqdn = thijsferyn-web.aws.combell.com health_check_id = name
= thijsferyn-web.aws.combell.com records.# = 1 records.1088376871 = 35.178.38.182 set_identifier = ttl = 60 type = A zone_id = Z3K2HG3W48B0MR data.aws_route53_zone.web: id = Z3K2HG3W48B0MR caller_reference = F7596F57-9ADE-9B0D-8F53-53DF42E03DB3 comment = name = aws.combell.com. private_zone = false resource_record_set_count = 3 zone_id = Z3K2HG3W48B0MR Outputs: hostname = thijsferyn-web.aws.combell.com public_ip = 35.178.38.182 -
✓ Artifactory ✓ Azurerm ✓ Consul ✓ Etcd ✓ Gcs
✓ HTTP ✓ Manta ✓ S3 ✓ Swift ✓ Terraform Enterprise Remote state -
~ update in-place -/+ destroy and then create replacement Terraform
will perform the following actions: -/+ aws_instance.web (new resource required) id: "i-0333e97ea6bdbc5ae" => <computed> (forces new resource) ami: "ami-e1e8f085" => "ami-20ccd644" (forces new resource) associate_public_ip_address: "true" => <computed> availability_zone: "eu-west-2a" => <computed> ebs_block_device.#: "0" => <computed> ephemeral_block_device.#: "0" => <computed> instance_state: "running" => <computed> instance_type: "t2.micro" => "t2.micro" ipv6_address_count: "" => <computed> ipv6_addresses.#: "0" => <computed> key_name: "" => <computed> network_interface.#: "0" => <computed> network_interface_id: "eni-c62e7193" => <computed> placement_group: "" => <computed> primary_network_interface_id: "eni-c62e7193" => <computed> private_dns: "ip-172-31-19-7.eu-west-2.compute.internal" => <computed> private_ip: "172.31.19.7" => <computed> -
key_name: "" => <computed> network_interface.#: "0" => <computed> network_interface_id: "eni-c62e7193"
=> <computed> placement_group: "" => <computed> primary_network_interface_id: "eni-c62e7193" => <computed> private_dns: "ip-172-31-19-7.eu-west-2.compute.internal" => <computed> private_ip: "172.31.19.7" => <computed> public_dns: "ec2-35-178-38-182.eu- west-2.compute.amazonaws.com" => <computed> public_ip: "35.178.38.182" => <computed> root_block_device.#: "1" => <computed> security_groups.#: "1" => "1" security_groups.763657905: "Web" => "Web" source_dest_check: "true" => "true" subnet_id: "subnet-11d3d56a" => <computed> tags.%: "1" => "1" tags.Name: "web" => "web" tenancy: "default" => <computed> volume_tags.%: "0" => <computed> vpc_security_group_ids.#: "0" => <computed> ~ aws_route53_record.web records.#: "" => <computed> Plan: 1 to add, 1 to change, 1 to destroy. -
$ terraform init $ terraform workspace new wsp1 $ terraform
workspace new wsp2 $ terraform workspace select wsp1 $ terraform plan $ terraform apply $ terraform workspace select wsp2 $ terraform plan $ terraform apply -
variable "ami" { type = "string" default = "ami-e1e8f085" #Stock
Debian Stretch } resource "aws_instance" "web" { ami = "${var.ami}" instance_type = "t2.micro" security_groups = ["Web"] tags { Name = "web-${terraform.workspace}" } } output "public_ip" { value = "${aws_instance.web.public_ip}" } Remove DNS resource Interpolate workspace info -
variable "ip" { type = "string" } data "aws_route53_zone" "web"
{ name = "aws.combell.com." } resource "aws_route53_record" "web" { zone_id = "${data.aws_route53_zone.web.zone_id}" name = "thijsferyn-web.${data.aws_route53_zone.web.name}" type = "A" ttl = "60" records = ["${var.ip}"] } output "hostname" { value = "${aws_route53_record.web.name}" } Separate Terraform project -
Deployment B Internet Entry point Drain connections and gradually switch
from deployment A to deployment B Deployment A ROLLING UPDATES -
resource "aws_vpc" "thijsferyn_terraform" { cidr_block = "10.0.0.0/16" tags { Name
= "thijsferyn_${terraform.workspace}_terraform" } } resource "aws_subnet" "thijsferyn_terraform_public" { availability_zone = "eu-west-2a" vpc_id = "${aws_vpc.thijsferyn_terraform.id}" cidr_block = "10.0.0.0/24" tags { Name = "thijsferyn_terraform_${terraform.workspace}_public" } } resource "aws_subnet" "thijsferyn_terraform_private" { availability_zone = "eu-west-2a" vpc_id = "${aws_vpc.thijsferyn_terraform.id}" cidr_block = "10.0.1.0/24" tags { Name = "thijsferyn_terraform_${terraform.workspace}_private" } } Virtual network -
resource "aws_security_group" "thijsferyn_terraform" { name = "thijsferyn-terraform-${terraform.workspace}" description = "Allow
HTTP(S) & SSH" vpc_id = "${aws_vpc.thijsferyn_terraform.id}" ingress { from_port = 80 to_port = 80 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"] } ingress { from_port = 22 to_port = 22 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 = "thijsferyn_terraform-${terraform.workspace}" } } Firewall -
data "aws_ami" "thijsferyn_terraform" { most_recent = true filter { name
= "name" values = ["thijsferyn_*"] } filter { name = "virtualization-type" values = ["hvm"] } owners = ["826481595599"] } resource "aws_launch_configuration" "thijsferyn_terraform" { image_id = "${data.aws_ami.thijsferyn_terraform.id}" instance_type = "t2.micro" security_groups = ["${aws_security_group.thijsferyn_terraform.id}"] lifecycle { create_before_destroy = true } } Prepare VMs -
resource "aws_lb" "thijsferyn_terraform" { name = "thijsferyn-terraform-${terraform.workspace}" internal = false
security_groups = ["${aws_security_group.thijsferyn_terraform.id}"] subnets = ["${aws_subnet.thijsferyn_terraform_public.*.id}","$ {aws_subnet.thijsferyn_terraform_public2.*.id}"] } resource "aws_lb_listener" "thijsferyn_terraform" { load_balancer_arn = "${aws_lb.thijsferyn_terraform.arn}" port = "80" protocol = "HTTP" default_action { target_group_arn = "${aws_lb_target_group.thijsferyn_terraform.arn}" type = "forward" } } resource "aws_lb_target_group" "thijsferyn_terraform" { name = "thijsferyn-terraform-${terraform.workspace}" port = 80 protocol = "HTTP" vpc_id = "${aws_vpc.thijsferyn_terraform.id}" } Load balancing -
resource "aws_autoscaling_group" "thijsferyn_terraform" { availability_zones = ["eu-west-2a"] name = "thijsferyn-terraform-${terraform.workspace}-$
{aws_launch_configuration.thijsferyn_terraform.name}" max_size = 10 min_size = 3 launch_configuration = "${aws_launch_configuration.thijsferyn_terraform.name}" target_group_arns = ["${aws_lb_target_group.thijsferyn_terraform.id}"] health_check_grace_period = 10 health_check_type = "ELB" vpc_zone_identifier = ["${aws_subnet.thijsferyn_terraform_private.id}"] default_cooldown = 60 depends_on = ["aws_launch_configuration.thijsferyn_terraform"] lifecycle { create_before_destroy = true } tag { key = "Name" value = "thijsferyn-terraform-${terraform.workspace}-$ {aws_launch_configuration.thijsferyn_terraform.name}" propagate_at_launch = true } } Autoscaling group -
resource "aws_autoscaling_policy" "thijsferyn_terraform_high" { name = "thijsferyn-terraform-${terraform.workspace}-high" scaling_adjustment = 1
adjustment_type = "ChangeInCapacity" cooldown = 10 autoscaling_group_name = "${aws_autoscaling_group.thijsferyn_terraform.name}" } resource "aws_autoscaling_policy" "thijsferyn_terraform_low" { name = "thijsferyn-terraform-${terraform.workspace}low" scaling_adjustment = -1 adjustment_type = "ChangeInCapacity" cooldown = 10 autoscaling_group_name = "${aws_autoscaling_group.thijsferyn_terraform.name}" } Scale up scale down -
resource "aws_cloudwatch_metric_alarm" "thijsferyn_terraform_high" { alarm_name = "thijsferyn-terraform-${terraform.workspace}-high" comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "1" metric_name = "RequestCountPerTarget" namespace = "AWS/ApplicationELB" period = "60" statistic = "Sum" threshold = "20" dimensions { TargetGroup = "${aws_lb_target_group.thijsferyn_terraform.name}" LoadBalancer = "${aws_lb.thijsferyn_terraform.name}" } alarm_description = "More than 20 requests per target causes scaleout" alarm_actions = ["${aws_autoscaling_policy.thijsferyn_terraform_high.arn}"] } High water mark -
✓ vars.tf ✓ output.tf ✓ secgroup.tf ✓ keypair.tf ✓ compute.tf
✓ network.tf ✓ provider.tf Organize Terraform files -
!"" autoscaling # !"" README.MD # !"" main.tf # !""
outputs.tf # $"" variables.tf !"" dns # !"" README.MD # !"" main.tf # !"" outputs.tf # $"" variables.tf !"" launch # !"" README.MD # !"" main.tf # !"" outputs.tf # $"" variables.tf !"" loadbalancing # !"" README.MD # !"" main.tf # !"" outputs.tf # $"" variables.tf !"" main.tf !"" networking # !"" README.MD # !"" main.tf # !"" outputs.tf # $"" variables.tf -
variable "zone_name" { default = "aws.combell.com." } variable "record_name" {
default = "" } variable "records" { type = "list" } output "dns_endpoint" { value = "${aws_route53_record.thijsferyn_terraform_aws_combell_com.fqdn}" } data "aws_route53_zone" "thijsferyn_terraform_aws_combell_com" { name = "${var.zone_name}" } resource "aws_route53_record" "thijsferyn_terraform_aws_combell_com" { zone_id = "${data.aws_route53_zone.thijsferyn_terraform_aws_combell_com.zone_id}" name = "${var.record_name == "" ? "thijsferyn-terraform${terraform.workspace == "default" ? "" : "-${terraform.workspace}"}": var.record_name}.$ {data.aws_route53_zone.thijsferyn_terraform_aws_combell_com.name}" type = "CNAME" ttl = "60" records = ["${var.records}"] } Variables.tf module input args Output.tf module output Main.tf processing -
module "dns" { source = "./dns" record_name = "www" records
= ["bla.domain.com"] } output "dns_endpoint" { value = "${module.dns.dns_endpoint}" } Root Terraform file -
module "networking" { source = "./networking" } module "loadbalancing" {
source = "./loadbalancing" security_groups = ["${module.networking.security_group_id}"] vpc_id = "${module.networking.vpc_id}" subnets = ["${module.networking.subnet_public1_id}","${module.networking.subnet_public2_id}"] } module "launch" { source = "./launch" instance_type = "t2.small" security_groups = ["${module.networking.security_group_id}"] } module "autoscaling" { source = "./autoscaling" target_group = "${module.loadbalancing.target_group_name}" loadbalancer = "${module.loadbalancing.loadbalancer_name}" min_size = "4" subnets = ["${module.networking.subnet_private1_id}","${module.networking.subnet_private2_id}"] launch_configuration = "${module.launch.launch_configuration_name}" target_group_arn = "${module.loadbalancing.target_group_id}" } module "dns" { source = "./dns" records = ["${module.loadbalancing.dns_name}"] } output "dns_endpoint" { value = "${module.dns.dns_endpoint}" } -
Downloading modules... Initializing provider plugins... - Checking for available provider
plugins on https://releases.hashicorp.com... - Downloading plugin for provider "aws" (1.9.0)... - Downloading plugin for provider "template" (1.0.0)... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 1.9" * provider.template: version = "~> 1.0" Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. -
module “example" { source = "github.com/hashicorp/example" } module "consul" {
source = "git::https://hashicorp.com/consul.git" } module "ami" { source = "git::ssh://[email protected]/owner/repo.git" } -
terraform { backend "consul" { address = "127.0.0.1:8500" path =
"example/terraform_state" } } -
$ terraform apply Error locking state: Error acquiring the state
lock: resource temporarily unavailable Lock Info: ID: d2c36deb-32c0-ecc7-b1f1-10068c2ed93b Path: terraform.tfstate Operation: OperationTypeApply Who: [email protected] Version: 0.10.7 Created: 2018-02-02 16:03:17.005327423 +0000 UTC Info: Terraform acquires a state lock to protect the state from being written by multiple users at the same time. Please resolve the issue above and try again. For most commands, you can disable locking with the "-lock=false" flag, but this is not recommended. -
data "terraform_remote_state" "web" { backend = "consul" config { address
= "127.0.0.1:8500" path = "thijsferyn/terraform/production" } } data "aws_route53_zone" "web" { name = "aws.combell.com." } resource "aws_route53_record" "web" { zone_id = "${data.aws_route53_zone.web.zone_id}" name = "thijsferyn-web.${data.aws_route53_zone.web.name}" type = "A" ttl = "60" records = ["${data.terraform_remote_state.web.public_ip}"] } output "hostname" { value = "${aws_route53_record.web.name}" }