Skip to content

Instantly share code, notes, and snippets.

@irvingpop
Last active January 30, 2023 22:31
Show Gist options
  • Save irvingpop/e8397a94088d9717e20f39692b5c52a4 to your computer and use it in GitHub Desktop.
Save irvingpop/e8397a94088d9717e20f39692b5c52a4 to your computer and use it in GitHub Desktop.
Launch EC2 spot instances with tags, like a boss
MY_INSTANCEID
MY_SERVER
user-data.txt
.zshrc
.gitconfig
.ssh
.byobu
.oh-my-zsh
global:
default-repo: localhost:32000
kubeContexts: []
#!/bin/bash -e
# Do you occasionally need an extra dev box (or seven) and want to save some money?
# This script shows you how to automatically launch a spot market instance (often at a 70% savings)
# while still complying with your corporate tagging standard and auto-picking the latest AMI
# Also demonstrates some pretty human-friendly spot behavior that I haven't seen elsewhere:
# - automatically sets your max price to the normal going price of the given instance type
# - stops your instance instead of terminating, so you don't lose your filez
# configure these
MY_KEYPAIR=irving
MY_NAME=irving
INSTANCE_TYPE=m5.2xlarge
ARCH="amd64"
IMAGE_OWNERID="099720109477" # self, amazon or 099720109477 (Canonical)
SG_ID="sg-069e5e9f5613c2947"
export AWS_DEFAULT_REGION=us-west-2
SSH_KEY_FILE="/Users/irving/.ssh/id_ed25519"
SSH_ARGS="-L 8080:localhost:8080 -L 8888:localhost:8888 -L 10350:localhost:10350 -L 3808:localhost:3808"
SSH_PUBKEY_CONTENTS=$(<${SSH_KEY_FILE}.pub)
# reconnect if there's already an instance
if [[ -f MY_SERVER ]]; then
ssh -i $SSH_KEY_FILE ${SSH_ARGS} ${MY_NAME}@$(cat MY_SERVER)
exit 0
fi
cat > user-data.txt <<EOF
#cloud-config
package_update: true
package_upgrade: true
groups:
- docker
- microk8s
# # mount microk8s data onto ephemeral storage for more speed
# # watch out for: https://bugs.launchpad.net/cloud-init/+bug/1828611
# disk_setup:
# /dev/nvme1n1:
# table_type: 'gpt'
# layout:
# - 60
# - 30
# - [10, 82]
# overwrite: True
# fs_setup:
# - label: microk8s
# filesystem: xfs
# device: '/dev/nvme1n1p1'
# partition: 'auto'
# - label: docker
# filesystem: xfs
# device: '/dev/nvme1n1p2'
# partition: 'auto'
# - label: swap
# filesystem: swap
# device: '/dev/nvme1n1p3'
# mounts:
# - [ "/dev/disk/by-label/docker", "/var/lib/docker", "xfs", "defaults" ]
# - [ "/dev/disk/by-label/microk8s", "/var/snap/microk8s", "xfs", "defaults" ]
# - [ "/dev/disk/by-label/swap", "none", "swap", "sw", "0", "0" ]
# Add users to the system. Users are added after groups are added.
users:
- default
- name: ${MY_NAME}
gecos: ${MY_NAME}
shell: /usr/bin/zsh
sudo: ALL=(ALL) NOPASSWD:ALL
groups: [users, admin, docker, microk8s]
lock_passwd: true
ssh-authorized-keys:
- ${SSH_PUBKEY_CONTENTS}
write_files:
- content: |
vm.swappiness=10
vm.max_map_count=262144
vm.dirty_ratio=20
vm.dirty_background_ratio=30
vm.dirty_expire_centisecs=30000
path: /etc/sysctl.d/00-highperf.conf
- content: |
* soft nproc 65536
* hard nproc 65536
* soft nofile 1048576
* hard nofile 1048576
path: /etc/security/limits.d/20-nproc.conf
- content: |
{
"insecure-registries" : ["localhost:32000"]
}
path: /etc/docker/daemon.json
apt:
sources:
docker.list:
source: "deb [arch=${ARCH}] https://download.docker.com/linux/ubuntu jammy stable"
keyid: 0EBFCD88 # GPG key ID published on a key server
packages:
- awscli
- build-essential
- direnv
- docker-ce
- docker-compose-plugin
- atop
- python3-pip
- python3-venv
- python-is-python3
- sysstat
- zsh
runcmd:
- 'sysctl -p /etc/sysctl.d/00-highperf.conf'
- 'iptables -P FORWARD ACCEPT'
- 'git clone https://github.com/syndbg/goenv.git /home/${MY_NAME}/.goenv'
- 'chown -R ${MY_NAME} /home/${MY_NAME}/.goenv'
- 'snap install microk8s --channel=1.26/stable --classic'
- '/snap/bin/microk8s status --wait-ready'
- 'snap alias microk8s.kubectl kubectl'
- 'snap alias microk8s.helm3 helm'
- 'ln -s /snap/bin/kubectl /usr/bin/kubectl'
- '/snap/bin/microk8s.enable dns hostpath-storage ingress registry'
- 'mkdir /home/irving/.kube'
- 'cp /var/snap/microk8s/current/credentials/client.config /home/${MY_NAME}/.kube/config'
- 'chown -R ${MY_NAME} /home/${MY_NAME}/.kube'
- 'curl -Lo /usr/local/bin/skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-${ARCH}'
- 'chmod +x /usr/local/bin/skaffold'
EOF
KEYPAIR_EXISTS=$(aws ec2 describe-key-pairs --key-name $MY_KEYPAIR)
if [ $? -ne 0 ]; then
echo "Creating a keypair ${MY_KEYPAIR} for you... "
aws ec2 import-key-pair \
--key-name "${MY_KEYPAIR}" \
--public-key-material fileb://${SSH_KEY_FILE}.pub
fi
LATEST_AMI=$(aws ec2 describe-images \
--owners $IMAGE_OWNERID \
--output text \
--query 'Images[*].{ID:ImageId, Name:Name}' \
--filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-${ARCH}-server-*" \
| sort -k 2 \
| tail -1 \
| awk '{print $1}')
MY_INSTANCEID=$(aws ec2 run-instances \
--image-id $LATEST_AMI \
--key-name $MY_KEYPAIR \
--instance-type ${INSTANCE_TYPE} \
--security-group-ids ${SG_ID} \
--block-device-mappings DeviceName=/dev/sda1,Ebs="{VolumeSize=100,VolumeType=gp3}" \
--user-data file://user-data.txt \
--ebs-optimized \
--tag-specifications ResourceType=instance,Tags="[{Key='Name',Value='$MY_NAME-dev'},{Key='X-Contact',Value='$MY_NAME'}]" \
--instance-market-options MarketType=spot,SpotOptions="{SpotInstanceType=persistent,InstanceInterruptionBehavior=stop}" \
--output text --query "Instances[0].InstanceId")
# get the server's IP
MY_SERVER=$(aws ec2 describe-instances \
--instance-id $MY_INSTANCEID \
--query "Reservations[0].Instances[0].PublicIpAddress" \
--output text)
echo "${MY_INSTANCEID}" > MY_INSTANCEID
echo "${MY_SERVER}" > MY_SERVER
echo "Waiting for ${MY_SERVER} to be ready"
until ssh -q -i $SSH_KEY_FILE -o ConnectTimeout=1 -o StrictHostKeyChecking=accept-new ${MY_NAME}@${MY_SERVER} "kubectl version > /dev/null 2>&1"
do
echo -n "."
sleep 1
done
# upload data to it (put your .bash* .gitconfig etc in a folder)
rsync -e "ssh -i $SSH_KEY_FILE" --exclude ".git" -az . ${MY_NAME}@${MY_SERVER}:
# Add an entry to the history for easy up-arrowing
#history -s ssh ${MY_NAME}@${MY_SERVER}
# ssh to it
ssh -i $SSH_KEY_FILE ${MY_NAME}@${MY_SERVER} "byobu-enable"
ssh -i $SSH_KEY_FILE ${MY_NAME}@${MY_SERVER} "mkdir .skaffold && mv .skaffold-config .skaffold/config"
# clone some of your favorite repos, change this
# ssh -i $SSH_KEY_FILE ${MY_NAME}@${MY_SERVER} "git clone -b full_jaeger [email protected]:irvingpop/microservices-demo.git src/microservices-demo"
ssh -i $SSH_KEY_FILE ${MY_NAME}@${MY_SERVER} "git clone -b irving/dockerize [email protected]:honeycombio/otel-load-generator.git src/otel-load-generator"
ssh -i $SSH_KEY_FILE ${SSH_ARGS} ${MY_NAME}@${MY_SERVER}
#!/bin/bash -xe
# Delete the instance created by launch_ec2_instance.sh
export AWS_DEFAULT_REGION=us-west-2
MY_INSTANCEID="$(cat MY_INSTANCEID)"
# clean up (when you're done)
MY_SPOT_ID=$(aws ec2 describe-spot-instance-requests \
--filters Name=instance-id,Values=$MY_INSTANCEID \
--output text \
--query "SpotInstanceRequests[0].SpotInstanceRequestId")
aws ec2 cancel-spot-instance-requests --spot-instance-request-ids $MY_SPOT_ID
aws ec2 terminate-instances --instance-ids $MY_INSTANCEID
rm MY_INSTANCEID
rm MY_SERVER
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment