Деплой PHP на Kubernetes: базовое руководство на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем деплоить PHP в Kubernetes?

PHP остается одним из самых популярных языков для веб-разработки. Однако по мере роста нагрузки и сложности проектов (Laravel, Symfony, Bitrix) традиционный LAMP-стек перестает справляться. Kubernetes (K8s) предлагает решение: автоматическое масштабирование, отказоустойчивость, zero-downtime деплой и управление конфигурациями.

В этом руководстве мы на практике разберем полный цикл деплоя PHP-приложения в Kubernetes: от создания Docker-образа до настройки Ingress. Вы узнаете, как подготовить манифесты, управлять переменными окружения и обеспечить работу PHP-FPM в кластере.

1. Подготовка PHP-приложения и Docker-образ

1.1. Структура PHP-проекта

Для деплоя нам потребуется минимальное PHP-приложение. Возьмем классический index.php:

<?php
// index.php
echo "Hello from Kubernetes! PHP version: " . phpversion();

Также создадим composer.json (если используете фреймворк):

{
    "require": {
        "php": "^8.1"
    }
}

1.2. Dockerfile для PHP-FPM

Ключевой момент: в Kubernetes PHP работает через PHP-FPM, а статику отдает Nginx. Создадим Dockerfile:

FROM php:8.2-fpm-alpine

# Установка необходимых расширений
RUN docker-php-ext-install pdo_mysql mysqli opcache

# Копируем код приложения
COPY . /var/www/html

# Права доступа
RUN chown -R www-data:www-data /var/www/html

# Настройки PHP
COPY php.ini /usr/local/etc/php/conf.d/custom.ini

WORKDIR /var/www/html

EXPOSE 9000
CMD ["php-fpm"]

Для продакшена добавьте opcache:

; php.ini
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000

1.3. Dockerfile для Nginx

Nginx будет проксировать запросы к PHP-FPM:

FROM nginx:alpine

COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY public/ /var/www/html/public

EXPOSE 80

Пример nginx.conf:

server {
    listen 80;
    root /var/www/html/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass php-service:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

2. Создание манифестов Kubernetes

2.1. Namespace

Изолируем наше приложение:

apiVersion: v1
kind: Namespace
metadata:
  name: php-app

2.2. ConfigMap для переменных окружения

PHP-приложения часто используют переменные окружения (например, для подключения к БД):

apiVersion: v1
kind: ConfigMap
metadata:
  name: php-config
  namespace: php-app
data:
  APP_ENV: production
  APP_DEBUG: "false"
  DB_HOST: mysql-service

2.3. Secret для чувствительных данных

Пароли и ключи храним в Secret:

apiVersion: v1
kind: Secret
metadata:
  name: php-secrets
  namespace: php-app
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQxMjM=  # base64 "password123"

2.4. Deployment для PHP-FPM

Основной компонент — PHP-FPM:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-deployment
  namespace: php-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: php-app
  template:
    metadata:
      labels:
        app: php-app
    spec:
      containers:
      - name: php-fpm
        image: my-registry/php-app:latest
        ports:
        - containerPort: 9000
        envFrom:
        - configMapRef:
            name: php-config
        - secretRef:
            name: php-secrets
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "256Mi"
            cpu: "500m"

2.5. Deployment для Nginx

Nginx будет отдельным подом:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: php-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: my-registry/nginx-php:latest
        ports:
        - containerPort: 80

2.6. Service для связи

Внутренние сервисы для связи между подами:

# Service для PHP-FPM
apiVersion: v1
kind: Service
metadata:
  name: php-service
  namespace: php-app
spec:
  selector:
    app: php-app
  ports:
  - protocol: TCP
    port: 9000
    targetPort: 9000

---
# Service для Nginx
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: php-app
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

3. Настройка Ingress и деплой

3.1. Ingress-контроллер

Для доступа извне создаем Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: php-ingress
  namespace: php-app
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  rules:
  - host: php-app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

3.2. Деплой на кластер

Применяем все манифесты:

kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment-php.yaml
kubectl apply -f deployment-nginx.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

Проверяем статус:

kubectl get pods -n php-app
kubectl get svc                

Блоги

Рекомендаций по книгам