D1.3 Ansible + Docker Αρχιτεκτονική 🏗️

Τα 3 επίπεδα αρχιτεκτονικής

┌─────────────────────────────────────────────────────────┐
│  ΕΠΙΠΕΔΟ 1: HOST INFRASTRUCTURE                         │
│  Ansible manages:                                       │
│  ├── OS configuration                                   │
│  ├── Docker engine installation                         │
│  ├── Docker daemon configuration                        │
│  ├── Firewall rules                                     │
│  └── System resources (CPU, RAM, disk)                  │
├─────────────────────────────────────────────────────────┤
│  ΕΠΙΠΕΔΟ 2: DOCKER PLATFORM                             │
│  Ansible + Docker manage:                               │
│  ├── Docker networks                                    │
│  ├── Docker volumes                                     │
│  ├── Registry authentication                            │
│  └── Image management                                   │
├─────────────────────────────────────────────────────────┤
│  ΕΠΙΠΕΔΟ 3: APPLICATIONS                                │
│  Docker manages (Ansible orchestrates):                 │
│  ├── Containers                                         │
│  ├── Container networking                               │
│  ├── Container storage                                  │
│  └── Application lifecycle                              │
└─────────────────────────────────────────────────────────┘

Pattern 1: Single Host Deployment

┌─────────────────────────────────────────────────────────┐
│  nextcloud (Debian 12)                                  │
│                                                         │
│  ┌──────────────────────────────────────────────────┐   │
│  │  Docker Engine                                   │   │
│  │                                                  │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐        │   │
│  │  │  nginx   │  │  myapp   │  │ postgres │        │   │
│  │  │ container│  │ container│  │ container│        │   │
│  │  │  :80     │  │  :3000   │  │  :5432   │        │   │
│  │  └──────────┘  └──────────┘  └──────────┘        │   │
│  │        │              │              │           │   │
│  │  ┌─────┴──────────────┴──────────────┴────────┐  │   │
│  │  │           Docker Network: app_net          │  │   │
│  │  └────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

Ansible:
├── Εγκαθιστά Docker
├── Δημιουργεί networks & volumes
├── Pull images
└── Start containers

Pattern 2: Multi-Host Deployment

┌─────────────────────────────────────────────────────────┐
│  Ansible Controller (bananapim4berry)                   │
│                │                                        │
│       ┌────────┼────────┐                               │
│       ▼        ▼        ▼                               │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐                    │
│  │ server1 │ │ server2 │ │ server3 │                    │
│  │         │ │         │ │         │                    │
│  │ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │                    │
│  │ │nginx│ │ │ │myapp│ │ │ │ db  │ │                    │
│  │ └─────┘ │ │ └─────┘ │ │ └─────┘ │                    │
│  └─────────┘ └─────────┘ └─────────┘                    │
│  [webservers]  [appservers] [dbservers]                 │
└─────────────────────────────────────────────────────────┘
# Inventory για multi-host
[webservers]
server1 ansible_host=192.168.1.10

[appservers]
server2 ansible_host=192.168.1.11

[dbservers]
server3 ansible_host=192.168.1.12

[docker_hosts:children]
webservers
appservers
dbservers

Pattern 3: Ansible Deploys Compose Stacks

┌─────────────────────────────────────────────────────────┐
│  Ansible Controller                                     │
│  ├── docker-compose.yml.j2  (template)                  │
│  ├── .env.j2                (template)                  │
│  └── playbook.yml                                       │
│                │                                        │
│                ▼ SSH                                    │
│  ┌─────────────────────────────────────────────────┐    │
│  │  Server                                         │    │
│  │  /opt/myapp/                                    │    │
│  │  ├── docker-compose.yml  (rendered)             │    │
│  │  └── .env                (rendered, no_log)     │    │
│  │                │                                │    │
│  │                ▼ docker compose up              │    │
│  │  ┌──────────────────────────────────────────┐   │    │
│  │  │  Stack: myapp                            │   │    │
│  │  │  ├── nginx    container                  │   │    │
│  │  │  ├── app      container                  │   │    │
│  │  │  └── postgres container                  │   │    │
│  │  └──────────────────────────────────────────┘   │    │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘

Pattern 4: Rolling Deployments

Υπάρχουσα κατάσταση:
┌────────────────────────────────────────────┐
│  myapp:1.0  myapp:1.0  myapp:1.0           │
│  server1    server2    server3             │
└────────────────────────────────────────────┘
                    ↓ ansible-playbook deploy.yml
Μετά:
┌────────────────────────────────────────────┐
│  myapp:2.0  myapp:2.0  myapp:2.0           │
│  server1    server2    server3             │
└────────────────────────────────────────────┘

Διαδικασία (serial: 1):
1. Stop old container
2. Pull new image
3. Start new container
4. Health check
5. → Επόμενος server

