We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

К списку статей

Контейнеризация legacy‑приложений: миграция старого Symfony‑кода в Kubernetes

04 фев 2026 в 07:30 Усачёв Денис Евгеньевич

Многие компании продолжают поддерживать проекты, написанные на старых версиях Symfony (2.x‑3.x). Такие «legacy‑приложения» часто работают на собственных серверах, где управление зависимостями, масштабирование и обновление инфраструктуры становятся проблемой. Перенос в Kubernetes позволяет решить эти задачи, но требует грамотного подхода к контейнеризации старого кода.

Аудит текущего проекта

  • Определить используемую версию PHP, расширения и системные зависимости.
  • Выявить сервисы, от которых зависит приложение (MySQL, Redis, Elasticsearch и пр.).
  • Проверить наличие кастомных скриптов и конфигураций в app/config и web/.htaccess.

Результат аудита – список пакетов и переменных окружения, которые необходимо передать в контейнер.

Создание Dockerfile

Для legacy‑приложений рекомендуется использовать многослойные сборки, чтобы уменьшить размер образа и ускорить повторные сборки.

# syntax=docker/dockerfile:1.4
FROM php:7.2-cli-alpine AS builder
WORKDIR /app
# Устанавливаем зависимости, необходимые для Composer
RUN apk add --no-cache git zip unzip
# Кешируем зависимости Composer
COPY composer.json composer.lock ./
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
    && composer install --no-dev --optimize-autoloader
# Копируем исходники и собираем assets (если есть)
COPY . .
RUN php bin/console assets:install --no-dev && php bin/console cache:clear --env=prod

FROM php:7.2-fpm-alpine AS runtime
WORKDIR /app
# Копируем только необходимые файлы из builder
COPY --from=builder /app /app
# Устанавливаем системные расширения, требуемые Symfony
RUN apk add --no-cache icu-dev libzip-dev \
    && docker-php-ext-install intl zip
# Настраиваем права
RUN chown -R www-data:www-data /app/var /app/vendor
EXPOSE 9000
CMD ["php-fpm"]

Docker‑compose для локального тестирования

version: "3.8"
services:
  app:
    build: .
    ports:
      - "8080:9000"
    environment:
      APP_ENV: prod
      APP_DEBUG: 0
    volumes:
      - .:/app:ro
    depends_on:
      - db
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: legacy_symfony
    volumes:
      - db_data:/var/lib/mysql
volumes:
  db_data:

Подготовка манифестов Kubernetes

После того как образ успешно собирается, создаём Deployment и Service. Для legacy‑приложений удобно использовать ConfigMap и Secret для параметров окружения.

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: symfony-config
  labels:
    app: legacy-symfony

data:
  APP_ENV: prod
  APP_DEBUG: "0"
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: symfony-secret
  labels:
    app: legacy-symfony

type: Opaque
stringData:
  DATABASE_URL: "mysql://root:secret@db:3306/legacy_symfony"
---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: legacy-symfony
  labels:
    app: legacy-symfony
spec:
  replicas: 3
  selector:
    matchLabels:
      app: legacy-symfony
  template:
    metadata:
      labels:
        app: legacy-symfony
    spec:
      containers:
        - name: php-fpm
          image: ghcr.io/yourorg/legacy-symfony:latest
          ports:
            - containerPort: 9000
          envFrom:
            - configMapRef:
                name: symfony-config
            - secretRef:
                name: symfony-secret
          resources:
            limits:
              cpu: "500m"
              memory: "512Mi"
            requests:
              cpu: "250m"
              memory: "256Mi"
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: legacy-symfony-svc
  labels:
    app: legacy-symfony
spec:
  selector:
    app: legacy-symfony
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9000
  type: ClusterIP
---
# ingress.yaml (опционально)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: legacy-symfony-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - host: symfony.example.com
      http:
        paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: legacy-symfony-svc
                port:
                  number: 80

CI/CD‑pipeline

Для автоматической сборки и деплоя удобно использовать GitLab CI, GitHub Actions или Azure Pipelines. Ниже пример GitLab CI, который собирает образ, пушит его в GitLab Container Registry и применяет манифесты в кластер.

stages:
  - build
  - deploy

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build_image:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
  only:
    - main

deploy_to_k8s:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config set-cluster k8s --server=$K8S_SERVER --certificate-authority=$K8S_CA_CERT
    - kubectl config set-credentials deploy --token=$K8S_TOKEN
    - kubectl config set-context default --cluster=k8s --user=deploy
    - kubectl config use-context default
    - kubectl set image deployment/legacy-symfony php-fpm=$IMAGE_TAG -n production
  only:
    - main

Мониторинг и логирование

Для legacy‑приложений важно собрать метрики PHP‑FPM и логи Symfony. Рекомендуется добавить sidecar‑контейнер с prometheus/node-exporter и использовать fluentd или filebeat для отправки логов в Elasticsearch/Graylog.

Типичные подводные камни

  • Отсутствие поддержки новых PHP‑расширений – в Alpine‑образах иногда требуется собрать расширения из исходников.
  • Кеширование конфигураций – Symfony 2/3 кэширует в app/cache. При запуске в контейнере убедитесь, что каталог доступен для записи и монтируется как emptyDir в pod.
  • Сессии в файловой системе – лучше переключить их на Redis или Memcached, иначе сессии будут «теряться» при масштабировании.
  • Отладка локально – используйте docker-compose с теми же образами, что и в prod, чтобы избежать различий среды.

Заключение

Контейнеризация legacy‑Symfony‑приложений – реальный путь к масштабируемой, управляемой и безопасной инфраструктуре. Правильный Dockerfile, многослойные сборки, автоматизированный CI/CD и интеграция с мониторингом позволяют перенести даже старый код в Kubernetes без потери стабильности.

RybinskLab предоставляет услуги по полной миграции legacy‑приложений в контейнеры, разработке CI/CD‑pipeline, настройке Kubernetes‑кластера и поддержке эксплуатации. Обратитесь к нам, чтобы ускорить цифровую трансформацию вашего бизнеса.

* Материал подготовлен с использованием ИИ-ассистента, проверен и отредактирован экспертом RybinskLab.

Поделиться материалом:

Нужна сложная разработка?

Усачёв Денис Евгеньевич — проектирование архитектуры, бэкенд на PHP/Python, интеграции API и базы данных.

Обсудить проект