Skip to content

Commit

Permalink
feat(dns): use dns resolvers to for dns failover routing scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Schönthal committed Jan 24, 2025
1 parent 86f30ce commit 6fccf91
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 26 deletions.
87 changes: 68 additions & 19 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ jobs:
docker logs statista_proxy
- name: Test Docker Image with Cookie Strategy without cookie
id: test-cookie-no-cookie
continue-on-error: true
run: |
curl -Is localhost:80 | grep -i -e "x-proxy-flow: route-to-legacy"
- name: Test Docker Image with Cookie Strategy with cookie
continue-on-error: true
run: |
curl -Is --cookie "my_app_routing=new" localhost:80 | grep -i -e "x-proxy-flow: route-to-new"
Expand All @@ -86,18 +89,26 @@ jobs:
docker logs statista_proxy
- name: Test Docker Image with Percentage Strategy backend selection
id: test-percentage-strategy
continue-on-error: true
run: |
curl -Is localhost:80 | grep -i -e "x-proxy-flow: route-to-percentage"
- name: Test Docker Image with Percentage Strategy with sticky cookie on old domain
id: test-percentage-sticky-old-domain
continue-on-error: true
run: |
curl -Is localhost:80 --cookie "my_app=old_domain" | grep -i -e "server: Apache"
- name: Test Docker Image with Percentage Strategy with sticky cookie on new domain
id: test-percentage-sticky-new-domain
continue-on-error: true
run: |
curl -Is localhost:80 --cookie "my_app=new_domain" | grep -i -e "x-served-by: cache-"
- name: Test Docker Image with Percentage Strategy with round robin
id: test-percentage-round-robin
continue-on-error: true
# sadly we dont know which server serves us first, so we have to check both
run: |
curl -Is localhost:80 | grep -i -e "server:" -e "x-served-by:" -e "set-cookie: my_app=new_domain; path=/" -e "set-cookie: my_app=old_domain; path=/"
Expand All @@ -107,53 +118,91 @@ jobs:
if: success() || failure()
run: docker rm -f statista_proxy

# validation TEMPLATE
#- name: name of the test
# timeout-minutes: 1 # set so if the command runs successfully the test will fail
# id: test-validation-percentage-new # important since all steps run and we collect the failure at then end
# continue-on-error: true # important for allowing other steps to be run regardless of this one which might fail
# run: |
# ! docker run \ # important simply negate the exit code, since we expect the container to fail (which means succesfull validation)
# -e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 \
# "${{ env.IMAGE_NAME }}"

# variable validation
- name: Run Docker Image with Invalid new Percentage
timeout-minutes: 1
id: test-validation-percentage-new
continue-on-error: true
run: |
set +e
docker run \
! docker run \
-e STRATEGY=PERCENTAGE \
-e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 \
-e PERCENTAGE_NEW=foo -e PERCENTAGE_OLD=50 \
-e COOKIE_PERCENTAGE_NAME=my_app \
"${{ env.IMAGE_NAME }}"
if [[ $? == 1 ]]; then exit 0; else exit 1; fi
- name: Run Docker Image with Invalid old Percentage
timeout-minutes: 1
id: test-validation-percentage-old
continue-on-error: true
run: |
set +e
docker run \
! docker run \
-e STRATEGY=PERCENTAGE \
-e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 \
-e PERCENTAGE_NEW=50 -e PERCENTAGE_OLD=foo \
-e COOKIE_PERCENTAGE_NAME=my_app \
"${{ env.IMAGE_NAME }}"
if [[ $? == 1 ]]; then exit 0; else exit 1; fi
- name: Run Docker Image with Invalid old domain
timeout-minutes: 1
id: test-validation-old-domain
continue-on-error: true
run: |
set +e
docker run \
! docker run \
-e STRATEGY=PERCENTAGE \
-e NEW_DOMAIN=apache.org:443 \
-e COOKIE_PERCENTAGE_NAME=my_app \
"${{ env.IMAGE_NAME }}"
if [[ $? == 1 ]]; then exit 0; else exit 1; fi
- name: Run Docker Image with Invalid new domain
timeout-minutes: 1
id: test-validation-new-domain
continue-on-error: true
run: |
set +e
docker run \
! docker run \
-e STRATEGY=PERCENTAGE \
-e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:lol \
-e COOKIE_PERCENTAGE_NAME=my_app \
"${{ env.IMAGE_NAME }}"
if [[ $? == 1 ]]; then exit 0; else exit 1; fi
- name: Run Docker Image with Invalid server count
timeout-minutes: 1
id: test-validation-server-count
continue-on-error: true
run: |
! docker run \
-e STRATEGY=PERCENTAGE \
-e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 \
-e COOKIE_PERCENTAGE_NAME=my_app \
-e SERVER_COUNT=foo \
"${{ env.IMAGE_NAME }}"
- name: Run Docker Image with Invalid DNS Resolver
timeout-minutes: 1
id: test-validation-dns-resolver
continue-on-error: true
run: |
! docker run \
-e STRATEGY=PERCENTAGE \
-e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 \
-e COOKIE_PERCENTAGE_NAME=my_app \
-e DNS_RESOLVER=foo \
"${{ env.IMAGE_NAME }}"
- name: Check for failures
if: always()
env:
STEPS_CONTEXT: ${{ toJson(steps) }}
run: |
set +e
! echo "$STEPS_CONTEXT" | grep -q 'failure'
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM haproxy:lts-alpine

