Reliable apps with (HA)Proxy — Part 3.

Docker Cake

This one is very easy on the eyes (and stomach), and rather useful. You can have your cake and eat it too! Just launch HAProxy inside docker container, where HAProxy will proxy the trafic and log to stdout. In addition to that, HAProxy can start and monitor additional processes, so you don’t have to play stupid tricks to start multiple processes in the container.

global
log stdout format raw local0 debug
defaults
log global
mode http
option httplog clf
option dontlognull
option httpchk
default-server check inter 5s fall 5 downinter 1s rise 2
timeout connect 5s
timeout client 10s
timeout server 10s
timeout http-request 1s
listen myapp
bind :8080
option httpchk GET /
server srv1 127.0.0.1:8081 check
program myserver
command /usr/bin/python3 -m http.server 8081

Docker file is not that complicated, we only make sure to install the latest stable HAProxy stuff from back-ports (regular Debian/Ubuntu HAProxy packages, back-ports and private PPA repository is managed by the same guy, thanks Vincent!).

FROM debian:bullseye
RUN export DEBIAN_FRONTEND=noninteractive && \\
echo 'deb <http://deb.debian.org/debian> bullseye-backports main' > \\
/etc/apt/sources.list.d/backports.list && \\
apt-get update -y && \\
apt-get install -y -t bullseye-backports haproxy && \\
apt-get install -y python3
COPY haproxy.conf /etc/haproxy/haproxy.cfg
CMD haproxy -W -db -f /etc/haproxy/haproxy.cfg

We’ve instructed HAProxy to start in foreground and master-worker mode, so it can start/restart other programs. This avoids random hacks necessary when you want to start multiple processes in the container. HAProxy can send UNIX signals on reload to your program, but it will not restart a crashed program (it will log the event though). If you really need restarts try catatonit, a proper minimal init system for containers, or even run with Podman, which properly supports running systemd inside container.

Say my name

In the cloud environments, you often need to speak with other services using DNS name of the service. One common pitfall is that such DNS records have very short TTL, and can easily change. Is your application ready for such environment? Do you need to restart it, do you have code handling DNS stuff? HAProxy to the rescue. Lets imagine you run your service in the AWS cloud:

resolvers aws
nameserver aws_local 169.254.169.253:53
hold valid 60s
listen myservice
http-request set-header Host %[env(MYSERVICE_HOST)]
bind 127.0.0.1:8081
server srv1 "${MYSERVICE_HOST}":443 ssl verify none check resolvers aws resolve-prefer ipv4

169.254.169.253:53 is AWS DNS resolver, in the reserved IP block, always available to your applications. We’ve instructed HAProxy to run DNS resolver on our behalf, and cache results for 60 seconds. Our application doesn’t need nor should do any DNS resolving by itself. It should only connect to the outside world via HAProxy.

We didn’t hard-code the DNS name of the service, it is specified in the execution environment (e.g. that works on bare EC2 machines, but on ECS/EKS too). To be on the safe side, we set Host header, so our application doesn’t need to know anything about the service, it just needs to connect to localhost, port 8081 (i.e. we can route many apps just by mapping port numbers).

The Docker Cake + Say my name essay is part of a series of "recipes" that explore the ways of bulding reliable applications with (HA)Proxy.PS. If you have any questions on any of the above outlined thoughts, feel free to share them in the comment section.Click here to read Part 4.: Service Discovery Ice cream — The long and winding road to K8s

--

--