• Stars
    star
    229
  • Rank 174,666 (Top 4 %)
  • Language
    Go
  • License
    Apache License 2.0
  • Created over 9 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

'Anycast' in AWS

AWSnycast

Build Status Coverage Status

AWSnycast is a routing daemon for AWS route tables, to simulate an Anycast like service, and act as an extension of in-datacenter Anycast. It can also be used to provide HA NAT service.

WARNING

Please use release version 0.1.5 rather than master.

Anycast in AWS?

AWSnycast allows you to implement an Anycast-like method of route publishing - based on healthchecks, and HA/failover. This is very similar to using systems like exabgp or bird on traditional datacenter hosts to publish BGP routing information for individual /32 IPs of services they're running.

This means that all your systems in AWS (no matter what region or account) can use the same IP/subnet for highly available services (avoiding the need to reconfigure things at boot time if you're constructing AMIs).

If you have a physical datacenter with Anycast already, you can configure VPN tunnels, or Direct Connects to AWS then publish routes to the Amazon routing tables using BGP, including an Anycast /24 or /16 - things you bring up in AWS will have more specific routes locally, but services which only reside in your datacenter will automatically be routed there.

This is super useful for bootstrapping a new VPC (before you have any local services running), or for providing high availability.

N.B. Whilst publishing routes from AWS into your datacenter's BGP would be useful, at this time that is beyond the goals for this project.

NAT

A common pattern in AWS is to route egressing traffic (from private subnets) through a NAT instance in a public subnet. AWSnycast can publish routes for one or more NAT instances for you automatically, allowing you to deploy one or more NAT instances per VPC.

AWS have recently added a NAT gateway product, which simplifies redunent NAT, and allows you to burst to 10G (which needs high spec NAT instances to do).

For small amounts of traffic, NAT gateway is cheaper than NAT instancesm for large amounts of traffic it becomes more expensive - however NAT instances with AWSnycast probably have a lower reliability, as HA/failover won't happen until the failed machine is stopped/blackholed.

If you choose to use NAT instances, and AWSnycast to manage their routes, you can deploy 2 (or more) NAT machines, in different availability zones, and configure a private routing table for each AZ. AWSnycast can then be used to advertise the routes to these NAT machines for High Availability, such that by default, both machines will be active (for their AZ - to avoid cross AZ transfer costs + latency), however if one machine fails, then the remaining machine will take over it's route for the duration that it's down.

How does this even work?

You can setup routes in AWS to go to an individual instance. This means that you inject routes that are outside the addesses space for your VPC, and point them to an instance, failing over to a different instance if the machine providing the service fails.

All you have to do on the instance itself is setup a network interface which can deal with this traffic; for example, alias lo0:0 as 192.168.1.1 and disable source/destination checking for that instance in AWS.

By advertising a larger range via BGP (from VPN or Direct connect) and then injecting /32 routes for the AWS instances of individual services, you get both bootstrapping (being able to bootstrap new AWS regions from a VPN connection, as critical services such as dns and puppet/chef are always at a fixed IP address) and HA.

Why not manage / move ENIs?

Good question! You can provide HA in AWS by assigning each service an ENI (Elastic Network Interface), and moving them between healthy instances.

There are a number of reasons I chose not to do this:

  • Most AWS machine classes/sizes are fairly restricted about the number of ENIs they can have attached.
  • ENIs need to be detached then re-attached - so failover isn't atomic and it makes writing reliable distributed software to do this hard without a strong consensus store. (Think detach-fight!)
  • I explicitly didn't want to depend on a strong consensus store (to make this useful for VPC bootstrapping).
  • ENIs are an AWS only solution, and don't/can't provide parity with existing Anycast implementations in datacenter.

What do you recommend using this for?

Basic infrastructure services, like DNS (if you use your own DNS already), puppet or chef servers, package repositories, etc. This is not a load balancing or SOA service discovery solution.

I'd highly recommend putting any TCP service you use AWSnycast for behind haproxy, for load balancing (as only one route can be active at a time - i.e. AWS doesn't support any form of ECMP), and to make AWSnycast's failover only needed when an instance dies, rather than an individual service instance.

