Search code examples
dockerdnsvarnishvarnish-vcl

Varnish in Docker change backend with no downtime


Setup: [Varnish] <-> [Nginx] <-> [PHP FPM] <-> [PostgreSQL] Varnish, Nginx and PHP FPM run as Docker containers.

When we push new code, we need to update at least the PHP container with the new build. Our CI/CD pipeline also triggers Nginx to restart docker exec -i $CONTAINER_ID_API_NGINX nginx -s reload so it will fetch the (internal) ip of the newly created PHP Container.

However sometimes the Nginx container has to be restarted as well, for example if there are new static assets. In this case we also need to restart Varnish and this is where our troubles lie, and where we have some downtime on our API.

Things we've tried:

 1. Starting second Nginx
 2. Starting second Varnish
 3. Killing first Nginx
 4. Killing first Varnish

Problem: The second Varnish Container complains that there are 2 IPs for the backend and goes in a restart cycle until the first Nginx container is shut down.

 1. Starting second Nginx
 2. Killing first Nginx
 3. Starting second Varnish
 4. Killing first Varnish

Problem: Before the second varnish is accepting connections, API request still go to the first Varnish instance, it tries to forward them to the first (now killed) Nginx instance

Question: Is there a way to get Varnish to switch it's backend host to the new Nginx container, with or without a restart? Our VCL file currently contains

backend default {
  .host = "api-api";
  .port = "80";
}

In an ideal world, we would start a second Nginx instance, Varnish still has the DNS cached to the first Nginx instance, we kill the first Nginx instance and trigger a DNS refresh on the Varnish instance without needing to kill the Varnish container itself.


Solution

  • varnishreload

    Reloading the VCL can be done using the varnishreload command.

    This command will load a new VCL, compile it, deactivate the previous VCL and activate the newly added one.

    Any backend DNS resolution will happen while the new VCL file is parsed and compiled.

    The varnishreload command runs multiple varnishadm commands. See https://github.com/varnishcache/pkg-varnish-cache/blob/master/systemd/varnishreload for more information on the code.

    You can choose to either run varnishreload inside your container to automate the VCL reload, which also resolves the DNS of your backend endpoint.

    varnishadm remote calls

    You can also call varnishadm remotely, but that requires some extra measures.

    See http://varnish-cache.org/docs/6.0/reference/varnishadm.html for varnishadm docs.

    See http://varnish-cache.org/docs/6.0/reference/varnish-cli.html for more information about the Varnish CLI which varnishadm wraps around.