Enable IPv6 connectivity to and from containers deployed with Kamal

At the moment, Kamal doesn’t support IPv6 out of the box. Meaning your containers won’t be able to reach IPv6 hosts at all. IPv6 support is expanding, and on some of my projects, I need such connectivity. Taking Kamal for a ride, I’ve run into this issue and had to solve it.

I’ll show you how to do this, both with an already deployed app, as well as if you haven’t run “kamal setup” just yet.

Already deployed app

There will be a short downtime (couple of seconds) while you do the switch. So plan for that.

All we need to do is to recreate the kamal Docker network, which is created with IPv4 support only, by Kamal. The problem is, you can’t remove a Docker network if containers are attached to it.

Here’s a script that reconnects the containers to a temporary network, recreates kamal network with IPv6 support, connects the containers back to it and cleans up. During this, there will be a few seconds of a downtime, as your containers will briefly loose connection to the network and/or between each other.

#!/usr/bin/env bash
set -euo pipefail

OLD_NET="kamal"
TEMP_NET="kamal_tmp_v6"

echo "Collecting containers connected to network '$OLD_NET'..."
CONTAINERS=$(docker network inspect "$OLD_NET" -f '{{range .Containers}}{{.Name}} {{end}}')

if [ -z "$CONTAINERS" ]; then
  echo "No containers found on network '$OLD_NET'."
  exit 1
fi

echo "Creating temporary IPv6-enabled network '$TEMP_NET'..."
docker network create \
  --ipv6 \
  "$TEMP_NET"

echo "Connecting containers to temporary network..."
for c in $CONTAINERS; do
  echo " → Connecting $c to $TEMP_NET"
  docker network connect "$TEMP_NET" "$c"
done

echo "Disconnecting containers from old network '$OLD_NET'..."
for c in $CONTAINERS; do
  echo " → Disconnecting $c from $OLD_NET"
  docker network disconnect "$OLD_NET" "$c" || true
done

echo "Removing old network '$OLD_NET'..."
docker network rm "$OLD_NET"

echo "Recreating network '$OLD_NET' with IPv6 enabled..."
docker network create \
  --ipv6 \
  "$OLD_NET"

echo "Reconnecting containers to new '$OLD_NET'..."
for c in $CONTAINERS; do
  echo " → Connecting $c to $OLD_NET"
  docker network connect "$OLD_NET" "$c"
  echo " → Disconnecting $c from $TEMP_NET"
  docker network disconnect "$TEMP_NET" "$c" || true
done

echo "Cleaning up temporary network '$TEMP_NET'..."
docker network rm "$TEMP_NET"

echo "✅ IPv6 successfully enabled on '$OLD_NET' and containers reattached."

Copy it anywhere on your server, for example ~/enable_ipv6_on_kamal.sh, make it executable and run it:

chmod +x enable_ipv6_on_kamal.sh

# Run it
./enable_ipv6_on_kamal.sh

You’re done. After a few seconds you should be able to access your app, as kamal-proxy succeeds with it’s health checks.

Before your first deployment

This is easier. On the host, just create the Docker network Kamal expects manually, and Kamal will use that once you start deploying.

docker network create --ipv6 kamal 

That’s all! Now you can run kamal setup from your developer machine and you’ll have IPv6 connectivity from and to your containers right away.

Dockerized Percona MySQL Server with automated replication, tools & tests

Docker & Percona Server I developed this container to solve specific needs and alleviate pain points present when dealing with deployment and administration of MySQL on servers that I manage.

I decided to look into Docker during a migration from MySQL 5.5 to 5.6 on one of the production servers. The server hosts multiple applications and services and is running in a hot spare configuration (another server mirrors this server, acts as the MySQL slave, etc.). Thus I wanted a migration strategy where I can have the 5.6 installation ready and running on the server, so that I can test it with production data and when ready just turn the switch to replace the old 5.5. Docker turned out to be the cleanest solution.

Since the MySQL server is such a critical part of the infrastructure I decided to develop the container utilizing test driven development. This allowed me to quickly add new features, like performance optimization and replication over a ssh tunnel (to support servers in different public clouds). Having this functionality in a standalone, tested and isolated unit is amazing. Before, all this complexity would be managed by Chef provisioning, which is much harder to test and experiment with on the production server. Having this functionality contained in a Docker container allows me to just use Chef for orchestration and deployment of the containers themselves, witch requires much simpler logic, compared to provisioning a full MySQL server install, configuration, replication and upgrading.

  • Code is available at Github.

This project is released under the MIT license.