Skip to content

Instantly share code, notes, and snippets.

@devkid devkid/ecs.sh
Last active Mar 10, 2019

Embed
What would you like to do?
Wrapper script for an etcd cluster on AWS ECS
#!/bin/sh
# This script decides if we are part of the process of bootstrapping a new etcd cluster
# or if we are joining an already existing cluster.
set -eux -o pipefail
# own IP address
own_ip=$(curl -f -s http://169.254.169.254/latest/meta-data/local-ipv4)
# get default route to query ECS agent
gw=$(ip route show default 0.0.0.0/0 | awk '{print $3}')
# find our cluster
cluster=$(curl -f -s http://${gw}:51678/v1/metadata | jq --raw-output '.Cluster')
# find our own task by looking at tasks which have 'etcd' containers
arn=$(curl -f -s http://${gw}:51678/v1/tasks | jq --raw-output '.Tasks[] | select([.Containers[].Name == "etcd"] | any) | .Arn')
# get deployment of that task
deployment=$(aws ecs describe-tasks --cluster ${cluster} --tasks ${arn} | jq --raw-output '.tasks[0].startedBy')
# get a list of all services
services=$(aws ecs list-services --cluster ${cluster} | jq --raw-output '.serviceArns[]')
# find the service that did the deployment
service=$(aws ecs describe-services --cluster ${cluster} --services ${services} | jq --raw-output '.services[] | select([.deployments[].id == "'"${deployment}"'"] | any) | .serviceName')
# get all tasks of that service
tasks=$(aws ecs list-tasks --cluster ${cluster} --service-name ${service} | jq --raw-output '.taskArns[]')
# get the container instances the tasks are running on
instances=$(aws ecs describe-tasks --cluster ${cluster} --tasks ${tasks} | jq --raw-output '.tasks[].containerInstanceArn')
# get the EC2 instance IDs of those instances
ec2_ids=$(aws ecs describe-container-instances --cluster ${cluster} --container-instances ${instances} | jq --raw-output '.containerInstances[].ec2InstanceId')
# get the IPs of those EC2 instances
ips=($(aws ec2 describe-instances --instance-ids ${ec2_ids} | jq --raw-output '.Reservations[].Instances[].NetworkInterfaces[0].PrivateIpAddresses[0].PrivateIpAddress'))
# try every IP
existing_node=
for ip in ${ips}
do
if [ "${ip}" == "$own_ip" ]
then
continue
fi
# try to get a list of members of the cluster
members=$(curl -f -s http://${ip}:2379/v2/members) || continue
# there is at least one node of the cluster already online
peers=$(jq --raw-output '.[][].peerURLs[0]' <<< $members)
for peer in ${peers}
do
if [ "${peer}" == "http://${own_ip}:2380" ]
then
# we are alread part of the cluster before we have added ourself as a member;
# this means this is a new cluster
break
fi
done
# use this node to add ourself (see below)
existing_node=${ip}
break
done
export ETC_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
export ETC_LISTEN_PEER_URLS=http://0.0.0.0:2380
export ETC_ADVERTISE_CLIENT_URLS=http://${own_ip}:2379
export ETC_INITIAL_ADVERTISE_PEER_URLS=http://${own_ip}:2380
export ETCD_NAME=$(curl -f -s http://169.254.169.254/latest/meta-data/instance-id)
if [[ ${existing_node} ]]
then
# join existing cluster
export ETCD_DISCOVERY=
export ETCD_INITIAL_CLUSTER_STATE=existing
export ETCD_INITIAL_CLUSTER=$(jq --raw-output '.[] | map(.name + "=" + .peerURLs[0]) | join(",")' <<< $members)
# delete bad members
for peer in ${peers}
do
if ! [[ " ${${ips[@]/#/http://}/%/:2379} " =~ " ${peer} " ]]
then
# this member is not in the ECS cluster anymore, delete it
curl -f -s "http://${existing_node}:2379/v2/members/${peer}" -XDELETE
fi
done
# add ourself to the cluster
curl -f -s -XPOST "${existing_node}/v2/members" -H "Content-Type: application/json" -d "{\"peerURLs\": [\"http://${own_ip}:2380\"], \"name\": \"${ETCD_NAME}\"}"
else
# join new cluster, $ETCD_DISCOVERY is set externally
fi
exec etcd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.