D1.4 Προετοιμασία Περιβάλλοντος 🛠️

Τι χρειαζόμαστε

┌─────────────────────────────────────────────────────────┐
│  Controller (bananapim4berry)                           │
│  ✅ Ansible 2.20.4                                      │
│  ✅ community.docker collection                         │
│  ⬜ docker Python library (στον controller)             │
│                                                         │
│  Managed Server (nextcloud)                             │
│  ⬜ Docker Engine                                       │
│  ⬜ docker Python library (στον server)                 │
│  ⬜ docker-compose plugin                               │
└─────────────────────────────────────────────────────────┘

Βήμα 1: Έλεγχος Controller

# Ως ansible user στο Armbian
cd ~/ansible

# ── Έλεγχος collection ────────────────────────
ansible-galaxy collection list | grep docker

# ── Έλεγχος Python docker library ────────────
python3 -c "import docker; print(docker.__version__)"
# Αν βγάλει error → χρειάζεται εγκατάσταση

# ── Εγκατάσταση docker Python library ─────────
pip install docker docker-compose

# ── Επαλήθευση ────────────────────────────────
python3 -c "import docker; print('docker SDK:', docker.__version__)"

Βήμα 2: Έλεγχος Managed Server

# Έλεγχος αν υπάρχει Docker
ansible nextcloud -m ansible.builtin.command \
    -a "docker --version" \
    --become

# Έλεγχος Python docker library στον server
ansible nextcloud -m ansible.builtin.command \
    -a "python3 -c 'import docker; print(docker.__version__)'" \
    --become

# Έλεγχος Docker service
ansible nextcloud -m ansible.builtin.service_facts \
    --become | grep -i docker

Βήμα 3: Ενημέρωση requirements.yml

cat > ~/ansible/requirements.yml << 'EOF'
---
roles:
  - name:    geerlingguy.nginx
    version: "3.2.0"

collections:
  - name:    community.general
    version: ">=7.0.0"

  - name:    ansible.posix
    version: ">=1.5.0"

  - name:    community.docker
    version: ">=3.0.0"     # ← για Docker automation
EOF

# Εγκατάσταση
ansible-galaxy collection install -r requirements.yml

Βήμα 4: Ενημέρωση group_vars

# Προσθήκη Docker variables στο group_vars
cat >> ~/ansible/inventory/group_vars/all/vars.yml << 'EOF'

# ── Docker Settings ───────────────────────────
docker_edition:         ce            # community edition
docker_install_compose: true
docker_compose_version: "v2.24.0"
docker_users:
  - ansible             # ← ποιοι users μπορούν να τρέχουν docker

# ── Docker Registry ───────────────────────────
docker_registry_url:    "https://index.docker.io/v1/"

# ── Container defaults ────────────────────────
container_restart_policy: unless-stopped
container_log_driver:     json-file
container_log_max_size:   "10m"
container_log_max_file:   "3"
EOF

Βήμα 5: Δημιουργία Docker Role Structure

# Δημιουργία Docker installation role
cd ~/ansible/roles
ansible-galaxy role init docker

# Δομή που θα φτιάξουμε:
tree ~/ansible/roles/docker/
# docker/
# ├── defaults/
# │   └── main.yml
# ├── handlers/
# │   └── main.yml
# ├── tasks/
# │   ├── main.yml
# │   ├── install.yml
# │   ├── configure.yml
# │   └── users.yml
# └── meta/
#     └── main.yml

Βήμα 6: Docker Role — defaults/main.yml

cat > ~/ansible/roles/docker/defaults/main.yml << 'EOF'
---
# ============================================================
# Docker Role Defaults
# ============================================================

# ── Edition ───────────────────────────────────
docker_edition: ce    # ce = Community Edition

# ── Packages ──────────────────────────────────
docker_packages_debian:
  - docker-ce
  - docker-ce-cli
  - containerd.io
  - docker-buildx-plugin
  - docker-compose-plugin

docker_packages_redhat:
  - docker-ce
  - docker-ce-cli
  - containerd.io
  - docker-buildx-plugin
  - docker-compose-plugin

docker_packages_suse:
  - docker
  - docker-compose

# ── Service ───────────────────────────────────
docker_service_enabled: true
docker_service_state:   started

# ── Users ─────────────────────────────────────
docker_users: []    # ← users που θα μπουν στο docker group

# ── Daemon config ─────────────────────────────
docker_daemon_options:
  log-driver: json-file
  log-opts:
    max-size: "10m"
    max-file: "3"
  storage-driver: overlay2

# ── Compose ───────────────────────────────────
docker_install_compose: true
EOF

Βήμα 7: Docker Role — tasks/main.yml

