Многие компании продолжают поддерживать проекты, написанные на старых версиях 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‑кластера и поддержке эксплуатации. Обратитесь к нам, чтобы ускорить цифровую трансформацию вашего бизнеса.