Skip to content

Kubernetes 容器化部署(arm64)

本方案适用于 Kubernetes 单组件部署,也可用 Docker Compose 在单机快速部署。镜像为 arm64(aarch64) 架构。

组件清单

组件镜像说明
PostgreSQLcornerstone365/informat-postgresql:1.0数据库
Rediscornerstone365/informat-redis:1.0缓存
RabbitMQcornerstone365/informat-rabbitmq:1.0消息队列
SeaweedFScornerstone365/informat-seaweedfs:1.0文件存储(S3)
Elasticsearchcornerstone365/informat-elasticsearch:7.15.2全文检索(可选)
Accountcornerstone365/informat-account:2.37informat-account
Bizcornerstone365/informat-biz:2.37informat-biz
Nginxcornerstone365/informat-nginx:1.0网关
OnlyOfficecornerstone365/informat-onlyoffice:8.1文件预览服务(已内置 license)

一、前置要求

要求
节点架构arm64 / aarch64
Kubernetes1.20 及以上,kubectl 可用
容器运行时containerd 或 docker,节点使用 cgroup v2
特权集群允许 privileged Pod
存储提供可用的 StorageClass(StatefulSet 动态供给 PVC)
内核参数使用 Elasticsearch 时,节点设置 vm.max_map_count=262144

二、获取部署模板与镜像

2.1 下载部署模板(编排文件)

编排 YAML、一键部署脚本、Docker Compose 模板已打包为 informat-k8s-yaml.zip。下载并解压:

bash
curl -fSLO https://repo.informat.cn/downloads/installer/k8s/arm/manifests/informat-k8s-yaml.zip
unzip informat-k8s-yaml.zip -d informat-k8s
cd informat-k8s

解压后内容如下(后续所有命令均在 informat-k8s/ 目录下执行):

informat-k8s/
├── k8s/                          # Kubernetes 编排 YAML
│   ├── 00-namespace.yaml         # 命名空间
│   ├── 01-configmap.yaml         # 地址与端口配置(按需修改)
│   ├── 02-secret.yaml            # 密码配置(按需修改)
│   ├── 10-postgresql.yaml        # PostgreSQL(StatefulSet + Service + PVC)
│   ├── 11-redis.yaml             # Redis
│   ├── 12-rabbitmq.yaml          # RabbitMQ
│   ├── 13-seaweedfs.yaml         # SeaweedFS 文件存储
│   ├── 14-elasticsearch.yaml     # Elasticsearch(可选)
│   ├── 30-account.yaml           # Account 服务
│   ├── 31-biz.yaml               # Biz 服务
│   ├── 40-onlyoffice.yaml        # OnlyOffice 文档服务
│   └── 50-nginx.yaml             # Nginx 网关
├── deploy.sh                     # 一键部署脚本(仅改顶部参数区,见第八节)
├── docker-compose.yml            # 单机 Docker Compose 模板
└── .env.example                  # Compose 的端口/密码模板(复制为 .env 使用)

2.2 加载镜像

镜像以 tar.gz 形式分发,目录:https://repo.informat.cn/downloads/installer/k8s/arm/

每个 arm64 节点上执行:

bash
mkdir -p /opt/informat-images && cd /opt/informat-images
for f in informat-postgresql-1.0 informat-redis-1.0 informat-rabbitmq-1.0 \
         informat-seaweedfs-1.0 informat-nginx-1.0 informat-elasticsearch-7.15.2 \
         informat-account-2.37 informat-biz-2.37 informat-onlyoffice-8.1; do
  curl -fSLO https://repo.informat.cn/downloads/installer/k8s/arm/${f}.tar.gz
done

# containerd(Kubernetes 默认运行时)
for f in *.tar.gz; do gunzip -c "$f" | ctr -n k8s.io images import -; done

# 或 docker
# for f in *.tar.gz; do docker load -i "$f"; done

编排中 imagePullPolicy: IfNotPresent,本地已加载即不会远程拉取。若使用私有镜像仓库,可 docker tag 后推送,并将 YAML 中 image: 改为仓库地址。

三、配置

所有可自定义项集中在两个文件,部署前按需修改

地址与端口:k8s/01-configmap.yaml

