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