The Curious Dev

Various programming sidetracks and shiny-object detours

Updating DNS Automatically

This post is the next in the series on Cloudifying MoinMoin and Scheduling an ASG, here we Update the DNS record automatically upon the provisioning of an instance.

Now that we’ve got everything up and running on the schedule that we want, and being automatically replaced upon failure, we need to ensure our domain alias A record i.e. gets updated with the IP of each new instance as they’re provisioned.

An easy way to do this is to simply execute a script that runs at provisioning time for the instance and updates Route53 with the appropriate IP. A great place to execute this script from is the UserData section of the LaunchConfiguration within the CloudFormation template.

EC2_PUBLIC=`/usr/bin/curl -s`

export AWS_ACCESS_KEY_ID=<your-key>
export AWS_SECRET_ACCESS_KEY=<your-secret-key>

RESULT=`/usr/bin/cli53 rrcreate --replace $DOMAIN "$HOSTNAME 60 A $EC2_PUBLIC"`
#e.g. cli53 rrcreate --replace "wiki 60 A"

exit 0

This script was inspired by this answer on Stackoverflow. The script utilises a great little library, cli53 that augments the AWS CLI to provide the needed extra DNS functionality. Alternatively I could use the appropriate AWS CLI command for Route53, which would be cleaner as it wouldn’t require my storing of the AWS Access Keys on the instance. Unfortunately this time around I gave up after 30+ mins trying to work it out with somewhat unhelpful “Invalid request” responses. What I have done is create an AWS user and associated Access Keys for solely updating Route53.

Another way is to avoid the changing IP altogether and simply fork out the few extra $/month for an Elastic IP, they’re free when attached to a running instance. But working within the boundaries of the above configured schedule, it’d cost almost as much to pay for the EIP (0.5c/hr) as it would for the instance (0.6c/hr), based on current US-West-2 / Oregon pricing.

Scheduling Actions on an ASG

This post builds on Cloudified MoinMoin further where we’re going to schedule the application to be down at certain times of the day/week. A relatively new feature of CloudFormation templates is the AWS::AutoScaling::ScheduledAction block, which allows us to alter the MinSize and MaxSize properties of the AutoScalingGroup.

This can be useful in a number of settings, but perhaps a good example is an internal webapp for a business where there are quite clear “business hours” where it’s critical to have the application up and responsive all day long. The flipside is at night time and other out of hours times it might be desirable to trim the number of instances deployed down to the minimum, which could be zero.

So in this case I’m going to bring the MoinMoin ASG down completely just before midnight every night and then wake it up at 6pm the next day. This makes sense as a dead simple way to save 75% on instance costs (obviously the EBS storage keeps on costing, but that is quite minimal anyway). Which gives me a great wiki for use in the evenings.

I’ve added two new sections to the Resources segment of the template, one to schedule the ASG down to be at MinSize=0 and MaxSize=0 and another to bring it up to be at MinSize=1 and MaxSize=1. As this little wiki is hardly taxing the t2.nano instance, there’s plenty of room to scale up and certainly no need to scale out but it is likely it would be easy enough to have two or more instances in an ASG sharing an EFS file system if high-availability was desired.

Scaling down the ASG:

