Можно ли внутри контейнера поднять другую операционную систему
Что проверяют
Понимаете ли вы, что контейнер это изолированный процесс на ядре хоста, а не маленькая виртуальная машина. Следом часто спрашивают, как Docker на Mac запускает Linux-образы и что лежит в образе FROM scratch с Go-бинарником.
Как отвечать
Ответ зависит от того, что называть операционной системой.
- другой дистрибутив Linux: можно. Образ
ubuntuспокойно работает на хосте с Fedora, потому что в образе лежит только пользовательское окружение:libc, пакетный менеджер, утилиты. Ядро общее, иuname -rвнутри контейнера покажет версию ядра хоста; - другое ядро: нельзя. Windows-контейнеру нужно ядро Windows, Linux-контейнеру нужно ядро Linux. Docker Desktop на macOS и Windows запускает Linux-контейнеры внутри виртуальной машины с Linux;
- другая архитектура: образ
arm64наamd64запустится через эмуляцию QEMU иbinfmt_misc, но заметно медленнее; - своё ядро на контейнер: Kata Containers запускает каждый контейнер в лёгкой виртуальной машине, gVisor перехватывает системные вызовы собственным ядром в пространстве пользователя. Это уже гибрид, за изоляцию платят производительностью.
Для Go-разработчика тема практическая. Бинарник, собранный с CGO_ENABLED=0, статический и может жить в образе scratch или distroless, где никакой ОС нет вовсе. Кросс-компиляция делается переменными GOOS и GOARCH, а мультиархитектурный образ собирается командой docker buildx build --platform linux/amd64,linux/arm64.
Где спотыкаются
Говорят, что в контейнере запускается только та же ОС, что на хосте. Контейнер с Alpine на хосте с Ubuntu работает: ограничение касается ядра, а не дистрибутива.
Считают, что Docker на Mac выполняет Linux-контейнеры нативно. Там всегда есть прослойка в виде виртуальной машины, отсюда и разница в скорости работы с примонтированными файлами.
Кладут Go-сервис в scratch и получают x509: certificate signed by unknown authority на первом HTTPS-запросе. В пустом образе нет корневых сертификатов и базы часовых поясов: сертификаты копируют из сборочного этапа, а часовые пояса встраивают в бинарник через import _ "time/tzdata".