traefik, docker compose and dns

Continuing from the previous article.

Problem

How do you run multiple instances of a docker container, all based on the same image, to execute inside a docker compose environment and send requests (via REST for example) that are handled in a round robin like algorithm?

Assumptions

Assume a docker-compose.yml file that looks like this:

services:
  container1:
    container_name: container1
    image: ...  
    ports:
      - "100:100"
      
  container2:
    container_name: containerA 
    image: containerA
    ports:
      - "200"
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.container1.loadbalancer.healthCheck.path=/"
      - "traefik.http.services.container1.loadbalancer.server.port=200"
    
  container2A:
    image: containerA
    ports:
      - "200"
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.container1.loadbalancer.healthCheck.path=/"
      - "traefik.http.services.container1.loadbalancer.server.port=200"
      
  traefik:
    container_name: traefiklb
    image: ...
    ports:
      - "8180:8080"
      - "200:200"
    command:
      - "--entrypoints.web.address=:200"
      

Changes here from the last post, include adding the traefik tags.  Configurations of note are that the ports for both container2 configurations are internal only.  Also note that Container2A does not have a container_name config.

when we run the following command: docker compose up container1 container2 container2A traefik

you should get the 4 containers running.  

Details

Our goal is to be able to _external to docker compose_ run a command that will round robin to container2 and container2A.  First - what is it mean to run external to docker compose.  A simple option here is to run your browser as the "external" system.  Specifically, external is used here to mean external to docker compose networking and DNS.  If you were to run a browser inside container1, it will function very much like the earlier article, where we used a curl statement to do cross container communication.

Using a browser to navigate to http://localhost:200 is how we do the same curl statement, but external do the docker compose network.  Lets follow the network traffic.

  1. First, the browser hits the Windows dns.  localhost will be resolved to 127.0.0.1 - see C:\Windows\System32\drivers\etc\hosts for more details.
  2. Docker Desktop on windows is running on your local desktop and therefore will respond.  Notice that this is all IPv4 and ymmv using IPv6.
  3. We asked for port 200 - docker will see if there is a container running on port 200 externally - traefik is a match. docker gateway facilitates this routing - it is at 172.18.0.1.
  4. the request is routed to traefik, which in turn, looks for any registered containers that can handle a port 200 request - it has two. 
  5. next traefik is checking the health of the two docker containers via the healthCheck, if both are healthy, and assuming this simple configuration, it picks one to route the request to.
  6. the request will now be routed using docker's internal network - that is, the container will have an ip address like 172.18.x.x.  But our containers still have an internal port of 200.  So the request will be routed to the selected container via ip address and port.  This is very much like our curl example above.
    1. the external port of container2 and container2A is dynamic - specifically so that they will not conflict externally.
  7. the request comes into a container (say container2) and will be handled by the service.
  8. the response will be routed back to traefik
  9. and then traefik will return the response outside the docker network
  10. the browser will receive the response.
In the above example, you can see the routing going to multiple containers by looking at the log viewer for the traefik container (assuming standard logging configuration).  Hitting refresh on the browser will show that the requests are routed to each container in more or less a round robin fashion.

next, we will hit how to configure dns on windows to inject an entry so that internal docker containers resolve to external ip addresses.

references

Comments

Popular Posts