cat > ~/ansible/roles/docker/tasks/main.yml << 'EOF'
---
# ============================================================
# Docker Role — Main Entry Point
# ============================================================

- name: Install Docker
  ansible.builtin.import_tasks:
    file: install.yml
  tags: [install, docker]

- name: Configure Docker
  ansible.builtin.import_tasks:
    file: configure.yml
  tags: [config, docker]

- name: Configure Docker users
  ansible.builtin.import_tasks:
    file: users.yml
  tags: [users, docker]
  when: docker_users | length > 0
EOF

Βήμα 8: Docker Role — tasks/install.yml

cat > ~/ansible/roles/docker/tasks/install.yml << 'EOF'
---
# ============================================================
# Docker Installation — Και στις 3 διανομές
# ============================================================

# ══════════════════════════════════════════
# DEBIAN / UBUNTU
# ══════════════════════════════════════════
- name: Install prerequisites (Debian)
  ansible.builtin.apt:
    name:
      - ca-certificates
      - curl
      - gnupg
      - lsb-release
    state:        present
    update_cache: true
  when: ansible_facts['os_family'] == "Debian"

- name: Add Docker GPG key (Debian)
  ansible.builtin.apt_key:
    url:   "https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }}/gpg"
    state: present
  when: ansible_facts['os_family'] == "Debian"

- name: Add Docker repository (Debian)
  ansible.builtin.apt_repository:
    repo: >-
      deb [arch={{ ansible_facts['architecture'] | replace('x86_64', 'amd64') | replace('aarch64', 'arm64') }}]
      https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }}
      {{ ansible_facts['distribution_release'] }}
      stable
    state:    present
    filename: docker
  when: ansible_facts['os_family'] == "Debian"

- name: Install Docker packages (Debian)
  ansible.builtin.apt:
    name:         "{{ docker_packages_debian }}"
    state:        present
    update_cache: true
  when: ansible_facts['os_family'] == "Debian"
  notify: Restart Docker

# ══════════════════════════════════════════
# REDHAT / FEDORA
# ══════════════════════════════════════════
- name: Add Docker repository (RedHat)
  ansible.builtin.yum_repository:
    name:        docker-ce
    description: Docker CE Stable
    baseurl:     "https://download.docker.com/linux/centos/$releasever/$basearch/stable"
    gpgcheck:    true
    gpgkey:      "https://download.docker.com/linux/centos/gpg"
    enabled:     true
  when: ansible_facts['os_family'] == "RedHat"

- name: Install Docker packages (RedHat)
  ansible.builtin.dnf:
    name:  "{{ docker_packages_redhat }}"
    state: present
  when: ansible_facts['os_family'] == "RedHat"
  notify: Restart Docker

# ══════════════════════════════════════════
# OPENSUSE
# ══════════════════════════════════════════
- name: Install Docker packages (openSUSE)
  community.general.zypper:
    name:  "{{ docker_packages_suse }}"
    state: present
  when: ansible_facts['os_family'] == "Suse"
  notify: Restart Docker

# ══════════════════════════════════════════
# ΚΟΙΝΟ ΓΙΑ ΟΛΕΣ ΤΙΣ ΔΙΑΝΟΜΕΣ
# ══════════════════════════════════════════
- name: Enable and start Docker
  ansible.builtin.service:
    name:    docker
    state:   "{{ docker_service_state }}"
    enabled: "{{ docker_service_enabled }}"

- name: Install Python Docker SDK
  ansible.builtin.pip:
    name:
      - docker
      - docker-compose
    state:      present
    virtualenv: "{{ ansible_env.VIRTUAL_ENV | default(omit) }}"

- name: Verify Docker installation
  ansible.builtin.command:
    cmd: docker --version
  register:     docker_version
  changed_when: false

- name: Show Docker version
  ansible.builtin.debug:
    msg: "✅ {{ docker_version.stdout }}"
EOF

Βήμα 9: Docker Role — tasks/configure.yml

cat > ~/ansible/roles/docker/tasks/configure.yml << 'EOF'
---
# ============================================================
# Docker Daemon Configuration
# ============================================================

- name: Create Docker config directory
  ansible.builtin.file:
    path:  /etc/docker
    state: directory
    owner: root
    group: root
    mode:  '0755'

- name: Deploy Docker daemon config
  ansible.builtin.copy:
    dest:    /etc/docker/daemon.json
    owner:   root
    group:   root
    mode:    '0644'
    content: "{{ docker_daemon_options | to_nice_json }}"
  notify: Restart Docker

- name: Create Docker systemd override directory
  ansible.builtin.file:
    path:  /etc/systemd/system/docker.service.d
    state: directory
    mode:  '0755'

