Last active
January 30, 2023 22:31
-
-
Save irvingpop/e8397a94088d9717e20f39692b5c52a4 to your computer and use it in GitHub Desktop.
Launch EC2 spot instances with tags, like a boss
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
MY_INSTANCEID | |
MY_SERVER | |
user-data.txt | |
.zshrc | |
.gitconfig | |
.ssh | |
.byobu | |
.oh-my-zsh |
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
global: | |
default-repo: localhost:32000 | |
kubeContexts: [] |
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/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 git@github.com:irvingpop/microservices-demo.git src/microservices-demo" | |
ssh -i $SSH_KEY_FILE ${MY_NAME}@${MY_SERVER} "git clone -b irving/dockerize git@github.com:honeycombio/otel-load-generator.git src/otel-load-generator" | |
ssh -i $SSH_KEY_FILE ${SSH_ARGS} ${MY_NAME}@${MY_SERVER} |
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/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