Skip to content

Instantly share code, notes, and snippets.

@haproxytechblog
Last active April 25, 2019 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haproxytechblog/8356bdfce96c839476604cc9f92c4544 to your computer and use it in GitHub Desktop.
Save haproxytechblog/8356bdfce96c839476604cc9f92c4544 to your computer and use it in GitHub Desktop.
HAProxy on AWS: Best Practices Part 2
export AWS_ACCESS_KEY_ID=[YOUR ACCESS KEY]
export AWS_SECRET_ACCESS_KEY=[YOUR SECRET ACCESS KEY]
terraform init
terraform apply -auto-approve
// Lookup latest HAPEE AWS AMI (1.8r1 at this moment)
data "aws_ami" "hapee_aws_amis" {
most_recent = true
filter {
name = "product-code"
values = ["483gxnuft87jy44d3q8n4kvt1"]
}
filter {
name = "name"
values = ["hapee-ubuntu-xenial-amd64-hvm-1.8*"]
}
owners = ["aws-marketplace"]
}
// Lookup latest Ubuntu Xenial 16.04 AMI
data "aws_ami" "ubuntu_aws_amis" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
}
owners = ["099720109477"]
}
// IAM policy document - Assume role policy
data "aws_iam_policy_document" "instance_assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
// IAM policy document - EIP permissions policy
data "aws_iam_policy_document" "eip_policy" {
statement {
sid = "1"
actions = [
"ec2:DescribeAddresses",
"ec2:AllocateAddress",
"ec2:ReleaseAddress",
"ec2:DescribeInstances",
"ec2:AssociateAddress",
"ec2:DisassociateAddress",
"ec2:DescribeNetworkInterfaces",
"ec2:AssignPrivateIpAddresses",
"ec2:UnassignPrivateIpAddresses",
]
resources = ["*"]
}
}
// IAM role - EIP role
resource "aws_iam_role" "eip_role" {
name = "hapee_eip_role"
assume_role_policy = "${data.aws_iam_policy_document.instance_assume_role_policy.json}"
}
// IAM role policy - EIP role policy
resource "aws_iam_role_policy" "eip_role_policy" {
name = "hapee_eip_role_policy"
role = "${aws_iam_role.eip_role.id}"
policy = "${data.aws_iam_policy_document.eip_policy.json}"
}
// IAM instance profile - EIP instance profile
resource "aws_iam_instance_profile" "eip_instance_profile" {
name = "hapee_instance_profile"
role = "${aws_iam_role.eip_role.id}"
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"iam:AddRoleToInstanceProfile",
"iam:CreateInstanceProfile",
"iam:CreateRole",
"iam:GetInstanceProfile",
"iam:GetRole",
"iam:GetRolePolicy",
"iam:DeleteInstanceProfile",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:ListInstanceProfilesForRole",
"iam:PassRole",
"iam:PutRolePolicy",
"iam:RemoveRoleFromInstanceProfile",
"ec2:AllocateAddress",
"ec2:AssociateRouteTable",
"ec2:AssociateAddress",
"ec2:AttachInternetGateway",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:CreateInternetGateway",
"ec2:CreateRoute",
"ec2:CreateRouteTable",
"ec2:CreateSecurityGroup",
"ec2:CreateSubnet",
"ec2:CreateTags",
"ec2:CreateVpc",
"ec2:DescribeAddresses",
"ec2:DescribeImages",
"ec2:DescribeVpcs",
"ec2:DescribeVpcAttribute",
"ec2:DescribeVpcClassicLink",
"ec2:DescribeVpcClassicLinkDnsSupport",
"ec2:DescribeSecurityGroups",
"ec2:DescribeInternetGateways",
"ec2:DescribeNetworkAcls",
"ec2:DescribeRouteTables",
"ec2:DescribeSubnets",
"ec2:DescribeInstances",
"ec2:DescribeVolumes",
"ec2:DescribeTags",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstanceCreditSpecifications",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeAccountAttributes",
"ec2:DeleteSubnet",
"ec2:DeleteSecurityGroup",
"ec2:DeleteRouteTable",
"ec2:DeleteInternetGateway",
"ec2:DeleteVpc",
"ec2:DetachInternetGateway",
"ec2:DisassociateAddress",
"ec2:DisassociateRouteTable",
"ec2:ModifySubnetAttribute",
"ec2:ModifyVpcAttribute",
"ec2:ReleaseAddress",
"ec2:TerminateInstances",
"ec2:RevokeSecurityGroupEgress",
"ec2:RunInstances"
],
"Resource": "*"
}
]
}
ansible-playbook site.yml
apt install python-pip
pip install jmespath
- name: gather HAPEE EC2 ENI details
ec2_eni_facts:
region: "{{ region | default('us-east-1') }}"
filters:
attachment.instance-id: "{{ ec2_id }}"
register: aws_ec2_eni_facts
- name: add secondary IP address
ec2_eni:
region: "{{ region | default('us-east-1') }}"
eni_id: "{{ aws_ec2_eni_facts['network_interfaces'][0]['id'] }}"
subnet_id: "{{aws_ec2_eni_facts['network_interfaces'][0]['subnet_id'] }}"
state: present
secondary_private_ip_address_count: 1
#!/bin/bash
MAC_ADDR=$(ifconfig eth0 | sed -n 's/.*HWaddr \([a-f0-9:]*\).*/\1/p')
IP=($(curl "http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s" 2>/dev/null))
for ip in ${IP[@]:1}; do
echo "Adding IP: $ip"
ip addr show dev eth0 | grep -q "inet $ip/24" || ip addr add dev eth0 "$ip/24"
done
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
user hapee-lb
group hapee
chroot /var/empty
pidfile /var/run/hapee-1.8/hapee-lb.pid
stats socket /var/run/hapee-1.8/hapee-lb.sock user hapee-lb group hapee mode 660 level admin
stats timeout 10m
module-path /opt/hapee-1.8/modules
daemon
defaults
mode http
log global
option httplog
option dontlognull
option forwardfor except 127.0.0.0/8
option tcp-smart-accept
option tcp-smart-connect
option redispatch
retries 3
timeout connect 10s
timeout client 30s
timeout server 30s
listen webapp
bind *:80
balance roundrobin
cookie SERVERID insert indirect nocache
{% for backend in groups['tag_Name_hapee_web_node'] %}
server {{ hostvars[backend]['ec2_private_dns_name'] }} {{ hostvars[backend]['ec2_private_ip_address'] }}:80 cookie {{ hostvars[backend]['ec2_private_dns_name'] }} check
{% endfor %}
listen webapp
bind *:80
balance roundrobin
cookie SERVERID insert indirect nocache
server ip-20-0-0-66.ec2.internal 20.0.0.61:80 cookie ip-20-0-0-66.ec2.internal check
server ip-20-0-0-5.ec2.internal 20.0.0.252:80 cookie ip-20-0-0-5.ec2.internal check
server ip-20-0-0-63.ec2.internal 20.0.0.24:80 cookie ip-20-0-0-63.ec2.internal check
crm no
keepalive 2
deadtime 15
initdead 60
udpport 694
{% for backend in groups['tag_Name_hapee_lb_node'] %}
{% for addr in hostvars[backend]['aws_ec2_eni_facts']['network_interfaces'][0]['private_ip_addresses'] | map(attribute='private_ip_address') | list %}
ucast eth0 {{ addr }}
{% endfor %}
{% endfor %}
ping {{ ansible_default_ipv4.gateway }}
auto_failback on
{% for backend in groups['tag_Name_hapee_lb_node'] %}
node {{ hostvars[backend]['ansible_hostname'] }}
{% endfor %}
crm no
keepalive 2
deadtime 15
initdead 60
udpport 694
ucast eth0 20.0.0.33
ucast eth0 20.0.0.161
ucast eth0 20.0.0.182
ucast eth0 20.0.0.16
ping 20.0.0.1
auto_failback on
node ip-20-0-0-98
node ip-20-0-0-43
{{ hostvars[first_eip]['ansible_hostname'] }} updateEIP1
{{ hostvars[second_eip]['ansible_hostname'] }} updateEIP2
#!/bin/sh
EIP={{ first_eip }} # EIP1
ENI_ID={{ aws_ec2_eni_facts['network_interfaces'][0]['id'] }} # ENI local
ALLOCATION_ID={{ hostvars[first_eip]['aws_ec2_eip_facts']['addresses'][0]['allocation_id'] }} # EIP1 ID
PRIVATE_IP={% if ansible_host == first_eip %}{{ ec2_private_ip_address }}{% else %}{{ aws_ec2_eni_facts['network_interfaces'][0]['private_ip_addresses'] | json_query("[?private_ip_address!='" + ec2_private_ip_address + "'].private_ip_address") | first }}{% endif %}
export AWS_DEFAULT_REGION={{ ec2_region }}
case "$1" in
start)
timeout 60 aws ec2 associate-address --allow-reassociation --allocation-id "$ALLOCATION_ID" --network-interface-id "$ENI_ID" --private-ip-address "$PRIVATE_IP"
echo "$0" started
;;
stop)
timeout 60 aws ec2 disassociate-address --allocation-id "$ALLOCATION_ID"
echo "$0" stopped
;;
status)
timeout 10 aws ec2 describe-addresses --allocation-ids "$ALLOCATION_ID" | fgrep -q "\"$PRIVATE_IP\""
[ $? -eq 0 ] && echo OK || echo FAIL
;;
Esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment