独立站容器化:Docker配置、镜像优化、编排与资源限制

独立站用Docker的目标不是上K8s,而是把"这台服务器能跑"变成"任何机器都能跑"。合格标准是:生产镜像控制在200MB以内、用多阶段构建、每个容器显...

独立站Docker镜像:从1.2GB臃肿镜像到180MB生产镜像Independent-site Docker: from 1.2GB bloated image to 180MB prod 反直觉:镜像大不是因为代码多,而是因为把构建工具和源码全塞进了运行层Counter-intuitive: bloat comes from build tools shipped into runtime 错误做法:单阶段构建Wrong: single-stage build 正确做法:多阶段构建Right: multi-stage build Ubuntu基础镜像 500MBUbuntu base 500MB Node/PHP 全量 200MBFull runtime 200MB 源码 + node_modules 300MBSource + node_modules 300MB 编译工具链 200MBBuild toolchain 200MB alpine 基础 5MBalpine base 5MB 运行时 40MBRuntime 40MB 系统库 20MBSystem libs 20MB 应用代码 30MBApp code 30MB 静态资源 80MBAssets 80MB PHP扩展/依赖 50MBPHP ext 50MB 合计 ≈ 225MBTotal ≈ 225MB 资源限制:CPU 1至2核、内存512MB至1GB是独立站容器的甜蜜点;不设限制会把宿主机内存吃光Limits: 1-2 CPU, 512MB-1GB RAM; without limits host starves 编排选择:单台VPS用docker compose即可,3台以上再考虑Swarm;K8s对独立站是过度设计Compose for 1 box, Swarm for 3+, K8s overkill
Сравнение размера образа при одноэтапной и многоэтапной сборке

独立站容器化:Docker配置、镜像优化、编排与资源限制

Сначала вывод: 独立站用Docker的目标不是上K8s,而是把”这台服务器能跑”变成”任何机器都能跑”。合格标准是:生产镜像控制在200MB以内、用多阶段构建、每个容器显式声明CPU和内存限制、单台VPS用docker compose编排即可。反直觉的一点是,镜像臃肿几乎从来不是代码写多了,而是把编译工具、npm缓存、源码全留在了运行镜像里——这三件东西加起来能让镜像从200MB膨胀到1.5GB。

一、独立站为什么要容器化,不是直接装在服务器上

Можно поставить PHP, Nginx и MySQL прямо на VPS — работать будет, но через полгода всплывут три проблемы: первая — новый сотрудник потратит два дня на настройку окружения; вторая — при переезде с Alibaba Cloud на Tencent Cloud придётся заново ставить все зависимости; третья — при обновлении патчей безопасности страшно трогать продакшн. Docker упаковывает приложение и зависимости в неизменяемый образ — именно эти три проблемы он и решает.

Простой критерий: если в вашей инструкции по деплою есть “сначала apt install php8.3-fpm, потом установить эти 12 расширений, затем поправить эти 8 пунктов в php.ini” — вам нужна контейнеризация. Запишите эти 12 расширений и 8 настроек в Dockerfile, и дальше на любой машине один docker run всё воспроизведёт. О связке CDN и статики см.Глобальное ускорение CDN.

Способ развёртывания Стоимость воспроизведения окружения Переезд на другой сервер Скорость отката Для какого масштаба
Прямая установка на VPS 2 человеко-дня Заново ставить зависимости Через снапшот, 30 минут Этап прототипа
Установка через shell-скрипт 0,5 человеко-дня Запуск скрипта, но различия остаются 15 минут Один сайт работает год
Docker-образ 5 минут Скачал образ — и запустил Переключить тег образа, 3 минуты Продакшн, несколько окружений
Оркестрация через Docker Compose 5 минут Скопировал yaml — и запустил Откат одной командой Приложение + база данных + очередь

II. Как писать Dockerfile, чтобы образ не раздувался

独立站最常见的Dockerfile错误是单阶段构建:FROM ubuntu,然后装PHP、装Composer、composer install、把源码COPY进去、暴露端口。这种做法打出来的镜像通常在1GB以上,因为包含了编译工具、npm缓存、.git目录。正确做法是多阶段构建:第一阶段用builder镜像编译前端、装composer依赖;第二阶段只把编译产物和运行时拷进alpine镜像。

Несколько жёстких правил: базовый образ — alpine, а не ubuntu; в .dockerignore обязательно исключите node_modules, .git, .env и каталог загрузок; при npm/composer install добавляйте –no-dev и –no-cache; в рантайме используйте непривилегированного пользователя. Цель по размеру образа: чистые PHP/Node-приложения — до 200 МБ, со статикой — не больше 400 МБ. Сканирование образов и базовые требования к безопасности см.Бэкап и восстановление сайта.

Реальный случай: команда через полгода после запуска обнаружила, что образ весит 1,4 ГБ. Проверили по слоям через docker history и увидели, что composer install шёл без –no-dev и затащил в продакшен-образ phpunit и кучу dev-зависимостей; а COPY . . скопировал ещё и каталог .git. Перешли на многоэтапную сборку: на этапе builder ставятся зависимости, в рантайм копируются только каталоги vendor и public — образ сразу упал до 180 МБ, а деплой сократился с 3 минут до 40 секунд.

Уровень Типичная ошибка Как оптимизировать Экономия размера
Базовый образ FROM ubuntu:22.04 FROM php:8.3-fpm-alpine около 400 МБ
Системные зависимости apt-get install build-essential Многоэтапная сборка, установка на этапе builder около 200 МБ
PHP-зависимости composer install composer install –no-dev –no-cache около 80 МБ
Фронтенд-зависимости COPY . . на этапе builder: npm ci && npm run build около 300 МБ
Каталог с исходниками COPY . /var/www COPY –from=builder /app/public ./public около 100 МБ
Пользователь в рантайме запуск от root RUN adduser -D app выигрыш в безопасности, размер не меняется

三、docker compose怎么编排独立站

独立站典型架构是四个容器:Nginx反代、PHP-FPM或Node应用、MySQL/PostgreSQL、Redis。用一个docker-compose.yml把这四个服务串起来,数据卷挂出来持久化MySQL数据,端口只暴露Nginx的80和443,其他服务走内部网络。不要把MySQL端口暴露到公网。

Рабочий фрагмент конфигурации: Nginx depends_on php, php depends_on db и redis; проверка здоровья — команда curl -fsS http://localhost/health каждые 30 секунд; политика перезапуска везде unless-stopped. Стратегия бэкапа: том с данными MySQL по расписанию монтируется в каталог бэкапов на хосте, затем rsync синхронизирует его в другое место. Мониторинг для многоконтейнерной оркестрации см.Мониторинг сайта и оповещения.

Пример: сервер Alibaba Cloud с 4 ядрами и 8 ГБ памяти, на нём три контейнера — WordPress, MySQL и Redis. Контейнер MySQL монтирует named volume для данных, Nginx пробрасывает порты 80 и 443 на хост, контейнер WordPress портов не открывает и работает только во внутренней сети. После перезагрузки хоста docker compose up -d сам поднимает все три сервиса — ничего не нужно запускать вручную. В этом и есть самая простая ценность compose.

Услуги Базовый образ Лимит CPU Лимит памяти Персистентность
nginx nginx:1.27-alpine 0,5 ядра 128 МБ Нет
php-fpm / node php:8.3-fpm-alpine 1–2 ядра 512 МБ – 1 ГБ нет (каталог загрузок монтируется томом)
mysql mysql:8.4 1–2 ядра 1–2 ГБ да (каталог data)
redis redis:7-alpine 0,5 ядра 256 МБ да (персистентность AOF)
cron/очереди тот же образ, что у приложения 0,5 ядра 256 МБ Нет

4. Ограничения ресурсов: контейнер без лимитов утащит за собой всю машину

Многие запускают Docker для простоты и не указывают –cpus и –memory. В итоге PHP-FPM ловит один медленный запрос, память вырастает с 512MB до 4GB и вытесняет MySQL на той же машине в OOM. Каждый контейнер обязан явно объявлять лимиты ресурсов — это жёсткое требование.

独立站的资源配额参考:应用容器1至2核CPU、512MB至1GB内存;MySQL容器按数据量给,10GB以下数据给1核1GB足够;Nginx和Redis各0.5核、128至256MB。宿主机预留20%余量给Docker daemon和系统。一个判断标准:宿主机总内存的80%分配给容器,20%留给系统,超过这个比例就加机器。CPU按峰值分配,不要按平均分配——独立站流量有工作日高峰和夜间低谷,按平均CPU配会导致高峰期排队。

独立站规模 Рекомендуемая конфигурация Распределение CPU Распределение памяти Ориентир по месячным визитам
Период проверки гипотезы 1 VPS на 2 ядра и 2GB Приложение 1 ядро + DB 0,5 ядра Приложение 512MB + DB 1GB <50 тыс.
Период стабильного роста 1 VPS на 4 ядра и 8GB Приложение 2 ядра + DB 1,5 ядра Приложение 2GB + DB 4GB 50–300 тыс.
Пик по многоязычным версиям 2 машины по 4 ядра и 8GB Приложение по 2 ядра на машину По 2GB на машину, DB отдельно 4GB 300 тыс. – 1 млн
Пик в день независимости Приложение масштабируется до 3–4 машин По 2 ядра на машину По 2GB на машину Трафик с акций и выставок

5. Когда пора переходить на Swarm или K8s

反直觉的结论是:独立站90%的场景不需要K8s。docker compose在单台VPS上能跑4到8个容器,足够支撑日访10万以内的B2B站。只有当你出现以下三个信号之一,才考虑升级到Swarm:需要跨两台以上VPS跑应用、需要蓝绿部署自动切流量、需要健康检查自动重启挂掉的容器。

Критерий простой: если ваш docker-compose.yml содержит больше 30 сервисов или эту среду одновременно поддерживают больше 5 человек, тогда думайте об оркестраторе. В остальных случаях compose — оптимальное решение, и вкладывать силы в контент и SEO выгоднее, чем в поддержку K8s.

Порог K8s в том, что нужен отдельный человек на поддержку etcd, сетевых плагинов и Ingress-контроллера, и только разбор ошибок съедает день в неделю. Для небольшой команды вкладывать это время в контент и SEO выгоднее. Если в будущем действительно понадобится разворачивать несколько экземпляров, про проектирование балансировки читайте в разделе Балансировка нагрузки и развёртывание нескольких экземпляров.

Инструмент оркестрации Порог входа Стоимость поддержки Подходящее число узлов Когда его выбирать
docker compose 1–2 дня Крайне низкая 1 90%独立站首选
docker swarm 3–5 дней Низкая 2–10 машин Нужна оркестрация между машинами и rolling update
K8s 2–4 недели Высокий Более 5 машин Несколько команд, много сервисов, автомасштабирование
Managed K8s от облачного провайдера 1–2 недели Средний Более 10 машин Уже есть выделенный DevOps

FAQ: частые вопросы

独立站用Docker是不是比直接装服务器更慢?
Потери производительности самого контейнера — в пределах 2%, практически незаметны. Реальная причина замедления — когда MySQL тоже засунули в контейнер или не подключили том данных, и запись идёт в слой overlay. Правильно так: контейнеры MySQL и Redis используют named volume для персистентности, а приложение остаётся stateless. Так получается чище, чем ставить всё прямо на сервер, а производительность та же.
Какой размер образа считается разумным?
Чистый образ для PHP/Node — до 200 МБ, с собранным фронтендом — до 400 МБ. Если больше 1 ГБ, почти наверняка внутрь попали инструменты сборки или исходники. Смотрите размер через docker images, а через docker history — какой слой самый большой. Частые виновники: node_modules не удалили на этапе multi-stage сборки или после apt-get install не сделали apt-get clean.
Потянет ли docker compose 100 тысяч визитов в день?
Один VPS на 4 ядра и 8 ГБ с compose спокойно держит до 100 тысяч визитов в день. Узкое место обычно MySQL, а не Nginx. Когда дойдёте до 200 тысяч в день, сначала вынесите MySQL на отдельную машину, а приложение крутите через compose на двух VPS. И только при 500 тысячах в день думайте про балансировщик и несколько инстансов. Не покупайте сложность заранее под трафик, которого ещё нет.
Как быть с логами и загруженными файлами в контейнере?
Логи не пишите в слой контейнера — монтируйте каталог на хосте или просто выводите в stdout, пусть docker json-file их собирает. Загруженные файлы (вложения из заявок, PDF от клиентов) обязательно монтируйте в volume на хосте, иначе после пересборки контейнера всё пропадёт. Советую вынести каталог uploads в отдельный том и регулярно синхронизировать его в объектное хранилище через rsync. Полный порядок работы с дампами и бэкапами базы — в Бэкап и восстановление сайта.
Когда пора переходить на K8s, а когда хватит compose?
Переходите на K8s, когда появились два из трёх сигналов: инстансы приложения нужно разнести на 3+ машины, есть чёткая потребность в автомасштабировании, в команде есть человек, который может каждый день чинить K8s. До этого compose полностью закрывает задачу. Скрытая цена K8s — разбираться с etcd, CNI, Ingress, управлением сертификатами и всей этой обвязкой, а это минимум один человеко-день в неделю.
Не окажется ли в alpine-образе нехватки зависимостей, из-за которой ничего не запустится?
Окажется. Самая частая засада: расширениям PHP при сборке нужен build-base, а в рантайме он не нужен. Multi-stage сборка это решает: на этапе builder ставите build-base и libpng-dev и прочие зависимости для сборки, а в рантайм-образ ставите только libpng и подобные библиотеки. Если возиться не хочется, берите официальный образ php:8.3-fpm-alpine — в нём нужные расширения уже предустановлены. А если поймали undefined symbol, доставляйте то, чего не хватает.

В заключение

容器化对独立站的价值,80%在于”环境一致性”,20%在于”编排能力”。先把Dockerfile写对、镜像压到200MB、compose文件管理好四个服务,就解决了独立站技术栈里最痛的环境漂移问题。不要一上来就追K8s,那是另一项全职工作。

План внедрения: на первой неделе пишем многоэтапный Dockerfile и сжимаем образ с 1 ГБ до 200 МБ; на второй — собираем в compose Nginx, приложение, MySQL и Redis и подключаем тома данных; на третьей — подключаем CI/CD к реестру образов, чтобы при пуше кода образ собирался автоматически. Три шага — и перенос сервера сокращается с двух дней до двух часов. О связке с CDN и мониторингом читайте Глобальное ускорение CDN. В повседневной эксплуатации раз в неделю запускайте docker system df и удаляйте висячие образы — так диск не будет постепенно забиваться мусором.

Запомните одну фразу: первый шаг к контейнеризации — не переход на K8s, а возможность одной командой поднять сайт на любом чистом сервере.

crater
crater Эксперт Crater

Официальный аккаунт организации · crater Crater

环形山 (Crater) — компания, которая помогает выходить на зарубежные рынки: разработка сайтов на WordPress, Google SEO и комплексный рост в GEO. Мы работаем с умными устройствами, промышленным оборудованием, SaaS и новой энергетикой.

Возможности продуктаБелая книга по методологииОтраслевые отчёты
965篇分享
78статей в базе знаний