D3.1 Docker Images με Ansible 🖼️
Τι είναι Docker Image
Docker Image
├── Αμετάβλητο template για containers
├── Layers — κάθε εντολή Dockerfile = layer
├── Αποθηκεύεται σε registry (Docker Hub, private)
└── Tag format: registry/namespace/name:tag
└── nginx:latest
registry.example.com/myapp:2.1.4
Pull Images
tasks:
# ── Βασικό pull ───────────────────────────
- name: Pull nginx image
community.docker.docker_image:
name: nginx
tag: latest
source: pull
# ── Συγκεκριμένη έκδοση (best practice!) ──
- name: Pull specific versions
community.docker.docker_image:
name: "{{ item.name }}"
tag: "{{ item.tag }}"
source: pull
loop:
- { name: nginx, tag: "1.25.3" }
- { name: postgres, tag: "15.4" }
- { name: redis, tag: "7.2" }
- { name: alpine, tag: "3.19" }
loop_control:
label: "{{ item.name }}:{{ item.tag }}"
# ── Pull από private registry ──────────────
- name: Pull από private registry
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: pull
# ── Force pull (πάντα κατεβάζει) ──────────
- name: Force pull latest
community.docker.docker_image:
name: nginx
tag: latest
source: pull
force_source: true # ← πάντα pull ακόμα κι αν υπάρχει
Build Images από Dockerfile
tasks:
# ── Βασικό build ──────────────────────────
- name: Build application image
community.docker.docker_image:
name: myapp
tag: "{{ app_version }}"
source: build
build:
path: /opt/myapp # ← φάκελος με Dockerfile
# ── Build με arguments ────────────────────
- name: Build με build args
community.docker.docker_image:
name: myapp
tag: "{{ app_version }}"
source: build
build:
path: /opt/myapp
pull: true # ← pull base image πρώτα
nocache: false # ← χρησιμοποίησε cache
args:
APP_VERSION: "{{ app_version }}"
NODE_ENV: production
BUILD_DATE: "{{ ansible_facts['date_time']['date'] }}"
# ── Build με custom Dockerfile ────────────
- name: Build με custom Dockerfile
community.docker.docker_image:
name: myapp-test
tag: latest
source: build
build:
path: /opt/myapp
dockerfile: Dockerfile.test # ← custom dockerfile
# ── Build και push ────────────────────────
- name: Build και push σε registry
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: build
push: true # ← push μετά το build
build:
path: /opt/myapp
Παράδειγμα Dockerfile
# Δημιουργία test Dockerfile στον server
cat > /tmp/test-dockerfile/Dockerfile << 'EOF'
FROM nginx:1.25.3-alpine
# Build arguments
ARG APP_VERSION=1.0.0
ARG BUILD_DATE
# Labels
LABEL version="${APP_VERSION}"
LABEL build-date="${BUILD_DATE}"
LABEL maintainer="ansible@example.com"
# Copy custom config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy application files
COPY html/ /usr/share/nginx/html/
# Health check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD wget -q -O /dev/null http://localhost/ || exit 1
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
EOF
# Ansible: deploy Dockerfile και build
tasks:
- name: Δημιουργία build directory
ansible.builtin.file:
path: /opt/myapp/docker
state: directory
mode: '0755'
- name: Deploy Dockerfile
ansible.builtin.template:
src: templates/Dockerfile.j2
dest: /opt/myapp/docker/Dockerfile
- name: Deploy nginx.conf
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /opt/myapp/docker/nginx.conf
- name: Build image
community.docker.docker_image:
name: myapp
tag: "{{ app_version }}"
source: build
build:
path: /opt/myapp/docker
args:
APP_VERSION: "{{ app_version }}"
BUILD_DATE: "{{ ansible_facts['date_time']['date'] }}"
register: build_result
- name: Build result
ansible.builtin.debug:
msg: "Built: {{ build_result.image.Id[:12] }}"
Tag & Push Images
tasks:
# ── Tag image ─────────────────────────────
- name: Tag image για registry
community.docker.docker_image:
name: "myapp:{{ app_version }}"
repository: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: local # ← από local images
push: false # ← μόνο tag, όχι push
# ── Tag ως latest ─────────────────────────
- name: Tag ως latest
community.docker.docker_image:
name: "myapp:{{ app_version }}"
repository: "registry.example.com/myapp"
tag: latest
source: local
push: false
# ── Push σε registry ──────────────────────
- name: Push image στο registry
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ item }}"
source: local
push: true
loop:
- "{{ app_version }}"
- latest
loop_control:
label: "registry.example.com/myapp:{{ item }}"
Registry Authentication
tasks:
# ── Login πριν pull/push ───────────────────
- name: Login στο Docker Hub
community.docker.docker_login:
username: "{{ docker_hub_user }}"
password: "{{ vault_docker_hub_token }}"
no_log: true
register: login_result
- name: Login σε private registry
community.docker.docker_login:
registry_url: "https://registry.example.com"
username: "{{ registry_user }}"
password: "{{ vault_registry_pass }}"
no_log: true
# ── Pull protected image ───────────────────
- name: Pull private image
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: pull
# ← χρησιμοποιεί το login από πάνω
# ── Logout μετά ───────────────────────────
- name: Logout από registry
community.docker.docker_login:
username: "{{ docker_hub_user }}"
state: absent
no_log: true
Image Information & Cleanup
tasks:
# ── Image info ────────────────────────────
- name: Get image info
community.docker.docker_image_info:
name:
- "nginx:latest"
- "myapp:{{ app_version }}"
register: image_info
- name: Show image info
ansible.builtin.debug:
msg:
- "Image: {{ item.RepoTags | first | default('untagged') }}"
- "Size : {{ (item.Size / 1048576) | round(1) }}MB"
- "ID : {{ item.Id[:12] }}"
- "Created: {{ item.Created[:10] }}"
loop: "{{ image_info.images }}"
loop_control:
label: "{{ item.RepoTags | first | default('untagged') }}"
# ── List all images ────────────────────────
- name: List all Docker images
ansible.builtin.command:
cmd: docker images --format json
register: images_list
changed_when: false
# ── Remove specific image ──────────────────
- name: Remove old image
community.docker.docker_image:
name: "myapp"
tag: "{{ old_version }}"
state: absent
force_absent: true
when: old_version is defined
# ── Prune dangling images ─────────────────
- name: Remove dangling images
community.docker.docker_prune:
images: true
images_filters:
dangling: true
# ── Full system prune (ΠΡΟΣΟΧΗ!) ───────────
- name: Docker system prune
community.docker.docker_prune:
containers: true
images: true
networks: true
volumes: false # ← ΠΟΤΕ volumes χωρίς λόγο!
builder_cache: true
when: docker_full_prune | default(false)
Πρακτικό Playbook — Image Management
cat > ~/ansible/playbooks/docker-images.yml << 'EOF'
---
# ============================================================
# Docker Image Management Playbook
# ============================================================
- name: Docker Image Management
hosts: "{{ target | default('all_managed') }}"
become: true
gather_facts: true
vars:
app_name: mywebapp
app_version: "1.0.0"
# Images που χρειαζόμαστε
required_images:
- name: nginx
tag: "1.25.3-alpine"
- name: postgres
tag: "15.4-alpine"
- name: redis
tag: "7.2-alpine"
tasks:
# ── Pull required images ───────────────────
- name: Pull required images
community.docker.docker_image:
name: "{{ item.name }}"
tag: "{{ item.tag }}"
source: pull
loop: "{{ required_images }}"
loop_control:
label: "{{ item.name }}:{{ item.tag }}"
tags: [pull, images]
# ── Verify images ──────────────────────────
- name: Verify images are available
community.docker.docker_image_info:
name: "{{ required_images | map(attribute='name') | list }}"
register: image_check
tags: [verify, images]
- name: Image verification report
ansible.builtin.debug:
msg:
- "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- "Available Images"
- "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- "{% for img in image_check.images %}\
{{ img.RepoTags | first | default('untagged') }}: \
{{ (img.Size / 1048576) | round(1) }}MB\
{% endfor %}"
- "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tags: [verify, images]
# ── Prune old images ───────────────────────
- name: Prune dangling images
community.docker.docker_prune:
images: true
images_filters:
dangling: true
tags: [cleanup, images]
# ── Docker disk usage ─────────────────────
- name: Show Docker disk usage
ansible.builtin.command:
cmd: docker system df
register: disk_usage
changed_when: false
tags: [verify, disk]
- name: Disk usage report
ansible.builtin.debug:
msg: "{{ disk_usage.stdout_lines }}"
tags: [verify, disk]
EOF
# Εκτέλεση
ansible-playbook playbooks/docker-images.yml \
--limit nextcloud \
-v
# Μόνο pull
ansible-playbook playbooks/docker-images.yml \
--limit nextcloud \
--tags pull
# Μόνο cleanup
ansible-playbook playbooks/docker-images.yml \
--limit nextcloud \
--tags cleanup
Σύνοψη D3.1
Docker Images με Ansible
├── Pull:
│ ├── docker_image: source=pull
│ ├── Συγκεκριμένα tags (όχι :latest σε production)
│ └── force_source=true για πάντα fresh pull
│
├── Build:
│ ├── docker_image: source=build, build.path=...
│ ├── Build args, custom Dockerfile
│ └── push=true για αυτόματο push
│
├── Tag & Push:
│ ├── docker_image: source=local, push=true
│ └── Multiple tags (version + latest)
│
├── Registry Auth:
│ ├── docker_login (no_log: true!)
│ └── Logout μετά
│
└── Cleanup:
├── docker_image: state=absent
├── docker_prune: images=true, dangling=true
└── ΠΟΤΕ volume prune χωρίς προσοχή!