Сначала arm64, amd64 — по необходимости
Mac серии M запускает Linux-контейнеры на ядре Linux arm64. При скачивании мультиархитектурного образа (postgres, redis, node, python и большинство официальных образов) Docker автоматически выбирает вариант arm64, работающий с нативной скоростью.
Некоторые образы по-прежнему выпускаются только для amd64: старые внутренние образы, инструменты поставщиков и всё, что собрано на ноутбуке Intel или исполнителе CI без флага платформы. Для них укажите платформу явно:
services:
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64 Oxcart запускает образы amd64 через Rosetta — транслятор x86-64 от Apple, а Buildx может собирать и загружать образы amd64, которые движок затем запускает локально. Проверить фактическую архитектуру контейнера можно командой docker run --rm --platform linux/amd64 alpine uname -m, которая выведет x86_64.
| Ситуация | Что делать |
|---|---|
| Образ доступен для arm64 | Ничего. Compose скачает вариант arm64. |
| Образ доступен только для amd64 | Добавьте platform: linux/amd64 в сервис. |
| Вы развёртываете на серверах amd64 | Собирайте отправляемый образ через docker buildx build --platform linux/amd64; для локальной работы оставьте arm64, если стек позволяет. |
| "exec format error" | Архитектура исполняемого файла не соответствует архитектуре контейнера. Задайте платформу или пересоберите для arm64. |
Полный пример
База данных Postgres, API, собираемый из текущей папки и ожидающий готовности базы, и инструмент только для amd64, включаемый профилем:
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: dev
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 2s
timeout: 3s
retries: 15
api:
build: .
init: true
environment:
DATABASE_URL: postgres://postgres:dev@db:5432/postgres
ports:
- "127.0.0.1:8080:8080"
depends_on:
db:
condition: service_healthy
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64
profiles: ["tools"]
volumes:
pgdata: Что делает каждая часть:
healthcheckсообщает Compose, когда Postgres действительно принимает подключения, а не просто запущен.depends_on: condition: service_healthyзадерживает запуск API до успешного прохождения проверки.init: trueзапускает небольшой init как PID 1, чтобы сигналы доходили до вашего процесса, а процессы-зомби убирались. Тогдаdocker stopзавершает работу корректно, не дожидаясь тайм-аута.127.0.0.1:8080:8080публикует API только на loopback-интерфейсе Mac. Без адреса опубликованный порт слушает на всех IPv4-адресах Mac, и к нему могут обращаться другие машины в вашей сети.pgdata— именованный том: данные сохраняются послеdocker compose downи удаляются только командойdown -v.
Запуск стека Compose на Apple silicon
- Проверьте инструменты. Выполните
docker compose versionиdocker context show. Oxcart поставляется с Docker Compose 5.6.0, CLI docker 29.9.0 и Buildx 0.38.0; его контекст называетсяoxcart. - Напишите файл Compose. Добавьте
healthcheckкаждому сервису, которого ждёт приложение, и задайте ожидание зависимым сервисам черезdepends_on: condition: service_healthy. - Запустите и дождитесь готовности. Выполните
docker compose up -d --build --wait. Команда завершается, когда все сервисы работают и проходят проверки состояния, или выдаёт ошибку, если это не так. - Проверьте порты. Выполните
docker compose psили откройте раздел Ports в Oxcart: у каждого опубликованного порта показано состояние — готов, ожидает или ошибка — с указанием причины. - Продолжайте разработку. Измените код и выполните
docker compose up -d --build api. Неизменённые шаги сборки берутся из кеша. - Остановите и удалите окружение. Выполните
docker compose down, чтобы остановить и удалить контейнеры, илиdocker compose down -v, чтобы также удалить именованные тома.
Более быстрая пересборка
Compose выполняет сборку через Buildx и BuildKit. Расположите установку зависимостей в Dockerfile перед COPY . ., чтобы при изменении кода повторно использовать все закешированные слои выше него. В Oxcart сборка тестового проекта с кешем заняла 121 ms, а без кеша с локальным контекстом — 341 ms: лучший результат среди трёх протестированных сред в обоих случаях. Короткие циклы разработки экономят время: docker run --rm занял 42 ms, а остановка и удаление 20 контейнеров — 77 ms.
Oxcart 0.1.2 измерен 2026-10-10 с комплектным клиентом docker 29.9; остальные среды измерены ранее в тот же день на том же Mac и тем же набором тестов с docker 29.4. Apple M5 Max, по 8 CPU и 12 GiB каждой, среды запускались по одной.
Порты, Mac и другие сервисы
- Синтаксис портов такой же, как в Docker: TCP и UDP, эфемерные порты (
"127.0.0.1::8080") и"[::]:8080:80"для прослушивания IPv4 и IPv6. TCP и UDP могут использовать один номер порта хоста. - Доступ к Mac из контейнера:
host.docker.internalпозволяет обращаться по TCP к сервисам на127.0.0.1Mac из контейнеров и из шагов сборки. - Локальный реестр: опубликуйте контейнер реестра на порту 5000, и
docker push localhost:5000/appсможет к нему обратиться. - Sidecar-контейнеры:
network_mode: service:apiпомещает контейнер в сетевое пространство имён другого сервиса, чтобы он использовал егоlocalhost.
О VPN, DNS, межсетевых экранах и защите сетевого пути читайте в руководстве Сети контейнеров на Mac.
Именованные тома и bind mount
Используйте именованные тома для данных с интенсивной записью со стороны базы или сборки: node_modules, кешей пакетов, файлов баз данных. Данные хранятся внутри хранилища движка; в Oxcart именованный том выполнил 1 000 операций создания, stat, чтения и удаления небольших файлов за 17.8 ms — быстрее остальных из трёх протестированных сред.
Используйте bind mount для исходного кода, который редактируете на Mac. По умолчанию Oxcart предоставляет контейнерам доступ на чтение и запись к домашней папке, /private/tmp и /private/var/folders; изменения на Mac видны в контейнерах, а изменения в контейнерах — на Mac. Есть ограничение: изменения файлов на Mac не создают события inotify внутри контейнеров, поэтому файловому наблюдателю в контейнере нужен опрос, если он должен замечать изменения из редактора.
Устранение неполадок
| Симптом | Причина | Решение |
|---|---|---|
exec format error | Исполняемый файл amd64 в контейнере arm64 или наоборот | platform: linux/amd64 или пересборка для arm64 |
| "no matching manifest for linux/arm64" | У образа нет варианта arm64 | platform: linux/amd64 |
| "address already in use" | Порт хоста занят другим процессом или контейнером | Измените порт хоста или найдите его владельца в разделе Ports в Oxcart |
| Отказ в соединении на опубликованном порту | Сервер слушает на 127.0.0.1 внутри контейнера или пока ничто не слушает | Слушайте на 0.0.0.0; добавьте проверку состояния и используйте --wait |
| Приложение запускается до готовности базы данных | depends_on без условия ждёт только запуска | condition: service_healthy вместе с healthcheck |
docker stop ждёт 10 s | PID 1 игнорирует SIGTERM | init: true или обработка SIGTERM в приложении |
Вопросы
Работает ли Docker Compose на Mac с Apple silicon?
Да. Compose работает нативно на arm64, и большинство официальных образов выпускаются для arm64. Oxcart включает Docker Compose 5.6.0; проверки совместимости охватывают несколько сервисов, зависимости от проверок состояния, up --wait, build, down, DNS по именам сервисов, init: true и network_mode: service:.
Как запустить образ amd64 (x86-64) на Mac серии M?
Задайте platform: linux/amd64 в сервисе или передайте --platform linux/amd64 команде docker run. Oxcart запускает образы amd64 через Rosetta. Предпочитайте нативный образ arm64, если он есть; используйте amd64 для образов без сборки arm64.
Что означает «exec format error»?
Контейнер попытался запустить исполняемый файл для другой архитектуры CPU. Обычно образ или исполняемый файл в нём доступен только для amd64. Добавьте platform: linux/amd64 в этот сервис или пересоберите образ для arm64.
Почему приложение сообщает «connection refused», хотя контейнер работает?
Самая частая причина — сервер слушает на 127.0.0.1 внутри контейнера. Опубликованные порты обращаются к сетевому интерфейсу контейнера, а не к loopback, поэтому сервер должен слушать на 0.0.0.0. Раздел Ports в Oxcart явно указывает на этот случай.
Как заставить один сервис ждать готовности другого?
Добавьте healthcheck зависимости и depends_on: { db: { condition: service_healthy } } зависимому сервису. Тогда docker compose up --wait завершится только после успешных проверок состояния всех сервисов.
Могут ли контейнеры обращаться к серверу на моём Mac?
Да. Используйте host.docker.internal: в Oxcart он даёт доступ по TCP к сервисам на 127.0.0.1 Mac из контейнеров и сборок.
Что использовать для баз данных: именованные тома или bind mount?
Используйте именованный том для данных базы: он находится в собственном хранилище движка. Для исходного кода, который редактируете на Mac, используйте bind mount. В Oxcart именованный том выполнил 1 000 операций создания, stat, чтения и удаления небольших файлов за 17.8 ms.
Источники и методика
- Совместимость: проверенные интеграции Oxcart (CLI docker, Compose с зависимостями от проверок состояния,
up --wait,init: true,network_mode: service:, Buildx, amd64 через Rosetta). - Показатели скорости: Oxcart 0.1.2, 2026-10-10, Apple M5 Max, 8 CPU и 12 GiB, медианы пяти замеров после прогрева; остальные среды измерены ранее в тот же день на том же Mac и тем же набором тестов с клиентом docker 29.4.
- Комплектные инструменты: docker 29.9.0, Docker Compose 5.6.0, Buildx 0.38.0.