yaml
data:
  PG_HOST: "informat-postgresql"
  PG_PORT: "5432"
  PG_USER: "postgres"
  REDIS_HOST: "informat-redis"
  REDIS_PORT: "6379"
  RABBITMQ_HOST: "informat-rabbitmq"
  RABBITMQ_PORT: "5672"
  SEAWEEDFS_HOST: "informat-seaweedfs"
  S3_PORT: "19000"            # 文件存储 S3 endpoint 端口
  ES_HOST: "informat-elasticsearch"
  ES_PORT: "9200"
  ACCOUNT_HOST: "informat-account"
  ACCOUNT_PORT: "9881"
  BIZ_HOST: "informat-biz"
  BIZ_PORT: "8881"
  INTRANET_URL: "http://informat-nginx:19881/"

各组件启动时按这些值生成自身配置(数据库连接、Redis/RabbitMQ 端口、Nginx 上游、S3 endpoint 等),改端口无需重新构建镜像

使用内置中间件时若修改了端口,需同步修改对应组件 Service 的端口(见第五节注意)。

密码:k8s/02-secret.yaml

yaml
stringData:
  PG_PASSWORD: "请改为强密码"
  REDIS_PASSWORD: "请改为强密码"
  RABBITMQ_USER: "admin"
  RABBITMQ_PASSWORD: "请改为强密码"
  S3_ACCESS_KEY: "admin"
  S3_SECRET_KEY: "请改为强密码"

生产环境务必修改为自定义强密码。密码值请避免包含 " \ : 等字符。

四、部署

YAML 已按文件名前缀编号好依赖顺序:

bash
# 1. 命名空间 + 地址配置 + 密码配置
kubectl apply -f k8s/00-namespace.yaml
kubectl apply -f k8s/01-configmap.yaml
kubectl apply -f k8s/02-secret.yaml

# 2. 中间件(有状态,StatefulSet + PVC)
kubectl apply -f k8s/10-postgresql.yaml
kubectl apply -f k8s/11-redis.yaml
kubectl apply -f k8s/12-rabbitmq.yaml
kubectl apply -f k8s/13-seaweedfs.yaml
kubectl apply -f k8s/14-elasticsearch.yaml

# 3. 等待中间件就绪(PostgreSQL 首启会自动创建空库)
kubectl -n informat get pods -w

# 4. 应用(首启自动从镜像内置安装包初始化库表)
kubectl apply -f k8s/30-account.yaml
kubectl apply -f k8s/31-biz.yaml

# 5. 文档服务 + 网关
kubectl apply -f k8s/40-onlyoffice.yaml
kubectl apply -f k8s/50-nginx.yaml

五、验证与访问

bash
# 全部 Pod Running
kubectl -n informat get pods

# 应用健康
kubectl -n informat exec deploy/informat-account -- curl -s http://127.0.0.1:9881/actuator/health
kubectl -n informat exec deploy/informat-biz -- curl -s http://127.0.0.1:8881/actuator/health

对外访问入口为网关 informat-nginx(NodePort,默认 30080):

http://<任一节点IP>:30080/

修改端口注意:若改了 01-configmap.yaml 中某中间件端口,需同步把对应 Service(如 informat-redis)的 port/targetPort 改为同一值;应用端无需改动。

六、使用外部中间件

如已有自建/云上的 PostgreSQL、Redis、RabbitMQ、Elasticsearch、对象存储,可不部署内置中间件,让应用直接连接外部地址。

步骤

  1. 不执行对应中间件的 YAML(跳过 1014 中相应文件)。
  2. 01-configmap.yaml 把对应 *_HOST / *_PORT 改为外部地址与端口。
  3. 02-secret.yaml 把对应密码改为外部中间件的真实凭据。

可任意混搭(例如外部 PostgreSQL + 内置 Redis/RabbitMQ)。

外部 PostgreSQL 须先建库(内置 PG 会自动建库,外部不会)。在外部数据库以超级用户执行:

