Last active
December 11, 2022 10:40
-
-
Save alfredkrohmer/0e15d36789348abaf64ce82bff31eb8a to your computer and use it in GitHub Desktop.
Wrapper script for an etcd cluster on AWS ECS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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