"moinmoinScheduleSleep": {
  "Type" : "AWS::AutoScaling::ScheduledAction",
  "Properties" : {
    "AutoScalingGroupName" : { "Ref": "moinmoinASG" },
    "DesiredCapacity" : 0,
    "MaxSize" : 0,
    "MinSize" : 0,
    "Recurrence": "59 15 * * *"

Waking the ASG back up:

"moinmoinScheduleWake": {
  "Type" : "AWS::AutoScaling::ScheduledAction",
  "Properties" : {
    "AutoScalingGroupName" : { "Ref": "moinmoinASG" },
    "DesiredCapacity" : 1,
    "MaxSize" : 1,
    "MinSize" : 1,
    "Recurrence": "0 10 * * *"

This is how it then appears in your ASG configuration within the AWS console:

Schedule tab for ASG

Note: You may have noticed the cron / “Recurrence” times are not 6pm and midnight as I described above, these times are actually UTC time and I’m in UTC+8 so I’ve had to adjust for this.

Cloudifying MoinMoin

This post takes the Installing MoinMoin on Nginx and uWSGI post further by deploying the built instance of MoinMoin within an AutoScalingGroup (ASG).

Creating the AMI

From my previous post of we have come out with a running instance configured as desired. The only trouble with this situation is that it’s a snowflake.

First step to producing a server that can be repeatedly recreated is to take a snapshot of the instance, this is as simple as choosing so in the AWS console and giving it a name.

Create an Amazon Machine Image(AMI)

Take the time to describe your image so you can remember what it does down the track.

Describe your image

It doesn’t typically take very long, certainly not with these tiny instances with only 8GB of disk.

Pending image

You can then find the created image under the Images > AMIs menu in the console.

Pending image

This AMI ID is what we’ll use in the next step.

Templating with CloudFormation

So now we’ve got an AMI, the next step is to create a CloudFormation template that will produce an ASG for the MoinMoin application to be served out of.

First up, we create a skeleton of the template, with some metadata, parameters and resources:

"AWSTemplateFormatVersion" : "2010-09-09",
"Description": "Template for the MoinMoin wiki at",
"Parameters" : {

"Resources": {


In the Parameters section I’ll add a few options that might be needed to be tweaked at deployment time. Properties such as the aforementioned AMI, the EC2 instance type and the VPC subnet to operate in. I’m cheating a little here by using a Security Group that I created manually for another project.

"Parameters" : {
  "BaseAMI": {
      "Description": "AMI to use for AutoScaling",
      "Type": "String",
      "Default": "ami-00bd6960"
  "InstanceType": {
      "Description": "Instance Type",
      "Type": "String",
      "Default": "t2.nano"
  "moinmoinSG": {
    "Description": "SecurityGroup to control access to instance",
    "Type": "String",
    "Default": "sg-0feddb69"
  "moinmoinKeypair": {
    "Description": "The keypair used by instances within the ASG",
    "Type": "AWS::EC2::KeyPair::KeyName",
    "Default": "ec2-user-keys"
  "vpcSubnet": {
    "Description": "VPC Subnet for all the things, for now",
    "Type": "String",
    "Default": "subnet-2653ec43"

Next up is the meat of the template, Resources, where the actual ASG is declared along with the LaunchConfiguration that it needs to know how to fire up instances.

Here’s the LaunchConfiguration, where we start with the MoinMoin AMI, configure an 8GB disk, and then setup the UserData to ensure that MoinMoin is up and running as soon as the instance comes up:

"Resources": {
  "moinmoinLC": {
    "Type": "AWS::AutoScaling::LaunchConfiguration",
    "Properties": {
        "AssociatePublicIpAddress": "true",
        "BlockDeviceMappings": [
            "DeviceName": "/dev/xvda",
            "Ebs": {
              "DeleteOnTermination": "true",
              "VolumeType": "gp2",
              "VolumeSize": "8"
        "ImageId": { "Ref" : "BaseAMI" },
        "KeyName": { "Ref" : "moinmoinKeypair" },
        "IamInstanceProfile": "moinmoin-role",
        "InstanceType": { "Ref" : "InstanceType" },
        "SecurityGroups": [ { "Ref" : "moinmoinSG" }  ],
        "UserData": {"Fn::Base64" : { "Fn::Join" : ["", [
          "#!/bin/sh", "\n",
          "yum update -y", "\n",
          "#TODO call script to update IP in Route53 config for"
          "start moin", "\n",
          "service nginx start", "\n"

An ASG is a really powerful way to provide reliability with minimal effort. The AutoScalingGroup is where we reference the above “moinmoinLC” LaunchConfiguration and declare the UpdatePolicy and the number of instances.

The UpdatePolicy is the way that CloudFormation knows how to transition from one version of a template to another. The DesiredCapacity is just that, how many instances we’d prefer to have. Having the MinSize and MaxSize both set to one simply ensures there’s always a new instance brought up if the running one were to fail with no more than one instance being provisioned at any one time.

"Resources": {
  "moinmoinASG": {
    "Type" : "AWS::AutoScaling::AutoScalingGroup",
    "Properties": {
      "DesiredCapacity": "1",
      "HealthCheckGracePeriod": 180,
      "HealthCheckType": "EC2",
      "LaunchConfigurationName": { "Ref": "moinmoinLC" },
      "MaxSize": "1",
      "MinSize": "1",
      "Tags": [
          "Key": "Name",
          "Value": "moinmoin-wiki",
          "PropagateAtLaunch": true
      "VPCZoneIdentifier": [ { "Ref": "vpcSubnet" } ]
    "UpdatePolicy" : {
      "AutoScalingRollingUpdate" : {
        "MinInstancesInService" : "0",
        "MaxBatchSize" : "1",
        "WaitOnResourceSignals" : "true",
        "PauseTime" : "PT5M"

So that completes the template and we can simply run that in the CloudFormation console, there are several options but here I just upload the file:

Choose your template file

Then we select the values for the parameters, most of which are conveniently prefilled by the default values of our template parameters:

Select parameter values

Add some tags, Name becomes the name of the provisioned instance(s):

Tagging the template

Review and confirm the template execution:

Review and confirm the template

If things go smoothly, you’ll be able to see the template execute and end up in a clean “CREATE_COMPLETE” state.

Successful template creation

You should then be able to go on over to the EC2 console and see the running instance:

The provisioned instance for the ASG

And of course, check out the site!

MoinMoin, cloudified!

As an alternative to using the AWS console, you can execute a CloudFormation template from the AWS CLI incredibly easily:

aws cloudformation create-stack --stack-name mystackname --template-url s3://mybucket/a.template.file.json --parameters s3://mybucket/my.parameters.file.json

Hope that helps demonstrate how easy it can be to fire up an Auto Scaled server with minimal fuss.

Included file 'facebook_like.html' not found in _includes directory