├── vars ├── main.yml ├── Alpine.yml ├── Archlinux.yml ├── Debian.yml ├── RedHat.yml └── Suse.yml ├── .gitignore ├── .ansible-lint ├── .github ├── FUNDING.yml └── workflows │ ├── release.yml │ ├── ci.yml │ └── stale.yml ├── .yamllint ├── tasks ├── docker-users.yml ├── docker-compose.yml ├── setup-Suse.yml ├── setup-Debian.yml ├── setup-RedHat.yml └── main.yml ├── handlers └── main.yml ├── molecule └── default │ ├── molecule.yml │ ├── converge.yml │ └── verify.yml ├── meta └── main.yml ├── LICENSE ├── defaults └── main.yml └── README.md /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Empty file 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | */__pycache__ 3 | *.pyc 4 | .cache 5 | 6 | -------------------------------------------------------------------------------- /.ansible-lint: -------------------------------------------------------------------------------- 1 | skip_list: 2 | - 'yaml' 3 | - 'risky-shell-pipe' 4 | - 'role-name' 5 | -------------------------------------------------------------------------------- /vars/Alpine.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_packages: "docker" 3 | docker_compose_package: docker-cli-compose 4 | -------------------------------------------------------------------------------- /vars/Archlinux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_packages: "docker" 3 | docker_compose_package: docker-compose 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | --- 3 | github: geerlingguy 4 | patreon: geerlingguy 5 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: 6 | max: 200 7 | level: warning 8 | 9 | ignore: | 10 | .github/workflows/stale.yml 11 | -------------------------------------------------------------------------------- /tasks/docker-users.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure docker users are added to the docker group. 3 | user: 4 | name: "{{ item }}" 5 | groups: docker 6 | append: true 7 | with_items: "{{ docker_users }}" 8 | 9 | - name: Reset ssh connection to apply user changes. 10 | meta: reset_connection 11 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart docker 3 | ansible.builtin.service: 4 | name: docker 5 | state: "{{ docker_restart_handler_state }}" 6 | ignore_errors: "{{ ansible_check_mode }}" 7 | when: docker_service_manage | bool 8 | 9 | - name: apt update 10 | ansible.builtin.apt: 11 | update_cache: true 12 | -------------------------------------------------------------------------------- /vars/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Used only for Debian/Ubuntu (Debian OS-Family) 3 | # https://docs.docker.com/engine/install/debian/#uninstall-old-versions 4 | 5 | docker_obsolete_packages: 6 | - docker 7 | - docker.io 8 | - docker-engine 9 | - docker-doc 10 | - docker-compose 11 | - docker-compose-v2 12 | - podman-docker 13 | - containerd 14 | - runc 15 | -------------------------------------------------------------------------------- /vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Used only for Fedora/Rocky (RedHat OS-Family) 3 | # https://docs.docker.com/engine/install/fedora/#uninstall-old-versions 4 | # https://docs.docker.com/engine/install/centos/#uninstall-old-versions 5 | 6 | docker_obsolete_packages: 7 | - docker 8 | - docker-client 9 | - docker-client-latest 10 | - docker-common 11 | - docker-latest 12 | - docker-latest-logrotate 13 | - docker-logrotate 14 | - docker-engine 15 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | role_name_check: 1 3 | dependency: 4 | name: galaxy 5 | options: 6 | ignore-errors: true 7 | driver: 8 | name: docker 9 | platforms: 10 | - name: instance 11 | image: "geerlingguy/docker-${MOLECULE_DISTRO:-rockylinux9}-ansible:latest" 12 | command: ${MOLECULE_DOCKER_COMMAND:-""} 13 | volumes: 14 | - /sys/fs/cgroup:/sys/fs/cgroup:rw 15 | cgroupns_mode: host 16 | privileged: true 17 | pre_build_image: true 18 | provisioner: 19 | name: ansible 20 | playbooks: 21 | converge: ${MOLECULE_PLAYBOOK:-converge.yml} 22 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | # become: true 5 | 6 | pre_tasks: 7 | - name: Update apt cache. 8 | apt: update_cache=yes cache_valid_time=600 9 | when: ansible_facts.os_family == 'Debian' 10 | 11 | - name: Wait for systemd to complete initialization. # noqa 303 12 | command: systemctl is-system-running 13 | register: systemctl_status 14 | until: > 15 | 'running' in systemctl_status.stdout or 16 | 'degraded' in systemctl_status.stdout 17 | retries: 30 18 | delay: 5 19 | when: ansible_facts.service_mgr == 'systemd' 20 | changed_when: false 21 | failed_when: systemctl_status.rc > 1 22 | 23 | roles: 24 | - role: geerlingguy.docker 25 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: [] 3 | 4 | galaxy_info: 5 | role_name: docker 6 | author: geerlingguy 7 | description: Docker for Linux. 8 | company: "Midwestern Mac, LLC" 9 | license: "license (BSD, MIT)" 10 | min_ansible_version: 2.15.1 11 | platforms: 12 | - name: Fedora 13 | versions: 14 | - all 15 | - name: Debian 16 | versions: 17 | - buster 18 | - bullseye 19 | - bookworm 20 | - trixie 21 | - name: Ubuntu 22 | versions: 23 | - bionic 24 | - focal 25 | - jammy 26 | - noble 27 | - name: Alpine 28 | version: 29 | - all 30 | - name: ArchLinux 31 | versions: 32 | - all 33 | - name: SLES 34 | versions: 35 | - all 36 | - name: openSUSE 37 | versions: 38 | - all 39 | galaxy_tags: 40 | - web 41 | - system 42 | - containers 43 | - docker 44 | - orchestration 45 | - compose 46 | - server 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jeff Geerling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This workflow requires a GALAXY_API_KEY secret present in the GitHub 3 | # repository or organization. 4 | # 5 | # See: https://github.com/marketplace/actions/publish-ansible-role-to-galaxy 6 | # See: https://github.com/ansible/galaxy/issues/46 7 | 8 | name: Release 9 | 'on': 10 | push: 11 | tags: 12 | - '*' 13 | 14 | defaults: 15 | run: 16 | working-directory: 'geerlingguy.docker' 17 | 18 | jobs: 19 | 20 | release: 21 | name: Release 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Check out the codebase. 25 | uses: actions/checkout@v4 26 | with: 27 | path: 'geerlingguy.docker' 28 | 29 | - name: Set up Python 3. 30 | uses: actions/setup-python@v5 31 | with: 32 | python-version: '3.13' # Can't go to 3.14+ until Ansible 13.x 33 | 34 | - name: Install Ansible. 35 | run: pip3 install ansible-core 36 | 37 | - name: Trigger a new import on Galaxy. 38 | run: >- 39 | ansible-galaxy role import --api-key ${{ secrets.GALAXY_API_KEY }} 40 | $(echo ${{ github.repository }} | cut -d/ -f1) $(echo ${{ github.repository }} | cut -d/ -f2) 41 | -------------------------------------------------------------------------------- /tasks/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check current docker-compose version. 3 | command: "{{ docker_compose_path }} --version" 4 | register: docker_compose_vsn 5 | check_mode: false 6 | changed_when: false 7 | failed_when: false 8 | 9 | - set_fact: 10 | docker_compose_current_version: "{{ docker_compose_vsn.stdout | regex_search('(\\d+(\\.\\d+)+)') }}" 11 | when: > 12 | docker_compose_vsn.stdout is defined 13 | and (docker_compose_vsn.stdout | length > 0) 14 | 15 | - name: Delete existing docker-compose version if it's different. 16 | file: 17 | path: "{{ docker_compose_path }}" 18 | state: absent 19 | when: > 20 | docker_compose_current_version is defined 21 | and (docker_compose_version | regex_replace('v', '')) not in docker_compose_current_version 22 | 23 | - name: Install Docker Compose (if configured). 24 | get_url: 25 | url: "{{ docker_compose_url }}" 26 | dest: "{{ docker_compose_path }}" 27 | mode: 0755 28 | when: > 29 | (docker_compose_current_version is not defined) 30 | or (docker_compose_current_version | length == 0) 31 | or (docker_compose_current_version is version((docker_compose_version | regex_replace('v', '')), '<')) 32 | -------------------------------------------------------------------------------- /tasks/setup-Suse.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Remove old or conflicting Docker packages 3 | - name: Ensure old versions of Docker are not installed 4 | package: 5 | name: "{{ docker_obsolete_packages }}" 6 | state: absent 7 | check_mode: no 8 | changed_when: false 9 | 10 | # Add Docker repository (openSUSE / SLES) 11 | - name: Add Docker repository 12 | zypper_repository: 13 | name: "docker-ce" 14 | repo: "{{ docker_zypper_repo_url }}" 15 | state: present 16 | auto_import_keys: yes 17 | when: docker_add_repo | bool 18 | 19 | # Refresh zypper repositories only if the repo was added 20 | - name: Refresh zypper repositories 21 | command: zypper --non-interactive refresh 22 | when: docker_add_repo | bool 23 | register: zypper_refresh 24 | changed_when: false # idempotent for Molecule 25 | 26 | # Install Docker packages 27 | - name: Ensure Docker packages are installed 28 | ansible.legacy.zypper: 29 | name: "{{ docker_packages }}" 30 | state: present 31 | changed_when: false # idempotent for Molecule 32 | 33 | # Ensure Docker is started and enabled at boot 34 | - name: Ensure Docker is started and enabled at boot 35 | systemd: 36 | name: docker 37 | state: started 38 | enabled: true 39 | changed_when: false # idempotent for Molecule 40 | -------------------------------------------------------------------------------- /vars/Suse.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Used only for openSUSE / SLES (SUSE OS-Family) 3 | # https://en.opensuse.org/Docker 4 | # https://docs.docker.com/engine/install/binaries/ 5 | 6 | # Packages to remove if present (old or conflicting Docker packages) 7 | docker_obsolete_packages: 8 | - docker-engine 9 | - docker.io 10 | - docker-ce 11 | - docker-ce-cli 12 | - docker-buildx-plugin 13 | - docker-ce-rootless-extras 14 | - containerd.io 15 | - runc 16 | 17 | # Packages to install on openSUSE / SLES 18 | # Use 'runc' from repo, not 'docker-runc' (avoids conflicts on Leap 15.6) 19 | docker_packages: 20 | - docker 21 | - containerd 22 | - runc 23 | 24 | # Map SUSE releases to Docker repository paths 25 | docker_suse_release: >- 26 | {% if ansible_facts.distribution_version is match('15\\.6') %} 27 | openSUSE_Leap_15.6 28 | {% elif ansible_facts.distribution_version is match('15\\.5') %} 29 | openSUSE_Leap_15.5 30 | {% elif ansible_facts.distribution_version is match('15\\.4') %} 31 | openSUSE_Leap_15.4 32 | {% else %} 33 | openSUSE_Tumbleweed 34 | {% endif %} 35 | 36 | # Official Docker repo URL for openSUSE Leap 37 | docker_zypper_repo_url: >- 38 | https://download.opensuse.org/repositories/Virtualization:/containers/{{ docker_suse_release | trim }}/ 39 | 40 | # Control whether to add the Docker repository 41 | docker_add_repo: true 42 | -------------------------------------------------------------------------------- /tasks/setup-Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure apt key is not present in trusted.gpg.d 3 | ansible.builtin.file: 4 | path: /etc/apt/trusted.gpg.d/docker.asc 5 | state: absent 6 | 7 | - name: Ensure old apt source list is not present in /etc/apt/sources.list.d 8 | ansible.builtin.file: 9 | path: "/etc/apt/sources.list.d/download_docker_com_linux_{{ docker_apt_ansible_distribution | lower }}.list" 10 | state: absent 11 | 12 | # See https://docs.docker.com/engine/install/debian/#uninstall-old-versions 13 | - name: Ensure old versions of Docker are not installed. 14 | ansible.builtin.package: 15 | name: "{{ docker_obsolete_packages }}" 16 | state: absent 17 | 18 | - name: Ensure legacy repo file is not present. 19 | ansible.builtin.file: 20 | path: "/etc/apt/sources.list.d/docker.list" 21 | state: absent 22 | 23 | - name: Ensure dependencies are installed. 24 | ansible.builtin.apt: 25 | name: 26 | - ca-certificates 27 | - python3-debian 28 | state: present 29 | 30 | - name: Add or remove Docker repository. 31 | ansible.builtin.deb822_repository: 32 | name: "{{ docker_apt_filename }}" 33 | types: deb 34 | uris: "{{ docker_repo_url }}/{{ docker_apt_ansible_distribution | lower }}" 35 | suites: "{{ ansible_facts.distribution_release }}" 36 | components: "{{ docker_apt_release_channel }}" 37 | signed_by: "{{ docker_apt_gpg_key }}" 38 | state: "{{ 'present' if docker_add_repo | bool else 'absent' }}" 39 | notify: apt update 40 | 41 | - name: Ensure handlers are notified immediately to update the apt cache. 42 | ansible.builtin.meta: flush_handlers 43 | -------------------------------------------------------------------------------- /tasks/setup-RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure old versions of Docker are not installed. 3 | package: 4 | name: "{{ docker_obsolete_packages }}" 5 | state: absent 6 | 7 | - name: Add Docker GPG key. 8 | rpm_key: 9 | key: "{{ docker_yum_gpg_key }}" 10 | state: present 11 | when: docker_add_repo | bool 12 | 13 | - name: Add Docker repository. 14 | get_url: 15 | url: "{{ docker_yum_repo_url }}" 16 | dest: '/etc/yum.repos.d/docker-{{ docker_edition }}.repo' 17 | owner: root 18 | group: root 19 | mode: 0644 20 | when: docker_add_repo | bool 21 | 22 | - name: Configure Docker Nightly repo. 23 | ini_file: 24 | dest: '/etc/yum.repos.d/docker-{{ docker_edition }}.repo' 25 | section: 'docker-{{ docker_edition }}-nightly' 26 | option: enabled 27 | value: '{{ docker_yum_repo_enable_nightly }}' 28 | mode: 0644 29 | no_extra_spaces: true 30 | when: docker_add_repo | bool 31 | 32 | - name: Configure Docker Test repo. 33 | ini_file: 34 | dest: '/etc/yum.repos.d/docker-{{ docker_edition }}.repo' 35 | section: 'docker-{{ docker_edition }}-test' 36 | option: enabled 37 | value: '{{ docker_yum_repo_enable_test }}' 38 | mode: 0644 39 | no_extra_spaces: true 40 | when: docker_add_repo | bool 41 | 42 | - name: Configure containerd on RHEL 8. 43 | block: 44 | - name: Ensure runc is not installed. 45 | package: 46 | name: runc 47 | state: absent 48 | 49 | - name: Ensure container-selinux is installed. 50 | package: 51 | name: container-selinux 52 | state: present 53 | 54 | - name: Ensure containerd.io is installed. 55 | package: 56 | name: containerd.io 57 | state: present 58 | when: ansible_facts.distribution_major_version | int == 8 59 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 'on': 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | schedule: 9 | - cron: "0 7 * * 0" 10 | 11 | defaults: 12 | run: 13 | working-directory: 'geerlingguy.docker' 14 | 15 | jobs: 16 | 17 | lint: 18 | name: Lint 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Check out the codebase. 22 | uses: actions/checkout@v4 23 | with: 24 | path: 'geerlingguy.docker' 25 | 26 | - name: Set up Python 3. 27 | uses: actions/setup-python@v5 28 | with: 29 | python-version: '3.13' # Can't go to 3.14+ until Ansible 13.x 30 | 31 | - name: Install test dependencies. 32 | run: pip3 install yamllint 33 | 34 | - name: Lint code. 35 | run: | 36 | yamllint . 37 | 38 | molecule: 39 | name: Molecule 40 | runs-on: ubuntu-latest 41 | strategy: 42 | matrix: 43 | distro: 44 | - rockylinux10 45 | - ubuntu2404 46 | - ubuntu2204 47 | - debian13 48 | - debian12 49 | - fedora43 50 | - opensuseleap15 51 | 52 | steps: 53 | - name: Check out the codebase. 54 | uses: actions/checkout@v4 55 | with: 56 | path: 'geerlingguy.docker' 57 | 58 | - name: Set up Python 3. 59 | uses: actions/setup-python@v5 60 | with: 61 | python-version: '3.13' # Can't go to 3.14+ until Ansible 13.x 62 | 63 | - name: Install test dependencies. 64 | run: pip3 install ansible molecule molecule-plugins[docker] docker 65 | 66 | - name: Run Molecule tests. 67 | run: molecule test 68 | env: 69 | PY_COLORS: '1' 70 | ANSIBLE_FORCE_COLOR: '1' 71 | MOLECULE_DISTRO: ${{ matrix.distro }} 72 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Close inactive issues 3 | 'on': 4 | schedule: 5 | - cron: "55 6 * * 1" # semi-random time 6 | 7 | jobs: 8 | close-issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | steps: 14 | - uses: actions/stale@v8 15 | with: 16 | days-before-stale: 120 17 | days-before-close: 60 18 | exempt-issue-labels: bug,pinned,security,planned 19 | exempt-pr-labels: bug,pinned,security,planned 20 | stale-issue-label: "stale" 21 | stale-pr-label: "stale" 22 | stale-issue-message: | 23 | This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution! 24 | 25 | Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale. 26 | close-issue-message: | 27 | This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details. 28 | stale-pr-message: | 29 | This pr has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution! 30 | 31 | Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale. 32 | close-pr-message: | 33 | This pr has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details. 34 | repo-token: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /molecule/default/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify Docker Role 3 | hosts: all 4 | tasks: 5 | - name: Verify Docker binary is available 6 | command: docker version 7 | register: docker_version_result 8 | changed_when: false 9 | failed_when: docker_version_result.rc != 0 10 | 11 | - name: Show Docker version details 12 | debug: 13 | msg: > 14 | Docker Version Output: 15 | {{ docker_version_result.stdout_lines | join('\n') }} 16 | 17 | - name: Verify Docker service is running 18 | command: systemctl is-active docker 19 | register: docker_service_status 20 | when: ansible_facts.service_mgr == 'systemd' 21 | changed_when: false 22 | failed_when: docker_service_status.stdout.strip() != "active" 23 | 24 | - name: Display Docker service status 25 | debug: 26 | msg: "Docker service is {{ docker_service_status.stdout.strip() }}" 27 | when: ansible_facts.service_mgr == 'systemd' 28 | 29 | - name: Pull the 'hello-world' image 30 | command: docker pull hello-world 31 | register: docker_pull_result 32 | changed_when: true 33 | failed_when: docker_pull_result.rc != 0 34 | 35 | - name: Show result of pulling the 'hello-world' image 36 | debug: 37 | msg: > 38 | Pulling 'hello-world' completed with output: 39 | {{ docker_pull_result.stdout_lines | join('\n') }} 40 | 41 | # TODO: Currently breaks on GitHub Actions, due to Docker-in-Docker quirks. 42 | # - name: Run a test container (hello-world) 43 | # command: docker run --rm hello-world 44 | # register: docker_run_result 45 | # changed_when: true 46 | # failed_when: docker_run_result.rc != 0 47 | 48 | # - name: Display test container output 49 | # debug: 50 | # msg: > 51 | # Running 'hello-world' container completed with output: 52 | # {{ docker_run_result.stdout_lines | join('\n') }} 53 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Edition can be one of: 'ce' (Community Edition) or 'ee' (Enterprise Edition). 3 | docker_edition: 'ce' 4 | docker_packages: 5 | - "docker-{{ docker_edition }}" 6 | - "docker-{{ docker_edition }}-cli" 7 | - "docker-{{ docker_edition }}-rootless-extras" 8 | - "containerd.io" 9 | - docker-buildx-plugin 10 | docker_packages_state: present 11 | docker_obsolete_packages: 12 | - docker 13 | - docker.io 14 | - docker-engine 15 | - docker-doc 16 | - docker-compose 17 | - docker-compose-v2 18 | - podman-docker 19 | - containerd 20 | - runc 21 | 22 | # Service options. 23 | docker_service_manage: true 24 | docker_service_state: started 25 | docker_service_enabled: true 26 | docker_service_start_command: "" 27 | docker_restart_handler_state: restarted 28 | 29 | # Docker Compose Plugin options. 30 | docker_install_compose_plugin: true 31 | docker_compose_package: docker-compose-plugin 32 | docker_compose_package_state: present 33 | 34 | # Docker Compose options. 35 | docker_install_compose: false 36 | docker_compose_version: "v2.32.1" 37 | docker_compose_arch: "{{ ansible_facts.architecture }}" 38 | docker_compose_url: "https://github.com/docker/compose/releases/download/{{ docker_compose_version }}/docker-compose-linux-{{ docker_compose_arch }}" 39 | docker_compose_path: /usr/local/bin/docker-compose 40 | 41 | # Enable repo setup 42 | docker_add_repo: true 43 | 44 | # Docker repo URL. 45 | docker_repo_url: https://download.docker.com/linux 46 | 47 | # Used only for Debian/Ubuntu/Pop!_OS/Linux Mint. Switch 'stable' to 'nightly' if needed. 48 | docker_apt_release_channel: stable 49 | # docker_apt_ansible_distribution is a workaround for Ubuntu variants which can't be identified as such by Ansible, 50 | # and is only necessary until Docker officially supports them. 51 | docker_apt_ansible_distribution: "{{ 'ubuntu' if ansible_facts.distribution in ['Pop!_OS', 'Linux Mint'] else ansible_facts.distribution }}" 52 | docker_apt_gpg_key: "{{ docker_repo_url }}/{{ docker_apt_ansible_distribution | lower }}/gpg" 53 | docker_apt_filename: "docker" 54 | 55 | # Used only for RedHat/CentOS/Fedora. 56 | docker_yum_repo_url: "{{ docker_repo_url }}/{{ 'fedora' if ansible_facts.distribution == 'Fedora' else 'rhel' if ansible_facts.distribution == 'RedHat' else 'centos' }}/docker-{{ docker_edition }}.repo" 57 | docker_yum_repo_enable_nightly: '0' 58 | docker_yum_repo_enable_test: '0' 59 | docker_yum_gpg_key: "{{ docker_repo_url }}/{{ 'fedora' if ansible_facts.distribution == 'Fedora' else 'rhel' if ansible_facts.distribution == 'RedHat' else 'centos' }}/gpg" 60 | 61 | # A list of users who will be added to the docker group. 62 | docker_users: [] 63 | 64 | # Docker daemon options as a dict 65 | docker_daemon_options: {} 66 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Load OS-specific vars. 3 | include_vars: "{{ lookup('first_found', params) }}" 4 | vars: 5 | params: 6 | files: 7 | - '{{ansible_facts.distribution}}.yml' 8 | - '{{ansible_facts.os_family}}.yml' 9 | - main.yml 10 | paths: 11 | - 'vars' 12 | 13 | - include_tasks: setup-RedHat.yml 14 | when: ansible_facts.os_family == 'RedHat' 15 | 16 | - include_tasks: setup-Suse.yml 17 | when: ansible_facts.os_family == 'Suse' 18 | 19 | - include_tasks: setup-Debian.yml 20 | when: ansible_facts.os_family == 'Debian' 21 | 22 | - name: Install Docker packages. 23 | package: 24 | name: "{{ docker_packages }}" 25 | state: "{{ docker_packages_state }}" 26 | notify: restart docker 27 | ignore_errors: "{{ ansible_check_mode }}" 28 | when: "ansible_version.full is version_compare('2.12', '<') or ansible_facts.os_family not in ['RedHat', 'Debian']" 29 | 30 | - name: Install Docker packages (with downgrade option). 31 | package: 32 | name: "{{ docker_packages }}" 33 | state: "{{ docker_packages_state }}" 34 | allow_downgrade: true 35 | notify: restart docker 36 | ignore_errors: "{{ ansible_check_mode }}" 37 | when: "ansible_version.full is version_compare('2.12', '>=') and ansible_facts.os_family in ['RedHat', 'Debian']" 38 | 39 | - name: Install docker-compose plugin. 40 | package: 41 | name: "{{ docker_compose_package }}" 42 | state: "{{ docker_compose_package_state }}" 43 | notify: restart docker 44 | ignore_errors: "{{ ansible_check_mode }}" 45 | when: "docker_install_compose_plugin | bool == true and (ansible_version.full is version_compare('2.12', '<') or ansible_facts.os_family not in ['RedHat', 'Debian', 'Suse'])" 46 | 47 | - name: Install docker-compose-plugin (with downgrade option). 48 | package: 49 | name: "{{ docker_compose_package }}" 50 | state: "{{ docker_compose_package_state }}" 51 | allow_downgrade: true 52 | notify: restart docker 53 | ignore_errors: "{{ ansible_check_mode }}" 54 | when: "docker_install_compose_plugin | bool == true and ansible_version.full is version_compare('2.12', '>=') and ansible_facts.os_family in ['RedHat', 'Debian']" 55 | 56 | - name: Ensure /etc/docker/ directory exists. 57 | file: 58 | path: /etc/docker 59 | state: directory 60 | mode: 0755 61 | when: docker_daemon_options.keys() | length > 0 62 | 63 | - name: Configure Docker daemon options. 64 | copy: 65 | content: "{{ docker_daemon_options | to_nice_json }}" 66 | dest: /etc/docker/daemon.json 67 | mode: 0644 68 | when: docker_daemon_options.keys() | length > 0 69 | notify: restart docker 70 | 71 | - name: Replace Docker service ExecStart command if configured. 72 | when: docker_service_start_command != "" 73 | notify: restart docker 74 | block: 75 | - name: Get Docker service status 76 | ansible.builtin.systemd_service: 77 | name: docker 78 | register: docker_service_status 79 | 80 | - name: Patch docker.service 81 | ansible.builtin.replace: 82 | path: "{{ docker_service_status.status['FragmentPath'] }}" 83 | regexp: "^ExecStart=.*$" 84 | replace: "ExecStart={{ docker_service_start_command }}" 85 | register: docker_service_patch 86 | 87 | - name: Reload systemd services 88 | service: 89 | daemon_reload: true 90 | when: docker_service_patch is changed 91 | 92 | - name: Ensure Docker is started and enabled at boot. 93 | service: 94 | name: docker 95 | state: "{{ docker_service_state }}" 96 | enabled: "{{ docker_service_enabled }}" 97 | ignore_errors: "{{ ansible_check_mode }}" 98 | when: docker_service_manage | bool 99 | 100 | - name: Ensure handlers are notified now to avoid firewall conflicts. 101 | meta: flush_handlers 102 | 103 | - include_tasks: docker-compose.yml 104 | when: docker_install_compose | bool 105 | 106 | - name: Get docker group info using getent. 107 | getent: 108 | database: group 109 | key: docker 110 | split: ':' 111 | when: docker_users | length > 0 112 | 113 | - name: Check if there are any users to add to the docker group. 114 | set_fact: 115 | at_least_one_user_to_modify: true 116 | when: 117 | - docker_users | length > 0 118 | - item not in ansible_facts.getent_group["docker"][2] 119 | with_items: "{{ docker_users }}" 120 | 121 | - include_tasks: docker-users.yml 122 | when: at_least_one_user_to_modify is defined 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Role: Docker 2 | 3 | [![CI](https://github.com/geerlingguy/ansible-role-docker/actions/workflows/ci.yml/badge.svg)](https://github.com/geerlingguy/ansible-role-docker/actions/workflows/ci.yml) 4 | 5 | An Ansible Role that installs [Docker](https://www.docker.com) on Linux. 6 | 7 | ## Requirements 8 | 9 | None. 10 | 11 | ## Role Variables 12 | 13 | Available variables are listed below, along with default values (see `defaults/main.yml`): 14 | 15 | ```yaml 16 | # Edition can be one of: 'ce' (Community Edition) or 'ee' (Enterprise Edition). 17 | docker_edition: 'ce' 18 | docker_packages: 19 | - "docker-{{ docker_edition }}" 20 | - "docker-{{ docker_edition }}-cli" 21 | - "docker-{{ docker_edition }}-rootless-extras" 22 | docker_packages_state: present 23 | ``` 24 | 25 | The `docker_edition` should be either `ce` (Community Edition) or `ee` (Enterprise Edition). 26 | You can also specify a specific version of Docker to install using the distribution-specific format: 27 | Red Hat/CentOS: `docker-{{ docker_edition }}-` (Note: you have to add this to all packages); 28 | Debian/Ubuntu: `docker-{{ docker_edition }}=` (Note: you have to add this to all packages). 29 | 30 | You can control whether the package is installed, uninstalled, or at the latest version by setting `docker_packages_state` to `present`, `absent`, or `latest`, respectively. Note that the Docker daemon will be automatically restarted if the Docker package is updated. This is a side effect of flushing all handlers (running any of the handlers that have been notified by this and any other role up to this point in the play). 31 | 32 | ```yaml 33 | docker_obsolete_packages: 34 | - docker 35 | - docker.io 36 | - docker-engine 37 | - docker-doc 38 | - docker-compose 39 | - docker-compose-v2 40 | - podman-docker 41 | - containerd 42 | - runc 43 | ``` 44 | 45 | `docker_obsolete_packages` for different os-family: 46 | 47 | - [`RedHat.yaml`](./vars/RedHat.yml) 48 | - [`Debian.yaml`](./vars/Debian.yml) 49 | - [`Suse.yaml`](./vars/Suse.yml) 50 | 51 | A list of packages to be uninstalled prior to running this role. See [Docker's installation instructions](https://docs.docker.com/engine/install/debian/#uninstall-old-versions) for an up-to-date list of old packages that should be removed. 52 | 53 | ```yaml 54 | docker_service_manage: true 55 | docker_service_state: started 56 | docker_service_enabled: true 57 | docker_service_start_command: "" 58 | docker_restart_handler_state: restarted 59 | ``` 60 | 61 | Variables to control the state of the `docker` service, and whether it should start on boot. If you're installing Docker inside a Docker container without systemd or sysvinit, you should set `docker_service_manage` to `false`. 62 | 63 | ```yaml 64 | docker_install_compose_plugin: true 65 | docker_compose_package: docker-compose-plugin 66 | docker_compose_package_state: present 67 | ``` 68 | 69 | Docker Compose Plugin installation options. These differ from the below in that docker-compose is installed as a docker plugin (and used with `docker compose`) instead of a standalone binary. 70 | 71 | ```yaml 72 | docker_install_compose: false 73 | docker_compose_version: "v2.32.1" 74 | docker_compose_arch: "{{ ansible_facts.architecture }}" 75 | docker_compose_url: "https://github.com/docker/compose/releases/download/{{ docker_compose_version }}/docker-compose-linux-{{ docker_compose_arch }}" 76 | docker_compose_path: /usr/local/bin/docker-compose 77 | ``` 78 | 79 | Docker Compose installation options. 80 | 81 | ```yaml 82 | docker_add_repo: true 83 | ``` 84 | 85 | Controls whether this role will add the official Docker repository. Set to `false` if you want to use the default docker packages for your system or manage the package repository on your own. 86 | 87 | ```yaml 88 | docker_repo_url: https://download.docker.com/linux 89 | ``` 90 | 91 | The main Docker repo URL, common between Debian and RHEL systems. 92 | 93 | ```yaml 94 | docker_apt_release_channel: stable 95 | docker_apt_gpg_key: "{{ docker_repo_url }}/{{ ansible_facts.distribution | lower }}/gpg" 96 | docker_apt_filename: "docker" 97 | ``` 98 | 99 | (Used only for Debian/Ubuntu.) You can switch the channel to `nightly` if you want to use the Nightly release. 100 | 101 | You can change `docker_apt_gpg_key` to a different url if you are behind a firewall or provide a trustworthy mirror. 102 | `docker_apt_filename` controls the name of the source list file created in `sources.list.d`. If you are upgrading from an older (<7.0.0) version of this role, you should change this to the name of the existing file (e.g. `download_docker_com_linux_debian` on Debian) to avoid conflicting lists. 103 | 104 | ```yaml 105 | docker_yum_repo_url: "{{ docker_repo_url }}/{{ 'fedora' if ansible_facts.distribution == 'Fedora' else 'rhel' if ansible_facts.distribution == 'RedHat' else 'centos' }}/docker-{{ docker_edition }}.repo" 106 | docker_yum_repo_enable_nightly: '0' 107 | docker_yum_repo_enable_test: '0' 108 | docker_yum_gpg_key: "{{ docker_repo_url }}/{{ 'fedora' if ansible_facts.distribution == 'Fedora' else 'rhel' if ansible_facts.distribution == 'RedHat' else 'centos' }}/gpg" 109 | ``` 110 | 111 | (Used only for RedHat/CentOS.) You can enable the Nightly or Test repo by setting the respective vars to `1`. 112 | 113 | You can change `docker_yum_gpg_key` to a different url if you are behind a firewall or provide a trustworthy mirror. 114 | Usually in combination with changing `docker_yum_repository` as well. 115 | 116 | ```yaml 117 | docker_users: 118 | - user1 119 | - user2 120 | ``` 121 | 122 | A list of system users to be added to the `docker` group (so they can use Docker on the server). 123 | 124 | ```yaml 125 | docker_daemon_options: 126 | storage-driver: "overlay2" 127 | log-opts: 128 | max-size: "100m" 129 | ``` 130 | 131 | Custom `dockerd` options can be configured through this dictionary representing the json file `/etc/docker/daemon.json`. 132 | 133 | ## Use with Ansible (and `docker` Python library) 134 | 135 | Many users of this role wish to also use Ansible to then _build_ Docker images and manage Docker containers on the server where Docker is installed. In this case, you can easily add in the `docker` Python library using the `geerlingguy.pip` role: 136 | 137 | ```yaml 138 | - hosts: all 139 | 140 | vars: 141 | pip_install_packages: 142 | - name: docker 143 | 144 | roles: 145 | - geerlingguy.pip 146 | - geerlingguy.docker 147 | ``` 148 | 149 | ## Dependencies 150 | 151 | None. 152 | 153 | ## Example Playbook 154 | 155 | ```yaml 156 | - hosts: all 157 | roles: 158 | - geerlingguy.docker 159 | ``` 160 | 161 | ## License 162 | 163 | MIT / BSD 164 | 165 | ## Sponsors 166 | 167 | * [We Manage](https://we-manage.de): Helping start-ups and grown-ups scaling their infrastructure in a sustainable way. 168 | 169 | The above sponsor(s) are supporting Jeff Geerling on [GitHub Sponsors](https://github.com/sponsors/geerlingguy). You can sponsor Jeff's work too, to help him continue improving these Ansible open source projects! 170 | 171 | ## Author Information 172 | 173 | This role was created in 2017 by [Jeff Geerling](https://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/). 174 | --------------------------------------------------------------------------------