Coder Social home page Coder Social logo

haproxy-autoscale's Introduction

haproxy-autoscale

Description

I had a project I was working on where I needed a private load balancer to use on Amazon Web Services. Unfortunately, AWS Elastic Load Balancers do not support private listeners so I needed to make my own load balancer using Linux.

Making a load balancer is pretty straight forward. The challenge was that the instances under it were auto-scaling and there was no built-in mechanism for the load balancer to know to send traffic to new instances and to stop sending traffic to deleted instances.

Enter haproxy-autoscale. This is a wrapper of sorts that will automatically add all instances in a security group that are currently in a running state to the haproxy configuration. It then reloads haproxy in a manner which gracefully terminates connections so there is no downtime. Also, haproxy will only be reloaded if there are changes. If there are no changes in the isntances that should be sent traffic then it just exits.

I've actually bundled the haproxy binary with this repo to make things easier when getting started.

The update-haproxy.py script does a good job with basic setups using the default options but as things get more complex you may want to get more specific with the paramters. For instance, if you decide to run multiple instances at the same time then you should probably specifify different templates, outputs and pid files for each.

Installation

Run sudo python setup.py install and if everything goes well you're ready to configure (if you have complex needs) and run the update-haproxy.py command.

OR

sudo pip install git+https://github.com/markcaudill/haproxy-autoscale

Configuration

Most of the configuration is done via command line options. The only configuration that may need to be done is the haproxy.cfg template. You can customize it to suit your needs or you can specify a different on on the command line. Make sure to read the existing template to see what variables will be available to use.

IAM

Below is an example policy that should provide the minimal access necessary for this to work.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1458960803000",
            "Effect": "Allow",
            "Action": [
                "ec2:AssociateAddress",
                "ec2:DescribeAddresses",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeInstanceAttribute",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:DescribeRegions",
                "ec2:DescribeSecurityGroups"
            ],
            "Resource": [
                "arn:aws:ec2:*"
            ]
        }
    ]
}

Usage

haproxy-autoscale was designed to be run from the load balancer itself as a cron job. Ideally it would be run every minute.

update-haproxy.py [-h] --security-group SECURITY_GROUP
                  [SECURITY_GROUP ...] --access-key ACCESS_KEY
                  --secret-key SECRET_KEY [--output OUTPUT]
                  [--template TEMPLATE] [--haproxy HAPROXY] [--pid PID]
                  [--eip EIP] [--health-check-url HEALTH_CHECK_URL]
                  [--safe-mode]

Update haproxy to use all instances running in a security group.

optional arguments:
  -h, --help            show this help message and exit
  --security-group SECURITY_GROUP [SECURITY_GROUP ...]
  [--access-key ACCESS_KEY
  --secret-key SECRET_KEY]
                        Optional parameters in case the policy is assigned to the instance's role
  --output OUTPUT       Defaults to haproxy.cfg if not specified.
  --template TEMPLATE
  --haproxy HAPROXY     The haproxy binary to call. Defaults to haproxy if not
                        specified.
  --pid PID             The pid file for haproxy. Defaults to
                        /var/run/haproxy.pid.
  --eip EIP             The Elastic IP to bind to when VIP seems unhealthy.
  --health-check-url HEALTH_CHECK_URL
                        The URL to check. Assigns EIP to self if health check
                        fails.
  --safe-mode           If enabled, the script exits if there is any AWS exception.
                        E.g., wrong key/secret.'
                        Also if there is no instance in any of the security groups, haproxy conf
                        will be generated but NOT reloaded.

Example:

/usr/bin/python update-haproxy.py --access-key='SOMETHING' --secret-key='SoMeThInGeLsE' --security-group='webheads' 'tomcat-servers'

/usr/bin/python update-haproxy.py --access-key='SOMETHING' --secret-key='SoMeThInGeLsE' --security-group='webheads' 'tomcat-servers' --safe-mode

Changelog

  • v0.1 - Initial release.
  • v0.2 - Added ability to specify multiple security groups. This version is not compatible with previous versions' templates.
  • v0.3 - Added support for all regions.
  • v0.4 - Added accessor class for autobackend generation (see tests/data/autobackends_example.tpl for example usage)
  • v0.5 - Made access and security keys optional, replaced haproxy restart to reload, added path to the service command

(Above change logs are for version 0.4.1 and before.)

  • version 0.5.0 - Add --safe-mode: exit on aws exception, and no reload when security group is empty Redirect log to stdout so you can pipe it to other programs; Add timestamp for logging.
  • version 0.5.1 - Add --delay option. If specified, instances that were just created within DELAY seconds are not added into haproxy conf. Use when you want to give it some time to make sure the service on the instance is up and running before adding it into haproxy.

haproxy-autoscale's People

Contributors

alexandrusavin avatar bookest avatar erikbergsma avatar ironcore864 avatar jazzl0ver avatar markcaudill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

haproxy-autoscale's Issues

haproxy restarts constantly although configuration has not changed

Hey Mark,

I am doing some more testing, so far so good, excellent addition with the multiple security groups. One thing I found though is that when I cron the script to run every minute it restarts haproxy even though there are no new instances to add (or remove). See the log file bellow:

