|
37 | 37 | # NOTE: APT cache update logic has been moved to update-apt-cache.yml |
38 | 38 | # Run that playbook first if you need to update the package cache |
39 | 39 |
|
40 | | - # Task 0: Detect CI environment to adjust behavior |
41 | | - - name: Detect CI environment |
| 40 | + # Task 0: Set robust retry/timeout defaults for all environments |
| 41 | + - name: Set network operation defaults |
42 | 42 | ansible.builtin.set_fact: |
43 | | - is_ci_environment: "{{ ansible_env.GITHUB_ACTIONS is defined or ansible_env.CI is defined }}" |
44 | | - ci_type: "{% if ansible_env.GITHUB_ACTIONS is defined %}github_actions{% elif ansible_env.CI is defined %}generic_ci{% else %}local{% endif %}" |
45 | | - |
46 | | - - name: Display environment information |
47 | | - ansible.builtin.debug: |
48 | | - msg: | |
49 | | - Environment: {{ ci_type }} |
50 | | - CI Environment: {{ is_ci_environment }} |
51 | | - Note: CI environments may have network connectivity limitations |
| 43 | + network_timeout: 120 # 2 minutes timeout for individual operations |
| 44 | + network_retries: 8 # High number of retries for flaky networks |
| 45 | + network_delay: 45 # 45 seconds between retries |
52 | 46 |
|
53 | 47 | # Task 1: Install required packages for Docker repository with retries |
54 | 48 | - name: Install required packages for Docker repository |
|
68 | 62 | until: prereq_packages is succeeded |
69 | 63 | when: ansible_os_family == "Debian" |
70 | 64 |
|
| 65 | + # Task 1b: Try to install aria2 (optional - better download utility for flaky networks) |
| 66 | + - name: Install aria2 (optional - enhanced download utility) |
| 67 | + ansible.builtin.apt: |
| 68 | + name: |
| 69 | + - aria2 |
| 70 | + state: present |
| 71 | + force_apt_get: true |
| 72 | + update_cache: false |
| 73 | + register: aria2_install |
| 74 | + when: ansible_os_family == "Debian" |
| 75 | + ignore_errors: true # Don't fail if aria2 is not available |
| 76 | + |
71 | 77 | # Task 2: Add Docker's official GPG key with retries and better error handling |
72 | 78 | - name: Create keyrings directory |
73 | 79 | ansible.builtin.file: |
|
76 | 82 | mode: "0755" |
77 | 83 | when: ansible_os_family == "Debian" |
78 | 84 |
|
79 | | - - name: Add Docker's official GPG key (with retries and CI-aware timeouts) |
| 85 | + - name: Add Docker's official GPG key (with robust retry/timeout settings) |
80 | 86 | ansible.builtin.get_url: |
81 | 87 | url: https://download.docker.com/linux/ubuntu/gpg |
82 | 88 | dest: /etc/apt/keyrings/docker.asc |
83 | 89 | mode: "0644" |
84 | | - timeout: "{{ 60 if is_ci_environment else 30 }}" |
| 90 | + timeout: "{{ network_timeout }}" |
85 | 91 | force: true |
86 | 92 | register: docker_gpg_key |
87 | | - retries: "{{ 5 if is_ci_environment else 3 }}" |
88 | | - delay: "{{ 30 if is_ci_environment else 10 }}" |
| 93 | + retries: "{{ network_retries }}" |
| 94 | + delay: "{{ network_delay }}" |
89 | 95 | until: docker_gpg_key is succeeded |
90 | 96 | when: ansible_os_family == "Debian" |
91 | 97 | ignore_errors: true |
92 | 98 |
|
93 | | - # Fallback: Use curl to download GPG key if get_url fails (especially for CI) |
94 | | - - name: Fallback - Download Docker GPG key with curl (CI-optimized) |
| 99 | + # Fallback: Use curl to download GPG key if get_url fails |
| 100 | + - name: Fallback - Download Docker GPG key with curl (high retry/timeout) |
95 | 101 | ansible.builtin.shell: | |
96 | 102 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ |
97 | | - --connect-timeout {{ 60 if is_ci_environment else 30 }} \ |
98 | | - --max-time {{ 180 if is_ci_environment else 60 }} \ |
99 | | - --retry {{ 5 if is_ci_environment else 2 }} \ |
100 | | - --retry-delay {{ 30 if is_ci_environment else 15 }} \ |
| 103 | + --connect-timeout {{ network_timeout }} \ |
| 104 | + --max-time {{ network_timeout * 2 }} \ |
| 105 | + --retry {{ network_retries }} \ |
| 106 | + --retry-delay {{ network_delay }} \ |
101 | 107 | --retry-connrefused \ |
102 | 108 | -o /etc/apt/keyrings/docker.asc |
103 | 109 | chmod 644 /etc/apt/keyrings/docker.asc |
104 | 110 | register: docker_gpg_curl |
105 | 111 | when: |
106 | 112 | - ansible_os_family == "Debian" |
107 | 113 | - docker_gpg_key is failed |
108 | | - retries: "{{ 3 if is_ci_environment else 2 }}" |
109 | | - delay: "{{ 45 if is_ci_environment else 15 }}" |
| 114 | + retries: "{{ network_retries // 2 }}" |
| 115 | + delay: "{{ network_delay }}" |
110 | 116 | until: docker_gpg_curl.rc == 0 |
111 | 117 | ignore_errors: true |
112 | 118 |
|
113 | | - # Final fallback: Skip Docker installation if GPG key cannot be obtained |
114 | | - - name: Check if Docker GPG key exists |
| 119 | + # Enhanced fallback: Use aria2 for more robust downloading (if available) |
| 120 | + - name: Enhanced fallback - Download Docker GPG key with aria2 (network-resilient) |
| 121 | + ansible.builtin.shell: | |
| 122 | + aria2c --file-allocation=none \ |
| 123 | + --retry-wait={{ network_delay }} \ |
| 124 | + --max-tries={{ network_retries }} \ |
| 125 | + --max-connection-per-server=1 \ |
| 126 | + --split=1 \ |
| 127 | + --timeout={{ network_timeout }} \ |
| 128 | + --connect-timeout={{ network_timeout // 2 }} \ |
| 129 | + --dir=/etc/apt/keyrings \ |
| 130 | + --out=docker.asc \ |
| 131 | + --user-agent="aria2/1.36.0" \ |
| 132 | + https://download.docker.com/linux/ubuntu/gpg |
| 133 | + chmod 644 /etc/apt/keyrings/docker.asc |
| 134 | + register: docker_gpg_aria2 |
| 135 | + when: |
| 136 | + - ansible_os_family == "Debian" |
| 137 | + - docker_gpg_key is failed |
| 138 | + - docker_gpg_curl is failed |
| 139 | + - aria2_install is succeeded # Only try aria2 if it was successfully installed |
| 140 | + retries: 3 |
| 141 | + delay: "{{ network_delay }}" |
| 142 | + until: docker_gpg_aria2.rc == 0 |
| 143 | + ignore_errors: true |
| 144 | + |
| 145 | + # Ultimate fallback: Use embedded GPG key (no network required) |
| 146 | + - name: Ultimate fallback - Create Docker GPG key from embedded content (offline) |
| 147 | + ansible.builtin.copy: |
| 148 | + content: | |
| 149 | + -----BEGIN PGP PUBLIC KEY BLOCK----- |
| 150 | +
|
| 151 | + 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 |
| 208 | + YT90qFF93M3v01BbxP+EIY2/9tiIPbrd |
| 209 | + =0YYh |
| 210 | + -----END PGP PUBLIC KEY BLOCK----- |
| 211 | + dest: /etc/apt/keyrings/docker.asc |
| 212 | + mode: "0644" |
| 213 | + register: docker_gpg_embedded |
| 214 | + when: |
| 215 | + - ansible_os_family == "Debian" |
| 216 | + - docker_gpg_key is failed |
| 217 | + - docker_gpg_curl is failed |
| 218 | + - docker_gpg_aria2 is failed |
| 219 | + ignore_errors: true |
| 220 | + |
| 221 | + # Final check: Verify if Docker GPG key exists after all attempts |
| 222 | + - name: Check if Docker GPG key exists (after all fallback attempts) |
115 | 223 | ansible.builtin.stat: |
116 | 224 | path: /etc/apt/keyrings/docker.asc |
117 | | - register: docker_gpg_exists |
| 225 | + register: docker_gpg_final_check |
118 | 226 | when: ansible_os_family == "Debian" |
119 | 227 |
|
120 | 228 | - name: Warning about Docker GPG key failure |
121 | 229 | ansible.builtin.debug: |
122 | 230 | msg: | |
123 | 231 | ⚠️ WARNING: Could not download Docker GPG key due to network issues. |
124 | | - {% if is_ci_environment %} |
125 | | - This is a known limitation in CI environments, particularly GitHub Actions. |
126 | | - See: https://github.com/actions/runner-images/issues/2890 |
127 | | - {% else %} |
128 | 232 | This may be due to network connectivity issues or firewall restrictions. |
129 | | - {% endif %} |
130 | | - Docker installation will be skipped but the playbook will continue. |
| 233 | + Using embedded GPG key as fallback to continue installation. |
131 | 234 | when: |
132 | 235 | - ansible_os_family == "Debian" |
133 | | - - not docker_gpg_exists.stat.exists |
| 236 | + - not docker_gpg_final_check.stat.exists |
134 | 237 |
|
135 | 238 | # Task 3: Add Docker repository (only if GPG key exists) |
136 | 239 | - name: Add Docker repository |
|
141 | 244 | update_cache: true # Need to update cache after adding new repository |
142 | 245 | when: |
143 | 246 | - ansible_os_family == "Debian" |
144 | | - - docker_gpg_exists.stat.exists |
| 247 | + - docker_gpg_final_check.stat.exists |
145 | 248 | register: docker_repo_added |
146 | 249 |
|
147 | 250 | # Task 4: Install Docker packages with retries (only if repository was added) |
|
161 | 264 | until: docker_install is succeeded |
162 | 265 | when: |
163 | 266 | - ansible_os_family == "Debian" |
164 | | - - docker_gpg_exists.stat.exists |
| 267 | + - docker_gpg_final_check.stat.exists |
165 | 268 | - docker_repo_added is succeeded |
166 | 269 |
|
167 | 270 | # Alternative: Try to install Docker from default repositories if GPG/repo setup failed |
|
176 | 279 | register: docker_fallback_install |
177 | 280 | when: |
178 | 281 | - ansible_os_family == "Debian" |
179 | | - - not docker_gpg_exists.stat.exists |
| 282 | + - not docker_gpg_final_check.stat.exists |
| 283 | + ignore_errors: true |
| 284 | + |
| 285 | + # Snap fallback: Install Docker via snap (more likely to work in minimal containers) |
| 286 | + - name: Ultimate fallback - Install Docker via snap (container-friendly) |
| 287 | + ansible.builtin.snap: |
| 288 | + name: docker |
| 289 | + state: present |
| 290 | + register: docker_snap_install |
| 291 | + when: |
| 292 | + - ansible_os_family == "Debian" |
| 293 | + - not docker_gpg_final_check.stat.exists |
| 294 | + - docker_fallback_install is failed |
180 | 295 | ignore_errors: true |
181 | 296 |
|
182 | 297 | # Task 5: Start and enable Docker service (if Docker was installed) |
|
187 | 302 | enabled: true |
188 | 303 | when: docker_install is succeeded or docker_fallback_install is succeeded |
189 | 304 |
|
| 305 | + # Task 5b: Start snap Docker service (if installed via snap) |
| 306 | + - name: Start and enable snap Docker service |
| 307 | + ansible.builtin.systemd: |
| 308 | + name: snap.docker.dockerd |
| 309 | + state: started |
| 310 | + enabled: true |
| 311 | + when: docker_snap_install is succeeded |
| 312 | + ignore_errors: true |
| 313 | + |
190 | 314 | # Task 6: Add user to docker group (for non-root Docker usage) (if Docker was installed) |
191 | 315 | - name: Add user to docker group |
192 | 316 | ansible.builtin.user: |
193 | 317 | name: "{{ ansible_user }}" |
194 | 318 | groups: docker |
195 | 319 | append: true |
196 | 320 | register: user_added_to_docker_group |
197 | | - when: docker_install is succeeded or docker_fallback_install is succeeded |
| 321 | + when: docker_install is succeeded or docker_fallback_install is succeeded or docker_snap_install is succeeded |
198 | 322 |
|
199 | 323 | # Task 7: Verify Docker installation (if Docker was installed) |
200 | 324 | - name: Verify Docker installation |
201 | 325 | ansible.builtin.command: docker --version |
202 | 326 | register: docker_version |
203 | 327 | changed_when: false |
204 | | - when: docker_install is succeeded or docker_fallback_install is succeeded |
| 328 | + when: docker_install is succeeded or docker_fallback_install is succeeded or docker_snap_install is succeeded |
205 | 329 | ignore_errors: true |
206 | 330 |
|
207 | 331 | # Task 8: Display Docker version (if Docker was installed) |
|
216 | 340 | - name: Display Docker installation status |
217 | 341 | ansible.builtin.debug: |
218 | 342 | msg: | |
219 | | - ⚠️ Docker installation was skipped due to network connectivity issues. |
220 | | - {% if is_ci_environment %} |
221 | | - This is a known issue with {{ ci_type }} environments - see: |
222 | | - https://github.com/actions/runner-images/issues/2890 |
| 343 | + ⚠️ Docker installation failed after trying multiple methods: |
| 344 | + 1. Official Docker repository (get_url) - {{ 'FAILED' if docker_gpg_key is failed else 'SKIPPED' }} |
| 345 | + 2. Curl download fallback - {{ 'FAILED' if docker_gpg_curl is failed else 'SKIPPED' }} |
| 346 | + 3. Aria2 download fallback - {{ 'FAILED' if docker_gpg_aria2 is failed else 'SKIPPED' if aria2_install is succeeded else 'NOT_AVAILABLE' }} |
| 347 | + 4. Embedded GPG key fallback - {{ 'FAILED' if docker_gpg_embedded is failed else 'SKIPPED' }} |
| 348 | + 5. Default apt repositories - {{ 'FAILED' if docker_fallback_install is failed else 'SKIPPED' }} |
| 349 | + 6. Snap installation - {{ 'FAILED' if docker_snap_install is failed else 'SKIPPED' }} |
223 | 350 |
|
224 | | - The playbook completed successfully despite this limitation. |
225 | | - In production environments, network connectivity should be stable. |
226 | | - {% else %} |
227 | | - This may be due to firewall restrictions or temporary network issues. |
228 | | - Please check network connectivity and try again. |
229 | | - {% endif %} |
| 351 | + This may be due to network connectivity or repository access issues. |
| 352 | + All available fallback methods have been attempted. |
230 | 353 | when: |
231 | 354 | - docker_install is skipped or docker_install is failed |
232 | 355 | - docker_fallback_install is skipped or docker_fallback_install is failed |
| 356 | + - docker_snap_install is skipped or docker_snap_install is failed |
233 | 357 |
|
234 | 358 | # Task 10: Test Docker with hello-world (optional verification) (if Docker was installed) |
235 | 359 | - name: Test Docker with hello-world container |
|
258 | 382 | Alternatively, you can use 'newgrp docker' to activate the group membership in the current session. |
259 | 383 |
|
260 | 384 | NOTE: If you need to update the APT cache, run the update-apt-cache.yml playbook first. |
261 | | - {% if is_ci_environment %} |
262 | | - CI Environment Note: This playbook is designed to handle network limitations gracefully. |
263 | | - {% endif %} |
| 385 | + This playbook uses robust retry/timeout settings optimized for unreliable networks. |
264 | 386 | when: user_added_to_docker_group is changed |
265 | 387 |
|
266 | 388 | # Handlers section - tasks that run when triggered by other tasks |
|
0 commit comments