Get a URL for each EC2 instance running under a load balancer

I have to admit, that this was a task I wanted to accomplish quickly. The kind of ‘quickly’ where you just do a Google search and nice internet person tells you which APIs to use. But no such internet person seemed to exist, so I figured I’ll share my solution.


My problem was that I have a disk-based Codeigniter DB cache running on several EC2 instances. But when I make a change to my RDS database, I need to clear each cache on each individual running EC2 instance. These EC2 instances are within an auto-scaling group, so there’s no guarantee of how many caches will need to be cleared when I decide to purge.

The basic strategy involves calling (using the AWS PHP SDK):

  1. AmazonELB->describe_load_balancers() passing the name of your load balancer
  2. AmazonEC2->describe_instances() and parsing out the dnsName

Here’s a quick Codeigniter model that covers querying my live load balancer and then EC2 to get the public DNS names that I can later use to construct a URL to each running instance:

/models/aws_model.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<?php

require_once APPPATH . "/models/abstract_model.php";
require_once APPPATH . "/models/vo/AWSEC2InstanceVO.php";
require_once "application/libraries/aws_sdk/sdk.class.php";

class AWS_model extends Abstract_model
{
    function __construct()
    {
        parent::__construct();
    }

    /**
     * Query AWS to get a list of AWSEC2InstanceVO
     * for each instance in the ek_live load balancer group
     *
     * @return array
     */

    public function getLiveAppInstanceList()
    {
        return $this->getInstances( $this->getLiveAppInstanceIDList() );
    }

    /**
     * Gets the instance IDs currently running under the live
     * load balancer
     *
     * @return array
     */

    public function getLiveAppInstanceIDList()
    {
        return $this->getELBInstanceIDList( 'ADD_YOUR_LIVE_LOAD_BALANCER_NAME_HERE' );
    }

    /**
     * Query AWS to get the list of DNS names for specified instances.
     * Use getLiveAppDNSNameList() to get for all live instances
     *
     * @param $instanceIDList   array   An array of instance IDs
     * @return array
     */

    public function getInstances( $instanceIDList )
    {
        $ec2 = new AmazonEC2();
        $response = $ec2->describe_instances( array( 'InstanceId' => $instanceIDList ) );
        $instances = $response->body->reservationSet;

        $instanceList = array();
        foreach( $instances->item as $instance )
        {
            $item = $instance->instancesSet->item;
            $vo                     = new AWSEC2InstanceVO();
            $vo->id                 = (string)$item->instanceId;
            $vo->imageID            = (string)$item->imageId;
            $vo->state              = (string)$item->instanceState->name;
            $vo->stateCode          = (int)$item->instanceState->code;
            $vo->privateDnsName     = (string)$item->privateDnsName;
            $vo->dnsName            = (string)$item->dnsName;
            $vo->type               = (string)$item->instanceType;
            $vo->launchTime         = (string)$item->launchTime;
            $vo->availabilityZone   = (string)$item->placement->availabilityZone;
            $vo->privateIpAddress   = (string)$item->privateIpAddress;
            $vo->ipAddress          = (string)$item->ipAddress;
            $instanceList[] = $vo;
        }

//      echo "<pre>";
//      print_r( $instances );
//      echo "</pre>";

        return $instanceList;
    }

    /**
     * Gets a list of instance IDs under the specified load balancer
     *
     * @param $loadBalancerName     string      The name of the load balancer
     * @return array
     */

    public function getELBInstanceIDList( $loadBalancerName )
    {
        $elb = new AmazonELB();

        $response = $elb->describe_load_balancers( array( 'LoadBalancerNames' => $loadBalancerName ) );
        $instances = $response->body->DescribeLoadBalancersResult->LoadBalancerDescriptions->Instances();

        $instanceIDList = array();
        foreach( $instances[0] as $instanceID )
            $instanceIDList[] = (string)$instanceID->InstanceId;
       
//      echo "<pre>";
//      print_r( $instanceIDList );
//      echo "</pre>";

        return $instanceIDList;
    }

}

/models/vo/AWSEC2InstanceVO.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
 
class AWSEC2InstanceVO
{
    /** @var string */
    var $id;

    /** @var string */
    var $imageID;

    /** @var string */
    var $state;

    /** @var int */
    var $stateCode;

    /** @var string */
    var $privateDnsName;

    /** @var string */
    var $dnsName;

    /** @var string */
    var $type;

    /** @var string */
    var $launchTime;

    /** @var string */
    var $availabilityZone;

    /** @var string */
    var $privateIpAddress;

    /** @var string */
    var $ipAddress;

}

I can now call a URL/script on each EC2 instance like so:

1
2
3
4
5
6
7
8
9
10
11
12
$instanceList = $this->AWS_model->getLiveAppInstanceList();

$message = "<ol>";
/** @var $instance AWSEC2InstanceVO */
foreach( $instanceList as $instance )
{
    $url = 'http://' . $instance->dnsName . '/path/to/script';
    $result = file_get_contents( $url );
    $message .= "<li>".$instance->id." - ".$instance->dnsName."<ul><li>Result: <strong>".$result."</strong></li></ul></li>";
}
$message .= "</ol>";
echo $message;

Hope this saves you a bit of time :)

Tags: , , ,

Leave a Reply