Δομή Project για Ansible + Docker

ansible/
├── inventory/
│   ├── hosts.ini
│   └── group_vars/
│       ├── all/
│       │   ├── vars.yml      ← common vars
│       │   └── vault.yml     ← secrets
│       └── docker_hosts/
│           └── vars.yml      ← docker-specific vars
│
├── playbooks/
│   ├── docker-install.yml    ← εγκατάσταση Docker
│   ├── docker-deploy.yml     ← deployment
│   └── docker-update.yml     ← rolling update
│
├── roles/
│   ├── docker/               ← Docker installation role
│   │   ├── tasks/
│   │   │   ├── main.yml
│   │   │   ├── install.yml
│   │   │   └── configure.yml
│   │   ├── defaults/main.yml
│   │   └── handlers/main.yml
│   │
│   └── myapp/                ← Application role
│       ├── tasks/
│       │   ├── main.yml
│       │   ├── networks.yml
│       │   ├── volumes.yml
│       │   └── containers.yml
│       ├── templates/
│       │   ├── docker-compose.yml.j2
│       │   └── .env.j2
│       └── defaults/main.yml
│
└── requirements.yml          ← community.docker

Βέλτιστες πρακτικές

1. Πάντα χρησιμοποίησε explicit tags

tasks:
  - name: Run container
    community.docker.docker_container:
      name:  myapp
      image: "myapp:{{ app_version }}"    # ← ποτέ :latest σε production!
      state: started

2. Secrets με no_log

tasks:
  - name: Run με secrets
    community.docker.docker_container:
      name:  myapp
      image: myapp:1.0
      env:
        DB_PASSWORD: "{{ vault_db_password }}"
    no_log: true    # ← ΠΑΝΤΑ για sensitive env vars!

3. Health checks πριν rolling update

tasks:
  - name: Wait for container health
    community.docker.docker_container_info:
      name: myapp
    register: container_info
    until: >
      container_info.container.State.Health.Status == 'healthy'
    retries: 10
    delay:   5

4. Cleanup παλιών images

tasks:
  - name: Remove old images
    community.docker.docker_prune:
      images:         true
      images_filters:
        dangling: true    # ← μόνο untagged images

5. Idempotent container management

# ✅ Idempotent — χρησιμοποίησε state
tasks:
  - name: Ensure container running
    community.docker.docker_container:
      name:  myapp
      image: myapp:1.0
      state: started         # ← idempotent!

# ❌ Non-idempotent — αποφύγε
  - name: Start container
    ansible.builtin.command:
      cmd: docker start myapp   # ← non-idempotent!

Ansible Variables → Docker Configuration

# group_vars/docker_hosts/vars.yml
---
# ── Docker settings ───────────────────────────
docker_compose_version: "2"
docker_registry:        "registry.example.com"
docker_network_subnet:  "172.20.0.0/16"

# ── Application settings ──────────────────────
app_name:     myapp
app_version:  "2.1.4"
app_port:     8080
app_replicas: 3

# ── Database settings ─────────────────────────
db_name:  "{{ app_name }}_db"
db_user:  "{{ app_name }}_user"
db_port:  5432

# ── Secrets (από vault) ───────────────────────
db_password:  "{{ vault_db_password }}"
app_secret:   "{{ vault_app_secret }}"
# Χρήση στο playbook
tasks:
  - name: Run application
    community.docker.docker_container:
      name:  "{{ app_name }}"
      image: "{{ docker_registry }}/{{ app_name }}:{{ app_version }}"
      ports:
        - "{{ app_port }}:3000"
      env:
        DB_HOST:     postgres
        DB_NAME:     "{{ db_name }}"
        DB_USER:     "{{ db_user }}"
        DB_PASSWORD: "{{ db_password }}"
        APP_SECRET:  "{{ app_secret }}"
      networks:
        - name: "{{ app_name }}_network"
      restart_policy: unless-stopped
      memory:         "512m"
      cpus:           "0.5"
      no_log: true

Σύνοψη D1.3

Ansible + Docker Architecture
├── 3 Επίπεδα:
│   ├── Host Infrastructure → Ansible manages OS
│   ├── Docker Platform     → Ansible + Docker
│   └── Applications        → Docker containers
│
├── Patterns:
│   ├── Single Host    → όλα σε έναν server
│   ├── Multi-Host     → distributed deployment
│   ├── Compose Stacks → template → deploy
│   └── Rolling Update → zero-downtime updates
│
├── Project Structure:
│   ├── roles/docker/  → installation role
│   └── roles/myapp/   → application role
│
└── Best Practices:
    ├── Explicit image tags (όχι :latest)
    ├── no_log για secrets
    ├── Health checks πριν rolling update
    ├── Cleanup παλιών images
    └── Idempotent state management