
Начало...
Все, кто пишет Ansible-роли, рано или поздно сталкиваются с необходимостью быстрых локальных тестов, проверить работу роли на раннем этапе разработки. Для этого существует инструмент Molecule — он управляет жизненным циклом тестовых инстансов, запускает роль, проверяет идемпотентность и в��полняет тесты. Molecule сам по себе не создаёт виртуальные машины — он использует драйверы, которые создают инстансы (локально или в облаке) и предоставляют Molecule доступ по SSH.
Почему macOS Apple Silicon — отдельная "боль"?
Пользователи Mac с чипами Apple Silicon (M1, M2, M3, M4) часто сталкиваются с ограничениями традиционных локальных провайдеров виртуализации.
Например, VirtualBox 7.2 действительно имеет поддержку Apple Silicon но пока только экспериментальную, и связка Vagrant + VirtualBox в целом запускается, но работает неэффективно. При выделении 1 ГБ оперативной памяти для гостевой системы VirtualBox фактически “съедает” около 1.6 ГБ из оперативки хоста — т.е. примерно на 60 % больше заявленного.
Попытка запустить Molecule в связке Molecule → Vagrant → VirtualBox у меня так и не увенчалась успехом. Процесс падает с ошибкой:
[ERROR]: couldn't resolve module/action 'vagrant'.
This often indicates a misspelling, missing collection, or incorrect module path.
Вероятно, причина в том, что модуль vagrant был удалён из коллекции community.general, а проект community.vagrant так и остался в состоянии «Initial commit» с версией 0.0.0 — то есть фактически заброшен.
Связка Molecule + Vagrant + VMware формально работает, но требует множества ручных настроек, плагинов и лицензий — в общем, типичные "танцы с бубном". В этой статье подробно описаны обходные пути и хаки, но, на мой взгляд, они слишком громоздки для повседневной разработки, но вполне рабочий вариант. Лично я больше стремлюсь к нативной виртуализации без "костылей", все таки они заметно снижают производительность и надежность.
После появления QEMU for macOS и поддержки ARM-архитектуры можно попробовать связку Vagrant + QEMU. У меня заработало. Но так же как и в Virtualbox при выделении 1 ГБ оперативной памяти для гостевой системы фактически “съедает” около 1.4 ГБ из оперативки хоста. QEMU умеет эмулировать разные архитектуры. И на первый взгляд, QEMU кажется универсальным решением: поддерживает ARM, доступен через Homebrew, умеет cloud-init и позволяет Molecule запускать полноценные образы. Однако на практике всё оказывается гораздо сложнее.
Во-первых, на macOS Apple Silicon QEMU не может использовать классический tun/tap или bridge — для сетевого режима vmnet-shared требуется root-доступ. Molecule автоматически поднимает виртуалки через sudo, и если не настроен NOPASSWD, выполнение обрывается ошибкой:
[ERROR]: Task failed: Premature end of stream waiting for become success.
sudo: a password is required
Premature end of stream waiting for become success.
Проблема в том, что даже добавление правил в /etc/sudoers часто не решает ситуацию, поскольку Ansible выполняет команды в неинтерактивном окружении, а sudo на macOS дополнительно защищён системным SIP (System Integrity Protection).
Во-вторых, QEMU требует утилиту mkisofs (или genisoimage) для генерации cloud-init ISO. На macOS её нет по умолчанию, Homebrew не всегда добавляет бинарь в $PATH, и таска падает с ошибкой:
Error executing command: [Errno 2] No such file or directory: 'mkisofs'
В итоге связка Molecule + QEMU на macOS превращается в набор обходных решений, ручных правок sudoers, странных флагов и долгого ожидания запуска виртуалок. Это всё делает процесс тестирования Ansible-ролей не автоматизированным, а экспериментальным. У меня так и не запустилась связка molecule-qemu.
Еще можно использовать драйвер Docker — Molecule прекрасно работает с контейнерами и позволяет запускать роли в изолированных окружениях. Однако у этого подхода есть важное ограничение: контейнеры не поддерживают полноценный systemd.
Если роль использует systemd-юниты, управляет сервисами через ansible.builtin.service, изменяет конфигурации в /etc/systemd/system — внутри Docker это просто не будет работать. Можно попытаться использовать образы с «поддельным systemd» (например, jrei/systemd-ubuntu), но это лишь частично решает проблему и часто приводит к нестабильным тестам.
Поэтому для большинства «реальных» ролей, особенно тех, что настраивают сервисы уровня ОС (Nginx, Prometheus, Consul, и т.д.), требуется полноценная виртуальная машина с настоящим systemd — а значит, Docker-драйвер не подходит.
Lima: Современная альтернатива Vagrant для macOS
Что такое Lima?
Lima (Linux Machines) — это легковесный кроссплатформенный инструмент командной строки для запуска полноценных Linux виртуальных машин на macOS и Linux. Lima работает на базе QEMU, использует простые YAML файлы для конфигурации и полностью совместим с Apple Silicon.
Выше в статье я рассмотрел использование Vagrant с различными провайдерами и отметил их недостатки. Теперь перейдём к преимуществам Lima, которая во многих случаях становится более удобной и современной альтернативой.
Нативная поддержка Apple Silicon
Lima работает через встроенный в macOS Hypervisor.framework, обеспечивая полную поддержку архитектуры ARM64 без эмуляции. Образы Ubuntu, Debian и других дистрибутивов запускаются напрямую, быстро и без накладных расходов на виртуализацию.
Кроссплатформенность
Хотя Lima создавалась как альтернатива Docker Desktop для macOS, она прекрасно работает и под Linux с использованием QEMU, что делает её удобным инструментом для разработчиков, работающих на разных платформах.
Декларативные ВМ “как код”
Все параметры виртуальной машины описываются в YAML-файле — от количества CPU до сетевых интерфейсов и примонтированных директорий. Один конфиг можно хранить в репозитории и воспроизводить окружения одинаково у всей команды.
Автоматический проброс папок
Каталоги из хоста автоматически монтируются внутрь ВМ (/Users, /Volumes, /tmp и т. д.) без ручной настройки 9p, sshfs или virtio-fs, что особенно удобно для Molecule — роли и зависимости доступны сразу.
Быстрый SSH-доступ
Каждая Lima-машина автоматически получает SSH-ключ и конфиг, доступ к ВМ выполняется простой командой
limactl shell <vm-name>
или напрямую через ssh без поиска IP-адреса и паролей.
Поддержка Ansible из коробки
Lima может использовать Ansible для провижининга ВМ при создании, а в связке с драйвером molecule-lima она становится полноценным тестовым бэкендом для Ansible-ролей — локально, быстро и без root-прав.
Поддержка Docker без Docker Desktop
Lima может запускать Docker или containerd внутри гостевой ВМ, предоставляя локальный контейнерный runtime без лицензий и ограничений Docker Desktop.
Установка Lima
macOS:
brew install lima
Linux:
# Установка QEMU
sudo apt update && sudo apt install -y qemu-utils qemu-kvm qemu-system-x86
# Установка Lima
VERSION=$(curl -fsSL https://api.github.com/repos/lima-vm/lima/releases/latest | jq -r .tag_name)
curl -fsSL "https://github.com/lima-vm/lima/releases/download/${VERSION}/lima-${VERSION:1}-$(uname -s)-$(uname -m).tar.gz" | sudo tar Cxzvm /usr/local
Теперь создать полностью настроенную Ubuntu VM можно за секунды:
# Запуск из предустановленного шаблона
limactl start ubuntu-lts
lima ubuntu-lts
# Или запуск из собственного YAML файла
limactl start ./vm-test.yaml
Сравнение конфигурации: Vagrant vs Lima
Vagrant (Ruby DSL)
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.synced_folder ".", "/vagrant"
config.vm.provider "virtualbox" do |vb|
vb.memory = 2048
vb.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y cowsay
SHELL
end
Lima (YAML)
# file: vm-test.yaml
images:
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
arch: "aarch64" # или "x86_64" для Intel/AMD
cpus: 2
memory: "2GiB"
disk: "20GiB"
# Настройка сети
networks:
- lima: bridged
# Проброс папок
mounts:
- location: "."
writable: true
mountPoint: "/home/ubuntu/workspace"
# SSH порт
ssh:
localPort: 60022
# Проброс портов
portForwards:
- guestPort: 80
hostPort: 8080
# Провижининг через shell
provision:
- mode: system
script: |
#!/bin/bash
apt update
apt install -y cowsay ansible curl
Запуск:
limactl start ./myvm.yaml
Основные команды Lima
# Запустить ВМ
limactl start vm-test.yaml
limactl start --name="custom-name-vm" vm-test.yaml
# SSH в ВМ
limactl shell vm-test
# Остановить ВМ
limactl stop vm-test
# Перезапустить ВМ
limactl stop vm-test && limactl start vm-test
# Удалить ВМ
limactl delete vm-test
# Список всех ВМ
limactl list
# Показать SSH конфигурацию
limactl show-ssh vm-test
Провижининг с Ansible
Lima поддерживает два способа провижининга через Ansible:
1. Внутри ВМ (проще и надежнее)
provision:
- mode: system
script: |
apt update
apt install -y ansible
cd /home/ubuntu/workspace
ansible-playbook playbook.yml -i localhost, --connection=local
2. С хоста (требует Ansible на хосте)
provision:
- mode: host
script: |
# Ждем готовности SSH
for i in $(seq 1 30); do
if ssh -F ~/.lima/vm-test/ssh.config default 'echo ready'; then
break
fi
sleep 2
done
# Запускаем Ansible с хоста
ansible-playbook -i ~/.lima/vm-test/ssh.config playbook.yml
Где искать образы для Lima
Lima использует cloud-init ready образы. Нет централизованного репозитория (как Vagrant Cloud), можно использовать в принципе любой образ поддерживающий cloud-init:
Ubuntu ARM64:
images:
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
arch: "aarch64"
Debian x86_64:
images:
- location: "https://cloud.debian.org/images/cloud/bullseye/20240311-1467/debian-11-genericcloud-amd64.qcow2"
arch: "x86_64"
Fedora ARM64:
images:
- location: "https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/aarch64/images/Fedora-Cloud-Base-39-1.5.aarch64.raw.xz"
arch: "aarch64"
Требования к образам:
Форматы:
.img,.qcow2, или.rawОбязательна поддержка cloud-init
Используйте cloud server images, а не desktop ISO
Lima — это современная, легковесная альтернатива Vagrant, которая обеспечивает простоту и нативную производительность. С декларативными YAML конфигурациями, встроенным провижинингом Ansible и поддержкой Intel, AMD и Apple Silicon.
Molecule-lima: Интеграция Lima с Molecule
О проекте
Открыв для себя Lima, я понял, что это идеальное решение для локального тестирования Ansible ролей на Apple Silicon. Вдохновившись статьей "Пишем свой драйвер Molecule без костылей и боли", я решил написать полноценный драйвер для Molecule.
molecule-lima — это драйвер, который интегрирует Lima в экосистему Molecule, предоставляя:
Полную совместимость со стандартным Molecule workflow
Декларативную конфигурацию инстансов через
molecule.ymlАвтоматическое управление жизненным циклом
Lima VMПрозрачную интеграцию с Ansible через SSH
Поддержку множественных платформ и параллельного тестирования
Драйвер полностью реализован на Ansible playbooks, что делает его прозрачным, расширяемым и легким для понимания. Это beta-версия, но она уже полностью рабочая. Исходный код лежит здесь Все настройки инстансов и зависимости смотрите в репозитории.
Установка molecule-lima
Подготовим окружение. И активируем его:
# Создать окружение
python3 -m venv venv
# Активировать его
source venv/bin/activate
# Обновим pip
python3 -m pip install --upgrade pip
# Установим Ansible и Molecule
pip install ansible molecule
#
Драйвер доступен в PyPI:
pip install molecule-lima
Так же можно установить из исходников:
# Клонировать репозиторий
git clone https://github.com/filatof/molecule-lima.git
cd molecule-lima
# Установить
pip install -e .
Возможно кому то понадобится установить коллекцию community.general, если не установлена глобально в ~/.ansible/collections :
ansible-galaxy collection install -r requirements.yml
Теперь все готово для локального тестирования разрабатываемой Ansible роли. Для опыта можно взять мою роль ansible-role-docker
Для начала создадим сценарий molecule командой:
molecule init scenario
По умолчанию будет создан сценарий с именем default, однако при желании ��ожно задать своё имя, например lima:
molecule init scenario lima
В этом случае при запуске команд molecule (например, molecule create, molecule converge и т.д.) необходимо будет явно указывать имя сценария, добавляя флаг -s, например:
molecule create -s lima
После инициализации сценария default Molecule создаёт базовую структуру файлов:
(venv) fill@MacBookAir ~/Documents/ansible_role/ansible-role-docker ➜ ls -l molecule/default
total 40
-rw-r--r--@ 1 fill staff 372 13 нояб. 17:39 converge.yml
-rw-r--r--@ 1 fill staff 1182 13 нояб. 17:39 create.yml
-rw-r--r--@ 1 fill staff 622 13 нояб. 17:39 destroy.yml
-rw-r--r--@ 1 fill staff 1170 13 нояб. 17:39 molecule.yml
-rw-r--r--@ 1 fill staff 312 13 нояб. 17:39 verify.yml
Начиная с версии Molecule 6.0+, параметр --driver-name для команды molecule init scenario был удалён. Теперь Molecule использует только delegated driver (также называемый “default”), а все остальные драйверы — Docker, Podman, LXD, Proxmox и др. — подключаются как плагины через этот драйвер. Драйвер molecule-lima также реализует этот механизм — он наследуется от molecule.api.Driver и подключается как плагин через систему entry_points. Таким образом, Molecule взаимодействует с ним так же, как с любым другим драйвером (Docker, Podman и т.д.), просто загружая его по имени molecule-lima, указанному в molecule.yml.
Таким образом, команда molecule init scenario создаёт лишь базовый набор файлов без привязки к конкретному драйверу, а выбор нужного драйвера осуществляется вручную в файле molecule.yml.
Чтобы подготовить сценарий для собственного драйвера, удалим ненужные файлы, созданные по умолчанию:
rm molecule/default/create.yml
rm molecule/default/destroy.yml
Файл molecule.yml заменим следующим:
---
dependency:
name: galaxy
driver:
name: molecule-lima
ssh_timeout: 120
platforms:
- name: instance-ubuntu
image: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
arch: aarch64
vm_type: vz
cpus: 2
memory: 2GiB
disk: 20GiB
python_interpreter: /usr/bin/python3
provisioner:
name: ansible
config_options:
defaults:
callbacks_enabled: profile_tasks,timer
stdout_callback: yaml
host_key_checking: false
verifier:
name: ansible
scenario:
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroy
Файл converge.yml заменим следующим:
---
- name: Converge
hosts: all
gather_facts: true
become: true
pre_tasks:
- name: Display connection info
ansible.builtin.debug:
msg:
- "Connected to: {{ inventory_hostname }}"
- "Host: {{ ansible_host }}:{{ ansible_port }}"
roles:
- role: "../../.."
Файл verify.yml заменим следующим:
---
- name: Verify
hosts: all
gather_facts: false
become: true
tasks:
- name: Check if Docker is installed
ansible.builtin.command: docker --version
register: docker_version
changed_when: false
- name: Display Docker version
ansible.builtin.debug:
var: docker_version.stdout
- name: Check if Docker service is running
ansible.builtin.systemd:
name: docker
register: docker_service
failed_when: false
- name: Verify Docker service is active
ansible.builtin.assert:
that:
- docker_service.status.ActiveState == "active"
fail_msg: "Docker service is not active"
success_msg: "Docker service is running"
- name: Test Docker run
ansible.builtin.command: docker run --rm hello-world
register: docker_test
changed_when: false
- name: Verify Docker run output
ansible.builtin.assert:
that:
- "'Hello from Docker!' in docker_test.stdout"
fail_msg: "Docker test container failed"
success_msg: "Docker is working correctly"
- name: Display verification result
ansible.builtin.debug:
msg: "All Docker verification tests passed!"
Сейчас можно выполнить:
molecule create
Результат вывода работы плейбука:

Запускаем установку роли:
molecule converge
Результат:

Запускаем тесты:
molecule verify
Результат:

Посмотреть инстансы можно так:
molecule list

Зайти на инстанс можно так:
molecule login -h instance-ubuntu

Удаляем инстанс:
molecule destroy

Заключение
Molecule Lima решает актуальную проблему локального тестирования Ansible ролей на macOS Apple Silicon, избавляя от "танцев с бубном" вокруг Vagrant.
Что получаем:
Нативная виртуализация через Virtualization.framework — максимальная производительность
Простота установки —
pip install molecule-limaи готовоПривычный Molecule workflow — все стандартные команды работают
Прозрачная архитектура на Ansible playbooks — легко понять и расширить
Кроссплатформенность — macOS (ARM/Intel) и Linux
Драйвер находится в beta-версии, но уже полностью функционален и протестирован. Код открыт, документирован и доступен для улучшений сообществом.
Попробуйте: https://github.com/filatof/molecule-lima
Если вы разрабатываете Ansible роли на Apple Silicon — molecule-lima изб��вит вас от головной боли с локальным тестированием.