- name: Verify Docker daemon config
  ansible.builtin.command:
    cmd: docker info
  register:     docker_info
  changed_when: false
  ignore_errors: true

- name: Docker info summary
  ansible.builtin.debug:
    msg:
      - "Docker Storage Driver: {{ docker_info.stdout | regex_search('Storage Driver: (.+)', '\\1') | first | default('N/A') }}"
      - "Docker Logging Driver: {{ docker_info.stdout | regex_search('Logging Driver: (.+)', '\\1') | first | default('N/A') }}"
  when: not docker_info.failed
EOF

Βήμα 10: Docker Role — tasks/users.yml

cat > ~/ansible/roles/docker/tasks/users.yml << 'EOF'
---
# ============================================================
# Docker User Configuration
# ============================================================

- name: Add users to docker group
  ansible.builtin.user:
    name:   "{{ item }}"
    groups: docker
    append: true
  loop: "{{ docker_users }}"
  loop_control:
    label: "{{ item }}"

- name: Verify docker group membership
  ansible.builtin.command:
    cmd: "id {{ item }}"
  register:     user_groups
  changed_when: false
  loop: "{{ docker_users }}"
  loop_control:
    label: "{{ item }}"

- name: Show user group info
  ansible.builtin.debug:
    msg: "{{ item.stdout }}"
  loop: "{{ user_groups.results }}"
  loop_control:
    label: "{{ item.item }}"
EOF

Βήμα 11: Docker Role — handlers/main.yml

cat > ~/ansible/roles/docker/handlers/main.yml << 'EOF'
---
- name: Restart Docker
  ansible.builtin.service:
    name:  docker
    state: restarted
  ignore_errors: "{{ ansible_check_mode }}"

- name: Reload Docker
  ansible.builtin.service:
    name:  docker
    state: reloaded
  ignore_errors: "{{ ansible_check_mode }}"
EOF

Βήμα 12: Docker Install Playbook

cat > ~/ansible/playbooks/docker-install.yml << 'EOF'
---
# ============================================================
# Docker Installation Playbook
# ============================================================

- name: Install Docker
  hosts: "{{ target | default('all_managed') }}"
  become: true
  gather_facts: true

  pre_tasks:
    - name: Pre-install info
      ansible.builtin.debug:
        msg:
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          - "Installing Docker"
          - "Host: {{ inventory_hostname }}"
          - "OS  : {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}"
          - "Arch: {{ ansible_facts['architecture'] }}"
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
      tags: always

  roles:
    - role: docker
      vars:
        docker_users:
          - ansible
          - "{{ ansible_user }}"
      tags: docker

  post_tasks:
    - name: Test Docker
      ansible.builtin.command:
        cmd: docker run --rm hello-world
      register:     hello_world
      changed_when: false
      ignore_errors: true
      tags: verify

    - name: Test Docker Compose
      ansible.builtin.command:
        cmd: docker compose version
      register:     compose_version
      changed_when: false
      ignore_errors: true
      tags: verify

    - name: Installation Report
      ansible.builtin.debug:
        msg:
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          - "✅ DOCKER INSTALLATION COMPLETE"
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          - "Docker  : {{ '✅ OK' if not hello_world.failed else '❌ Check manually' }}"
          - "Compose : {{ compose_version.stdout | default('❌ Not found') }}"
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
      tags: always
EOF

Βήμα 13: Εκτέλεση

# ── Syntax check ──────────────────────────────
ansible-playbook playbooks/docker-install.yml \
    --syntax-check

# ── Dry run ───────────────────────────────────
ansible-playbook playbooks/docker-install.yml \
    --check \
    --limit nextcloud

# ── Εκτέλεση ──────────────────────────────────
ansible-playbook playbooks/docker-install.yml \
    --limit nextcloud \
    -v

# ── Επαλήθευση ────────────────────────────────
ansible nextcloud -m ansible.builtin.command \
    -a "docker --version" --become

ansible nextcloud -m ansible.builtin.command \
    -a "docker compose version" --become

ansible nextcloud -m ansible.builtin.command \
    -a "docker run --rm hello-world" --become

Σύνοψη D1.4

Προετοιμασία Περιβάλλοντος
├── Controller:
│   ├── community.docker collection ✅
│   └── pip install docker
│
├── Docker Role:
│   ├── defaults/main.yml  → packages, daemon config
│   ├── tasks/install.yml  → Debian/RedHat/openSUSE
│   ├── tasks/configure.yml→ daemon.json
│   ├── tasks/users.yml    → docker group
│   └── handlers/main.yml  → restart docker
│
├── Playbook:
│   └── docker-install.yml → full installation
│
└── Verify:
    ├── docker --version
    ├── docker compose version
    └── docker run hello-world