《PHP容器在iSulad/Kata Containers(国产安全容器)上的运行实践》
第三部分:PHP 容器在 iSulad / Kata Containers 国产安全容器上的运行实践
3.1 先搞明白这俩是什么、什么关系
大白话:
- iSulad(读"爱苏拉德"):华为开源的容器引擎,是 Docker 的国产替代。它负责"管理容器的一生":拉镜像、创建、启动、停止、删除。命令行工具叫
isula,用法和docker几乎一模一样(isula run、isula ps……),学习成本约等于零。优点:C/C++ 写的,比 Docker(Go 写的)更轻、内存占用更小、启动更快,openEuler 官方源直接就能装。 - Kata Containers:一种容器运行时。普通容器(runc)的隔离靠 Linux 内核的 namespace/cgroup,所有容器共享宿主机内核——一个内核漏洞可能让容器"越狱"。Kata 给每个容器套一个轻量级虚拟机(有自己独立的内核),隔离级别达到虚拟机水平,但用起来还是容器的体验。代价:启动慢一点(百毫秒级 → 秒级)、内存开销多一点(每容器约多 100~200MB)。
- 两者关系:iSulad 是"调度经理",Kata 是"其中一种干活方式"。iSulad 默认用 runc(普通隔离)跑容器,也可以配置成用 Kata(强隔离)跑。选择建议:内部可信应用用 runc 就够了;多租户、跑第三方代码、等保要求高的场景用 Kata。
isula run --runtime runc ──► 普通容器(合租房:快、省资源)
iSulad(引擎)──┤
isula run --runtime kata-runtime ──► Kata 容器(独栋:强隔离)
3.2 第一步:openEuler 上安装 iSulad
# openEuler 22.03 LTS 官方源直接装(麒麟 V10 SP2+ 同样自带 iSulad 源)
dnf install -y iSulad
# 启动并设置开机自启
systemctl enable --now isulad
# 验证
isula version
配置 iSulad(/etc/isulad/daemon.json)
大白话:这个文件相当于 Docker 的 daemon.json。重点配三样——镜像仓库地址(指向公司 Harbor)、日志大小限制(防止日志把磁盘写爆)、以及注册 Kata 运行时。
{
"group": "isula",
"default-runtime": "runc",
"graph": "/var/lib/isulad",
"state": "/var/run/isulad",
"log-level": "INFO",
"log-driver": "json-file",
"log-opts": {
"log-file-mode": "0600",
"log-path": "/var/lib/isulad",
"max-file": "3",
"max-size": "30MB"
},
"registry-mirrors": [
"https://harbor.example.internal"
],
"insecure-registries": [
"harbor.example.internal"
],
"runtimes": {
"kata-runtime": {
"path": "/usr/bin/kata-runtime",
"runtime-args": [
"--kata-config",
"/usr/share/defaults/kata-containers/configuration.toml"
]
}
}
}
# 改完配置重启生效
systemctl restart isulad
3.3 第二步:用 iSulad 跑起一套 PHP 应用(nginx + php-fpm)
大白话:iSulad 没有 docker-compose 那种编排工具,单机场景就写个启动脚本,让 nginx 容器和 php-fpm 容器共享一个网络。下面是完整可跑的脚本。
run-php-app.sh:
#!/usr/bin/env bash
# ============================================================
# 用 iSulad 启动 PHP 应用(nginx + php-fpm 双容器)
# 用法:./run-php-app.sh start|stop|restart|status
# ============================================================
set -e
HARBOR="harbor.example.internal"
APP_IMAGE="$HARBOR/php/demo-php-app:latest" # 第一部分流水线打出来的镜像
NGINX_IMAGE="$HARBOR/library/nginx:1.25"
NET_NAME="php-net"
APP_NAME="php-fpm-app"
NGINX_NAME="php-nginx"
start() {
# 1. 建一个专用网络,两个容器都加入,nginx 就能用容器名连到 php-fpm
isula network inspect $NET_NAME >/dev/null 2>&1 || isula network create $NET_NAME
# 2. 拉最新镜像
isula pull $APP_IMAGE
isula pull $NGINX_IMAGE
# 3. 启动 php-fpm 容器
isula run -d \
--name $APP_NAME \
--network $NET_NAME \
--restart always \
-m 512m --cpus 1 \
$APP_IMAGE
# 4. 准备 nginx 配置(转发 .php 请求给 php-fpm 容器的 9000 端口)
mkdir -p /opt/php-app/nginx
cat > /opt/php-app/nginx/default.conf <<'EOF'
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-fpm-app:9000; # 直接写容器名,走 php-net 网络解析
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/public$fastcgi_script_name;
include fastcgi_params;
}
}
EOF
# 5. 启动 nginx 容器,对外暴露 8080
isula run -d \
--name $NGINX_NAME \
--network $NET_NAME \
--restart always \
-p 8080:80 \
-v /opt/php-app/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro \
$NGINX_IMAGE
echo "启动完成,访问 http://本机IP:8080"
}
stop() {
isula rm -f $NGINX_NAME $APP_NAME 2>/dev/null || true
echo "已停止"
}
status() {
isula ps -a --filter "name=php-"
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
status) status ;;
*) echo "用法: $0 start|stop|restart|status"; exit 1 ;;
esac
再配一个 systemd 服务,让它跟随开机自启(第一部分 SSH 部署里 systemctl restart demo-php-app 重启的就是它):
/etc/systemd/system/demo-php-app.service:
[Unit]
Description=Demo PHP App (iSulad)
After=isulad.service
Requires=isulad.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/php-app/run-php-app.sh start
ExecStop=/opt/php-app/run-php-app.sh stop
TimeoutStartSec=300
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now demo-php-app
3.4 第三步:安装 Kata Containers 并用强隔离跑 PHP
安装
# openEuler 官方源提供 kata 相关包(底层用 QEMU 起轻量虚拟机)
dnf install -y kata-containers qemu-kvm
# 检查本机硬件支持不支持(需要 CPU 虚拟化:鲲鹏的 ARM 虚拟化 / 海光的 AMD-V)
kata-runtime check
# 输出 "System is capable of running Kata Containers" 就 OK
Kata 配置调优(/usr/share/defaults/kata-containers/configuration.toml 关键项)
大白话:Kata 的每个容器都是一个微型虚拟机,这个文件决定"虚拟机的默认配置"。给 PHP 应用重点关注内存和 CPU:
[hypervisor.qemu]
path = "/usr/bin/qemu-kvm"
kernel = "/usr/share/kata-containers/vmlinux.container"
initrd = "/usr/share/kata-containers/kata-containers-initrd.img"
# 每个 Kata 容器的虚拟机默认给 1 核,实际能按需热插到 default_maxvcpus
default_vcpus = 1
default_maxvcpus = 4
# 默认内存 512MB(php-fpm + OPcache 一般够了;不够的容器启动时用 -m 覆盖)
default_memory = 512
# 开启内存气球,虚拟机没用完的内存可以还给宿主机,省资源
enable_balloon = true
[runtime]
# 网络用 tcfilter 模式,兼容性最好
internetworking_model = "tcfilter"
# 出问题时打开 debug 看详细日志
enable_debug = false
用 Kata 跑 php-fpm(就改一个参数)
# 和普通启动唯一的区别:--runtime kata-runtime
isula run -d \
--name php-fpm-secure \
--network php-net \
--restart always \
--runtime kata-runtime \
-m 512m --cpus 1 \
harbor.example.internal/php/demo-php-app:latest
# 验证它真的跑在独立内核里:
isula exec php-fpm-secure uname -r # 显示的是 Kata 虚拟机的内核版本
uname -r # 宿主机内核版本,两者不同 = 隔离生效
大白话验证逻辑:普通容器和宿主机共享内核,uname -r 结果一样;Kata 容器有自己的内核,结果不一样。结果不一样就说明强隔离生效了。
3.5 第四步:K8s 集群里用 iSulad + Kata(生产标准姿势)
大白话:单机脚本适合小场景,生产一般是 K8s 集群。思路是:
- K8s 的节点用 iSulad 做容器运行时(代替 containerd/docker);
- 在 K8s 里注册一个叫
kata的 RuntimeClass(运行时类别); - 哪个 Pod 需要强隔离,就在 Pod 里写一行
runtimeClassName: kata,其它 Pod 不受影响。
节点侧:iSulad 打开 CRI 接口(让 K8s 能指挥它)
在 /etc/isulad/daemon.json 里追加:
{
"network-plugin": "cni",
"cni-bin-dir": "/opt/cni/bin",
"cni-conf-dir": "/etc/cni/net.d",
"pod-sandbox-image": "harbor.example.internal/library/pause:3.9",
"cri-runtimes": {
"kata": "kata-runtime"
}
}
kubelet 指向 iSulad 的接口(/etc/sysconfig/kubelet 或 kubeadm 配置):
KUBELET_EXTRA_ARGS="--container-runtime-endpoint=unix:///var/run/isulad.sock"
systemctl restart isulad kubelet
集群侧:注册 RuntimeClass + 部署 PHP
kata-runtimeclass.yaml:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: kata
# handler 对应 daemon.json 里 cri-runtimes 的 key
handler: kata
# Kata 每个 Pod 的虚拟机本身有固定开销,声明出来让 K8s 调度时算这笔账
overhead:
podFixed:
memory: "160Mi"
cpu: "250m"
# 只调度到装了 kata 的节点
scheduling:
nodeSelector:
katacontainers.io/kata-runtime: "true"
给装了 Kata 的节点打标签:
kubectl label node node-1 katacontainers.io/kata-runtime=true
需要强隔离的 PHP 部署(比如处理敏感数据的服务),在第一部分的 Deployment 基础上只加一行:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-php-app-secure
namespace: php-prod
spec:
replicas: 2
selector:
matchLabels: { app: demo-php-app-secure }
template:
metadata:
labels: { app: demo-php-app-secure }
spec:
runtimeClassName: kata # ← 就加这一行,这个服务就跑进独立虚拟机了
imagePullSecrets:
- name: harbor-cred
containers:
- name: app
image: harbor.example.internal/php/demo-php-app:latest
ports:
- containerPort: 9000
resources:
requests: { cpu: 250m, memory: 256Mi }
limits: { cpu: "1", memory: 512Mi }
kubectl apply -f kata-runtimeclass.yaml
kubectl apply -f deployment-secure.yaml
# 验证:进 Pod 看内核版本,和节点不一样就是 Kata 生效
kubectl -n php-prod exec deploy/demo-php-app-secure -- uname -r
3.6 PHP 在 Kata 里的性能调优要点
大白话逐条解释:
- php-fpm 进程数别开太大。Kata 虚拟机内存是"独占"的,
pm.max_children按"虚拟机内存 ÷ 单个 PHP 进程内存"算。512MB 的 Kata 容器建议:
; /etc/php-fpm.d/www.conf 关键段
pm = dynamic
pm.max_children = 10 ; 512MB ÷ 约40MB/进程 ≈ 12,留点余量取 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 1000 ; 每个进程处理1000个请求后重启,防内存泄漏累积
- OPcache 必开(Dockerfile 里已配)。Kata 有虚拟化开销,OPcache 省下的 PHP 编译时间正好补回来,实测综合性能损耗能压到 5% 以内。
- 磁盘 IO 敏感的操作走内存。Kata 的磁盘走 virtio 有损耗,session 之类高频小文件读写别放磁盘,改放 Redis:
; php.ini
session.save_handler = redis
session.save_path = "tcp://redis.example.internal:6379?auth=密码"
- 冷启动慢的对策。Kata 容器启动比普通容器慢约 1~2 秒,K8s 里把
readinessProbe的initialDelaySeconds适当调大(比如 10 秒),避免流量打到还没就绪的实例。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)