Appearance
Kubernetes 容器化部署(arm64)
本方案适用于 Kubernetes 单组件部署,也可用 Docker Compose 在单机快速部署。镜像为 arm64(aarch64) 架构。
组件清单
| 组件 | 镜像 | 说明 |
|---|---|---|
| PostgreSQL | cornerstone365/informat-postgresql:1.0 | 数据库 |
| Redis | cornerstone365/informat-redis:1.0 | 缓存 |
| RabbitMQ | cornerstone365/informat-rabbitmq:1.0 | 消息队列 |
| SeaweedFS | cornerstone365/informat-seaweedfs:1.0 | 文件存储(S3) |
| Elasticsearch | cornerstone365/informat-elasticsearch:7.15.2 | 全文检索(可选) |
| Account | cornerstone365/informat-account:2.37 | informat-account |
| Biz | cornerstone365/informat-biz:2.37 | informat-biz |
| Nginx | cornerstone365/informat-nginx:1.0 | 网关 |
| OnlyOffice | cornerstone365/informat-onlyoffice:8.1 | 文件预览服务(已内置 license) |
一、前置要求
| 项 | 要求 |
|---|---|
| 节点架构 | arm64 / aarch64 |
| Kubernetes | 1.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、对象存储,可不部署内置中间件,让应用直接连接外部地址。
步骤:
- 不执行对应中间件的 YAML(跳过
10~14中相应文件)。 - 在
01-configmap.yaml把对应*_HOST/*_PORT改为外部地址与端口。 - 在
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 首启会自动灌入库表结构(检测到已初始化则跳过)。
外部 RabbitMQ:RABBITMQ_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: DOWN | Elasticsearch 未就绪或地址不对;不使用 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 无需改动。
存储:单副本用的是
ReadWriteOncePVC(仅单节点可挂载),多副本需改为共享存储。两种方式:- 用
ReadWriteMany的 StorageClass(NFS / CephFS 等),把informat-account-data/informat-biz-data改为accessModes: ["ReadWriteMany"],多副本共享同一卷; - 或文件/数据已外置(文件在 SeaweedFS、数据在 PG),把
/data/informat-next改为每副本独立的emptyDir(注意 biz 的/data/docker本就用emptyDir,每副本独立 DinD,无需共享)。
- 用
数据库初始化竞争:多副本同时首启会并发执行建表脚本(脚本幂等,检测
t_config/t_biz_config是否存在),但仍有竞争窗口。建议先以 1 副本部署、待库初始化完成后再扩容;或用外部 PG 并预先初始化(见「六」)。跨节点打散:用
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 端口)。