sql
ALTER ROLE postgres WITH PASSWORD '与 Secret 中 PG_PASSWORD 一致';
CREATE DATABASE db_informat2_account_prd;
CREATE DATABASE db_informat2_biz_prd_0;
\c db_informat2_biz_prd_0
CREATE EXTENSION IF NOT EXISTS ltree;
-- 使用知识库/全文检索时(需外部 PG 已安装对应扩展,否则可跳过)
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS zhparser;

说明:

  • 库名固定(db_informat2_account_prd / db_informat2_biz_prd_0),应用以 PG_USER(默认 postgres)连接,该角色需对两个库有建表/读写权限。
  • 外部 PostgreSQL 的 pg_hba.conf 须允许应用 Pod 网段以密码方式连接。
  • account/biz 首启会自动灌入库表结构(检测到已初始化则跳过)。

外部 RabbitMQRABBITMQ_USER/RABBITMQ_PASSWORD 指定的账号需对 vhost / 有全部权限:

bash
rabbitmqctl set_permissions -p / <user> ".*" ".*" ".*"

Elasticsearch 非必需:将 ES_HOST 置空即可,biz 仍正常启动(仅全文检索不可用)。

七、数据库升级

升级到新版本时,先升级数据库,再更新 account/biz 镜像。

bash
# 1) 将新版本安装包拷入 biz Pod
POD=$(kubectl -n informat get pod -l app=informat-biz -o name | head -1)
kubectl -n informat cp informat_next_<新版>.zip ${POD#pod/}:/opt/pkg.zip

# 2) 执行内置升级入口(读取当前库版本,执行区间增量 SQL + 知识库;仅升级数据库)
kubectl -n informat exec ${POD#pod/} -- informat-db-upgrade --package /opt/pkg.zip

# 3) 升级应用:将 30-account.yaml / 31-biz.yaml 的 image 改为新版本 tag 后 kubectl apply 滚动更新

八、一键部署脚本

将下面脚本保存为 deploy.sh仅修改顶部参数区后执行,即可自动生成配置并完成部署。

bash
#!/bin/bash
set -euo pipefail

############### 参数区(按需修改) ###############
NAMESPACE="informat"
IMAGE_BASE="https://repo.informat.cn/downloads/installer/k8s/arm"   # 镜像下载目录
NODEPORT="30080"                          # 对外访问端口

# 端口(内置中间件按此监听;外部中间件填其真实端口)
PG_PORT="5432"
REDIS_PORT="6379"
RABBITMQ_PORT="5672"
ES_PORT="9200"
S3_PORT="19000"            # 文件存储 endpoint 端口
S3_CONSOLE_PORT="19011"    # filer 内部端口

# 密码(生产务必修改)
PG_PASSWORD="INFORMAT_1699434_582950525bd9"
REDIS_PASSWORD="Informat_Next-Redis_16994345829510287ce"
RABBITMQ_USER="admin"
RABBITMQ_PASSWORD="InformatMq510_287ce"
S3_ACCESS_KEY="admin"
S3_SECRET_KEY="admin1234551699434582951bd3afe"

# 中间件来源:internal=部署内置容器;external=连接外部,填写其地址
PG_MODE="internal";        PG_HOST="informat-postgresql"
REDIS_MODE="internal";     REDIS_HOST="informat-redis"
RABBITMQ_MODE="internal";  RABBITMQ_HOST="informat-rabbitmq"
SEAWEEDFS_MODE="internal"; SEAWEEDFS_HOST="informat-seaweedfs"
ES_MODE="internal";        ES_HOST="informat-elasticsearch"   # ES_MODE=off 则不使用 ES
################################################

cd "$(dirname "$0")"

echo ">>> [1/4] 命名空间"
kubectl get ns "$NAMESPACE" >/dev/null 2>&1 || kubectl create ns "$NAMESPACE"

echo ">>> [2/4] 生成并应用配置(ConfigMap + Secret)"
ES_HOST_VAL="$ES_HOST"; [ "$ES_MODE" = "off" ] && ES_HOST_VAL=""
kubectl -n "$NAMESPACE" create configmap informat-env \
  --from-literal=PG_HOST="$PG_HOST" --from-literal=PG_PORT="$PG_PORT" --from-literal=PG_USER="postgres" \
  --from-literal=REDIS_HOST="$REDIS_HOST" --from-literal=REDIS_PORT="$REDIS_PORT" \
  --from-literal=RABBITMQ_HOST="$RABBITMQ_HOST" --from-literal=RABBITMQ_PORT="$RABBITMQ_PORT" \
  --from-literal=SEAWEEDFS_HOST="$SEAWEEDFS_HOST" --from-literal=S3_PORT="$S3_PORT" --from-literal=S3_CONSOLE_PORT="$S3_CONSOLE_PORT" \
  --from-literal=ES_HOST="$ES_HOST_VAL" --from-literal=ES_PORT="$ES_PORT" \
  --from-literal=ACCOUNT_HOST="informat-account" --from-literal=ACCOUNT_PORT="9881" \
  --from-literal=BIZ_HOST="informat-biz" --from-literal=BIZ_PORT="8881" \
  --from-literal=INTRANET_URL="http://informat-nginx:19881/" \
  --dry-run=client -o yaml | kubectl apply -f -

kubectl -n "$NAMESPACE" create secret generic informat-secret \
  --from-literal=PG_PASSWORD="$PG_PASSWORD" --from-literal=REDIS_PASSWORD="$REDIS_PASSWORD" \
  --from-literal=RABBITMQ_USER="$RABBITMQ_USER" --from-literal=RABBITMQ_PASSWORD="$RABBITMQ_PASSWORD" \
  --from-literal=S3_ACCESS_KEY="$S3_ACCESS_KEY" --from-literal=S3_SECRET_KEY="$S3_SECRET_KEY" \
  --dry-run=client -o yaml | kubectl apply -f -

echo ">>> [3/4] 部署内置中间件(external/off 的自动跳过)"
[ "$PG_MODE" = internal ]        && kubectl apply -f k8s/10-postgresql.yaml
[ "$REDIS_MODE" = internal ]     && kubectl apply -f k8s/11-redis.yaml
[ "$RABBITMQ_MODE" = internal ]  && kubectl apply -f k8s/12-rabbitmq.yaml
[ "$SEAWEEDFS_MODE" = internal ] && kubectl apply -f k8s/13-seaweedfs.yaml
[ "$ES_MODE" = internal ]        && kubectl apply -f k8s/14-elasticsearch.yaml

# 等内置 PG 就绪(用外部 PG 时请确保已建库)
if [ "$PG_MODE" = internal ]; then
  echo "    等待 PostgreSQL 就绪..."
  kubectl -n "$NAMESPACE" rollout status statefulset/informat-postgresql --timeout=300s || true
fi

echo ">>> [4/4] 部署应用 + 网关"
kubectl apply -f k8s/30-account.yaml
kubectl apply -f k8s/31-biz.yaml
kubectl apply -f k8s/40-onlyoffice.yaml
kubectl apply -f k8s/50-nginx.yaml

echo ">>> 完成。查看状态:kubectl -n $NAMESPACE get pods"
echo ">>> 访问入口:http://<节点IP>:${NODEPORT}/"

脚本默认使用 k8s/ 目录下的 YAML,请在项目根目录执行(与 k8s/ 同级)。使用外部中间件时,把对应 *_MODE 改为 external 并填写 *_HOST,脚本会自动跳过该中间件的部署;外部 PostgreSQL 仍需按第六节预先建库。

九、常见问题

现象处理
systemd 容器无法启动(Exited 255)确认 Pod privileged: true 且节点为 cgroup v2;个别 containerd 版本需调整 /sys/fs/cgroup 挂载方式
应用启动报数据库连接失败检查 configmap 地址/端口、secret 密码是否与中间件一致;外部 PG 是否已建库、pg_hba 是否放通
biz 健康检查 elasticsearch: DOWNElasticsearch 未就绪或地址不对;不使用 ES 时将 ES_HOST 置空
修改端口后连接不上内置中间件改端口需同步改对应 Service 的 port/targetPort
Elasticsearch 启动报 max_map_count节点执行 sysctl -w vm.max_map_count=262144

十、多副本 / 多节点部署(生产高可用)

前面章节是单副本示例。生产环境通常把应用层组件横向扩展到多节点多副本(如 account 2 副本、biz 2 副本),由 Kubernetes 跨节点调度并自动负载均衡。

哪些可多副本

组件是否可多副本说明
account / biz✅ 可多副本应用层无状态化(会话/缓存在 Redis、文件在 S3、数据在 PG),多实例自动组成集群
nginx / onlyoffice✅ 可多副本无状态
PostgreSQL / Redis / RabbitMQ / Elasticsearch⚠️ 内置镜像为单实例中间件高可用请用各自集群方案或云托管服务,并按「六、使用外部中间件」接入;不要简单把内置中间件 replicas 调大
SeaweedFS⚠️ 单实例需要分布式存储时用其集群模式或换其他对象存储

扩展 account / biz 到多副本

Service 名不变,Kubernetes Service 会自动在多个 Pod 间负载均衡,nginx 上游 informat-account / informat-biz 无需改动。

  1. 存储:单副本用的是 ReadWriteOnce PVC(仅单节点可挂载),多副本需改为共享存储。两种方式:

    • ReadWriteMany 的 StorageClass(NFS / CephFS 等),把 informat-account-data / informat-biz-data 改为 accessModes: ["ReadWriteMany"],多副本共享同一卷;
    • 或文件/数据已外置(文件在 SeaweedFS、数据在 PG),把 /data/informat-next 改为每副本独立的 emptyDir(注意 biz 的 /data/docker 本就用 emptyDir,每副本独立 DinD,无需共享)。
  2. 数据库初始化竞争:多副本同时首启会并发执行建表脚本(脚本幂等,检测 t_config/t_biz_config 是否存在),但仍有竞争窗口。建议先以 1 副本部署、待库初始化完成后再扩容;或用外部 PG 并预先初始化(见「六」)。

  3. 跨节点打散:用 podAntiAffinity 让同组件副本尽量分布到不同节点。

31-biz.yaml(account 同理)的 Deployment 调整为:

yaml
spec:
  replicas: 2                      # 副本数
  template:
    spec:
      affinity:
        podAntiAffinity:           # 副本尽量分散到不同节点
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app: informat-biz
                topologyKey: kubernetes.io/hostname
      containers:
        - name: biz
          # ... 其余不变
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: informat-biz-data   # 对应 PVC 需为 ReadWriteMany

对应 PVC 改为共享读写:

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: informat-biz-data
  namespace: informat
spec:
  accessModes: ["ReadWriteMany"]   # 多副本共享
  storageClassName: <你的RWX StorageClass>
  resources:
    requests:
      storage: 20Gi

应用后扩缩容:

bash
kubectl -n informat scale deploy/informat-account --replicas=2
kubectl -n informat scale deploy/informat-biz --replicas=2
kubectl -n informat get pods -o wide        # 查看副本分布到的节点

也可配合 HorizontalPodAutoscaler 按 CPU/内存自动伸缩。

资源建议

每个 account/biz Pod 的 JVM 堆见镜像内 instance/*/env.properties(默认 biz 6g、account 4g)。请按节点规格设置 Pod 的 resources.requests/limits,并保证 limits.memory ≥ JVM -Xmx + 堆外内存(建议预留 1~2g)。内存不足会导致 Pod 被 OOMKill。

中间件高可用

内置中间件镜像为单实例,仅适合中小规模。生产高可用建议:

  • PostgreSQL:主备 / Patroni / 云数据库
  • Redis:哨兵 / Cluster / 云缓存
  • RabbitMQ:镜像队列 / Quorum 队列集群
  • Elasticsearch:多节点集群
  • 对象存储:SeaweedFS 集群或 MinIO 集群 / 云对象存储

部署好后按「六、使用外部中间件」把 01-configmap.yaml 地址与 02-secret.yaml 密码指向外部集群,并跳过对应内置中间件的 YAML。

附录:单机 Docker Compose 部署

适用于快速验证或单机部署(arm64,已安装 docker 与 compose 插件)。

bash
# 加载镜像
for f in *.tar.gz; do docker load -i "$f"; done
# 自定义端口/密码:复制 .env.example 为 .env 并修改
cp .env.example .env && vi .env
# 启动
docker compose up -d
docker compose ps

入口:http://<主机IP>/(Nginx 映射宿主 80 端口)。