- Overview
- Module Description - What the module does and why it is useful
- Setup - The basics of getting started with haproxy
- Usage - Configuration options and additional functionality
- Configure HAProxy options
- HAProxy and Software Collections
- Configure HAProxy daemon listener
- Configure multi-network daemon listener
- Configure HAProxy load-balanced member nodes
- Configure a load balancer with exported resources
- Set up a frontend service
- Set up a backend service
- Set up a resolver
- Configure multiple haproxy instances on one machine
- Manage a map file
- Reference - An under-the-hood peek at what the module is doing and how
- Limitations - OS compatibility, etc.
- Development - Guide for contributing to the module
The haproxy module lets you use Puppet to install, configure, and manage HAProxy.
HAProxy is a daemon for load-balancing and proxying TCP- and HTTP-based services. This module lets you use Puppet to configure HAProxy servers and backend member servers.
The simplest HAProxy configuration consists of a server that listens on a port and balances against some other nodes:
node 'haproxy-server' {
include ::haproxy
haproxy::listen { 'puppet00':
collect_exported => false,
ipaddress => $facts['networking']['ip'],
ports => '8140',
}
haproxy::balancermember { 'server00':
listening_service => 'puppet00',
server_names => 'server00.example.com',
ipaddresses => '10.0.0.10',
ports => '8140',
options => 'check',
}
haproxy::balancermember { 'server01':
listening_service => 'puppet00',
server_names => 'server01.example.com',
ipaddresses => '10.0.0.11',
ports => '8140',
options => 'check',
}
}
The main haproxy
class has many options for configuring your HAProxy server:
class { 'haproxy':
global_options => {
'log' => "${facts['networking']['ip']} local0",
'chroot' => '/var/lib/haproxy',
'pidfile' => '/var/run/haproxy.pid',
'maxconn' => '4000',
'user' => 'haproxy',
'group' => 'haproxy',
'daemon' => '',
'stats' => 'socket /var/lib/haproxy/stats',
},
defaults_options => {
'log' => 'global',
'stats' => 'enable',
'option' => [
'redispatch',
],
'retries' => '3',
'timeout' => [
'http-request 10s',
'queue 1m',
'connect 10s',
'client 1m',
'server 1m',
'check 10s',
],
'maxconn' => '8000',
},
}
The above shown values are the module's defaults for platforms like Debian and RedHat (see haproxy::params
for details). If you wish to override or add to any of these defaults set merge_options => true
(see below) and set global_options
and/or defaults_options
to a hash containing just the option => value
pairs you need changed or added. In case of duplicates your supplied values will "win" over the default values (this is especially noteworthy for arrays -- they cannot be merged easily). If you want to completely remove a parameter set it to the special value undef
:
class { 'haproxy':
global_options => {
'maxconn' => undef,
'user' => 'root',
'group' => 'root',
'stats' => [
'socket /var/lib/haproxy/stats',
'timeout 30s'
]
},
defaults_options => {
'retries' => '5',
'option' => [
'redispatch',
'http-server-close',
'logasap',
],
'timeout' => [
'http-request 7s',
'connect 3s',
'check 9s',
],
'maxconn' => '15000',
},
}
To use this module with a software collection such as rh-haproxy18 you will need to set a few extra parameters like so:
class { 'haproxy':
package_name => 'rh-haproxy18',
config_dir => '/etc/opt/rh/rh-haproxy18/haproxy',
config_file => '/etc/opt/rh/rh-haproxy18/haproxy/haproxy.cfg',
config_validate_cmd => '/bin/scl enable rh-haproxy18 "haproxy -f % -c"',
service_name => 'rh-haproxy18-haproxy',
}
To export the resource for a balancermember and collect it on a single HAProxy load balancer server:
haproxy::listen { 'puppet00':
ipaddress => $facts['networking']['ip'],
ports => '8140',
mode => 'tcp',
options => {
'option' => [
'tcplog',
],
'balance' => 'roundrobin',
},
}
If you need a more complex configuration for the listen block, use the $bind
parameter:
haproxy::listen { 'puppet00':
mode => 'tcp',
options => {
'option' => [
'tcplog',
],
'balance' => 'roundrobin',
},
bind => {
'10.0.0.1:443' => ['ssl', 'crt', 'puppetlabs.com'],
'168.12.12.12:80' => [],
'192.168.122.42:8000-8100' => ['ssl', 'crt', 'puppetlabs.com'],
':8443,:8444' => ['ssl', 'crt', 'internal.puppetlabs.com']
},
}
Note: $ports
and $ipaddress
cannot be used in combination with $bind
.
First export the resource for a balancermember:
@@haproxy::balancermember { 'haproxy':
listening_service => 'puppet00',
ports => '8140',
server_names => $facts['networking']['hostname'],
ipaddresses => $facts['networking']['ip'],
options => 'check',
}
Then collect the resource on a load balancer:
Haproxy::Balancermember <<| listening_service == 'puppet00' |>>
Then create the resource for multiple balancermembers at once:
haproxy::balancermember { 'haproxy':
listening_service => 'puppet00',
ports => '8140',
server_names => ['server01', 'server02'],
ipaddresses => ['192.168.56.200', '192.168.56.201'],
options => 'check',
}
This example assumes a single-pass installation of HAProxy where you know the members in advance. Otherwise, you'd need a first pass to export the resources.
Install and configure an HAProxy service listening on port 8140 and balanced against all collected nodes:
node 'haproxy-server' {
include ::haproxy
haproxy::listen { 'puppet00':
ipaddress => $facts['networking']['ip'],
ports => '8140',
}
}
node /^server\d+/ {
@@haproxy::balancermember { $facts['networking']['fqdn']:
listening_service => 'puppet00',
server_names => $facts['networking']['hostname'],
ipaddresses => $facts['networking']['ip'],
ports => '8140',
options => 'check',
}
}
The resulting HAProxy service uses storeconfigs to collect and realize balancermember servers, and automatically collects configurations from backend servers. The backend nodes export their HAProxy configurations to the Puppet Server, which then distributes them to the HAProxy server.
This example routes traffic from port 8140 to all balancermembers added to a backend with the title 'puppet_backend00':
haproxy::frontend { 'puppet00':
ipaddress => $facts['networking']['ip'],
ports => '8140',
mode => 'tcp',
bind_options => 'accept-proxy',
options => {
'default_backend' => 'puppet_backend00',
'timeout client' => '30s',
'option' => [
'tcplog',
'accept-invalid-http-request',
],
},
}
If option order is important, pass an array of hashes to the options
parameter:
haproxy::frontend { 'puppet00':
ipaddress => $facts['networking']['ip'],
ports => '8140',
mode => 'tcp',
bind_options => 'accept-proxy',
options => [
{ 'default_backend' => 'puppet_backend00' },
{ 'timeout client' => '30s' },
{ 'option' => [
'tcplog',
'accept-invalid-http-request',
],
}
],
}
This adds the frontend options to the configuration block in the same order as they appear within your array.
haproxy::backend { 'puppet00':
options => {
'option' => [
'tcplog',
],
'balance' => 'roundrobin',
},
}
If option order is important, pass an array of hashes to the options
parameter:
haproxy::backend { 'puppet00':
options => [
{ 'option' => [
'tcplog',
]
},
{ 'balance' => 'roundrobin' },
{ 'cookie' => 'C00 insert' },
],
}
Note: This is only available on haproxy 1.6+
# Need to start with an init-addr parameter set to none and enable runtime DNS resolution.
class { 'haproxy':
...
defaults_options => {
'default-server' => 'init-addr none',
...
},
}
# Declare the resolver
haproxy::resolver { 'puppet00':
nameservers => {
'dns1' => '192.168.56.1:53',
'dns2' => '192.168.56.2:53'
},
hold => {
'nx' => '30s',
'valid' => '10s'
},
resolve_retries => 3,
timeout => {
'retry' => '1s'
},
accepted_payload_size => 512,
}
# Setup the balancermember to use the resolver for DNS resolution
haproxy::balancermember { 'haproxy':
listening_service => 'puppet00',
ports => '8140',
server_names => ['server01', 'server02'],
ipaddresses => ['server01', 'server02'],
options => 'check resolvers puppet00 resolve-prefer ipv4',
}
haproxy::backend { 'backend01':
options => [
{ 'stick-table' => 'type ip size 1 nopurge peers LB' },
{ 'stick' => 'on dst' },
],
}
This adds the backend options to the configuration block in the same order as they appear within the array.
This is an advanced feature typically only used at large sites.
It is possible to run multiple haproxy processes ("instances") on the same machine. This has the benefit that each is a distinct failure domain, each can be restarted independently, and each can run a different binary.
In this use case, instead of using Class['haproxy']
, each process
is started using haproxy::instance{'inst'}
where inst
is the
name of the instance. It assumes there is a matching Service['inst']
that will be used to manage service. Different sites may have
different requirements for how the Service[]
is constructed.
However, haproxy::instance_service
exists as an example of one
way to do this, and may be sufficient for most sites.
In this example, two instances are created. The first uses the standard
class and uses haproxy::instance
to add an additional instance called
beta
.
include ::haproxy
haproxy::listen { 'puppet00':
instance => 'haproxy',
collect_exported => false,
ipaddress => $facts['networking']['ip'],
ports => '8800',
}
haproxy::instance { 'beta': }
->
haproxy::instance_service { 'beta':
haproxy_package => 'custom_haproxy',
haproxy_init_source => "puppet:///modules/${module_name}/haproxy-beta.init",
}
->
haproxy::listen { 'puppet00':
instance => 'beta',
collect_exported => false,
ipaddress => $facts['networking']['ip'],
ports => '9900',
}
In this example, two instances are created called group1
and group2
.
The second uses a custom package.
haproxy::instance { 'group1': }
->
haproxy::instance_service { 'group1':
haproxy_init_source => "puppet:///modules/${module_name}/haproxy-group1.init",
}
->
haproxy::listen { 'group1-puppet00':
section_name => 'puppet00',
instance => 'group1',
collect_exported => false,
ipaddress => $facts['networking']['ip'],
ports => '8800',
}
haproxy::instance { 'group2': }
->
haproxy::instance_service { 'group2':
haproxy_package => 'custom_haproxy',
haproxy_init_source => "puppet:///modules/${module_name}/haproxy-group2.init",
}
->
haproxy::listen { 'group2-puppet00':
section_name => 'puppet00',
instance => 'group2',
collect_exported => false,
ipaddress => $facts['networking']['ip'],
ports => '9900',
}
haproxy::mapfile { 'domains-to-backends':
ensure => 'present',
mappings => [
{ 'app01.example.com' => 'bk_app01' },
{ 'app02.example.com' => 'bk_app02' },
{ 'app03.example.com' => 'bk_app03' },
{ 'app04.example.com' => 'bk_app04' },
'app05.example.com bk_app05',
'app06.example.com bk_app06',
],
}
This creates a file /etc/haproxy/domains-to-backends.map
containing the mappings specified in the mappings
array.
The map file can then be used in a frontend to map Host:
values to backends, implementing name-based virtual hosting:
frontend ft_allapps
[...]
use_backend %[req.hdr(host),lower,map(/etc/haproxy/domains-to-backends.map,bk_default)]
Or expressed using haproxy::frontend
:
haproxy::frontend { 'ft_allapps':
ipaddress => '0.0.0.0',
ports => '80',
mode => 'http',
options => {
'use_backend' => '%[req.hdr(host),lower,map(/etc/haproxy/domains-to-backends.map,bk_default)]'
}
}
For information on the classes and types, see the REFERENCE.md
For an extensive list of supported operating systems, see metadata.json
Acceptance tests for this module leverage puppet_litmus. To run the acceptance tests follow the instructions here. You can also find a tutorial and walkthrough of using Litmus and the PDK on YouTube.
If you run into an issue with this module, or if you would like to request a feature, please file a ticket. Every Monday the Puppet IA Content Team has office hours in the Puppet Community Slack, alternating between an EMEA friendly time (1300 UTC) and an Americas friendly time (0900 Pacific, 1700 UTC).
If you have problems getting this module up and running, please contact Support.
If you submit a change to this module, be sure to regenerate the reference documentation as follows:
puppet strings generate --format markdown --out REFERENCE.md