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.
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"
}
}
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:
foo.randomstring.us-west-2.rds.amazonaws.com
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.
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?
Can now use instance ID instead of IP address when registering: https://aws.amazon.com/about-aws/whats-new/2020/07/aws-cloud-map-simplifies-amazon-ec2-instance-registration/.
Most helpful comment
In case someone else finds this useful, you can workaround by creating a CloudFormation stack to register the instance. For example: