Kamal — инструмент для деплоя контейнеров, которому не нужен Kubernetes. Его развивает компания 37signals, создатель Basecamp, и идея проста: есть обычный сервер с SSH и Docker, а всё остальное делает одна утилита на вашей машине. Никакого control plane, etcd и операторов. Kamal собирает образ, пушит его в registry, заходит на серверы по SSH и запускает контейнеры через Docker. Для небольшого проекта или пары VPS этого хватает с запасом.

Что именно делает Kamal

Схема укладывается в пять шагов. Kamal собирает Docker-образ и отправляет его в registry. Затем по SSH подключается к серверам и при необходимости ставит Docker. После этого запускает новый контейнер рядом со старым, ждёт healthcheck и переключает трафик. Балансировщиком служит kamal-proxy — обратный прокси, который Kamal 2 ставит автоматически и который сам получает сертификаты Let’s Encrypt.

Отличие от Kubernetes: состояние кластера нигде не хранится, а желаемое состояние описано в config/deploy.yml. Нет планировщика, самовосстановления подов и автомасштабирования. Взамен — предсказуемость и отладка на уровне docker ps.

Установка и инициализация

Kamal — Ruby-гем, поэтому нужен Ruby 3.x и Docker для сборки образов.

gem install kamal
kamal init
kamal version

Команда kamal init создаёт config/deploy.yml, файл .kamal/secrets и пример хука. Сразу добавьте .kamal/secrets в .gitignore: там лежат не пароли, а ссылки на них.

Разбираем deploy.yml

Минимальный конфиг для одного приложения выглядит так:

service: shop
image: registry.example.com/shop

servers:
  web:
    - 203.0.113.10

proxy:
  ssl: true
  host: shop.example.com
  app_port: 3000
  healthcheck:
    path: /up
    interval: 10

registry:
  server: registry.example.com
  username: deploy
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  clear:
    RAILS_ENV: production
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL

builder:
  arch: amd64

Поле service задаёт имя проекта и префикс контейнеров, image — адрес образа. В servers перечислены хосты по ролям: web получает трафик от прокси, остальные роли запускаются без входящих портов. Блок proxy включает HTTPS и healthcheck: пока новый контейнер не ответит на /up, трафик не переключится. В env:secret перечислены имена переменных, значения которых Kamal прочитает из .kamal/secrets. Параметр builder:arch важен при сборке на Apple Silicon для сервера x86_64.

Секреты

Файл .kamal/secrets — не хранилище паролей, а скрипт подстановки. В нём можно ссылаться на переменные окружения или читать файлы:

KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
RAILS_MASTER_KEY=$(cat config/master.key)
DATABASE_URL=$(op read "op://prod/shop/database_url")

Первый вариант удобен в CI, второй — локально, третий — с менеджером секретов вроде 1Password CLI. Команда kamal config печатает итоговую конфигурацию, но скрывает значения секретов.

Первый деплой

kamal setup

kamal setup — разовая команда для нового сервера: ставит Docker, поднимает kamal-proxy, собирает и пушит образ, запускает контейнер и настраивает HTTPS. Дальше используется kamal deploy — тот же цикл без установки инфраструктуры. Если нужно только пересобрать и выкатить код, есть kamal redeploy: он пропускает сборку и берёт образ с тем же тегом.

После деплоя полезно посмотреть, что запущено:

kamal details
kamal app logs -f
kamal app exec -i "bin/rails console"

kamal details показывает контейнеры по ролям, версии и состояние healthcheck. kamal app logs транслирует логи, kamal app exec запускает команду внутри контейнера.

Откат

Каждый деплой помечается тегом образа, обычно это SHA коммита. Если новая версия сломалась, откат делается одной командой:

kamal rollback a1b2c3d
kamal app logs -n 200

Kamal поднимет контейнер с указанным тегом и снова проведёт его через healthcheck. Образ с этим тегом должен оставаться в registry, иначе откатываться будет некуда. Политику хранения образов настройте заранее.

Базы данных и accessories

Stateful-сервисами Kamal не управляет как Kubernetes, но умеет запускать вспомогательные контейнеры — accessories. Это удобно для PostgreSQL, Redis или брокера очередей на отдельном хосте:

accessories:
  db:
    image: postgres:17
    host: 203.0.113.12
    port: 5432
    env:
      clear:
        POSTGRES_DB: shop
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

Accessory поднимается командой kamal accessory boot db и живёт независимо от деплоев приложения. Логи и консоль доступны через kamal accessory logs db и kamal accessory exec db «psql -U postgres». Данные лежат в Docker-томе на конкретном хосте, поэтому бэкапы остаются вашей задачей.

Несколько серверов и ролей

Роли позволяют разнести нагрузку без оркестратора. Для web можно указать несколько адресов — kamal-proxy на каждом хосте обслужит свой трафик, а DNS распределит запросы. Для фоновых задач заводится отдельная роль с собственной командой запуска:

servers:
  web:
    - 203.0.113.10
    - 203.0.113.11
  worker:
    hosts:
      - 203.0.113.12
    cmd: bin/jobs

Этого достаточно для отказоустойчивости на уровне «упал один хост — второй работает». Но Kamal не переносит контейнеры между машинами и не следит за их здоровьем после деплоя: умерший процесс поднимет Docker, а не планировщик.

Диагностика: чек-лист

  • kamal config — проверьте host, app_port и имена секретов.
  • kamal details — контейнер должен быть в running, healthcheck — проходить.
  • docker ps и docker logs на сервере — здесь видна проблема с подключением.
  • curl -I https://ваш-домен/up — проверка снаружи, без SSH.
  • kamal lock status — при ошибке «deploy locked» выполните kamal lock release.

Типичные причины сбоя: закрытый порт 22 или 443, неверный тег образа, отсутствие переменной в .kamal/secrets и падение healthcheck из-за долгого старта. В последнем случае увеличьте deploy_timeout и проверьте, что /up отвечает без авторизации. Прогоняйте чек-лист после каждого деплоя, а не только при аварии: так деградация заметна раньше.

Когда Kamal не подходит

Если нужны автомасштабирование, rolling-обновления на десятках узлов, service discovery или операторы для баз — смотрите в сторону Kubernetes, Nomad или managed-платформ. Kamal решает другую задачу: прозрачно выкатывать контейнеры на небольшое число серверов, которые вы контролируете.

Итог

Kamal даёт большую часть пользы оркестратора за малую долю сложности. Один YAML-файл, SSH и Docker — этого достаточно, чтобы держать несколько сервисов на VPS и не заводить кластер ради трёх контейнеров. Начните с kamal init, опишите один сервер и роль web, а базу вынесите в accessory или managed-сервис. Когда упрётесь в ограничения, решение о переходе на Kubernetes станет осознанным.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте