Command line scripts for registering external Linux instances with an ECS Cluster
Nathan Peck
Senior Developer Advocate at AWS
💡 Tip: The easiest way to register external capacity with an ECS cluster is to use the Elastic Container Service web console, as it will automatically create an activation key and code, and prepopulate the commands with the right activation key for you.
If you need to automate the ECS Anywhere registration process for Linux you can use the following command as a template:
The referenced install script which is downloaded from S3 is also embedded here for your review. This script handles the installation of Docker, the AWS Systems Manager agent, and the Elastic Container Service Agent:
#!/bin/bash
set -e # exit on failurefail(){echo""echo -e "\033[0;31mInstallation Failed\033[0m"# print it in redexit1}check-option-value(){if["${2:0:2}"=="--"];thenecho"Option $1 was passed an invalid value: $2. Perhaps you passed in an empty env var?" fail
fi}usage(){echo"$(basename "$0") [--help] --region REGION --activation-code CODE --activation-id ID [--cluster CLUSTER] [--enable-gpu] [--docker-install-source all|docker|distro|none] [--ecs-version VERSION] [--ecs-endpoint ENDPOINT] [--skip-registration] [--no-start]
--help
(optional) display this help message.
--region string
(required) this must match the region of your ECS cluster and SSM activation.
--activation-id string
(required) activation id from the create activation command. Not required if --skip-registration is specified.
--activation-code string
(required) activation code from the create activation command. Not required if --skip-registration is specified.
--cluster string
(optional) pass the cluster name that ECS agent will connect too. By default its value is 'default'.
--enable-gpu
(optional) if this flag is provided, GPU support for ECS will be enabled.
--docker-install-source
(optional) Source of docker installation. Possible values are 'all, docker, distro, none'. Defaults to 'all'.
--ecs-version string
(optional) Version of the ECS agent rpm/deb package to use. If not specified, default to latest.
--skip-registration
(optional) if this is enabled, SSM agent install and instance registration with SSM is skipped.
--certs-file
(optional) TLS certs for execute command feature. Defaults to searching for certs in known possible locations.
--no-start
(optional) if this flag is provided, SSM agent, docker and ECS agent will not be started by the script despite being installed."}# required:REGION=""ACTIVATION_CODE=""ACTIVATION_ID=""# optional:SKIP_REGISTRATION=falseECS_CLUSTER=""DOCKER_SOURCE=""ECS_VERSION=""DEB_URL=""RPM_URL=""ECS_ENDPOINT=""CERTS_FILE=""# Whether to check signature for the downloaded amazon-ecs-init package. true unless --skip-gpg-check# specified. --skip-gpg-check is mostly for testing purpose (so that we can test a custom build of ecs init package# without having to sign it).CHECK_SIG=trueNO_START=falsewhile :;docase"$1" in
--help) usage
exit0;; --region) check-option-value "$1""$2"REGION="$2"shift2;; --cluster) check-option-value "$1""$2"ECS_CLUSTER="$2"shift2;; --activation-code) check-option-value "$1""$2"ACTIVATION_CODE="$2"shift2;; --activation-id) check-option-value "$1""$2"ACTIVATION_ID="$2"shift2;; --docker-install-source) check-option-value "$1""$2"DOCKER_SOURCE="$2"shift2;; --ecs-version) check-option-value "$1""$2"ECS_VERSION="$2"shift2;; --deb-url) check-option-value "$1""$2"DEB_URL="$2"shift2;; --rpm-url) check-option-value "$1""$2"RPM_URL="$2"shift2;; --ecs-endpoint) check-option-value "$1""$2"ECS_ENDPOINT="$2"shift2;; --certs-file) check-option-value "$1""$2"CERTS_FILE="$2"shift2;; --skip-registration)SKIP_REGISTRATION=trueshift1;; --enable-gpu)GPU_ENABLED=trueshift1;; --no-start)NO_START=trueshift1;; --skip-gpg-check)CHECK_SIG=falseshift1;; *)[ -z "$1"]&&breakecho"invalid option: [$1]" fail
;;esacdone# check if the script is run with root or sudoif[$(id -u) -ne 0];thenecho"Please run as root." fail
fi# check if system is using systemd# from https://www.freedesktop.org/software/systemd/man/sd_booted.htmlif[ ! -d /run/systemd/system ];thenecho"The install script currently supports only systemd." fail
fiSSM_SERVICE_NAME="amazon-ssm-agent"SSM_BIN_NAME="amazon-ssm-agent"if systemctl is-enabled snap.amazon-ssm-agent.amazon-ssm-agent.service &>/dev/null;thenecho"Detected SSM agent installed via snap."SSM_SERVICE_NAME="snap.amazon-ssm-agent.amazon-ssm-agent.service"SSM_BIN_NAME="/snap/amazon-ssm-agent/current/amazon-ssm-agent"fiSSM_MANAGED_INSTANCE_ID=""if[ -z "$REGION"];thenecho"--region is required" fail
fi# If activation code is absent and skip activation flag is present, set flag to skip ssm registration# if both activation code is presentif$SKIP_REGISTRATION;thenecho"Skipping ssm registration."if ! systemctl is-enabled $SSM_SERVICE_NAME&>/dev/null;thenecho"--skip-registration flag specified but the SSM agent service is not running."echo"a running SSM agent service is required for ECS Anywhere." fail
fielseif[[ -z $ACTIVATION_ID|| -z $ACTIVATION_CODE]];thenecho"Both --activation-id and --activation-code are required unless --skip-registration is specified." fail
fifiif[ -z "$ECS_CLUSTER"];thenECS_CLUSTER="default"fiif[ -z "$DOCKER_SOURCE"];thenDOCKER_SOURCE="all"fiif[ -z "$ECS_VERSION"];thenECS_VERSION="latest"fiARCH=$(uname -m)if["$ARCH"=="x86_64"];thenARCH_ALT="amd64"elif["$ARCH"=="aarch64"];thenARCH_ALT="arm64"elseecho"Unsupported architecture: $ARCH" fail
fiS3_BUCKET="amazon-ecs-agent-$REGION"RPM_PKG_NAME="amazon-ecs-init-$ECS_VERSION.$ARCH.rpm"DEB_PKG_NAME="amazon-ecs-init-$ECS_VERSION.$ARCH_ALT.deb"S3_URL_SUFFIX=""if grep -q "^cn-"<<<"$REGION";thenS3_URL_SUFFIX=".cn"fiS3_URL="https://s3.${REGION}.amazonaws.com${S3_URL_SUFFIX}"SSM_S3_BUCKET="amazon-ssm-$REGION"if[ -z "$RPM_URL"];thenRPM_URL="${S3_URL}/${S3_BUCKET}/$RPM_PKG_NAME"fiif[ -z "$DEB_URL"];thenDEB_URL="${S3_URL}/${S3_BUCKET}/$DEB_PKG_NAME"fi# source /etc/os-release to get the VERSION_ID and ID fieldssource /etc/os-release
echo"Running ECS install script on $ID$VERSION_ID"echo"###"echo""DISTRO=""ifecho"$ID"| grep ubuntu;thenDISTRO="ubuntu"elifecho"$ID"| grep debian;thenDISTRO="debian"elifecho"$ID"| grep fedora;thenDISTRO="fedora"elifecho"$ID"| grep centos;thenDISTRO="centos"elifecho"$ID"| grep rhel;thenDISTRO="rhel"elif[["$ID"=="amzn"&&"$VERSION_ID"=="2"]];thenDISTRO="al2"fiif["$DISTRO"=="rhel"];thenif[ ! "$DOCKER_SOURCE"=="none"];thenecho"Docker install is not supported on RHEL. Please install yourself and rerun with --docker-install-source none" fail
fifiok(){echo""echo"# ok"echo"##########################"echo""}try(){localaction=$*echo""echo"##########################"echo"# Trying to $action ... "echo""}PKG_MANAGER=""if[ -x "$(command -v dnf)"];thenPKG_MANAGER="dnf" dnf install -y jq
elif[ -x "$(command -v yum)"];thenPKG_MANAGER="yum"if["$DISTRO" !="al2"];then yum install epel-release -y
fi yum install -y jq
elif[ -x "$(command -v apt)"];thenPKG_MANAGER="apt" try "Update apt repos" apt update -y
apt-get install -y curl jq
ok
elif[ -x "$(command -v zypper)"];thenPKG_MANAGER="zypper" zypper install -y jq
elseecho"Unsupported package manager. Could not find dnf, yum, or apt." fail
figet-ssm-managed-instance-id(){SSM_REGISTRATION_FILE='/var/lib/amazon/ssm/Vault/Store/RegistrationKey'if[ -f ${SSM_REGISTRATION_FILE}];thenSSM_MANAGED_INSTANCE_ID=$(jq -r ".instanceID"$SSM_REGISTRATION_FILE)fi}curl-helper(){if ! curl -o "$1""$2" -fSs;thenecho"Failed to download $2" fail
fi}register-ssm-agent(){ try "Register SSM agent" get-ssm-managed-instance-id
if[ -z "$SSM_MANAGED_INSTANCE_ID"];then systemctl stop "$SSM_SERVICE_NAME"&>/dev/null
$SSM_BIN_NAME -register -code "$ACTIVATION_CODE" -id "$ACTIVATION_ID" -region "$REGION" systemctl enable"$SSM_SERVICE_NAME"if ! $NO_START;then systemctl start "$SSM_SERVICE_NAME"elseecho"Skip starting ssm agent because --no-start is specified."fiecho"SSM agent has been registered."elseecho"SSM agent is already registered. Managed instance ID: $SSM_MANAGED_INSTANCE_ID"fi ok
}install-ssm-agent(){ try "install ssm agent"if systemctl is-enabled $SSM_SERVICE_NAME&>/dev/null;thenecho"SSM agent is already installed."elselocal dir
dir="$(mktemp -d)"localSSM_DEB_URL="${S3_URL}/${SSM_S3_BUCKET}/latest/debian_$ARCH_ALT/amazon-ssm-agent.deb"localSSM_RPM_URL="${S3_URL}/${SSM_S3_BUCKET}/latest/linux_$ARCH_ALT/amazon-ssm-agent.rpm"localSSM_DEB_PKG_NAME="ssm-agent.deb"localSSM_RPM_PKG_NAME="ssm-agent.rpm"case"$PKG_MANAGER" in
apt) curl-helper "$dir/$SSM_DEB_PKG_NAME""$SSM_DEB_URL" curl-helper "$dir/$SSM_DEB_PKG_NAME.sig""$SSM_DEB_URL.sig" ssm-agent-signature-verify "$dir/$SSM_DEB_PKG_NAME.sig""$dir/$SSM_DEB_PKG_NAME" chmod -R a+rX "$dir" dpkg -i "$dir/ssm-agent.deb";; dnf | yum | zypper) curl-helper "$dir/$SSM_RPM_PKG_NAME""$SSM_RPM_URL" curl-helper "$dir/$SSM_RPM_PKG_NAME.sig""$SSM_RPM_URL.sig" ssm-agent-signature-verify "$dir/$SSM_RPM_PKG_NAME.sig""$dir/$SSM_RPM_PKG_NAME"localargs=""localinstall_args="-y"if[["$PKG_MANAGER"=="zypper"]];theninstall_args="${install_args} --allow-unsigned-rpm"args="--no-gpg-checks"fi$PKG_MANAGER${args} install ${install_args}"$dir/$SSM_RPM_PKG_NAME";;esac rm -rf "$dir"fi# register the instance register-ssm-agent
ok
}ssm-agent-signature-verify(){ try "verify the signature of amazon-ssm-agent package"if ! command -v gpg;thenecho"WARNING: gpg command not available on this server, not able to verify amazon-ssm-agent package signature." ok
returnfi curl-helper "$dir/amazon-ssm-agent.gpg""https://raw.githubusercontent.com/aws/amazon-ecs-init/master/scripts/amazon-ssm-agent.gpg" gpg --import "$dir/amazon-ssm-agent.gpg"if gpg --verify "$1""$2";thenecho"amazon-ssm-agent GPG verification passed. Install the amazon-ssm-agent."elseecho"amazon-ssm-agent GPG verification failed. Stop the installation of the amazon-ssm-agent. Please contact AWS Support." fail
fi ok
}# order of operations:# all->docker->distro->noneinstall-docker(){if[ -x "$(command -v docker)"];thenecho"docker is already installed, skipping installation"returnficase"$1" in
all) install-docker "docker"return;; docker) try "install docker from docker repos"case"$DISTRO" in
centos)# TODO use dnf on centos if available yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
;; fedora) dnf install -y dnf-plugins-core
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
dnf install -y docker-ce docker-ce-cli containerd.io
;; debian) apt install -y apt-transport-https ca-certificates gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
add-apt-repository \
"deb [arch=$ARCH_ALT] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable" apt update -y
apt install -y docker-ce docker-ce-cli containerd.io
;; ubuntu) apt install -y apt-transport-https ca-certificates gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository \
"deb [arch=$ARCH_ALT] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable" apt update -y
apt install -y docker-ce docker-ce-cli containerd.io
;; *)echo"Docker install repos not supported for this distro, trying distro install" install-docker "distro"return;;esac;; distro) try "install docker from distribution repos"# centos and fedora enable selinux by default in their distro installscase"$DISTRO" in
centos | fedora)if["$VERSION_ID"=="8"];thenecho"--docker-install-source distro is not supported on centos 8 because docker package is not available."elseecho"--docker-install-source distro is not supported on $DISTRO$VERSION_ID because distro enables selinux by default."fiecho"We suggest installing using '--docker-install-source docker' or installing docker yourself before running this script." fail
;;esaccase"$PKG_MANAGER" in
dnf) dnf install -y docker
;; yum) yum install -y docker
;; apt) apt install -y docker.io
;; zypper) zypper install -y docker
;;esac;; none)echo"Docker install source is none, not installing docker";;esac ok
}install-ecs-agent(){ try "install ecs agent"if[ -x "/usr/libexec/amazon-ecs-init"];thenecho"ecs agent is already installed" ok
returnfilocal dir
dir="$(mktemp -d)"case"$PKG_MANAGER" in
apt) curl-helper "$dir/$DEB_PKG_NAME""$DEB_URL"if$CHECK_SIG;then curl-helper "$dir/$DEB_PKG_NAME.asc""$DEB_URL.asc" ecs-init-signature-verify "$dir/$DEB_PKG_NAME.asc""$dir/$DEB_PKG_NAME"fi chmod -R a+rX "$dir" apt install -y "$dir/$DEB_PKG_NAME" rm -rf "$dir";; dnf | yum | zypper) curl-helper "$dir/$RPM_PKG_NAME""$RPM_URL"if$CHECK_SIG;then curl-helper "$dir/$RPM_PKG_NAME.asc""$RPM_URL.asc" ecs-init-signature-verify "$dir/$RPM_PKG_NAME.asc""$dir/$RPM_PKG_NAME"filocalargs="-y"if[["$PKG_MANAGER"=="zypper"]];thenargs="${args} --allow-unsigned-rpm"fi$PKG_MANAGER install ${args}"$dir/$RPM_PKG_NAME" rm -rf "$dir";;esacif[ ! -f "/etc/ecs/ecs.config"];then touch /etc/ecs/ecs.config
elseecho"/etc/ecs/ecs.config already exists, preserving existing config and appending cluster name."fiecho"ECS_CLUSTER=$ECS_CLUSTER" >>/etc/ecs/ecs.config
if[ ! -f "/var/lib/ecs/ecs.config"];then touch /var/lib/ecs/ecs.config
elseecho"/var/lib/ecs/ecs.config already exists, preserving existing config and appending ECS anywhere requirements."fiecho"AWS_DEFAULT_REGION=$REGION" >>/var/lib/ecs/ecs.config
echo"ECS_EXTERNAL=true" >>/var/lib/ecs/ecs.config
if[ -n "$ECS_ENDPOINT"];thenecho"ECS_BACKEND_HOST=$ECS_ENDPOINT" >>/var/lib/ecs/ecs.config
fiif[ -n "$GPU_ENABLED"];thenif ! nvidia-smi &>/dev/null;thenecho"Failed to detect GPU with nvidia-smi command. Make sure that GPUs are attached and the latest NVIDIA driver is installed and running." fail
fiecho"ECS_ENABLE_GPU_SUPPORT=true" >>/var/lib/ecs/ecs.config
fi systemctl enable ecs
if ! $NO_START;then systemctl start ecs
elseecho"Skip starting ecs agent because --no-start is specified."fi ok
}ecs-init-signature-verify(){ try "verify the signature of amazon-ecs-init package"if ! command -v gpg;thenecho"WARNING: gpg command not available on this server, not able to verify amazon-ecs-init package signature." ok
returnfi curl-helper "$dir/amazon-ecs-agent.gpg""https://raw.githubusercontent.com/aws/amazon-ecs-init/master/scripts/amazon-ecs-agent.gpg" gpg --import "$dir/amazon-ecs-agent.gpg"if gpg --verify "$1""$2";thenecho"amazon-ecs-init GPG verification passed. Install amazon-ecs-init."elseecho"amazon-ecs-init GPG verification failed. Stop the installation of amazon-ecs-init. Please contact AWS Support." fail
fi ok
}wait-agent-start(){if$NO_START;thenecho"--no-start is specified. Not verifying ecs agent startup."returnfi try "wait for ECS agent to start"retryLimit=10i=0for((i=0; i < retryLimit ; i++))docurlResult="$(timeout 10 curl -s http://localhost:51678/v1/metadata | jq .ContainerInstanceArn)"if[ ! "$curlResult"=="null"]&&[ -n "$curlResult"];thenecho"Ping ECS Agent registered successfully! Container instance arn: $curlResult"echo""echo"You can check your ECS cluster here https://console.aws.amazon.com/ecs/home?region=$REGION#/clusters/$ECS_CLUSTER" ok
returnfi sleep 10# wait for 10s before next retry for agent to start up.done# TODO Update to ecs anywhere specific documentation when available.echo"Timed out waiting for ECS Agent to start. Please check logs at /var/log/ecs/ecs-agent.log and follow troubleshooting documentation at https://docs.aws.amazon.com/AmazonECS/latest/developerguide/troubleshooting.html" fail
}exec-setup(){ find-copy-certs-exec
download-ssm-binaries-exec
}find-copy-certs-exec(){# Reference for locations: https://golang.org/src/crypto/x509/root_linux.goCERTS_FILES_LOCATIONS=("/etc/ssl/certs/ca-certificates.crt""/etc/pki/tls/certs/ca-bundle.crt""/etc/ssl/ca-bundle.pem""/etc/pki/tls/cacert.pem""/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem""/etc/ssl/cert.pem")CERTS_PATH="/var/lib/ecs/deps/execute-command/certs"echo"Copying certs for exec feature"# Determine certs filecerts=""if[ -n "$CERTS_FILE"]&&[ -f "$CERTS_FILE"];thencerts=$CERTS_FILEelseif[ -n "$CERTS_FILE"];thenecho"Provided certs file does not exist, looking for certs in known possible locations"fifor f in "${CERTS_FILES_LOCATIONS[@]}"doif[ -f "$f"];thencerts=$fbreakfidonefi# Copy certs to exec directoryif[ -z "$certs"];thenecho"Could not find certificates. Please rerun with --certs-file and provide a valid path" fail
elseecho"Using $certs" openssl verify -x509_strict "$certs" mkdir -p $CERTS_PATH cp "$certs"$CERTS_PATH/tls-ca-bundle.pem
chmod 400$CERTS_PATH/tls-ca-bundle.pem
fi ok
}download-ssm-binaries-exec(){BINARY_VERSION="3.1.804.0"BINARY_PATH="/var/lib/ecs/deps/execute-command/bin/${BINARY_VERSION}"BINARY_DOWNLOAD_PATH="ssm-binaries"# Download SSM binaries from S3echo"Downloading SSM binaries for exec feature" mkdir -p $BINARY_DOWNLOAD_PATH curl "${S3_URL}/${SSM_S3_BUCKET}/${BINARY_VERSION}/linux_$ARCH_ALT/amazon-ssm-agent-binaries.tar.gz" -o ${BINARY_DOWNLOAD_PATH}/amazon-ssm-agent.tar.gz
tar -xvf ${BINARY_DOWNLOAD_PATH}/amazon-ssm-agent.tar.gz -C ${BINARY_DOWNLOAD_PATH}/
# Copy binaries to exec directory mkdir -p ${BINARY_PATH} cp ${BINARY_DOWNLOAD_PATH}/amazon-ssm-agent ${BINARY_PATH}/amazon-ssm-agent
cp ${BINARY_DOWNLOAD_PATH}/ssm-agent-worker ${BINARY_PATH}/ssm-agent-worker
cp ${BINARY_DOWNLOAD_PATH}/ssm-session-worker ${BINARY_PATH}/ssm-session-worker
rm -rf ${BINARY_DOWNLOAD_PATH} ok
}show-license(){echo""echo"##########################"echo"This script installed three open source packages that all use Apache License 2.0."echo"You can view their license information here:"echo" - ECS Agent https://github.com/aws/amazon-ecs-agent/blob/master/LICENSE"echo" - SSM Agent https://github.com/aws/amazon-ssm-agent/blob/master/LICENSE"echo" - Docker engine https://github.com/moby/moby/blob/master/LICENSE"echo"##########################"echo""}if ! $SKIP_REGISTRATION;then install-ssm-agent
fiinstall-docker "$DOCKER_SOURCE"exec-setup
install-ecs-agent
wait-agent-start
show-license