LABEL org.opencontainers.image.source=https://github.com/statista-oss/proxy-router
LABEL org.opencontainers.image.source="https://github.com/statista-oss/proxy-router"
LABEL org.opencontainers.image.description="haproxy configurable through env vars for different routing strategies"

USER root
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ how much traffic should be routed to the old application
### PERCENTAGE_NEW
how much traffic should be routed to the new application

### DNS_RESOLVER (optional, default=1.1.1.1)
The DNS resolver to use for resolving the domain names to IP addresses.
If you want to reroute internal traffic you might want to change that.

### SERVER_COUNT (optional, default=5)
as we are using DNS Resolver we try to create a server for each IP address we get back from the DNS query.
This is the maximum amount of servers we will create.


## Local Testing

Expand All @@ -54,7 +62,7 @@ docker build -t statista-proxy .
run the container

```bash
docker run -p80:80 -e STRATEGY=PERCENTAGE -e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 -e PERCENTAGE_NEW=50 -e PERCENTAGE_OLD=50 -e COOKIE_PERCENTAGE_NAME=my_app statista_proxy
docker run -p80:80 -e STRATEGY=PERCENTAGE -e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 -e PERCENTAGE_NEW=50 -e PERCENTAGE_OLD=50 -e COOKIE_PERCENTAGE_NAME=my_app statista-proxy
```

run requests (since its round robin every request should be flipped)
Expand All @@ -69,7 +77,7 @@ further requests made by the same client will stick to this server
### Cookie based routing

```bash
docker run -p80:80 -e STRATEGY=COOKIE -e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 -e COOKIE_STRATEGY_NAME="my_app_routing=new" statista_proxy
docker run -p80:80 -e STRATEGY=COOKIE -e OLD_DOMAIN=haproxy.com:443 -e NEW_DOMAIN=apache.org:443 -e COOKIE_STRATEGY_NAME="my_app_routing=new" statista-proxy
```

run requests (since its round robin every request should be flipped)
Expand Down
23 changes: 19 additions & 4 deletions haproxy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,27 @@ global
# default some environment variables
presetenv PERCENTAGE_NEW "0"
presetenv PERCENTAGE_OLD "100"
presetenv SERVER_COUNT "5"
presetenv DNS_RESOLVER "1.1.1.1:53"

# we source them from the environment here to actually typecheck them
set-var proc.percentage_new int("${PERCENTAGE_NEW}")
set-var proc.percentage_old int("${PERCENTAGE_OLD}")

set-var proc.server_count int("${SERVER_COUNT}")

#log stdout format raw local0

defaults
timeout connect 5s
timeout client 1m
timeout server 1m
mode http
default-server check
default-server resolvers dns
default-server resolve-prefer ipv4
default-server init-addr last,libc,none
default-server ssl verify required ca-file @system-ca
#log global
#option httplog

Expand All @@ -47,24 +56,30 @@ frontend http-in
backend old_domain
http-response set-header X-Proxy-Flow route-to-legacy
option tcp-check
balance leastconn

server default_old "$OLD_DOMAIN" check ssl verify none
server-template default_old "$SERVER_COUNT" "$OLD_DOMAIN"

backend percentage_strategy
http-response set-header X-Proxy-Flow route-to-percentage
option tcp-check
balance leastconn

cookie "$COOKIE_PERCENTAGE_NAME" insert indirect

# old domain
server old_domain_percentage "$OLD_DOMAIN" check cookie old_domain ssl verify none weight "$PERCENTAGE_OLD"
server-template old_domain_percentage "$SERVER_COUNT" "$OLD_DOMAIN" cookie old_domain weight "$PERCENTAGE_OLD"

# new domain
server new_domain_percentage "$NEW_DOMAIN" check cookie new_domain ssl verify none weight "$PERCENTAGE_NEW"
server-template new_domain_percentage "$SERVER_COUNT" "$NEW_DOMAIN" cookie new_domain weight "$PERCENTAGE_NEW"

backend cookie_strategy
balance leastconn
http-response set-header X-Proxy-Flow route-to-new
option tcp-check

server default_new "$NEW_DOMAIN" check ssl verify none
server-template default_new "$SERVER_COUNT" "$NEW_DOMAIN"

resolvers dns
nameserver default "$DNS_RESOLVER"
accepted_payload_size 8192

0 comments on commit 6fccf91

Please sign in to comment.