Blue-Green
Load balancing across two services.
Images are clickable.
Manifests
services:
blue:
image: hashicorp/http-echo
deploy:
labels:
- "millau.enabled=true"
- "millau.hosts=company.com blue.local company.local"
- "millau.cert=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURRVENDQWlrQ0ZIemVjY3FYaVg0V0ZNRXZUWklvUHdSUXQvZktNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1GMHgKQ3pBSkJnTlZCQVlUQWtSRk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbApjbTVsZENCWGFXUm5hWFJ6SUZCMGVTQk1kR1F4RmpBVUJnTlZCQU1NRFdOdmJYQmhibmt1Ykc5allXd3dIaGNOCk1qVXdOVEEwTVRZd09ERXpXaGNOTWpZd05UQTBNVFl3T0RFeldqQmRNUXN3Q1FZRFZRUUdFd0pFUlRFVE1CRUcKQTFVRUNBd0tVMjl0WlMxVGRHRjBaVEVoTUI4R0ExVUVDZ3dZU1c1MFpYSnVaWFFnVjJsa1oybDBjeUJRZEhrZwpUSFJrTVJZd0ZBWURWUVFEREExamIyMXdZVzU1TG14dlkyRnNNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DCkFROEFNSUlCQ2dLQ0FRRUFsa01mMzRsZitjM1BtS2dvM09LbkN5L3Fjc0FSK1YxNVZQS1pUeU1id1VGQ0FLVGIKOUpic2Jha3pNWnAyVHlQTU53MmF5WXkyVGFtZ3JSNW92bUQzWlk3WmNSU2xKZVdIRXR6ZHN1OWkyc1dWeHFRaQpqWEtZa1ZqaXBSRE1RdERnWWlLN1Z1d25pNmFKWFlFNlAwN05ISVVYbVdRL1NyMERSL2ZRVkxJSzVqWFVidktoCmNYbnZsZWk3ck5takpxRXJ1Q3ppc1Q2dTBDWW1kdGlBZUxRbEdRZkt3bzBMVUh5bllVcmlQK3BiT05FRFF2eWEKTWgydThPdW1LUGdFaVI0czloZlFGNkFDL1BGaUhVQVd5R0dRS3BYMDJKK0R3eG5hc1hSbkwzMmNXYkFaanlkZgpTOVF5QUo3WWsvSUl2cDVSSzdKK05aaUxCbjZEYlNKNU03ZVJPUUlEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBCkE0SUJBUUJLTW56QTkrU0FOVTFZNHdmR2FoK2MrTWpVSTA3UzZ6dHVWd3EvbEY3ZUxBVFNpUDc1cEJYOUUwR1AKd3dhMjY1SEVWUXFnVStmUHVLSlM4MFc5VUtxZGJxYVhQRHNlZng0MzBVc3cvUVVJYnhxTUVLTXZUcUpwcWk1NApMUlBjWHJCZTdvNzgyczFDUkF5UHpqNWJiRE1jeHlCVVdPeFFiQndZZ3UwY3ZnVFpTclRGWW1vbTRucnpiMCtmClA4eWZZMHRsTXFCYmo0Nm96Y0xaUU1JTFhLTWJVZlB2djZWVWlnYmoySFZ4aml3REQyL1B2elBwYnlsbnl5OXgKS1FlR1E5bU0xdm5wbm8valpCVjRqREg1OTV1UmNGNnFpY1JZYnNmdlZVWWwvNzhiREpxdXVmNHpwMHNIaks2egpCYlhHN29GV3pkQlJkQzBud0VXMGE4Q1FjVC9jCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
- "millau.key=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ1dReC9maVYvNXpjK1kKcUNqYzRxY0xMK3B5d0JINVhYbFU4cGxQSXh2QlFVSUFwTnYwbHV4dHFUTXhtblpQSTh3M0RackpqTFpOcWFDdApIbWkrWVBkbGp0bHhGS1VsNVljUzNOMnk3MkxheFpYR3BDS05jcGlSV09LbEVNeEMwT0JpSXJ0VzdDZUxwb2xkCmdUby9UczBjaFJlWlpEOUt2UU5IOTlCVXNncm1OZFJ1OHFGeGVlK1Y2THVzMmFNbW9TdTRMT0t4UHE3UUppWjIKMklCNHRDVVpCOHJDalF0UWZLZGhTdUkvNmxzNDBRTkMvSm95SGE3dzY2WW8rQVNKSGl6MkY5QVhvQUw4OFdJZApRQmJJWVpBcWxmVFluNFBER2RxeGRHY3ZmWnhac0JtUEoxOUwxRElBbnRpVDhnaStubEVyc240MW1Jc0dmb050Cklua3p0NUU1QWdNQkFBRUNnZ0VBQlBUQjA1SjEvTHdZUi84ZGdGSC80SG5JNmRab3dWd0ZndC9EK0ZhazZJTGoKVHppSE5ZVStjTEsxbFk3YXJvVEJXUytCc0VkWXFNY2F0elNuOWl4Wll3RytZSzRNQ3RKWTJpNXJqbG02S3BOOAorNVVYN3FqUTlkUHFURGQ1bnRxT2NucjhZdHpEOTR3QjJLdXZTMWRDMWorVDh1TkFYL2hNQWM3ZmVEaDZVNDEyCkJvZFhpL1g3L0VnV05BQko3d3BBWXFheGNaN1ZneUMvMVZkYzNRcUlPL2d3dDdPYzFpVHhUYkh5R1VRUnZaTFAKSkJaY2N4OUN4MzM1YWdHNFN1anJKUEZTa0pab1FHWkZQMFpBbUw3UkxPTlI1WFJXeGNzSGdQejNNTi9lVlhOeApzUSszRTJxYUc5eC81UDUrWnBaQ2M4YUxUSll4a0htL3d2TldkRkxHWVFLQmdRQzgwTFQzMFZZQ3R5UzZRbWRnClJUREtEa2xiQm41ZGxjamJjK1lFQzF0dnQzc2V6aDM2eTJ0Ym5aOXdDSWYreFcxVUEvOEN6bE9MbGtDRjdsT3EKMWV3MEFuZlU4OGdGaE4vMitNZXg4djVNcTk3Z1dOOTFPRHk2RCtyNk9LYTU5NEpKL0ZuRkZSS1VzcEtSYlV2MQpHOFdqSjFJaFQrU1JOY1gwYUlqbzB6NUlRd0tCZ1FETHVwallhczZwVlVoYWoyTEhPVDdOcVF6c0R5WEwrV0xSCkJGNXNYaEhJZ2ViaHlGYW14Q1Z5ZkpyOEtjUzZuekRwWEVjOU5PemZxaW9xZHJmSTgwbmptbW81Y2Z6WFZXQ0cKVnpmTEZrTXp0U0o1bURhK3RGYUgvczMvNG54bTl1Z3VLZGxWb0h0cTVLclFpeFJXSFJWaCt2a3phRVlaL3lIaQorVDRRVW43VzB3S0JnQ0RIMDBOYkVxV3lDaXhVTHdKbHdNeXpva1N0WWU3NWZEK3RaWGU2U1F1aVBUdmg2UTZMCmxuMzNaYURidWxDZkVoWU9BNDRIS0RZSnhmWDZwSWY2VCtIUHMrSkMySzBzbm4yUVA0dERkcWIxQitMSFN6UmMKcVI1Y2VSMHNETFlvcEhRWDNiWDdySmdvVUkzeS9jYjJKVi9vQ2JoQzJKbmxUaExhdXpwQXdvVmxBb0dCQUx1OApMNnorZjRJN1BIbDNPQ2N0OFZuRE5rMHhpRHIyak1EZnJjTmV6RFJnd0VtL08xcGgxY0F5WXYrTDNlVzdYRzh1CndkYjlObXJGZkNXMVVKYTAycG9LYVdpV1NkQ0V0SFlYV1Nxa1VUa002Yi96TEQrQUgxMGl5T0hMNjZkV1Q0NTYKc2ZQZDl0MEI2d1pSbzJQWFdTVDVDVHIrRTl0UTZBRW9mTEM5MUhSUkFvR0FlR3dCWU9xUmxvTkprNk12dkxNdgpQZVBueXNQVkp5UmFQeFkremJObWZxa283ZldaSjRLOWRZc2ZQRkhybEVQVVpoN0E3YUFVQnQ0d3dRU2EyM2RXCml2Z1hmd2Nic05oWTZUckxBRDdTWHJwUkFHeDlkOTN5aXRTWnZLdmo3Sm9qUkljVytUNjVNVFNVeXJva29lU2YKS0t0dlVCenpTZklQY3Z3aFFoZDRWTU09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
- "millau.port=9000"
- "millau.path=/api/"
command: ["-listen=:9000", "-text=blue"]
ports:
- "9000"
networks:
- millau
green:
image: hashicorp/http-echo
deploy:
labels:
- "millau.enabled=true"
- "millau.hosts=company.com green.local company.local"
- "millau.cert=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURRVENDQWlrQ0ZIemVjY3FYaVg0V0ZNRXZUWklvUHdSUXQvZktNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1GMHgKQ3pBSkJnTlZCQVlUQWtSRk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbApjbTVsZENCWGFXUm5hWFJ6SUZCMGVTQk1kR1F4RmpBVUJnTlZCQU1NRFdOdmJYQmhibmt1Ykc5allXd3dIaGNOCk1qVXdOVEEwTVRZd09ERXpXaGNOTWpZd05UQTBNVFl3T0RFeldqQmRNUXN3Q1FZRFZRUUdFd0pFUlRFVE1CRUcKQTFVRUNBd0tVMjl0WlMxVGRHRjBaVEVoTUI4R0ExVUVDZ3dZU1c1MFpYSnVaWFFnVjJsa1oybDBjeUJRZEhrZwpUSFJrTVJZd0ZBWURWUVFEREExamIyMXdZVzU1TG14dlkyRnNNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DCkFROEFNSUlCQ2dLQ0FRRUFsa01mMzRsZitjM1BtS2dvM09LbkN5L3Fjc0FSK1YxNVZQS1pUeU1id1VGQ0FLVGIKOUpic2Jha3pNWnAyVHlQTU53MmF5WXkyVGFtZ3JSNW92bUQzWlk3WmNSU2xKZVdIRXR6ZHN1OWkyc1dWeHFRaQpqWEtZa1ZqaXBSRE1RdERnWWlLN1Z1d25pNmFKWFlFNlAwN05ISVVYbVdRL1NyMERSL2ZRVkxJSzVqWFVidktoCmNYbnZsZWk3ck5takpxRXJ1Q3ppc1Q2dTBDWW1kdGlBZUxRbEdRZkt3bzBMVUh5bllVcmlQK3BiT05FRFF2eWEKTWgydThPdW1LUGdFaVI0czloZlFGNkFDL1BGaUhVQVd5R0dRS3BYMDJKK0R3eG5hc1hSbkwzMmNXYkFaanlkZgpTOVF5QUo3WWsvSUl2cDVSSzdKK05aaUxCbjZEYlNKNU03ZVJPUUlEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBCkE0SUJBUUJLTW56QTkrU0FOVTFZNHdmR2FoK2MrTWpVSTA3UzZ6dHVWd3EvbEY3ZUxBVFNpUDc1cEJYOUUwR1AKd3dhMjY1SEVWUXFnVStmUHVLSlM4MFc5VUtxZGJxYVhQRHNlZng0MzBVc3cvUVVJYnhxTUVLTXZUcUpwcWk1NApMUlBjWHJCZTdvNzgyczFDUkF5UHpqNWJiRE1jeHlCVVdPeFFiQndZZ3UwY3ZnVFpTclRGWW1vbTRucnpiMCtmClA4eWZZMHRsTXFCYmo0Nm96Y0xaUU1JTFhLTWJVZlB2djZWVWlnYmoySFZ4aml3REQyL1B2elBwYnlsbnl5OXgKS1FlR1E5bU0xdm5wbm8valpCVjRqREg1OTV1UmNGNnFpY1JZYnNmdlZVWWwvNzhiREpxdXVmNHpwMHNIaks2egpCYlhHN29GV3pkQlJkQzBud0VXMGE4Q1FjVC9jCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
- "millau.key=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ1dReC9maVYvNXpjK1kKcUNqYzRxY0xMK3B5d0JINVhYbFU4cGxQSXh2QlFVSUFwTnYwbHV4dHFUTXhtblpQSTh3M0RackpqTFpOcWFDdApIbWkrWVBkbGp0bHhGS1VsNVljUzNOMnk3MkxheFpYR3BDS05jcGlSV09LbEVNeEMwT0JpSXJ0VzdDZUxwb2xkCmdUby9UczBjaFJlWlpEOUt2UU5IOTlCVXNncm1OZFJ1OHFGeGVlK1Y2THVzMmFNbW9TdTRMT0t4UHE3UUppWjIKMklCNHRDVVpCOHJDalF0UWZLZGhTdUkvNmxzNDBRTkMvSm95SGE3dzY2WW8rQVNKSGl6MkY5QVhvQUw4OFdJZApRQmJJWVpBcWxmVFluNFBER2RxeGRHY3ZmWnhac0JtUEoxOUwxRElBbnRpVDhnaStubEVyc240MW1Jc0dmb050Cklua3p0NUU1QWdNQkFBRUNnZ0VBQlBUQjA1SjEvTHdZUi84ZGdGSC80SG5JNmRab3dWd0ZndC9EK0ZhazZJTGoKVHppSE5ZVStjTEsxbFk3YXJvVEJXUytCc0VkWXFNY2F0elNuOWl4Wll3RytZSzRNQ3RKWTJpNXJqbG02S3BOOAorNVVYN3FqUTlkUHFURGQ1bnRxT2NucjhZdHpEOTR3QjJLdXZTMWRDMWorVDh1TkFYL2hNQWM3ZmVEaDZVNDEyCkJvZFhpL1g3L0VnV05BQko3d3BBWXFheGNaN1ZneUMvMVZkYzNRcUlPL2d3dDdPYzFpVHhUYkh5R1VRUnZaTFAKSkJaY2N4OUN4MzM1YWdHNFN1anJKUEZTa0pab1FHWkZQMFpBbUw3UkxPTlI1WFJXeGNzSGdQejNNTi9lVlhOeApzUSszRTJxYUc5eC81UDUrWnBaQ2M4YUxUSll4a0htL3d2TldkRkxHWVFLQmdRQzgwTFQzMFZZQ3R5UzZRbWRnClJUREtEa2xiQm41ZGxjamJjK1lFQzF0dnQzc2V6aDM2eTJ0Ym5aOXdDSWYreFcxVUEvOEN6bE9MbGtDRjdsT3EKMWV3MEFuZlU4OGdGaE4vMitNZXg4djVNcTk3Z1dOOTFPRHk2RCtyNk9LYTU5NEpKL0ZuRkZSS1VzcEtSYlV2MQpHOFdqSjFJaFQrU1JOY1gwYUlqbzB6NUlRd0tCZ1FETHVwallhczZwVlVoYWoyTEhPVDdOcVF6c0R5WEwrV0xSCkJGNXNYaEhJZ2ViaHlGYW14Q1Z5ZkpyOEtjUzZuekRwWEVjOU5PemZxaW9xZHJmSTgwbmptbW81Y2Z6WFZXQ0cKVnpmTEZrTXp0U0o1bURhK3RGYUgvczMvNG54bTl1Z3VLZGxWb0h0cTVLclFpeFJXSFJWaCt2a3phRVlaL3lIaQorVDRRVW43VzB3S0JnQ0RIMDBOYkVxV3lDaXhVTHdKbHdNeXpva1N0WWU3NWZEK3RaWGU2U1F1aVBUdmg2UTZMCmxuMzNaYURidWxDZkVoWU9BNDRIS0RZSnhmWDZwSWY2VCtIUHMrSkMySzBzbm4yUVA0dERkcWIxQitMSFN6UmMKcVI1Y2VSMHNETFlvcEhRWDNiWDdySmdvVUkzeS9jYjJKVi9vQ2JoQzJKbmxUaExhdXpwQXdvVmxBb0dCQUx1OApMNnorZjRJN1BIbDNPQ2N0OFZuRE5rMHhpRHIyak1EZnJjTmV6RFJnd0VtL08xcGgxY0F5WXYrTDNlVzdYRzh1CndkYjlObXJGZkNXMVVKYTAycG9LYVdpV1NkQ0V0SFlYV1Nxa1VUa002Yi96TEQrQUgxMGl5T0hMNjZkV1Q0NTYKc2ZQZDl0MEI2d1pSbzJQWFdTVDVDVHIrRTl0UTZBRW9mTEM5MUhSUkFvR0FlR3dCWU9xUmxvTkprNk12dkxNdgpQZVBueXNQVkp5UmFQeFkremJObWZxa283ZldaSjRLOWRZc2ZQRkhybEVQVVpoN0E3YUFVQnQ0d3dRU2EyM2RXCml2Z1hmd2Nic05oWTZUckxBRDdTWHJwUkFHeDlkOTN5aXRTWnZLdmo3Sm9qUkljVytUNjVNVFNVeXJva29lU2YKS0t0dlVCenpTZklQY3Z3aFFoZDRWTU09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
- "millau.port=9000"
- "millau.path=/api/"
command: ["-listen=:9000", "-text=green"]
ports:
- "9000"
networks:
- millau
red:
image: hashicorp/http-echo
deploy:
labels:
- "millau.enabled=false"
- "millau.hosts=company.com company.local"
- "millau.port=9000"
- "millau.path=/api/"
command: ["-listen=:9000", "-text=red"]
ports:
- "9000"
networks:
- millau
other:
image: hashicorp/http-echo
command: ["-listen=:9000", "-text=other"]
ports:
- "9000"
networks:
millau:
external: true
Features
Load Balancing
curl -i -H 'Host: company.com' localhost:8080/api/
returns HTTP 200 and responds from the blue or green services due to multiple host matching.
curl -i -H 'Host: www.company.com' localhost:8080/api/
returns HTTP 200 and responds from the blue or green services due to multiple host matching.
No Load Balancing
The service red excluded from the load balancing. The service other is not controlled by Millau at all.
Host and Path Matching
curl -i -H 'Host: green.local' localhost:8080/api/
returns HTTP 200 and responds from the green service only due to single host matching.
curl -i -H 'Host: blue.local' localhost:8080/api/
returns HTTP 200 and responds from the blue service only due to single host matching.
No Matching
curl -i -H 'Host: company.locall' localhost:8080
returns HTTP 502 No matching services found because there is no matching host.
curl -i -H 'Host: company.local' localhost:8080/apii/
returns HTTP 502 No matching services found because there is no matching path.
TLS Termination
curl -k --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 -H 'Host: company.local' https://company.local:8443/api/
curl -k --http2 --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 -H 'Host: company.local' https://company.local:8443/api/
returns HTTP 200 and responds from the blue or green services due to multiple host matching.
This HTTPS request uses s self-signed TLS certificate issued to company.local.
The labels millau.cert and millau.key contain the certificate components encoded in base64.