From 7dfa6006e56ee36f2db20d67a0e4fc1136744b3a Mon Sep 17 00:00:00 2001
From: Tony Breeds <tony@bakeyournoodle.com>
Date: Tue, 4 Mar 2025 11:13:26 +1100
Subject: [PATCH] Add option to force docker.io addresses to IPv4

Change-Id: Ia2578dc5cf26b289e218cd17427a6367cdf42187
---
 playbooks/roles/install-docker/README.rst         | 12 ++++++++++++
 playbooks/roles/install-docker/defaults/main.yaml |  6 ++++++
 playbooks/roles/install-docker/tasks/main.yaml    | 15 +++++++++++++++
 playbooks/zuul/templates/group_vars/all.yaml.j2   |  1 +
 4 files changed, 34 insertions(+)

diff --git a/playbooks/roles/install-docker/README.rst b/playbooks/roles/install-docker/README.rst
index 071934df5a..20edf1bd17 100644
--- a/playbooks/roles/install-docker/README.rst
+++ b/playbooks/roles/install-docker/README.rst
@@ -25,3 +25,15 @@ such as:
    Which update channel to use for upstream docker. The two choices are
    ``stable``, which is the default and updates quarterly, and ``edge``
    which updates monthly.
+
+.. zuul:rolevar:: force_docker_io_ipv4
+   :default: False
+
+   Force all communication to docker.io over IPv4.  We do this as rate-limiting
+   is per IPv4 address as opposed to a /64 with IPv6.
+
+.. zuul:rolevar:: docker_registry_hostlist
+   :default: ['registry-1.docker.io', 'docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com', 'docker.io']
+
+   List of hosts to query for IPv4 addresses and add to /etc/hosts.  Used when
+   ``force_docker_io_ipv4`` is ``True``
diff --git a/playbooks/roles/install-docker/defaults/main.yaml b/playbooks/roles/install-docker/defaults/main.yaml
index 0f92e84217..d69772dfc5 100644
--- a/playbooks/roles/install-docker/defaults/main.yaml
+++ b/playbooks/roles/install-docker/defaults/main.yaml
@@ -1,3 +1,9 @@
 use_upstream_docker: True
 docker_update_channel: stable
 with_python_compose: True
+force_docker_io_ipv4: False
+# Taken from: https://docs.docker.com/desktop/setup/allow-list/
+docker_registry_hostlist:
+- registry-1.docker.io
+- docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com
+- docker.io
diff --git a/playbooks/roles/install-docker/tasks/main.yaml b/playbooks/roles/install-docker/tasks/main.yaml
index 381d4aa906..2221a42dc8 100644
--- a/playbooks/roles/install-docker/tasks/main.yaml
+++ b/playbooks/roles/install-docker/tasks/main.yaml
@@ -36,3 +36,18 @@
     name: logrotate
   vars:
     logrotate_file_name: '/var/log/containers/*.log'
+
+- name: Force registry actions for docker over IPv4
+  block:
+  - name: Resolve IPv4 Addresses for Docker resources
+    shell: for domain in {{ docker_registry_hostlist|join(' ') }} ; do host -t a "$domain" ; done
+    register: docker_io_dns
+
+  - name: Update to /etc/hosts according to force_docker_io_ipv4
+    lineinfile:
+      path: /etc/hosts
+      line: "{{ (item|split(' '))[-1] }}\t{{ (item|split(' '))[0] }}"
+      mode: "0644"
+      state: "present"
+    loop: "{{ docker_io_dns.stdout_lines }}"
+  when: force_docker_io_ipv4|bool
diff --git a/playbooks/zuul/templates/group_vars/all.yaml.j2 b/playbooks/zuul/templates/group_vars/all.yaml.j2
index cb80bcbd6a..ed83a0c366 100644
--- a/playbooks/zuul/templates/group_vars/all.yaml.j2
+++ b/playbooks/zuul/templates/group_vars/all.yaml.j2
@@ -8,6 +8,7 @@ bastion_ipv4: {{ bastion_ipv4 }}
 bastion_ipv6: {{ bastion_ipv6 }}
 {% endif %}
 bastion_public_key: {{ bastion_public_key }}
+force_docker_io_ipv4: true
 iptables_test_public_tcp_ports: {{ iptables_test_public_tcp_ports }}
 iptables_egress_rules:
   - -o lo -j ACCEPT