TCP Proxy to a Postgres Database
docker compose up -d
docker compose run test
🚀
--- | |
services: | |
pghost: | |
image: postgres:15-alpine | |
environment: | |
POSTGRES_PASSWORD: foo | |
proxy: | |
build: . | |
ports: | |
- 5432:5432 | |
volumes: | |
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro | |
test: | |
image: postgres:15-alpine | |
entrypoint: "" | |
command: | | |
sh -c ' | |
pg_isready --host=proxy --username=postgres | |
' | |
profiles: | |
- test |
FROM haproxy:2.7-alpine | |
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg | |
ARG SOURCE_COMMIT="" | |
ENV DD_SERVICE="haproxy" DD_ENV="local" DD_VERSION="$SOURCE_COMMIT" |
global | |
log stderr format raw daemon info | |
defaults | |
log-format "{\"service\":\"$DD_SERVICE\",\"env\":\"$DD_ENV\",\"version\":\"$DD_VERSION\",\"client_ip\":\"%ci\",\"duration\":%Tt,\"bytes\":%B,\"terminaton_state\":\"%ts\",\"actconn\":%ac,\"beconn\":%bc,\"feconn\":%fc,\"retries\":%rc,\"srv_queue\":%sq,\"backend_queue\":%bq}" | |
maxconn 512 | |
option dontlognull | |
retries 3 | |
timeout check 2s | |
timeout connect 1s | |
# align client and server timeouts with db server (e.g. match idle_session_timeout value) | |
timeout client 180m | |
timeout server 180m | |
resolvers foo | |
parse-resolv-conf | |
frontend health | |
bind *:8080 # https://github.com/aws/containers-roadmap/issues/1721 | |
mode http | |
monitor fail if { nbsrv(curly) eq 0 } | |
monitor-uri /status | |
frontend larry | |
bind *:${PROXY_PORT} | |
default_backend curly | |
log global | |
mode tcp | |
backend curly | |
server moe ${PROXY_HOST}:${PROXY_PORT} resolvers foo check |
In the above, the server FQDN is looked up once one startup and cached. In order to respond to PROXY_HOST IP changes, a resolvers
section must be used;
global
log stderr format raw daemon info
defaults
mode tcp
log global
option dontlognull
option redispatch
retries 3
maxconn 32
resolvers foo
parse-resolv-conf
frontend larry
bind *:${PROXY_PORT}
default_backend curly
backend curly
server moe ${PROXY_HOST}:${PROXY_PORT} resolvers foo check
HAProxy will now log IP changes;
curly/moe changed its IP from 172.16.238.36 to 172.16.238.33 by foo/127.0.0.11.
to simulate this, an extended docker compose file can be used;
docker compose up
pghost
, e.g. from "172.16.238.33" to "172.16.238.34" and run docker compose up pghost -d
---
services:
pghost:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: foo
networks:
foo:
ipv4_address: "172.16.238.33"
proxy:
build: .
environment:
PROXY_HOST: pghost
PROXY_PORT: 5432
networks:
- foo
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
test:
image: postgres:15-alpine
entrypoint: ""
networks:
- foo
command: |
sh -c '
pg_isready --host=proxy --username=postgres
'
profiles:
- test
networks:
foo:
ipam:
driver: default
config:
- subnet: "172.16.238.0/24"
recent versions of haproxy support environment variable substitution within the
haproxy.cfg
file. this plays well with docker and helps us provide a portable solution.we can rewrite the simple, hard-coded example with one that is configurable using environment variables;
haproxy.cfg
docker-compose.yml