podman: переход на Podman, Minikube, локальные образы и док для новичков
- Molecule: драйвер delegated, коллекция containers.podman, create/destroy/verify на Podman - Makefile: все вызовы docker заменены на podman, сокет /run/podman/podman.sock - Сборка образов: podman build (без buildx), buildall/buildall-image — только локально без push - Ansible-controller: Podman в образе, docker-compose на podman compose, сокет Podman - K8s: Kind заменён на Minikube (драйвер podman), скрипты и Makefile обновлены - Пресеты: проверка локальных образов, без podman pull (registry запрещён) - Документация: docs/podman.md, docs/quickstart-for-dummies.md (роли, плейбук, линт, тесты, пресеты, инвентори) - README: ссылка на quickstart-for-dummies Made-with: Cursor
This commit is contained in:
@@ -10,8 +10,9 @@
|
||||
# Проверяем сначала в папке k8s, затем в основной папке presets
|
||||
preset_file: "{{ '/workspace/molecule/presets/k8s/' + preset_name + '.yml' if (preset_name in ['k8s-minimal', 'kubernetes', 'k8s-full'] or preset_name.startswith('k8s-')) else '/workspace/molecule/presets/' + preset_name + '.yml' }}"
|
||||
|
||||
# Fallback значения если preset файл не найден
|
||||
# Fallback значения если preset файл не найден (Podman использует ту же сеть)
|
||||
docker_network: labnet
|
||||
podman_network: "{{ docker_network }}"
|
||||
generated_inventory: "{{ molecule_ephemeral_directory }}/inventory/hosts.ini"
|
||||
images:
|
||||
alt9: "inecs/ansible-lab:alt9-latest"
|
||||
@@ -89,20 +90,20 @@
|
||||
hosts: "{{ filtered_hosts | default(hosts) }}"
|
||||
|
||||
# =============================================================================
|
||||
# СЕТЕВОЕ ПОДКЛЮЧЕНИЕ
|
||||
# СЕТЕВОЕ ПОДКЛЮЧЕНИЕ (Podman)
|
||||
# =============================================================================
|
||||
- name: Network setup
|
||||
debug:
|
||||
msg: |
|
||||
================================================================================
|
||||
НАСТРОЙКА СЕТИ
|
||||
НАСТРОЙКА СЕТИ (Podman)
|
||||
================================================================================
|
||||
Network: {{ docker_network }}
|
||||
Network: {{ podman_network | default(docker_network) }}
|
||||
================================================================================
|
||||
|
||||
- name: Ensure network exists
|
||||
community.docker.docker_network:
|
||||
name: "{{ docker_network }}"
|
||||
containers.podman.podman_network:
|
||||
name: "{{ podman_network | default(docker_network) }}"
|
||||
state: present
|
||||
|
||||
# =============================================================================
|
||||
@@ -117,39 +118,39 @@
|
||||
Count: {{ hosts | selectattr('type','undefined') | list | length }}
|
||||
================================================================================
|
||||
|
||||
- name: Pull systemd images with correct platform
|
||||
command: "docker pull --platform {{ ansible_architecture }} {{ images[item.family] }}"
|
||||
# Только локальные образы (registry запрещён). Сборка: make buildall
|
||||
- name: Проверка наличия локальных образов (Podman)
|
||||
command: "podman image exists {{ images[item.family] }}"
|
||||
loop: "{{ hosts | selectattr('type','undefined') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
when: item.family is defined and images[item.family] is defined
|
||||
register: pull_result
|
||||
ignore_errors: yes
|
||||
register: image_check
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Display pull results
|
||||
debug:
|
||||
msg: "Pulled {{ item.item.name }}: {{ 'OK' if (item.rc is defined and item.rc == 0) else 'SKIPPED (not available for this platform)' }}"
|
||||
loop: "{{ pull_result.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.name }}"
|
||||
- name: Остановка при отсутствии локальных образов
|
||||
fail:
|
||||
msg: |
|
||||
Локальные образы не найдены (доступ к registry запрещён).
|
||||
Выполните: make buildall
|
||||
Отсутствуют образы: {{ image_check.results | default([]) | selectattr('rc', 'ne', 0) | map(attribute='item') | map(attribute='family') | list | join(', ') }}
|
||||
when: image_check.results is defined and (image_check.results | selectattr('rc', 'ne', 0) | list | length > 0)
|
||||
|
||||
- name: Start systemd nodes
|
||||
community.docker.docker_container:
|
||||
containers.podman.podman_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ images[item.family] }}"
|
||||
networks:
|
||||
- name: "{{ docker_network }}"
|
||||
network: "{{ podman_network | default(docker_network) }}"
|
||||
privileged: "{{ systemd_defaults.privileged }}"
|
||||
command: "{{ '/bin/bash -c \"while true; do sleep 30; done\"' if item.family in ['alt10', 'alt9'] else systemd_defaults.command }}"
|
||||
volumes: "{{ systemd_defaults.volumes | default([]) + (item.volumes | default([])) + ['/Users/inecs/PycharmProjects/DevOpsLab/vault:/workspace/vault:ro', '/Users/inecs/PycharmProjects/DevOpsLab/files:/workspace/files:ro', '/Users/inecs/PycharmProjects/DevOpsLab/roles:/workspace/roles:ro'] }}"
|
||||
volume: "{{ systemd_defaults.volumes | default([]) + (item.volumes | default([])) + ['/workspace/vault:/workspace/vault:ro', '/workspace/files:/workspace/files:ro', '/workspace/roles:/workspace/roles:ro'] }}"
|
||||
tmpfs: "{{ systemd_defaults.tmpfs | default([]) }}"
|
||||
capabilities: "{{ systemd_defaults.capabilities | default([]) }}"
|
||||
published_ports: "{{ item.publish | default([]) }}"
|
||||
cap_add: "{{ systemd_defaults.capabilities | default([]) }}"
|
||||
ports: "{{ item.publish | default([]) }}"
|
||||
env: "{{ item.env | default({}) }}"
|
||||
# Специальные настройки для Astra Linux и RedOS
|
||||
security_opts: "{{ ['seccomp=unconfined', 'apparmor=unconfined'] if item.family in ['astra', 'redos'] else [] }}"
|
||||
platform: "{{ item.docker_platform | default(item.platform) | default(omit) }}"
|
||||
security_opt: "{{ ['seccomp=unconfined', 'apparmor=unconfined'] if item.family in ['astra', 'redos'] else [] }}"
|
||||
state: started
|
||||
restart_policy: unless-stopped
|
||||
restart_policy: "unless-stopped"
|
||||
loop: "{{ hosts | selectattr('type','undefined') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
when: item.family is defined and images[item.family] is defined
|
||||
@@ -160,75 +161,44 @@
|
||||
seconds: 10
|
||||
when: hosts | length > 0
|
||||
|
||||
# Проверка готовности контейнеров
|
||||
# Проверка готовности контейнеров (Podman)
|
||||
- name: Wait for containers to be running
|
||||
community.docker.docker_container_info:
|
||||
name: "{{ item.name }}"
|
||||
command: "podman inspect --format '{{ '{{' }}.State.Running{{ '}}' }}' {{ item.name }}"
|
||||
register: container_info
|
||||
loop: "{{ hosts | selectattr('type','undefined') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
when: item.family is defined and images[item.family] is defined
|
||||
retries: 10
|
||||
delay: 5
|
||||
until: container_info.container.State.Running | default(false)
|
||||
until: container_info.stdout == 'true'
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# DIND NODES - Создание контейнеров Docker-in-Docker
|
||||
# POoD NODES - Создание контейнеров Podman-out-of-Podman (сокет Podman)
|
||||
# =============================================================================
|
||||
- name: DinD nodes setup
|
||||
- name: POoD nodes setup
|
||||
debug:
|
||||
msg: |
|
||||
================================================================================
|
||||
DIND NODES - Создание контейнеров Docker-in-Docker
|
||||
================================================================================
|
||||
Count: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list | length }}
|
||||
================================================================================
|
||||
|
||||
- name: Start DinD nodes (docker:27-dind)
|
||||
community.docker.docker_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "docker:27-dind"
|
||||
networks:
|
||||
- name: "{{ docker_network }}"
|
||||
privileged: true
|
||||
env:
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
published_ports: "{{ item.publish | default([]) }}"
|
||||
volumes: "{{ (item.volumes | default([])) + [item.name + '-docker:/var/lib/docker'] }}"
|
||||
state: started
|
||||
restart_policy: unless-stopped
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
|
||||
# =============================================================================
|
||||
# DOOD NODES - Создание контейнеров Docker-out-of-Docker
|
||||
# =============================================================================
|
||||
- name: DOoD nodes setup
|
||||
debug:
|
||||
msg: |
|
||||
================================================================================
|
||||
DOOD NODES - Создание контейнеров Docker-out-of-Docker
|
||||
POoD NODES - Контейнеры с монтированием сокета Podman
|
||||
================================================================================
|
||||
Count: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list | length }}
|
||||
================================================================================
|
||||
|
||||
- name: Start DOoD nodes (systemd + docker.sock mount)
|
||||
community.docker.docker_container:
|
||||
- name: Start POoD nodes (systemd + podman.sock mount)
|
||||
containers.podman.podman_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ images[item.family] }}"
|
||||
networks:
|
||||
- name: "{{ docker_network }}"
|
||||
network: "{{ podman_network | default(docker_network) }}"
|
||||
privileged: "{{ systemd_defaults.privileged }}"
|
||||
command: "{{ systemd_defaults.command }}"
|
||||
volumes: "{{ (systemd_defaults.volumes | default([])) + ['/var/run/docker.sock:/var/run/docker.sock'] + (item.volumes | default([])) + ['/Users/inecs/PycharmProjects/DevOpsLab/vault:/workspace/vault:ro', '/Users/inecs/PycharmProjects/DevOpsLab/files:/workspace/files:ro', '/Users/inecs/PycharmProjects/DevOpsLab/roles:/workspace/roles:ro'] }}"
|
||||
volume: "{{ (systemd_defaults.volumes | default([])) + ['/run/podman/podman.sock:/run/podman/podman.sock'] + (item.volumes | default([])) + ['/workspace/vault:/workspace/vault:ro', '/workspace/files:/workspace/files:ro', '/workspace/roles:/workspace/roles:ro'] }}"
|
||||
tmpfs: "{{ systemd_defaults.tmpfs | default([]) }}"
|
||||
capabilities: "{{ systemd_defaults.capabilities | default([]) }}"
|
||||
published_ports: "{{ item.publish | default([]) }}"
|
||||
env: "{{ item.env | default({}) }}"
|
||||
platform: "{{ item.docker_platform | default(item.platform) | default(omit) }}"
|
||||
cap_add: "{{ systemd_defaults.capabilities | default([]) }}"
|
||||
ports: "{{ item.publish | default([]) }}"
|
||||
env: "{{ (item.env | default({})) | combine({'CONTAINER_HOST': 'unix:///run/podman/podman.sock'}) }}"
|
||||
state: started
|
||||
restart_policy: unless-stopped
|
||||
restart_policy: "unless-stopped"
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
when: item.family is defined and images[item.family] is defined
|
||||
@@ -264,7 +234,7 @@
|
||||
set_fact:
|
||||
inv_content: |
|
||||
[all:vars]
|
||||
ansible_connection=community.docker.docker
|
||||
ansible_connection=containers.podman.podman
|
||||
ansible_remote_tmp=/tmp/.ansible-tmp
|
||||
|
||||
{% for group, members in (groups_map | dictsort) %}
|
||||
|
||||
@@ -56,71 +56,37 @@
|
||||
Count: {{ hosts | length }} containers
|
||||
================================================================================
|
||||
|
||||
- name: Stop and remove containers
|
||||
community.docker.docker_container:
|
||||
- name: Stop and remove containers (Podman)
|
||||
containers.podman.podman_container:
|
||||
name: "{{ item.name }}"
|
||||
state: absent
|
||||
force_kill: true
|
||||
cleanup: true
|
||||
force_delete: true
|
||||
loop: "{{ hosts }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
ignore_errors: true
|
||||
|
||||
- name: Force remove any remaining containers
|
||||
shell: |
|
||||
docker ps -a --filter "name={{ item.name }}" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r docker rm -f
|
||||
podman ps -a --filter "name={{ item.name }}" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r podman rm -f 2>/dev/null || true
|
||||
loop: "{{ hosts }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove DinD volumes
|
||||
community.docker.docker_volume:
|
||||
name: "{{ item.name }}-docker"
|
||||
state: absent
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove custom volumes
|
||||
community.docker.docker_volume:
|
||||
name: "{{ item.volumes | default([]) | select('match', '^[^:]+$') | list }}"
|
||||
state: absent
|
||||
loop: "{{ hosts }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
ignore_errors: true
|
||||
when: item.volumes is defined
|
||||
|
||||
# =============================================================================
|
||||
# ОЧИСТКА СЕТИ - Удаление Docker сети
|
||||
# =============================================================================
|
||||
- name: Network cleanup
|
||||
debug:
|
||||
msg: |
|
||||
================================================================================
|
||||
ОЧИСТКА СЕТИ - Удаление Docker сети
|
||||
================================================================================
|
||||
Network: {{ docker_network }}
|
||||
================================================================================
|
||||
|
||||
- name: Remove network
|
||||
community.docker.docker_network:
|
||||
name: "{{ docker_network }}"
|
||||
containers.podman.podman_network:
|
||||
name: "{{ podman_network | default(docker_network) }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
|
||||
- name: Force cleanup all project containers
|
||||
shell: |
|
||||
# Удаляем все контейнеры из загруженного пресета
|
||||
{% for host in hosts %}
|
||||
docker ps -a --filter "name={{ host.name }}" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r docker rm -f 2>/dev/null || true
|
||||
podman ps -a --filter "name={{ host.name }}" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r podman rm -f 2>/dev/null || true
|
||||
{% endfor %}
|
||||
# Удаляем все контейнеры с образами ansible-lab
|
||||
docker ps -a --filter "ancestor=inecs/ansible-lab" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r docker rm -f 2>/dev/null || true
|
||||
# Удаляем все контейнеры с сетью labnet
|
||||
docker ps -a --filter "network=labnet" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r docker rm -f 2>/dev/null || true
|
||||
podman ps -a --filter "ancestor=inecs/ansible-lab" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r podman rm -f 2>/dev/null || true
|
||||
podman ps -a --filter "network=labnet" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r podman rm -f 2>/dev/null || true
|
||||
ignore_errors: true
|
||||
vars:
|
||||
# Используем переменную hosts из загруженного пресета
|
||||
hosts: "{{ hosts }}"
|
||||
|
||||
- name: Display cleanup summary
|
||||
@@ -131,8 +97,8 @@
|
||||
================================================================================
|
||||
Containers: {{ hosts | length }}
|
||||
Volumes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list | length }}
|
||||
Network: {{ docker_network }}
|
||||
Clusters: {{ kind_clusters | default([]) | length }}
|
||||
Network: {{ podman_network | default(docker_network) }}
|
||||
Clusters: {{ minikube_profiles | default([]) | length }}
|
||||
================================================================================
|
||||
|
||||
- name: Display filtered hosts
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
# Используем delegated: создание/удаление контейнеров в create.yml и destroy.yml через Podman
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
driver:
|
||||
name: docker
|
||||
name: delegated
|
||||
|
||||
platforms:
|
||||
# Платформы будут созданы динамически через preset файлы
|
||||
|
||||
@@ -46,10 +46,8 @@
|
||||
Count: {{ hosts | selectattr('type','undefined') | list | length }}
|
||||
================================================================================
|
||||
|
||||
- name: Check systemd nodes status
|
||||
community.docker.docker_container_exec:
|
||||
container: "{{ item.name }}"
|
||||
command: systemctl is-system-running
|
||||
- name: Check systemd nodes status (Podman exec)
|
||||
command: "podman exec {{ item.name }} systemctl is-system-running"
|
||||
loop: "{{ hosts | selectattr('type','undefined') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
register: systemd_status
|
||||
@@ -61,43 +59,23 @@
|
||||
loop: "{{ systemd_status.results | default([]) }}"
|
||||
when: systemd_status is defined
|
||||
|
||||
# Проверка DinD узлов
|
||||
- name: Check DinD nodes docker daemon
|
||||
community.docker.docker_container_exec:
|
||||
container: "{{ item.name }}"
|
||||
command: docker version --format '{{.Server.Version}}'
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
register: dind_status
|
||||
ignore_errors: true
|
||||
|
||||
- name: Display DinD nodes status
|
||||
debug:
|
||||
msg: "DinD node {{ item.0.name }}: Docker {{ item.1.stdout | default('not running') }}"
|
||||
loop: "{{ dind_status.results | default([]) }}"
|
||||
when: dind_status is defined
|
||||
|
||||
# Проверка DOoD узлов
|
||||
- name: Check DOoD nodes docker access
|
||||
community.docker.docker_container_exec:
|
||||
container: "{{ item.name }}"
|
||||
command: docker ps --format '{{.Names}}'
|
||||
# Проверка POoD узлов (Podman-out-of-Podman)
|
||||
- name: Check POoD nodes podman access
|
||||
command: "podman exec {{ item.name }} podman ps --format '{{'{{' }}.Names{{ '}}' }}'"
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
register: dood_status
|
||||
ignore_errors: true
|
||||
|
||||
- name: Display DOoD nodes status
|
||||
- name: Display POoD nodes status
|
||||
debug:
|
||||
msg: "DOoD node {{ item.0.name }}: Can access {{ item.1.stdout_lines | length | default(0) }} containers"
|
||||
msg: "POoD node {{ item.0.name }}: Can access {{ item.1.stdout_lines | length | default(0) }} containers"
|
||||
loop: "{{ dood_status.results | default([]) }}"
|
||||
when: dood_status is defined
|
||||
|
||||
# Проверка сетевого подключения
|
||||
- name: Test network connectivity between nodes
|
||||
community.docker.docker_container_exec:
|
||||
container: "{{ item.0.name }}"
|
||||
command: ping -c 1 {{ item.1.name }}
|
||||
command: "podman exec {{ item.0.name }} ping -c 1 {{ item.1.name }}"
|
||||
loop: "{{ hosts | subelements(hosts, 'name') }}"
|
||||
loop_control: { label: "{{ item.0.name }} -> {{ item.1.name }}" }
|
||||
when: item.0.name != item.1.name
|
||||
@@ -112,9 +90,7 @@
|
||||
|
||||
# Проверка портов
|
||||
- name: Check published ports
|
||||
community.docker.docker_container_exec:
|
||||
container: "{{ item.name }}"
|
||||
command: netstat -tlnp
|
||||
command: "podman exec {{ item.name }} netstat -tlnp 2>/dev/null || podman exec {{ item.name }} ss -tlnp"
|
||||
loop: "{{ hosts | selectattr('publish','defined') | list }}"
|
||||
loop_control: { label: "{{ item.name }}" }
|
||||
register: port_status
|
||||
@@ -139,11 +115,10 @@
|
||||
- name: Display verification summary
|
||||
debug:
|
||||
msg: |
|
||||
✅ Verification Summary:
|
||||
✅ Verification Summary (Podman):
|
||||
- Total hosts: {{ hosts | length }}
|
||||
- Systemd nodes: {{ hosts | selectattr('type','undefined') | list | length }}
|
||||
- DinD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list | length }}
|
||||
- DOoD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list | length }}
|
||||
- POoD nodes: {{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list | length }}
|
||||
- Groups: {{ groups_map.keys() | list | join(', ') }}
|
||||
- Network: {{ docker_network }}
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ systemd_defaults:
|
||||
tmpfs: ["/run", "/run/lock"]
|
||||
capabilities: ["SYS_ADMIN"]
|
||||
|
||||
# Минимальный Kind кластер без аддонов
|
||||
kind_clusters:
|
||||
- name: minimal
|
||||
workers: 0 # Только control-plane
|
||||
api_port: 6443
|
||||
# Minikube (драйвер podman) — минимальный кластер без аддонов
|
||||
minikube_profile: minikube
|
||||
minikube_cpus: "2"
|
||||
minikube_memory: "4096"
|
||||
minikube_addons: []
|
||||
|
||||
hosts: []
|
||||
|
||||
Reference in New Issue
Block a user