Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dns): use dns resolvers to for dns failover routing scenarios #4

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading