D2.3 Post-installation Setup ⚙️

Τι κάνουμε μετά την εγκατάσταση

Post-installation:
├── Users & Permissions    → ποιος μπορεί να τρέχει Docker
├── Docker Compose plugin  → επαλήθευση & config
├── System optimizations   → performance tuning
├── Log rotation           → logrotate για Docker
├── Monitoring setup       → docker stats & health
└── First containers       → test deployment

1. Users & Permissions

# roles/docker/tasks/users.yml — Full Version
---
# ============================================================
# Docker User Management
# ============================================================

# ── Δημιουργία docker group (αν δεν υπάρχει) ─
- name: Ensure docker group exists
  ansible.builtin.group:
    name:  docker
    state: present

# ── Προσθήκη users στο docker group ──────────
- name: Add users to docker group
  ansible.builtin.user:
    name:   "{{ item }}"
    groups: docker
    append: true           # ← προσθήκη, όχι αντικατάσταση!
  loop: "{{ docker_users }}"
  loop_control:
    label: "{{ item }}"
  register: user_result

# ── Επαλήθευση ────────────────────────────────
- name: Verify docker group membership
  ansible.builtin.command:
    cmd: "groups {{ item }}"
  register:     group_check
  changed_when: false
  loop: "{{ docker_users }}"
  loop_control:
    label: "{{ item }}"

- name: Show group membership
  ansible.builtin.debug:
    msg: "{{ item.stdout }}"
  loop: "{{ group_check.results }}"
  loop_control:
    label: "{{ item.item }}"

# ── Socket permissions ────────────────────────
- name: Set Docker socket permissions
  ansible.builtin.file:
    path:  /var/run/docker.sock
    group: docker
    mode:  '0660'
  ignore_errors: true

# ── Sudoers για docker (αν χρειάζεται) ────────
- name: Add docker sudo rule (optional)
  ansible.builtin.copy:
    dest:    /etc/sudoers.d/docker
    mode:    '0440'
    content: |
      # Allow docker group to run docker without sudo
      %docker ALL=(ALL) NOPASSWD: /usr/bin/docker
    validate: visudo -cf %s
  when: docker_add_sudoers | default(false)

⚠️ Σημαντικό: Μετά την προσθήκη user στο docker group, ο user πρέπει να ξανασυνδεθεί για να ισχύσει!

# Ο ansible user πρέπει να:
su - ansible
# ή
newgrp docker

2. Docker Compose Verification

# tasks/compose.yml
---
# ============================================================
# Docker Compose Setup & Verification
# ============================================================

# ── Έλεγχος Docker Compose plugin ────────────
- name: Check Docker Compose plugin
  ansible.builtin.command:
    cmd: docker compose version
  register:     compose_check
  changed_when: false
  ignore_errors: true

- name: Show Compose version
  ansible.builtin.debug:
    msg: "{{ compose_check.stdout | default('Docker Compose plugin not found') }}"

# ── Εγκατάσταση standalone compose (αν χρειάζεται)
- name: Install Docker Compose standalone (fallback)
  ansible.builtin.get_url:
    url:  >-
      https://github.com/docker/compose/releases/latest/download/docker-compose-linux-{{ ansible_facts['architecture'] }}
    dest:  /usr/local/bin/docker-compose
    mode:  '0755'
    owner: root
    group: root
  when:
    - compose_check.rc != 0
    - docker_install_compose_standalone | default(false)

# ── Δημιουργία compose directories ────────────
- name: Create Docker Compose directories
  ansible.builtin.file:
    path:  "{{ item }}"
    state: directory
    mode:  '0755'
    owner: root
    group: docker
  loop:
    - /opt/docker
    - /opt/docker/compose
    - /opt/docker/data
    - /opt/docker/logs

# ── Verify compose works ──────────────────────
- name: Test Docker Compose
  ansible.builtin.command:
    cmd: docker compose version
  register:     compose_final
  changed_when: false

- name: Compose verification
  ansible.builtin.debug:
    msg: " {{ compose_final.stdout }}"

3. System Optimizations

# tasks/optimize.yml
---
# ============================================================
# System Optimizations for Docker
# ============================================================

# ── Kernel parameters ─────────────────────────
- name: Configure kernel parameters for Docker
  ansible.posix.sysctl:
    name:       "{{ item.name }}"
    value:      "{{ item.value }}"
    state:      present
    reload:     true
    sysctl_set: true
  loop:
    # ── Networking ────────────────────────────
    - name:  net.ipv4.ip_forward
      value: "1"

    - name:  net.bridge.bridge-nf-call-iptables
      value: "1"

    - name:  net.bridge.bridge-nf-call-ip6tables
      value: "1"

    - name:  net.ipv4.conf.all.rp_filter
      value: "1"

    # ── Connection tracking ───────────────────
    - name:  net.netfilter.nf_conntrack_max
      value: "1048576"

    - name:  net.nf_conntrack_max
      value: "1048576"

    # ── Socket buffers ────────────────────────
    - name:  net.core.somaxconn
      value: "65535"

    - name:  net.ipv4.tcp_max_syn_backlog
      value: "65535"

    # ── Memory ────────────────────────────────
    - name:  vm.max_map_count
      value: "262144"         # ← για Elasticsearch

    - name:  vm.swappiness
      value: "10"             # ← λιγότερο swap

    # ── File descriptors ──────────────────────
    - name:  fs.file-max
      value: "1048576"

    - name:  fs.inotify.max_user_watches
      value: "524288"

    - name:  fs.inotify.max_user_instances
      value: "512"
  ignore_errors: true         # ← μερικά μπορεί να μην υποστηρίζονται

# ── System limits ─────────────────────────────
- name: Configure system limits for Docker
  community.general.pam_limits:
    domain: "{{ item.domain }}"
    limit_type: "{{ item.type }}"
    limit_item: "{{ item.item }}"
    value:      "{{ item.value }}"
  loop:
    - domain: "*"
      type:   soft
      item:   nofile
      value:  "65536"
    - domain: "*"
      type:   hard
      item:   nofile
      value:  "1048576"
    - domain: "*"
      type:   soft
      item:   nproc
      value:  "65536"
    - domain: "*"
      type:   hard
      item:   nproc
      value:  "65536"
  ignore_errors: true

# ── Load br_netfilter module ──────────────────
- name: Load kernel modules for Docker
  community.general.modprobe:
    name:  "{{ item }}"
    state: present
  loop:
    - br_netfilter
    - overlay
  ignore_errors: true

- name: Persist kernel modules
  ansible.builtin.copy:
    dest:    /etc/modules-load.d/docker.conf
    mode:    '0644'
    content: |
      br_netfilter
      overlay

4. Log Rotation

# tasks/logrotate.yml
---
# ============================================================
# Docker Log Rotation
# ============================================================

- name: Configure Docker log rotation
  ansible.builtin.copy:
    dest:  /etc/logrotate.d/docker
    mode:  '0644'
    content: |
      # Docker container logs
      /var/lib/docker/containers/*/*.log {
          rotate 7
          daily
          compress
          missingok
          delaycompress
          copytruncate
          notifempty
      }

      # Docker daemon log
      /var/log/docker.log {
          rotate 7
          daily
          compress
          missingok
          delaycompress
          notifempty
          postrotate
              /usr/bin/systemctl kill -s HUP docker.service
          endscript
      }

5. Docker Cleanup Script

# tasks/cleanup.yml
---
# ============================================================
# Docker Cleanup Setup
# ============================================================

- name: Deploy Docker cleanup script
  ansible.builtin.copy:
    dest:  /usr/local/bin/docker-cleanup.sh
    mode:  '0755'
    owner: root
    content: |
      #!/bin/bash
      # Docker Cleanup Script
      # Managed by Ansible — DO NOT EDIT!

      echo "=== Docker Cleanup $(date) ==="

      # Remove stopped containers
      CONTAINERS=$(docker ps -aq -f status=exited | wc -l)
      if [ "$CONTAINERS" -gt 0 ]; then
          echo "Removing ${CONTAINERS} stopped containers..."
          docker container prune -f
      fi

      # Remove dangling images
      IMAGES=$(docker images -f "dangling=true" -q | wc -l)
      if [ "$IMAGES" -gt 0 ]; then
          echo "Removing ${IMAGES} dangling images..."
          docker image prune -f
      fi

      # Remove unused networks
      docker network prune -f

      # Remove unused volumes (CAREFUL!)
      # docker volume prune -f  ← disabled by default

      echo "=== Cleanup complete ==="
      docker system df

- name: Schedule Docker cleanup (cron)
  ansible.builtin.cron:
    name:    "Docker cleanup"
    minute:  "0"
    hour:    "2"
    weekday: "0"             # ← Κυριακή
    user:    root
    job:     "/usr/local/bin/docker-cleanup.sh >> /var/log/docker-cleanup.log 2>&1"
    state:   present

6. Health Check Script

# tasks/healthcheck.yml
---
# ============================================================
# Docker Health Monitoring
# ============================================================

- name: Deploy Docker health check script
  ansible.builtin.copy:
    dest:  /usr/local/bin/docker-health.sh
    mode:  '0755'
    owner: root
    content: |
      #!/bin/bash
      # Docker Health Check Script

      echo "=== Docker Health Report $(date) ==="
      echo ""

      # Docker service status
      echo "── Service Status ──────────────────────"
      systemctl is-active docker && echo "Docker: ✅ Running" || echo "Docker: ❌ Stopped"
      echo ""

      # Running containers
      echo "── Running Containers ──────────────────"
      docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
      echo ""

      # Resource usage
      echo "── Resource Usage ──────────────────────"
      docker stats --no-stream --format \
          "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
      echo ""

      # Disk usage
      echo "── Disk Usage ──────────────────────────"
      docker system df
      echo ""

      # Failed health checks
      echo "── Unhealthy Containers ────────────────"
      UNHEALTHY=$(docker ps --filter health=unhealthy -q | wc -l)
      if [ "$UNHEALTHY" -gt 0 ]; then
          echo "⚠️  ${UNHEALTHY} unhealthy container(s):"
          docker ps --filter health=unhealthy \
              --format "  ❌ {{.Names}} ({{.Status}})"
      else
          echo "✅ All containers healthy"
      fi

- name: Deploy Docker monitoring cron
  ansible.builtin.cron:
    name:   "Docker health check"
    minute: "*/30"            # ← κάθε 30 λεπτά
    user:   root
    job:    "/usr/local/bin/docker-health.sh >> /var/log/docker-health.log 2>&1"
    state:  present

7. Ενημερωμένο 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 daemon
  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

- name: Setup Docker Compose
  ansible.builtin.import_tasks:
    file: compose.yml
  tags: [compose, docker]

- name: Optimize system for Docker
  ansible.builtin.import_tasks:
    file: optimize.yml
  tags: [optimize, docker]

- name: Configure log rotation
  ansible.builtin.import_tasks:
    file: logrotate.yml
  tags: [logging, docker]

- name: Setup Docker cleanup
  ansible.builtin.import_tasks:
    file: cleanup.yml
  tags: [cleanup, docker]

- name: Setup Docker health monitoring
  ansible.builtin.import_tasks:
    file: healthcheck.yml
  tags: [monitoring, docker]
EOF

Σύνοψη D2.3

Post-installation Setup
├── Users & Permissions:
│   ├── docker group membership
│   ├── socket permissions (0660)
│   └── newgrp docker (για τρέχουσα session)
│
├── Docker Compose:
│   ├── Verify plugin
│   ├── Directories: /opt/docker/{compose,data,logs}
│   └── Standalone fallback (αν χρειάζεται)
│
├── System Optimizations:
│   ├── sysctl: ip_forward, bridge-nf, max_map_count
│   ├── PAM limits: nofile, nproc
│   └── Kernel modules: br_netfilter, overlay
│
├── Log Rotation:
│   └── /etc/logrotate.d/docker
│
├── Cleanup:
│   ├── /usr/local/bin/docker-cleanup.sh
│   └── Cron: κάθε Κυριακή 02:00
│
└── Health Monitoring:
    ├── /usr/local/bin/docker-health.sh
    └── Cron: κάθε 30 λεπτά