4. 容器化运行时环境部署

任务目标

在边缘智能工业网关(x86_64 / ARM64 Linux)上部署 containerd 作为容器运行时,配置 veth 桥接网络与本地持久化存储,验证边缘应用可在隔离环境中正常运行并访问外部网络。

环境依赖

  • Linux 内核 ≥ 5.11(建议),已加载 overlay、br_netfilter 模块
  • 已安装 containerd(版本 ≥ 1.7)与 runc
  • 已安装 cni-plugins(至少包含 bridge、loopback、portmap)
  • 已安装 nerdctl(containerd 的 CLI 客户端,兼容 Docker 命令风格)

核心实现

以下脚本完成:生成 CNI 桥接网络配置、创建持久化数据目录、启动一个运行 Nginx 的边缘容器并挂载宿主机目录,最后通过宿主机端口访问容器服务。

#!/bin/bash
# edge-container-deploy.sh
# 用途:在网关部署 containerd 容器运行时环境,验证隔离与持久化

set -euo pipefail

# ---------- 1. 检查运行时 ----------
if ! command -v nerdctl >/dev/null 2>&1; then
    echo "[ERROR] nerdctl 未安装,请先安装 containerd 与 nerdctl"
    exit 1
fi

# ---------- 2. 配置 CNI 桥接网络 ----------
CNI_CONF_DIR="/etc/cni/net.d"
CNI_CONF_FILE="${CNI_CONF_DIR}/10-edge-bridge.conflist"
mkdir -p "${CNI_CONF_DIR}"

cat > "${CNI_CONF_FILE}" <<'EOF'
{
  "cniVersion": "1.0.0",
  "name": "edge-bridge",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "cni0",
      "isGateway": true,
      "ipMasq": true,
      "ipam": {
        "type": "host-local",
        "subnet": "10.88.0.0/16",
        "routes": [{ "dst": "0.0.0.0/0" }]
      }
    },
    {
      "type": "portmap",
      "capabilities": { "portMappings": true }
    }
  ]
}
EOF
echo "[OK] CNI 网络配置已写入 ${CNI_CONF_FILE}"

# ---------- 3. 创建持久化存储目录 ----------
DATA_ROOT="/var/lib/edge-containers"
APP_DATA="${DATA_ROOT}/nginx-html"
mkdir -p "${APP_DATA}"
echo "<h1>Edge Gateway Container OK</h1>" > "${APP_DATA}/index.html"
echo "[OK] 持久化目录已创建: ${APP_DATA}"

# ---------- 4. 拉取镜像并启动容器 ----------
IMAGE="nginx:1.27-alpine"
CONTAINER_NAME="edge-nginx"

# 清理可能存在的同名容器
nerdctl rm -f "${CONTAINER_NAME}" 2>/dev/null || true

echo "[INFO] 拉取镜像 ${IMAGE} ..."
nerdctl pull "${IMAGE}"

echo "[INFO] 启动容器 ${CONTAINER_NAME} ..."
nerdctl run -d \
    --name "${CONTAINER_NAME}" \
    --network edge-bridge \
    -p 8080:80 \
    -v "${APP_DATA}:/usr/share/nginx/html:ro" \
    --restart=unless-stopped \
    "${IMAGE}"

# ---------- 5. 验证状态 ----------
sleep 2
echo ""
echo "===== 容器运行状态 ====="
nerdctl ps --filter "name=${CONTAINER_NAME}"

echo ""
echo "===== 网络连通性测试 ====="
if nerdctl exec "${CONTAINER_NAME}" wget -qO- http://127.0.0.1/ 2>/dev/null | grep -q "Edge Gateway"; then
    echo "[PASS] 容器内 HTTP 服务自检通过"
else
    echo "[FAIL] 容器内 HTTP 服务自检失败"
    exit 1
fi

echo ""
echo "===== 宿主机端口访问测试 ====="
HOST_IP=$(ip -4 addr show eth0 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
if [ -z "${HOST_IP}" ]; then
    HOST_IP="127.0.0.1"
fi
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://${HOST_IP}:8080/" || true)
if [ "${HTTP_CODE}" = "200" ]; then
    echo "[PASS] 宿主机通过 ${HOST_IP}:8080 访问成功 (HTTP 200)"
else
    echo "[FAIL] 宿主机访问失败,HTTP 状态码: ${HTTP_CODE}"
    exit 1
fi

echo ""
echo "===== 持久化验证 ====="
nerdctl exec "${CONTAINER_NAME}" ls -la /usr/share/nginx/html/index.html
echo "[PASS] 容器内已挂载宿主机持久化目录"

echo ""
echo "[DONE] 容器化运行时环境部署完成"

运行方式

  1. 将脚本保存为 edge-container-deploy.sh,赋予执行权限:chmod +x edge-container-deploy.sh
  2. 以 root 或具有 sudo 权限的用户执行:sudo ./edge-container-deploy.sh
  3. 脚本执行完成后,容器 edge-nginx 将持续运行

验证方法与判定标准

  • 运行时状态:执行 nerdctl ps,应看到 edge-nginx 状态为 Up
  • 网络隔离与连通:脚本自动执行容器内自检与宿主机端口访问测试,输出 [PASS] 即通过
  • 持久化存储:在宿主机执行 echo "test" >> /var/lib/edge-containers/nginx-html/index.html 后,容器内访问 http://127.0.0.1/ 应看到更新内容;重启容器(nerdctl restart edge-nginx)后数据仍保留
  • 手动验证:在网关局域网内另一台设备浏览器访问 http://<网关IP>:8080/,应显示 Edge Gateway Container OK 页面

常见问题

  • CNI 网络创建失败:确认 /etc/cni/net.d 下无其他冲突配置,且内核已加载 br_netfilter(执行 modprobe br_netfilter)
  • 端口映射不生效:检查 portmap 插件是否在 CNI 配置中正确声明,且 nerdctl run 使用了 -p 参数
  • 容器重启后数据丢失:确认挂载路径 -v 使用的是宿主机路径,而非容器卷名