Feb 2 14:16:01 127.0.0.1 haproxy[4210]: Proxy demo_services started.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Pausing frontend demo.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Pausing frontend demo_services.
Feb 2 14:16:01 127.0.0.1 haproxy[4210]: Proxy demo started.
Feb 2 14:16:01 127.0.0.1 haproxy[4210]: Proxy demo_services started.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Stopping frontend demo in 0 ms.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Stopping backend demo_portal in 0 ms.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Stopping frontend demo_services in 0 ms.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Stopping backend demo_services in 0 ms.
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Proxy demo stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Proxy demo_portal stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Proxy demo_services stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:16:01 127.0.0.1 haproxy[4203]: Proxy demo_services stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:17:01 127.0.0.1 haproxy[4218]: Proxy demo_portal started.
Feb 2 14:17:01 127.0.0.1 haproxy[4218]: Proxy demo_services started.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Pausing frontend demo.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Pausing frontend demo_services.
Feb 2 14:17:01 127.0.0.1 haproxy[4218]: Proxy demo started.
Feb 2 14:17:01 127.0.0.1 haproxy[4218]: Proxy demo_services started.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Stopping frontend demo in 0 ms.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Stopping backend demo_portal in 0 ms.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Stopping frontend demo_services in 0 ms.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Stopping backend demo_services in 0 ms.
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Proxy demo stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Proxy demo_portal stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Proxy demo_services stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:17:01 127.0.0.1 haproxy[4211]: Proxy demo_services stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:18:02 127.0.0.1 haproxy[4226]: Proxy demo_portal started.
Feb 2 14:18:02 127.0.0.1 haproxy[4226]: Proxy demo_services started.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Pausing frontend demo.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Pausing frontend demo_services.
Feb 2 14:18:02 127.0.0.1 haproxy[4226]: Proxy demo started.
Feb 2 14:18:02 127.0.0.1 haproxy[4226]: Proxy demo_services started.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Stopping frontend demo in 0 ms.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Stopping backend demo_portal in 0 ms.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Stopping frontend demo_services in 0 ms.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Stopping backend demo_services in 0 ms.
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Proxy demo stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Proxy demo_portal stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Proxy demo_services stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:18:02 127.0.0.1 haproxy[4219]: Proxy demo_services stopped (FE: 0 conns, BE: 0 conns).
Feb 2 14:19:02 127.0.0.1 haproxy[4235]: Proxy demo_portal started.
Feb 2 14:19:02 127.0.0.1 haproxy[4235]: Proxy demo_services started.
Feb 2 14:19:02 127.0.0.1 haproxy[4227]: Pausing frontend demo.
Feb 2 14:19:02 127.0.0.1 haproxy[4227]: Pausing frontend demo_services.
Feb 2 14:19:02 127.0.0.1 haproxy[4235]: Proxy demo started.
Feb 2 14:19:02 127.0.0.1 haproxy[4235]: Proxy demo_services started.

Is there any special configuration I need to do to make it restart only when it detects changes?

Thank you in advance!

IAM permissions

maybe something for the next release?

  • An example minimal IAM policy, so that the key + secret can only be used for the functionality of this script
  • IAM role / credential file support (since you can see the paramaters given on the system if you do a "ps auxf")

401 Unauthorized from AWS

This just suddenly started happening without anything changing on our end. Oddly enough, we run this lib both in a staging environment and prod, but only the prod server stopped working. Both servers have the exact same configuration, running boto (2.35.1).

>>> from boto.ec2 import EC2Connection, get_region
>>> conn=EC2Connection(aws_access_key_id='KEY ID', aws_secret_access_key='KEY SECRET')
>>> conn.get_all_regions()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/boto/ec2/connection.py", line 3477, in get_all_regions
    [('item', RegionInfo)], verb='POST')
  File "/usr/local/lib/python2.7/dist-packages/boto/connection.py", line 1185, in get_list
    raise self.ResponseError(response.status, response.reason, body)
boto.exception.EC2ResponseError: EC2ResponseError: 401 Unauthorized
<?xml version="1.0" encoding="UTF-8"?>
<Response><Errors><Error><Code>AuthFailure</Code><Message>AWS was not able to validate the provided access credentials</Message></Error></Errors><RequestID>53deb9bb-b3f5-484c-82aa-a0cb60c2be0a</RequestID></Response>

Help with execute!

Hi, Forgive my ignorance, i don't know how to run update-haproxy.py with their params...
help me!...

Thanks

Problem process, a new one soon. cfg generated

Hi
process, a new one soon. cfg generated. It becomes an issue.
maxconn limited because it should. generated by the new auto scaling doeseo server information
Is there any way to add to the cfg?

Does it work with boto 2.23.0?

Hello,

I tried to use haproxy-autoscale and it ends up throwing errors and exiting when iterating over eu-west-1 for a security group that does not exist in that region. It never makes it to us-east-1 where the security group I specified actually exists.

I'm kind of baffled how to get past this even though I debugged it a bit. Is haproxy-autoscale known to work under boto v2.23.0?

Thank you,
syn

multiple backend capabilities