If you're building an SOA, and for 'application level' rather than 'infrastructure level' services, I'd recommend checking out Consul, Smartstack and similar technologies.

Trying it out

In the tests/integration folder, there is Terraform code which will build a simple AWS VPC, with 2 AZs and 2 NAT machines (with HA and failover), and AWSnycast setup.

To try this, you can install the binary and then terraform apply in that directory to build the example network, then make sshnat to log into one of the machines, and journalctl -u awsnycast to view the logs.

Try terminating one of the machines and watch routes fail over!

FIXME!! More details about how to test / curl things here..

Installing (binary)

You can install binary release versions onto x86 Linux directly from github, e.g.

sudo wget https://github.com/bobtfish/AWSnycast/releases/download/v0.1.0/AWSnycast -O /usr/local/bin/AWSnycast
sudo chmod 700 /usr/local/bin/AWSnycast

or you can install the .deb or .rpm packages found at the same location

Building from source

You need go installed to build this project (tested on go 1.5+1.6).

Once you have go installed, and the GOPATH environment variable setup (to, for example, /Users/tdoran/go), you should be able to install with:

go get github.com/mattn/gom
go get github.com/bobtfish/AWSnycast
cd /Users/tdoran/go/src/github.com/bobtfish/AWSnycast
make

This will build the binary at the top level of the checkout (i.e. in /Users/tdoran/go/src/github.com/bobtfish/AWSnycast/AWSnycast in my example)

Running it

You can run AWSnycast -h to get a list of helpful options:

Usage of AWSnycast:
  -debug
        Enable debugging
  -f string
        Configration file (default "/etc/awsnycast.yaml")
  -noop
        Don't actually *do* anything, just print what would be done
  -oneshot
        Run route table manipulation exactly once, ignoring healthchecks, then exit

Once you've everything is fully set up, you shouldn't need any options.

To run AWSnycast also needs permissions to access the AWS API. This can be done either by supplying the standard AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or by applying an IAM Role to the instance running AWSnycast (recommended).

An example IAM Policy is shown below:

