I'm trying to create a script that will automatically deploy and install an AWS EC2 instance using a bash script. I have a deployment script that looks something like this:
#!/bin/bash
# Update apt-get
echo Updating apt-get repositories
apt-get update -yqq
# Install pre-requisits
echo Installing AWS CLI and Python 3
apt-get install -yqq awscli python3 python3-pip
# Set timezone to US/Eastern
# https://help.ubuntu.com/community/UbuntuTime
echo "US/Eastern" | sudo tee /etc/timezone
dpkg-reconfigure --frontend noninteractive tzdata
echo cloud-init userdata processed.
The deployment script (lets call userdata.bash
) runs fine when I deploy the instance via arguments:
aws ec2 run-instances \
--image-id ami-064a0193585662d74 \
--instance-type t3.micro \
--key-name "ssh key" \
--security-group-ids sg-abcdef01 sg-abcdef02 \
--user-data file://userdata.bash
The instance starts, the script runs, everything is great!
But when I put these same options into a json file, the user-data part doesn't parse properly.
The json file named launch.json
:
{
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"ImageId": "ami-064a0193585662d74",
"InstanceType": "t3.micro",
"KeyName": "ssh key",
"SecurityGroupIds": ["sg-abcdef01", "sg-abcdef02"],
"Placement": {
"AvailabilityZone": "us-east-1a"
},
"IamInstanceProfile": {
"Arn": "arn:aws:iam::111111111111:instance-profile/some-role"
},
"UserData": "file://userdata.bash"
}
When I run with the --cli-input-json
argument, everything loads fine, with the exception of the userdata script.
I've tried converting the script to base64 and loading directly, which didn't work. I've tried just the file name, and that didn't work either. The documentation seems to be mum about the format of the userdata part of the yaml file.
Any suggestions would be greatly appreciated.
One thing that will work is to assign the actual contents of the script to UserData in the json file and use a newline character to separate lines of the script. Here's a test script I used as an example:
This does install emacs on my instance at startup. It's possible that a base64 encoded version will work as well so long as it is one line.
Note the following for testing purposes:
curl http://169.254.169.254/latest/user-data
to see how the value you passed to UserData was interpreted. In my testing, if I had used"UserData": "file://userdata.bash"
,then the value returned was file://userdata.bash rather than the contents of the script.As you stated, this is not very well documented, and I suspect there is a way to get the command to read the contents of the file instead of using the literal value, but I have not seen it documented anywhere.