buildvars.json
{
"aws_access_key_id": "{{env `AWS_ACCESS_KEY_ID`}}",
"aws_secret_access_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
"aws_session_token": "{{env `AWS_SESSION_TOKEN`}}",
"time_zone": "{{env `TIME_ZONE`}}",
"instance_type": "t2.large",
"region": "eu-west-1",
"availability_zone": "eu-west-1a",
"ami": "ami-880d64f1",
"vpc_id": "vpc-",
"subnet_id": "subnet-",
"security_group_id": "sg-",
"ssh_keypair_name": "ssh-key-",
"ssh_username": "ec2-user",
"ami_name": "my-custom-ecs {{timestamp}}",
"ami_description": "Docker AWS ECS Base Image 2017.09",
"tags": {
"OS_Version": "Amazon Linux",
"Release": "amzn-ami-2017.09.h-amazon-ecs-optimized",
"Docker_Version", "17.09.1-ce",
"ECS-Agent_Version", "1.17.0",
"ECS-Init_Version", ""
}
}
my_custom_ecs_ami.json
{
"builders": [
{
"type": "amazon-ebs",
"instance_type": "{{user `instance_type`}}",
"availability_zone": "{{user `availability_zone`}}",
"vpc_id": "{{user `vpc_id`}}",
"subnet_id": "{{user `subnet_id`}}",
"security_group_id": "{{user `security_group_id`}}",
"ssh_username": "{{user `ssh_username`}}",
"ssh_keypair_name": "{{user `ssh_keypair_name`}}",
"ssh_agent_auth": true,
"ssh_private_ip": false,
"associate_public_ip_address": "true"
"access_key": "{{user `aws_access_key_id`}}",
"secret_key": "{{user `aws_secret_access_key`}}",
"token": "{{user `aws_session_token`}}",
"region": "{{user `region`}}",
"source_ami": "{{user `ami`}}",
"ami_name": "{{user `ami_name`}}-{{timestamp}}",
"tags": {
"OS_Version": "{{user `OS_Version`}}",
"SourceAMI": "{{user `ami`}}",
"DockerVersion": "{{user `Docker_Version`}}",
"ECSAgentVersion": "{{user `ECSAgent_Version`}}",
"ECS-Init_Version", "{{user `ECS-Init_Version`}}",
"ami_description": "{{user `ami_description`}}",
}
}],
"provisioners": [
{
"type": "shell",
"script": "prephost.sh",
"environment_vars": [
"TIME_ZONE={{user `time_zone`}}"
]
},
{
"type": "file",
"source": "bootstrap.sh",
"destination": "/home/ec2-user/bootstrap.sh"
}],
}
prephost.sh
#!/usr/bin/env bash
set -e
# Configure host to use timezone
# http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html
timezone=${TIME_ZONE:-GMT}
echo "### Setting timezone to $timezone ###"
sudo tee /etc/sysconfig/clock << EOF > /dev/null
ZONE="$timezone"
UTC=true
EOF
sudo ln -sf /usr/share/zoneinfo/$timezone /etc/localtime
# Enable NTP
sudo chkconfig ntpd on
# Additional operating system packages
packages="awslogs jq aws-cfn-bootstrap"
# Exclude Docker and ECS Agent from update
sudo yum -y -x docker\* -x ecs\* update
echo "### Installing extra packages: $packages ###"
sudo yum -y install $packages
# Disable cloud-init repo updates or upgrades
sudo sed -i -e '/^repo_update: /{h;s/: .*/: false/};${x;/^$/{s//repo_update: false/;H};x}' /etc/cloud/cloud.cfg
sudo sed -i -e '/^repo_upgrade: /{h;s/: .*/: none/};${x;/^$/{s//repo_upgrade: none/;H};x}' /etc/cloud/cloud.cfg
echo "### Performing final clean-up tasks ###"
sudo service docker stop
sudo chkconfig docker off
sudo rm -f /var/log/docker /var/log/ecs/*
# An intermittent failure scenario sees this created as a directory when the
# ECS agent attempts to map it into its container, so do rm -Rf just in case
sudo rm -Rf /var/run/docker.sock
# Remove Docker network database
sudo rm -rf /var/lib/docker/network
# Remove docker0 interface if it has been created
sudo ip link del docker0 || true
bootstrap.sh
#!/usr/bin/env bash
set -e
# Configure ECS Agent
echo "ECS_CLUSTER=${ECS_CLUSTER}" > /etc/ecs/ecs.config
# Set HTTP Proxy URL if provided
if [ -n $PROXY_URL ]
then
echo export HTTPS_PROXY=$PROXY_URL >> /etc/sysconfig/docker
echo HTTPS_PROXY=$PROXY_URL >> /etc/ecs/ecs.config
echo NO_PROXY=169.254.169.254,169.254.170.2,/var/run/docker.sock >> /etc/ecs/ecs.config
echo HTTP_PROXY=$PROXY_URL >> /etc/awslogs/proxy.conf
echo HTTPS_PROXY=$PROXY_URL >> /etc/awslogs/proxy.conf
echo NO_PROXY=169.254.169.254 >> /etc/awslogs/proxy.conf
fi
# Enable docker host networking mode if DOCKER_NETWORK_MODE is set to "host"
if [ $DOCKER_NETWORK_MODE = "host" ]
then
sudo sed -i -e "s|^\(OPTIONS=\".*\)\"$|\1 --bridge=none --ip-forward=false --ip-masq=false --iptables=false\"|" \
/etc/sysconfig/docker
fi
# Write AWS Logs region
sudo tee /etc/awslogs/awscli.conf << EOF > /dev/null
[plugins]
cwlogs = cwlogs
[default]
region = ${AWS_DEFAULT_REGION}
EOF
# Write AWS Logs config
sudo tee /etc/awslogs/awslogs.conf << EOF > /dev/null
[general]
state_file = /var/lib/awslogs/agent-state
[/var/log/dmesg]
file = /var/log/dmesg
log_group_name = ${STACK_NAME}/ec2/${AUTOSCALING_GROUP}/var/log/dmesg
log_stream_name = {instance_id}
[/var/log/messages]
file = /var/log/messages
log_group_name = ${STACK_NAME}/ec2/${AUTOSCALING_GROUP}/var/log/messages
log_stream_name = {instance_id}
datetime_format = %b %d %H:%M:%S
[/var/log/docker]
file = /var/log/docker
log_group_name = ${STACK_NAME}/ec2/${AUTOSCALING_GROUP}/var/log/docker
log_stream_name = {instance_id}
datetime_format = %Y-%m-%dT%H:%M:%S.%f
[/var/log/ecs/ecs-init.log]
file = /var/log/ecs/ecs-init.log*
log_group_name = ${STACK_NAME}/ec2/${AUTOSCALING_GROUP}/var/log/ecs/ecs-init
log_stream_name = {instance_id}
datetime_format = %Y-%m-%dT%H:%M:%SZ
time_zone = UTC
[/var/log/ecs/ecs-agent.log]
file = /var/log/ecs/ecs-agent.log*
log_group_name = ${STACK_NAME}/ec2/${AUTOSCALING_GROUP}/var/log/ecs/ecs-agent
log_stream_name = {instance_id}
datetime_format = %Y-%m-%dT%H:%M:%SZ
time_zone = UTC
EOF
# Start services
sudo service awslogs start
sudo chkconfig docker on
sudo service docker start
sudo start ecs
# Exit gracefully if ECS_CLUSTER is not defined
if [[ -z ${ECS_CLUSTER} ]]
then
echo "Skipping ECS agent check as ECS_CLUSTER variable is not defined"
exit 0
fi
# Loop until ECS agent has registered to ECS cluster
echo "Checking ECS agent is joined to ${ECS_CLUSTER}"
until [[ "$(curl --fail --silent http://localhost:51678/v1/metadata | jq '.Cluster // empty' -r -e)" == ${ECS_CLUSTER} ]]
do printf '.'
sleep 5
done
echo "ECS agent successfully joined to ${ECS_CLUSTER}"
packer build -var-file=buildvars.json my_custom_ecs_ami.json