Введение: зачем деплоить 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