Automate Salt-Minion Registrations on EC2

Posted by Miguel Lopez on Fri 30 March 2018 in automation

Automate Salt-Minion Registrations on EC2

Intro

These scripts can be used to register your Salt minion to a Salt-Master upon successful launch.

Whether you're launching single instances or instances as part of an auto-scaling group, I highly recommend using cloud-init scripts. They're easy to use and help you install all necessary packages.

My scripts also include CodeDeploy. If you haven't heard of CodeDeploy, take a moment to read about it here: AWS CodeDeploy.

CodeDeploy can help with:

  • Repeatable deployments
  • Automatic code deployments to scaled instances
  • Stops and rollbacks
  • Deployment history

Cloud Init Script

Technical Stack: SaltStack, EC2 (CentOS)

Use this as the cloud-init data for an EC2 instance. It works perfectly with auto-scaling groups. You should be able to pass this as the user data script for your EC2 instance.

This script installs CodeDeploy and automatically registers the Salt minion to a Salt-Master.

  • Dynamic by region
  • Installs the CodeDeploy agent
  • Registers the Salt minion to the master
  • Auto-deploys your latest revision from a CodeDeploy deployment group to this instance
#cloud-config
# Set hostname to match the instance ID, rather than the
# automatic hostname based on the IP address.
# In these three commands _GRP_ is a placeholder and
# should be changed to your Auto Scaling Group name.
bootcmd:
  # Dynamically fetch region for EC2 in aws
  - "region=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/.$//')"
  - "sudo yum -y install ruby wget jq"
  # Install codedeploy https://aws.amazon.com/codedeploy/
  - "sudo cd /home/ec2-user"
  - "sudo wget https://aws-codedeploy-${region}.s3.amazonaws.com/latest/install"
  - "sudo chmod +x ./install"
  - "sudo ./install auto"
  - "sudo service codedeploy-agent start"
  # BOX_NAME fetches the EC2 tag for "Name" - name used to register with salt master
  - "INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)"
  - "BOX_NAME=$(aws ec2 describe-tags --region $region --filters \"Name=resource-id,Values=$INSTANCE_ID\" | jq '.Tags[] | select(.Key == \"Name\") | .Value' | sed s/\\\"//g)"
  # Change hostnames on VM
  - "cloud-init-per instance my_set_hostname sh -xc \"echo $BOX_NAME-$INSTANCE_ID > /etc/hostname; hostname -F /etc/hostname\""
  - "cloud-init-per instance my_etc_hosts sh -xc \"sed -i -e '/^127.0.0.1/d' /etc/hosts; sed -i -e '/^::1/d' /etc/hosts; echo 127.0.0.1 $BOX_NAME-$INSTANCE_ID >> /etc/hosts\""
  # Install and bootstrap salt-minion to saltmaster
  - "SALT_MASTER_IP={IP-TO-SALT-MASTER-HERE}"
  - "mkdir -p /etc/salt/; $BOX_NAME-$INSTANCE_ID > /etc/salt/minion_id"
  - "sudo curl -o /tmp/bootstrap-salt.sh -L https://bootstrap.saltstack.com"
  - "sudo sh /tmp/bootstrap-salt.sh -i $BOX_NAME-$INSTANCE_ID -A $SALT_MASTER_IP"
  - "sudo rm -f /tmp/bootstrap-salt.sh"
# Preserve the hostname file since we've had to manually edit it
preserve_hostname: true
# Don't let cloud-init update the hosts file since we have edited it manually
manage_etc_hosts: false

You'll notice some curls to http://169.254.169.254. This is an internal API used by EC2 instances to fetch metadata about your instance.

Replace $SALT_MASTER_IP with the IP of your Salt-Master. Don't forget to tag your EC2 instance with a "Name" tag. Naming is important when defining Salt environments.

For example: - stage-api - stage-www - test-api - test-www

These are all great examples of "Name" tags for instances because they allow you to apply Salt states by patterns like *www, *api, stage*, or test*.

This can be extremely useful for defining how you run Salt commands. For example, the following command:

salt 'stage*' state.show_top

would only apply Salt states to environments tagged with stage in their name. In this example, that would include the stage-api and stage-www servers.

Shell Script Equivalent

Technical Stack: SaltStack, EC2 (CentOS)

This script installs CodeDeploy and automatically registers the Salt minion to a Salt-Master. Use this script only if you'd like your packages to be installed post-creation.

  • Dynamic by region
  • Installs the CodeDeploy agent
  • Registers the Salt Minion to the master

Run this as a bootstrapping script on an EC2 instance.

# Dynamically fetch region for EC2 in aws
region=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone | sed ’s/.$//‘);

# gr8 packages
sudo yum -y install ruby wget jq;

# Install codedeploy https://aws.amazon.com/codedeploy/
sudo cd /home/ec2-user;
sudo wget https://aws-codedeploy-${region}.s3.amazonaws.com/latest/install;
sudo chmod +x ./install;
sudo ./install auto;
sudo service codedeploy-agent start;

# Name used to register with salt master
BOX_NAME=$(aws ec2 describe-tags --region $region --filters \"Name=resource-id,Values=$INSTANCE_ID\" | jq '.Tags[] | select(.Key == \"Name\") | .Value' | sed s/\\\"//g);
INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id);

# Change hostnames on VM
echo $BOX_NAME-$INSTANCE_ID > /etc/hostname;
sed -i -e '/^127.0.0.1/d' /etc/hosts; 
sed -i -e '/^::1/d' /etc/hosts; 
echo 127.0.0.1 $BOX_NAME-$INSTANCE_ID >> /etc/hosts;

# Install and bootstrap salt-minion to saltmaster
SALT_MASTER_IP={IP-TO-SALT-MASTER-HERE}
mkdir -p /etc/salt/; $BOX_NAME-$INSTANCE_ID > /etc/salt/minion_id;
sudo curl -o /tmp/bootstrap-salt.sh -L https://bootstrap.saltstack.com;
sudo sh /tmp/bootstrap-salt.sh -i $BOX_NAME-$INSTANCE_ID -A $SALT_MASTER_IP;
sudo rm -f /tmp/bootstrap-salt.sh;

You'll notice some curls to http://169.254.169.254. This is an internal API used by EC2 instances to fetch metadata about your instance.

Replace $SALT_MASTER_IP with your own variables.