diff --git a/README.md b/README.md index 262f2e4..02e740e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,59 @@ # wulf-ansible +Ansible playbooks used by Semaphore for Wulf infrastructure automation. + +## Collection requirements + +Install required Ansible collections before running playbooks locally or in a new Semaphore worker environment: + +```bash +ansible-galaxy collection install -r collections/requirements.yml +``` + +Currently required collections: + +- `community.docker` +- `community.general` +- `ansible.posix` + +## Docker baseline + +Semaphore template: **Docker Baseline** + +Playbook: + +```bash +ansible-playbook playbooks/docker.yml +``` + +The Docker role: + +- supports Debian/Ubuntu apt-based hosts, +- removes conflicting distro/container packages, +- configures Docker's official apt repository, +- installs Docker Engine, Buildx, and Compose V2 plugin, +- configures Docker daemon log rotation and live-restore, +- enables Docker, +- adds the target Ansible user to the `docker` group, +- creates `/opt/stacks`, +- enables IPv4 forwarding, +- optionally disables IPv6, +- creates shared Docker networks such as `pangolin`, +- verifies `docker --version` and `docker compose version`. + +### Docker role variables + +```yaml +docker_package_state: present # set to latest when intentionally upgrading Docker packages +docker_stacks_dir: /opt/stacks +docker_networks: + - pangolin +docker_disable_ipv6: false +docker_run_hello_world: false # optional runtime pull/run verification +``` + +To run a full runtime verification during provisioning: + +```yaml +docker_run_hello_world: true +``` diff --git a/collections/requirements.yml b/collections/requirements.yml new file mode 100644 index 0000000..ff73cd7 --- /dev/null +++ b/collections/requirements.yml @@ -0,0 +1,5 @@ +--- +collections: + - name: community.docker + - name: community.general + - name: ansible.posix diff --git a/playbooks/docker.yml b/playbooks/docker.yml index 682b161..c0c2cc8 100644 --- a/playbooks/docker.yml +++ b/playbooks/docker.yml @@ -5,9 +5,3 @@ roles: - docker - - tasks: - - name: Create shared network (Pangolin/Newt) - community.docker.docker_network: - name: pangolin - state: present \ No newline at end of file diff --git a/roles/docker/defaults/main.yml b/roles/docker/defaults/main.yml index 2569c9a..f459cd1 100644 --- a/roles/docker/defaults/main.yml +++ b/roles/docker/defaults/main.yml @@ -1,4 +1,19 @@ --- +docker_conflicting_packages: + - docker.io + - docker-doc + - docker-compose + - docker-compose-v2 + - podman-docker + - containerd + - runc + +docker_prereq_packages: + - ca-certificates + - curl + - gnupg + - python3-docker + docker_packages: - docker-ce - docker-ce-cli @@ -6,6 +21,8 @@ docker_packages: - docker-buildx-plugin - docker-compose-plugin +docker_package_state: present + docker_daemon_config: log-driver: json-file log-opts: @@ -16,3 +33,10 @@ docker_daemon_config: live-restore: true docker_disable_ipv6: false + +docker_stacks_dir: /opt/stacks + +docker_networks: + - pangolin + +docker_run_hello_world: false diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml index 07a2de3..0d421a4 100644 --- a/roles/docker/tasks/main.yml +++ b/roles/docker/tasks/main.yml @@ -1,59 +1,57 @@ --- -# Remove conflicting packages +- name: Validate supported OS family + assert: + that: + - ansible_os_family == "Debian" + - ansible_distribution | lower in ["debian", "ubuntu"] + fail_msg: >- + Docker baseline currently supports Debian/Ubuntu apt-based hosts only. + Detected {{ ansible_distribution }} / {{ ansible_os_family }}. + - name: Remove conflicting Docker packages apt: - name: - - docker.io - - docker-doc - - docker-compose - - docker-compose-v2 - - podman-docker - - containerd - - runc + name: "{{ docker_conflicting_packages }}" state: absent -# Prerequisites - name: Install Docker prerequisites apt: - name: - - ca-certificates - - curl - - gnupg + name: "{{ docker_prereq_packages }}" state: present update_cache: true -# Keyrings directory - name: Create Docker APT keyrings directory file: path: /etc/apt/keyrings state: directory mode: "0755" -# Docker GPG key -- name: Add Docker GPG key - shell: | - curl -fsSL https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg - args: - creates: /etc/apt/keyrings/docker.gpg +- name: Determine dpkg architecture + command: dpkg --print-architecture + register: docker_dpkg_arch + changed_when: false + +- name: Download Docker GPG key + get_url: + url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg" + dest: /etc/apt/keyrings/docker.asc + mode: "0644" + force: true -# Docker repository - name: Add Docker APT repository apt_repository: repo: > - deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] + deb [arch={{ docker_dpkg_arch.stdout }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable filename: docker state: present update_cache: true -# Install Docker - name: Install Docker Engine and plugins apt: name: "{{ docker_packages }}" - state: present + state: "{{ docker_package_state }}" -# Docker daemon configuration - name: Configure Docker daemon copy: dest: /etc/docker/daemon.json @@ -63,31 +61,35 @@ mode: "0644" notify: Restart Docker -# Enable Docker - name: Enable and start Docker systemd: name: docker enabled: true state: started -# Non-root Docker usage - name: Add user to docker group user: name: "{{ docker_manage_user | default(ansible_user) }}" groups: docker append: true -# Kernel forwarding +- name: Ensure standard Docker stack directory exists + file: + path: "{{ docker_stacks_dir }}" + state: directory + owner: root + group: docker + mode: "0775" + - name: Enable IP forwarding - sysctl: + ansible.posix.sysctl: name: net.ipv4.ip_forward value: "1" state: present reload: true -# Optional IPv6 disable - name: Disable IPv6 - sysctl: + ansible.posix.sysctl: name: "{{ item }}" value: "1" state: present @@ -95,4 +97,35 @@ loop: - net.ipv6.conf.all.disable_ipv6 - net.ipv6.conf.default.disable_ipv6 - when: docker_disable_ipv6 \ No newline at end of file + when: docker_disable_ipv6 + +- name: Create shared Docker networks + community.docker.docker_network: + name: "{{ item }}" + state: present + loop: "{{ docker_networks }}" + when: docker_networks | length > 0 + +- name: Check Docker version + command: docker --version + register: docker_version + changed_when: false + +- name: Check Docker Compose version + command: docker compose version + register: docker_compose_version + changed_when: false + +- name: Verify Docker can run containers + command: docker run --rm hello-world + register: docker_hello_world + changed_when: false + when: docker_run_hello_world + +- name: Show Docker baseline summary + debug: + msg: + docker_version: "{{ docker_version.stdout }}" + docker_compose_version: "{{ docker_compose_version.stdout }}" + stacks_dir: "{{ docker_stacks_dir }}" + networks: "{{ docker_networks }}"