{
  "Version": "2012-10-17",
  "Statement": [
        {
            "Action": [
                "ec2:ReplaceRoute",
                "ec2:CreateRoute",
                "ec2:DeleteRoute",
                "ec2:DescribeRouteTables",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeInstanceAttribute"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

DescribeRouteTables + Create/Delete/ReplaceRoute are used for the core functionality, DescribeNetworkInterfaces is used to get the primary IP address of other instances which are found to be owning a route (for remote health checks), and DescribeInstanceAttribute is used to check that the local machine has src/dest checking disabled (and refusing to start if it doesn't as a safety precaution).

Note that this software does not need root permissions, and therefore should not be run as root on your system. Please run it as a normal user (or even as nobody if you're using an IAM Role).

Configuration

AWSnycast reads a YAML config file (by default /etc/awsnycast.yaml) to learn which routes to advertise.

An example config is shown below:

    ---
    poll_time: 300 # How often to poll AWS route tables
    healthchecks:
        public:
            type: ping
            destination: 8.8.8.8
            rise: 2  # How many need to succeed in a row to be up
            fall: 10 # How many need to fail in a row to be down
            every: 1 # How often, in seconds
        localservice:
            type: tcp
            destination: 192.168.1.1
            rise: 2
            fall: 2
            every: 30
            config:
                send: HEAD / HTTP/1.0 # String to send (optional)
                expect: 200 OK        # Response to get back (optional)
                port: 80
    remote_healthchecks:
        service:
            type: tcp
            rise: 20 # Note we set these a lot higher than local healthchecks
            fall: 20
            every: 30
            config:
                send: HEAD / HTTP/1.0 # String to send (optional)
                expect: 200 OK        # Response to get back (optional)
                port: 80
    routetables:
        # This is our AZ, so always try to takeover routes always
        our_az:
            find:
                type: and
                config:
                  - type: by_tag
                    config:
                        key: az 
                        value: eu-west-1a
                  - type: by_tag
                        config:
                            key: type
                            value: private
            manage_routes:
              - cidr: 0.0.0.0/0     # NAT box, so manage the default route
                instance: SELF
                healthcheck: public
                never_delete: true   # Don't delete the default route if google goes down ;)
              - cidr: 192.168.1.1/32 # Manage an AWSnycast service on this machine
                instance: SELF
                healthcheck: localservice
                remote_healthcheck: service
        # This is not our AZ, so only takeover routes only if they don't exist already, or
        # the instance serving them is dead (terminated or stopped).
        # Every backup AWSnycast instance should have if_unhealthy: true set for route tables
        # it is the backup server for, otherwise multiple instances can cause routes to flap
        other_azs:
            find:
                no_results_ok: true # This allows you to deploy the same config in regions you only have 1 AZ
                type: and
                config:
                    filters:
                      - type: by_tag
                        not: true
                        config:
                            key: az
                            value: eu-west-1a
                      - type: by_tag
                        config:
                            key: type
                            value: private
            manage_routes:
              - cidr: 0.0.0.0/0
                if_unhealthy: true # Note this is what causes routes only to be taken over not present currently, or the instance with them has failed
                instance: SELF
              - cidr: 192.168.1.1/32
                if_unhealthy: true
                instance: SELF
                healthcheck: localservice
                remote_healthcheck: service

Healthchecks

Healthchecks are indicated by the top level 'healthchecks' key. Values are a hash of name / definition.

The definition is composed of a few fields:

  • type - required
  • destination - required. The destination IP for the healthcheck. This must be an IP.
  • rise - optional, how many checks need to pass in a row to become healthy. Default 2
  • fall - optional, how many checks need to fail in a row to become unhealthy. Default 2
  • every - required, how often in seconds to run the healthcheck
  • config - optional, A hash of keys/values for the specific healthcheck type you are using
  • run_on_healthy - optional. An array holding a script/command to run when the healthcheck becomes healthy.
  • run_on_unhealthy - optional. An array holding a script/command to run when the healthcheck becomes unhealthy.

ping

Does an ICMP ping against the destination.

tcp

Makes a TCP connection against the destination on a port. Optionally sends data and checks returned data.

Takes a number of config parameters:

  • port - required, the port number to connect on
  • send - optional, a string to send to the remote side
  • expect - optional, a string to expect back in the response from the remote side
  • ssl - optional, a bool for if to use TLS to connect
  • certPath - optional, path to a file containing a certificate
  • cert - optional, the certificate as a string
  • skipVerify - optional, a bool which if true will skip certificate verification
  • serverName - FIXME

command

Run an arbitrary command. Exit status 0 is success, anything else is a failure.

Takes the following config parameters:

  • command - required, the command to run
  • arguments - options, a list of arguments to supply to the command.

If any of the arguments contains the string %DESTINATION% then it will be replaced by the healthcheck destination.

For example, you can replicate the ping healthcheck with the following arguments:

  • command - ping
  • arguments - -c, 1, %DESTINATION%

Route tables

Indicated by the top level 'route_tables' key. Values are a hash of name / definition.

The definition is composed of a few fields:

  • find (see Finding them below)
  • manage_routes (see Managing them below)

Finding them

Route tables are found by various 'filters' which you can configure. Each finder has a 'type' and some 'config'.

Depending on the type of your finder, different config keys are required / valid.

All filters can optionally take a 'not' key, which if true inverts the result

Top level filters can optionally take a 'no_results_ok' key, which if true stops AWSnycast from failing if no route tables can be found. Use this when you want a setup with a backup server / az in some regions, but you want to deploy the same config in all regions.

Currently supported filters are:

by_tag

Does a simple equality match on a tag. Expects config keys 'key' and 'value', whos values are exaclty matched with the tag's key and value.

by_tag_regexp

Does a regexp match on a tag. Expects config keys 'key' and 'regexp'. The regexp is non anchored so include ^ and/or $ if you want to test against the whole string.

and

Runs a series of other filters, and only matches if all of it's filters match.

Supply a list to the 'filters' config key, with values being hashes of other finders

or

Runs a series of other filters, and matches if any of it's filters match.

Supply a list to the 'filters' config key, with values being hashes of other finders

main

Matches the main route table only. Takes no config parmeters

subnet

Matches the route table associated with the subnet given in the 'subnet_id' config key

has_route_to

Matches any route tables which have a route to a specific (and exact) cidr (given by the 'cidr' config key).

Managing them

Routes to be managed are a list of hashes, with the following keys:

  • cidr - required. The address to advertise into the route table
  • instance - required. The Amazon instance ID to route this cidr to. Can be SELF to mean this instance
  • healthcheck - optional. The string name of the healthcheck to associate with this route. If the healthcheck doesn't pass then the route will be removed from the routing table (allowing you to failover to a wider scope Anycast route advertised from your datacenter)
  • if_unhealthy - true. Only take this route over if the instance currently associated with it is unhealthy in the AWS route table (i.e. black holing traffic). This is used for backup servers in a multi-az deployment.
  • remote_healthcheck - FIXME
  • run_before_replace_route - FIXME
  • run_after_replace_route - FIXME
  • run_before_add_route - FIXME
  • run_after_add_route - FIXME

Releases

Release (stable) versions of AWSnycast are tagged in the repository, and go binaries (generated by Travis CI) are uploaded to github - see the CHANGELOG.md for information about what is in each release.

Note that currently this project is pre-1.0, so I reserve the right to make massive sweeping changes between versions.

Note also that incorrect use of this project can completely mess up your AWS routing tables, and make your instances inaccessible! You are HIGHLY recommended to become confident using the -noop mode before running this for real!

TODO

This project is currently under heavy development.

Here's a list of the features that I'm planning to work on next, in approximate order:

  • Autodetect this machine's AZ
  • Make us autodetect the VPC this instance is running in, and refuse to adjust routing tables in other VPCs
  • Enable the use of multiple different healthchecks for a route (to only consider it down if multiple checks fail)
  • Add serf gossip between instances, to allow faster and reliable failover/STONITH
  • Add the ability to have external clients participate in healthchecks in the serf network.
  • Add a web interface to be able to get the state as HTML or JSON (and manually initiate failovers?)

Contributing

Bug reports, success(or failure) stories, questions, suggestions, feature requests and (documentation or code) patches are all very welcome.

Please feel free to ping t0m on Freenode or @bobtfish on Twitter if you'd like help configuring/using/debugging/improving this software.

Please note however that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Copyright

Copyright Tomas Doran 2015

License

Apache2 - See the included LICENSE file for more details.

More Repositories

1

text-markdown

The perl Text::Markdown CPAN module
HTML
50
star
2

catalystx-simplelogin

Simple login controller and template bundle for Catalyst
Perl
26
star
3

text-multimarkdown

Text::MultiMarkdown CPAN module
Perl
21
star
4

terraform-provider-nsone

A terraform provider to manage zones/records/feeds in nsone
Go
17
star
5

terraform-aws-coreos-kubernates-cluster

Smarty
16
star
6

catalyst-app-example-locallibapp

Perl
12
star
7

puppet-aws_api

DEPRECATED. DO NOT USE.
Ruby
12
star
8

tf_aws_mesos

Makefile
12
star
9

terraform-vpc-nat

HCL
10
star
10

docker-socket-http-proxy

Simple nginx proxy container for the docker socket
Nginx
9
star
11

CatalystX-JobServer

Asynchronous job AMQP job server and message handler, with long hair.
Perl
9
star
12

catalystx-dynamiccomponent

Generate an entire trivial app, including the code for controllers and models from config. Moosetastic.
Perl
8
star
13

catalyst-actionrole-acl

Apply ACLs to Catalyst actions
Perl
7
star
14

nerve-etcd

Nerve registration container (etcd backend)
Shell
6
star
15

synapse-etcd-amb

Synapse Ambassador container (etcd servicewatcher)
Shell
6
star
16

terraform-example-mesos-cluster

A self contained example of using Terraform to build a Mesos cluster
Makefile
6
star
17

perl-php-serialization

PHP::Serialization CPAN module
Perl
6
star
18

moosex-types-iso8601

ISO 8601 times and duration strings, with coercions from DateTimes
Perl
5
star
19

arduino-mumble-mic-ptt

An Arduino sketch to turn an UNO into a HID keyboard, for adapting a PTT CB mic for use with http://mumble.sourceforge.net/
Arduino
5
star
20

MogileFS-Client-Async

Asynchronous (AnyEvent) MogileFS client
Perl
5
star
21

log-message-structured

Simple structured log messages as JSON
Perl
4
star
22

terraform-vpc

HCL
4
star
23

puppet-ethtool

Set ethernet options from puppet
Ruby
4
star
24

app-git-sync

Little app to ensure that I have an up to date clone of everything relevant on my laptop.
Perl
4
star
25

aws-instance-health-exporter

Prometheus exporter for AWS instance health events
Go
4
star
26

sensuplugingo

A simple framework for writing sensu checks and handlers in golang
Go
3
star
27

catalyst-traitfor-request-proxybase

Catalyst Request trait which allows you to set the URI base with a HTTP header
Perl
3
star
28

test-eol

Test perl files in your distribution have correct line endings
Perl
3
star
29

MooseX-Types-LoadableClass

Trivial type coercion to load a class type.
Perl
3
star
30

catalyst-engine-stomp

Catalyst::Engine::Stomp - message-driven Catalyst
Perl
3
star
31

terraform-example-vpc

HCL
3
star
32

alien-apachemq

perl Alien::ActiveMQ package
Perl
3
star
33

MonitoringJS

Javascript mash up of mcollective registration data, mongodb puppet and nagios-api, with bootstrap
JavaScript
3
star
34

moosex-strictattributes

Make Moose attribute definitions stricter
Perl
2
star
35

catalyst-app-tutorial-kiffin-authissues

Perl
2
star
36

mcollective-discovery-sensu

mcollective-disocovery-sensu
Ruby
2
star
37

catalyst-app-example-chainedprotocol

Example app for a blog post :) (Nothing to see here yet)
Perl
2
star
38

IPC-Lock-RabbitMQ

Perl
2
star
39

App-RabbitTail

Spew log files into RabbitMQ
Perl
2
star
40

moosex-types-datetime-mysql

Perl
2
star
41

Devel-InterpreterSize

Devel-InterpreterSize
Perl
2
star
42

ipc-shellcmd

The IPC::ShellCmd perl module
Perl
2
star
43

mcollective-agent-repository

mco agent to update svn and git repositories
Ruby
2
star
44

moosex-types-email

Email address type for Moose
Perl
2
star
45

Kaizendo

A tool for collaborative authoring of polyscopic documents
Perl
2
star
46

catalyst-actionrole-findviewbyisa

Action role to find a view from the available application views by superclass
Perl
2
star
47

terraform-ubuntu-ami

Terraform module for finding public ubuntu AMIs
Ruby
2
star
48

fcgi2

Mirror of FCGI.pm from git://git.shadowcat.co.uk/catagits/fcgi2.git
C
2
star
49

terracraft

Minecraft server and terraform
HCL
2
star
50

catalyst-app-bug-unknown-error

Perl
2
star
51

Alien-Ditaa

Trivial wrapper for ditaa (http://ditaa.sourceforge.net) to enable using in in perl.
Perl
2
star
52

catalyst-app-bug-go_chain

Perl
2
star
53

acme-UNIVERSAL-cannot

Adds cannot, cant and can't methods to UNIVERSAL, so that all your perl programs get the 'benefit' of negative method assertions
Perl
2
star
54

net-zuora

perl SOAP::Lite wrapper for the Zuora Z-Billing API
Perl
2
star
55

Catalyst-View-ContentNegotiation-XHTML

Perl
1
star
56

puppet-pgx

Experimental puppet DSL parser, for the lols
Perl
1
star
57

Message-Passing-Output-Growl

Message-Passing-Output-Growl
Perl
1
star
58

catalyst-app-example-newscripts

Example catalyst app as generated by the new scripts. Just a placeholder so I don't keep having to install -Devel and generate one
Perl
1
star
59

vagrant-docker

Ruby
1
star
60

perl-smartmatch-tests

tests for the ~~ fixes for 5.10.1
Perl
1
star
61

Noose

just enough object orientation to hang yourself
Perl
1
star
62

App-TailRabbit

Perl
1
star
63

Net-AMQP-PP

Perl
1
star
64

Message-Passing-STOMP

Log-Stash-STOMP
Perl
1
star
65

coreos-smartstack-demo

Ruby
1
star
66

Message-Passing-Collectd

Message-Passing-Collectd
Perl
1
star
67

catalystx-script-fcgi-engine

A Catalyst FastCGI script to use FCGI::Engine
Perl
1
star
68

mayhem

Go
1
star
69

coreos-jenkins

Experimental Jenkins cluster
Shell
1
star
70

Form-Functional

Perl
1
star
71

perl_proc_background

git clone of the Proc::Background module from http://www.orcaware.com/svn/repos/perl_proc_background/
Perl
1
star
72

App-TailRabbit-Growl

Perl
1
star
73

catalyst-app-bug-lighty-encodingwarnings

Using lighty and fcgi with C::P::Session + C::P::Unicode - encoding can get totally screwed if you use encoding::warnings.. Weird! Please someone fix for me?
Perl
1
star
74

puppet-network_address_functions

Ruby
1
star
75

authen-ntlm-http

Authen::NTLM::HTTP - another one of my abandoned module rescues
Perl
1
star
76

Presentation-Refactoring_with_Moose

Rewrite of my original #london.pm presentation + infrastructure to build and install slides on disk..
JavaScript
1
star
77

griwlrssi

A stupid, no-brainer, unconfigurable growl notifier for irssi->screen->ssh
Perl
1
star
78

Presentation-Quanto-PerlLuaJQuery_MySQLStats

Lightning talk for the BCS dynamic languages evening
JavaScript
1
star
79

bobtfish.github.io

My blog
HTML
1
star
80

Math-Inequalities-Parser

Math::Inequalities::Parser CPAN module
Perl
1
star
81

Module-Install-Authority

Adds x_authority to META.yml for Module::Install based installers
Perl
1
star
82

puppet-disable_caller_module_name

Hacks the puppet DSL to make $caller_module_name == $module_name, thus disabling 'private' classes.
Ruby
1
star
83

CatalystX-Debug-ResponseHeaders

Add all the response headers to a Catalyst debug screen.
Perl
1
star
84

AnyMQ-Hippie

Perl
1
star
85

CatalystX-Debug-RequestHeaders

Add all the request headers to a Catalyst debug screen.
Perl
1
star
86

Audio-SndFile

Release history of Audio-SndFile
Perl
1
star
87

catalyst-traitfor-controller-renderview

Experimental replacement for Catalyst::Action::RenderView
Perl
1
star
88

catalyst-model-ldap-fromauthentication

Ties Catalyst::Authentication::Store::LDAP and Catalyst::Model::LDAP together to give you a model which is connected as the user you authenticated as.
Perl
1
star
89

local-lib-deps

This module uses local::lib to allow applications to maintain a private path of dependancy modules.
Perl
1
star
90

http-proxy-selective

HTTP::Proxy using CSS dev tool, now 'open sourced' by Venda who I wrote it for, so githubbing the code
Perl
1
star
91

DBD-mysql

DBD::mysql Perl client driver for the MySQL and MariaDB databases
Perl
1
star
92

Module-Install-AutoProvidesFromCompilation

Fill in the provides metadata in your distribution by hooking compilation of the code, ergo getting correct metadata for things PAUSE won't recognise itself, like MX::Declare classes
Perl
1
star