Terraform-provider-aws: Add an aws_service_discovery_instance resource

Created on 8 May 2019  路  6Comments  路  Source: hashicorp/terraform-provider-aws

Community Note

  • Please vote on this issue by adding a 馃憤 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Description

The AWS Cloud Map API supports manual (de-)registering of instances to service discovery services. For a service discovery DNS namespace, this is the only way to manually add DNS records to the zone (attempts to edit the zone from Route 53 return an error "can only be managed through servicediscovery.amazonaws.com"). Adding an instance resource will allow managing custom DNS records in service discovery namespaces.

New or Affected Resource(s)

  • aws_service_discovery_instance

Potential Terraform Configuration

resource "aws_vpc" "example" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
}

resource "aws_service_discovery_private_dns_namespace" "example" {
  name        = "example.terraform.local"
  description = "example"
  vpc         = "${aws_vpc.example.id}"
}

resource "aws_service_discovery_service" "example" {
  name = "example"

  dns_config {
    namespace_id = "${aws_service_discovery_private_dns_namespace.example.id}"

    dns_records {
      ttl  = 10
      type = "A"
    }

    routing_policy = "MULTIVALUE"
  }

  health_check_custom_config {
    failure_threshold = 1
  }
}

resource "aws_service_discovery_instance" "example" {
  service_id = "${aws_service_discovery_service.example.id}"

  # must be unique among instances belonging to this service, specifying an existing one will update it
  instance_id = "example1"

  # an optional attribute for each of the well-defined attributes documented in RegisterInstance
  instance_ipv4 = "1.1.1.1"

  # supports up to 30 custom attributes
  attribute {
    key = "custom"
    value = "manually managed by terraform"
  }
}

References

new-resource servicservicediscovery

Most helpful comment

In case someone else finds this useful, you can workaround by creating a CloudFormation stack to register the instance. For example:

resource "aws_cloudformation_stack" "alb_dns_alias" {
  name = "cfn-dns-alias"
  template_body = <<-STACK
  Resources:
    ALBServiceDiscoveryAlias:
      Type: AWS::ServiceDiscovery::Instance
      Properties:
        InstanceAttributes:
          AWS_ALIAS_DNS_NAME: ${var.dns_name}
        ServiceId: ${aws_service_discovery_service.alb_service.id}
  STACK
}

All 6 comments

Ran into this limitation today trying to create a Route53 alias for an internal ALB.

Service Discovery supports this use case by registering an instance and specifying the ALB's DNSName for the AWS_ALIAS_DNS_NAME attribute:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicediscovery-instance.html

Regarding the potential configuration, I would rather have a map(string) attribute than a nested block.

In case someone else finds this useful, you can workaround by creating a CloudFormation stack to register the instance. For example:

resource "aws_cloudformation_stack" "alb_dns_alias" {
  name = "cfn-dns-alias"
  template_body = <<-STACK
  Resources:
    ALBServiceDiscoveryAlias:
      Type: AWS::ServiceDiscovery::Instance
      Properties:
        InstanceAttributes:
          AWS_ALIAS_DNS_NAME: ${var.dns_name}
        ServiceId: ${aws_service_discovery_service.alb_service.id}
  STACK
}

This sort of thing is not very appropriate for ephemeral instances (like ec2) - however throwing immutable AWS endpoints into a normalized CloudMap namespace is extremely useful and this issue would be the final missing bit.

Example:

  • Terraform spins up an RDS instance foo that gets an endpoint like foo.randomstring.us-west-2.rds.amazonaws.com
  • Terraform creates a CloudMap namespace called RDS
  • Terraform creates a service in that namespace with same identifier as step 1 (foo in our example)
  • Terraform registers RDS instance(s) it created to that namespace, which is safe to do

My workaround for the final step is something like this:

  provisioner "local-exec" {
    command     = "./register-instance ${var.aws_account_id} ${aws_service_discovery_service.example.id} 0 Address=${aws_db_instance.default.address},Port=${aws_db_instance.default.port},HostedZoneId=${aws_db_instance.default.hosted_zone_id}"
    working_dir = "utils"
  }
#!/bin/bash
set -e

unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

# Execute:
# register-instance 214592427161 srv-123 testing x=x,x2=x2
#
# Description:
#   Registers an instance to an existing CloudMap Service

Creds=$(aws sts assume-role --role-arn arn:aws:iam::$1:role/Whatever --role-session-name "SeshName")

export AWS_ACCESS_KEY_ID=$(echo $Creds | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $Creds | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $Creds | jq -r .Credentials.SessionToken)
export AWS_DEFAULT_REGION=us-west-2

aws servicediscovery register-instance --service-id $2 --instance-id $3 --attributes $4

This works fine and enables anything that knows to look for an RDS instance by name to find it via the much nicer CloudMap API (or DNS). Obviously not limited to RDS, you can register ALB's, ElasticCaches 'etc.

Downside:

This will make terraform destroy fail without further workarounds as Terraform will (correctly) refuse to delete CloudMap services with registered instances.

That's a much larger subject and outside the scope of this. Shouldn't be a blocker to implementing the feature.

馃憤馃徎

Interesting, why this resources was not created? What did author(s) have in mind when left this bit unimplemented? What do they have in mind, how should service instance be registered in the Cloud Map?

Was this page helpful?
0 / 5 - 0 ratings