
Начало...
Все, кто пишет 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 избавит вас от головной боли с локальным тестированием.