A very useful add-on to this excellent tool would be the ability to support multiple backends and multiple security groups.

Sample haproxy configuration file:

frontend demo *:5000
default_backend demo

backend demo
mode http
balance roundrobin
option httpchk HEAD /ha.txt HTTP/1.0
server i-6f0bd222 1.1.1.1:80 weight 100 check

fronted demo2 *:5001
default_backend demo2

backend demo2
mode http
balance roundrobin
option httpchk HEAD /ha.txt HTTP/1.0
server i-6f0bd1111 2.2.2.2:80 weight 100 check

In the above example, there are 2 different backends with instances running on two different security groups. making this tool aware of multiple instances on different security groups would allow you to auto-scale multiple backends at the same time using just one load balancer which in my opinion would be of incredible value for a true auto-scaling infrastructure running on ec2.

The suggested functionality would allow for the following:

  • Poll one or more security groups for running instances
  • Manipulate haproxy configuration template to attach the running instances to the corresponding backends

Example:
/usr/bin/python update-haproxy.py --security-group(s)=''rails-servers,java-servers"

haproxy.tpl:

frontend www *:80
mode http
maxconn 50000
default_backend servers

backend servers
mode http
balance roundrobin
% for instance in instances $SECURITY_GROUP_1:
server ${ instance.id } ${ instance.private_dns_name }
% endfor

frontend java *:8080
mode http
maxconn 50000
default_backend java-servers

backend java-servers
mode http
balance roundrobin
% for instance in instances $SECURITY_GROUP_2:
server ${ instance.id } ${ instance.private_dns_name }
% endfor

Thank you and great job!!!

Wrong key/secret doesn't exit; empty instances list would generate empty cfg and reload and ruin the env.

Good script. Thanks a lot first. We are planning to use it in production.

But I met the issues mentioned in the title. I'm not sure if this is by design, or a bug.

  1. For example, you have a test environment, and a production one. After you test it, you run it on prod, but somehow you forget to update the key/secret, and boto.exception.EC2ResponseError is thrown, but since the program continues, a new conf with empty instance list would be generated and reloaded, and the environment won't work anymore.
  2. Or if the instance list from a group is empty, it would still generate a new conf with empty instance list.

My five cents:

  • Maybe we can add a new option, like IS_PRODUCTION, which if is true, don't generate empty conf and definitely don't reload the empty conf.
  • Or add some checks in generate_haproxy_config to test if instances is empty or not. If empty, give some warnings and don't reload.
  • Multiple ways to improve this. But again, I'm not sure if this is a bug or by design. Maybe you want to generate a conf no matter there is instance or not.

If I were you, I would exit directly in case of EC2ResponseError, and in case of empty instances list, give warning and don't reload.

What do you think? If you agree but don't have time I can contribute a PR for this.

make keys supplying not necessary

Hi,

Please make access and security keys non-required parameters, since they're not need when an instance's role has an appropriate policy setup

Feature request: Configurable Regions

Hello,
I have noticed that the script defaults to US Region, which is not where my SecurityGroups resides (they live in EU Region): It would be nice if one could have a switch to set the Region, otherwise the secgroup could not be found and the whole script would be unusable.
Thanks in advance,
Ernesto Ferrari

Issue running update-haproxy.py

user@myipaddress:~/haproxy-autoscale$ /usr/bin/python update-haproxy.py --access-key='***********************' --secret-key='**********************************' --security-group='my-sg'
INFO:root:no "--servicename" OR "--haproxy" arguments found, defaulting to restarting service haproxy
INFO:root:Getting instances for netadmin-sg.
INFO:root:Generating configuration for haproxy.
Traceback (most recent call last):
File "update-haproxy.py", line 89, in
main(args)
File "update-haproxy.py", line 57, in main
instances=instances)
File "/home/xdeploy/haproxy-autoscale/haproxy_autoscale/haproxy_autoscale.py", line 90, in generate_haproxy_config
return Template(filename=template).render(instances=instances)
File "/usr/local/lib/python2.7/dist-packages/Mako-1.0.6-py2.7.egg/mako/template.py", line 462, in render
return runtime.render(self, self.callable, args, data)
File "/usr/local/lib/python2.7/dist-packages/Mako-1.0.6-py2.7.egg/mako/runtime.py", line 838, in _render
**kwargs_for_callable(callable, data))
File "/usr/local/lib/python2.7/dist-packages/Mako-1.0.6-py2.7.egg/mako/runtime.py", line 873, in _render_context
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
File "/usr/local/lib/python2.7/dist-packages/Mako-1.0.6-py2.7.egg/mako/runtime.py", line 899, in exec_template
callable
(context, *args, **kwargs)
File "templates_haproxy_tpl", line 22, in render_body
KeyError: 'security-group-1'

This is what I get when I run the update file. I saw somewhere that you mentioned that the config won't work this way and it is just a template. How do I set the update-haproxy.py to simply pull from the 'my-sg' security group?

Can you please assist with this issue?

Regards,
Idan.

No module named setuptool

Hi, i have a problem,

When execute sudo python setup.py install, does not find "setuptools"

the Error is: ImportError: No module named setuptools

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.