Compare commits
5 Commits
86c76d485d
...
42fb065afe
| Author | SHA1 | Date | |
|---|---|---|---|
| 42fb065afe | |||
| 2279f8beba | |||
| 66f09c49bd | |||
| c5925f2a5a | |||
| b73d283e45 |
73
README.md
Normal file
73
README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# ansible-role-docker
|
||||
|
||||
An Ansible role to install and configure Docker.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Ansible 2.10 or higher
|
||||
- Debian or Ubuntu-based distribution
|
||||
|
||||
## Dependencies
|
||||
|
||||
This role doesn't have any dependencies to other roles or collections.
|
||||
|
||||
## Playbook Example
|
||||
|
||||
A pretty complete playbook example to install Docker and configure it for multiple users, expose the Docker API, configure a Docker registry and create a Docker network.
|
||||
|
||||
```yaml
|
||||
---
|
||||
- hosts: docker_servers
|
||||
become: true
|
||||
roles:
|
||||
- ansible-role-docker
|
||||
vars:
|
||||
docker_users:
|
||||
- titou
|
||||
- antoine
|
||||
docker_data_dir: /opt/docker
|
||||
docker_expose_api: true
|
||||
docker_registry_url: "docker.io"
|
||||
docker_registry_email: "user@example.com"
|
||||
docker_networks:
|
||||
- name: "my-network"
|
||||
driver: "bridge"
|
||||
subnet: "172.20.0.0/16"
|
||||
gateway: "172.20.0.1"
|
||||
ip_range: "172.20.0.0/24"
|
||||
```
|
||||
|
||||
**⚠️ SECURITY WARNING**: Exposing Docker API over TCP without TLS is insecure : consider using TLS or restrict access with firewall rules.
|
||||
|
||||
You can also use the role in its most simple form:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- hosts: docker_servers
|
||||
become: true
|
||||
roles:
|
||||
- ansible-role-docker
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
| -------------------------- | -------- | ----------- | -------------------------------------------------------------------------------------------- |
|
||||
| `docker_api_host` | No | `127.0.0.1` | Host address to expose Docker API on (when `docker_expose_api` is true) |
|
||||
| `docker_api_port` | No | `2375` | Port to expose Docker API on (when `docker_expose_api` is true) |
|
||||
| `docker_arch` | No | `amd64` | Architecture to install Docker for (e.g., "amd64", "arm64") |
|
||||
| `docker_data_dir` | No | `` | Directory to store Docker volumes data |
|
||||
| `docker_expose_api` | No | `false` | Whether to expose Docker API over TCP |
|
||||
| `docker_networks` | No | `[]` | List of networks to create (dicts with name, driver, subnet, etc.) |
|
||||
| `docker_registry_email` | No | `` | Registry email (mutually exclusive with `docker_registry_username`) |
|
||||
| `docker_registry_url` | No | `` | Docker registry URL (registry authentication is skipped if not set) |
|
||||
| `docker_registry_username` | No | `` | Registry username (mutually exclusive with `docker_registry_email`) |
|
||||
| `docker_users` | No | `[]` | List of users to be added to the `docker` group |
|
||||
|
||||
**Note**: When using registry authentication, the registry password must be provided via the `DOCKER_REGISTRY_PASSWORD` environment variable.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the GNU General Public License v3.0 or later (GPLv3+). See the [LICENSE](LICENSE) file for details.
|
||||
9
defaults/main.yml
Normal file
9
defaults/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
docker_expose_api: false
|
||||
docker_api_host: 127.0.0.1
|
||||
docker_api_port: 2375
|
||||
docker_arch: amd64
|
||||
|
||||
docker_users: []
|
||||
|
||||
docker_networks: []
|
||||
12
handlers/main.yml
Normal file
12
handlers/main.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: reload systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: restart docker
|
||||
ansible.builtin.systemd:
|
||||
name: docker
|
||||
state: restarted
|
||||
daemon_reload: true
|
||||
ignore_errors: false
|
||||
|
||||
57
tasks/configuration.yml
Normal file
57
tasks/configuration.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
- name: Add users to docker group
|
||||
ansible.builtin.user:
|
||||
name: "{{ item }}"
|
||||
groups: docker
|
||||
append: true
|
||||
loop: "{{ docker_users }}"
|
||||
when: docker_users | length > 0
|
||||
|
||||
- name: Create /etc/docker directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/docker
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Enable and start Docker
|
||||
ansible.builtin.systemd:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: true
|
||||
|
||||
- name: Create docker data directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ docker_data_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
group: docker
|
||||
when: docker_data_dir is defined and docker_data_dir | length > 0
|
||||
|
||||
- name: Create systemd override directory for Docker
|
||||
ansible.builtin.file:
|
||||
path: /etc/systemd/system/docker.service.d
|
||||
state: directory
|
||||
mode: "0755"
|
||||
when: docker_expose_api
|
||||
|
||||
- name: Deploy Docker systemd override for API exposure
|
||||
ansible.builtin.template:
|
||||
src: docker-override.conf.j2
|
||||
dest: /etc/systemd/system/docker.service.d/override.conf
|
||||
mode: "0644"
|
||||
notify: restart docker
|
||||
when: docker_expose_api
|
||||
|
||||
- name: Remove Docker systemd override when API exposure is disabled
|
||||
ansible.builtin.file:
|
||||
path: /etc/systemd/system/docker.service.d/override.conf
|
||||
state: absent
|
||||
notify: restart docker
|
||||
when: not docker_expose_api
|
||||
|
||||
- name: Deploy Docker daemon.json configuration file
|
||||
ansible.builtin.template:
|
||||
src: daemon.json.j2
|
||||
dest: /etc/docker/daemon.json
|
||||
mode: "0644"
|
||||
notify: restart docker
|
||||
12
tasks/healthcheck.yml
Normal file
12
tasks/healthcheck.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Wait for Docker daemon to be ready
|
||||
ansible.builtin.wait_for:
|
||||
path: /var/run/docker.sock
|
||||
state: present
|
||||
timeout: 30
|
||||
|
||||
- name: Verify Docker is running and healthy
|
||||
ansible.builtin.command: docker info
|
||||
register: docker_health
|
||||
changed_when: false
|
||||
failed_when: docker_health.rc != 0
|
||||
38
tasks/installation.yml
Normal file
38
tasks/installation.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
- name: Install dependencies to use docker's repository
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
- curl
|
||||
- gnupg
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Create /etc/apt/keyrings directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/apt/keyrings
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Import docker GPG key
|
||||
ansible.builtin.get_url:
|
||||
url: https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }}/gpg
|
||||
dest: /etc/apt/keyrings/docker.asc
|
||||
mode: "0644"
|
||||
|
||||
- name: Setup docker repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb [arch={{ docker_arch }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }} {{ ansible_facts['distribution_release'] }} stable"
|
||||
state: present
|
||||
filename: docker
|
||||
|
||||
- name: Install docker packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-buildx-plugin
|
||||
- docker-compose-plugin
|
||||
state: present
|
||||
update_cache: true
|
||||
17
tasks/main.yml
Normal file
17
tasks/main.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Running installation
|
||||
ansible.builtin.include_tasks: installation.yml
|
||||
|
||||
- name: Configure Docker
|
||||
ansible.builtin.include_tasks: configuration.yml
|
||||
|
||||
- name: Verify Docker installation
|
||||
ansible.builtin.include_tasks: healthcheck.yml
|
||||
|
||||
- name: Create Docker networks
|
||||
ansible.builtin.include_tasks: networks.yml
|
||||
when: docker_networks is defined
|
||||
|
||||
- name: Configure Docker registry authentication
|
||||
ansible.builtin.include_tasks: registry.yml
|
||||
when: docker_registry_url is defined
|
||||
51
tasks/networks.yml
Normal file
51
tasks/networks.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
- name: Get all Docker networks
|
||||
ansible.builtin.command: docker network ls --format "{{ '{{' }}.Name{{ '}}' }}"
|
||||
register: all_networks
|
||||
changed_when: false
|
||||
when: docker_networks is defined
|
||||
|
||||
- name: Get list of managed network names
|
||||
ansible.builtin.set_fact:
|
||||
managed_network_names: "{{ docker_networks | map(attribute='name') | list }}"
|
||||
when: docker_networks is defined
|
||||
|
||||
- name: Check networks to remove
|
||||
ansible.builtin.set_fact:
|
||||
networks_to_remove: "{{ all_networks.stdout_lines | difference(managed_network_names | default([])) | difference(['bridge', 'host', 'none']) | list }}"
|
||||
when: docker_networks is defined
|
||||
|
||||
- name: Remove Docker networks no longer in configuration
|
||||
ansible.builtin.command: docker network rm {{ item }}
|
||||
loop: "{{ networks_to_remove | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
when:
|
||||
- docker_networks is defined
|
||||
- networks_to_remove | default([]) | length > 0
|
||||
ignore_errors: true
|
||||
failed_when: false
|
||||
|
||||
- name: Check if Docker network exists
|
||||
ansible.builtin.command: docker network inspect {{ item.name }}
|
||||
register: network_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
loop: "{{ docker_networks }}"
|
||||
when: docker_networks | length > 0
|
||||
|
||||
- name: Create Docker networks
|
||||
ansible.builtin.command: >
|
||||
docker network create
|
||||
--driver {{ item.driver | default('bridge') }}
|
||||
{% if item.subnet is defined %}--subnet {{ item.subnet }}{% endif %}
|
||||
{% if item.gateway is defined %}--gateway {{ item.gateway }}{% endif %}
|
||||
{% if item.ip_range is defined %}--ip-range {{ item.ip_range }}{% endif %}
|
||||
{{ item.name }}
|
||||
loop: "{{ docker_networks }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
when:
|
||||
- docker_networks | length > 0
|
||||
- network_check.results | selectattr('item.name', 'equalto', item.name) | selectattr('rc', 'equalto', 1) | list | length > 0
|
||||
ignore_errors: true
|
||||
36
tasks/registry.yml
Normal file
36
tasks/registry.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
- name: Validate registry credentials
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- docker_registry_username is defined or docker_registry_email is defined
|
||||
fail_msg: "When docker_registry_url is set, either docker_registry_username or docker_registry_email must be provided"
|
||||
when: docker_registry_url is defined
|
||||
|
||||
- name: Login to Docker registry as users
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
docker login
|
||||
--password-stdin
|
||||
{% if docker_registry_username is defined %}-u {{ docker_registry_username }}{% elif docker_registry_email is defined %}-u {{ docker_registry_email }}{% endif %}
|
||||
{{ docker_registry_url }}
|
||||
stdin: "{{ lookup('env', 'DOCKER_REGISTRY_PASSWORD') | default('', true) }}"
|
||||
become_user: "{{ item }}"
|
||||
loop: "{{ docker_users }}"
|
||||
when:
|
||||
- docker_registry_url is defined
|
||||
- docker_users is defined
|
||||
- docker_users | length > 0
|
||||
no_log: true
|
||||
|
||||
- name: Login to Docker registry as root
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
docker login
|
||||
--password-stdin
|
||||
{% if docker_registry_username is defined %}-u {{ docker_registry_username }}{% elif docker_registry_email is defined %}-u {{ docker_registry_email }}{% endif %}
|
||||
{{ docker_registry_url }}
|
||||
stdin: "{{ lookup('env', 'DOCKER_REGISTRY_PASSWORD') | default('', true) }}"
|
||||
when:
|
||||
- docker_registry_url is defined
|
||||
- docker_users is not defined or docker_users | length == 0
|
||||
no_log: true
|
||||
11
templates/daemon.json.j2
Normal file
11
templates/daemon.json.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
{% if docker_data_dir is defined and docker_data_dir | length > 0 %}
|
||||
"data-root": "{{ docker_data_dir }}",
|
||||
{% endif %}
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
}
|
||||
}
|
||||
|
||||
4
templates/docker-override.conf.j2
Normal file
4
templates/docker-override.conf.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://{{ docker_api_host }}:{{ docker_api_port }} --containerd=/run/containerd/containerd.sock
|
||||
|
||||
Reference in New Issue
Block a user