远程协作已不再是“可选项”,而是现代团队运作的核心能力。从产品原型讨论到系统架构设计,一张共享的白板往往比十页文档更高效。但传统的绘图工具要么过于刻板,要么难以集成——直到 Excalidraw 的出现。
这款开源手绘风格白板以极简界面和自然交互迅速赢得开发者青睐。它不只是“画得像草图”,更重要的是支持实时协作、插件扩展,甚至能通过AI将一句话变成流程图。然而,当团队规模扩大、并发用户增多时,如何保证服务稳定?如何应对会议高峰期的流量激增?又如何实现无缝升级而不中断正在进行的头脑风暴?
答案很明确:将 Excalidraw 部署在 Kubernetes 上。
K8s 不仅能提供高可用与自动扩缩容,还能统一管理配置、监控和服务发现。但这并非简单地把容器跑起来就行——真正挑战在于:如何让一个原本轻量级、本地优先的应用,在分布式环境中依然保持低延迟、强一致的协作体验。
Excalidraw 默认是“开箱即用”的静态服务。你拉取镜像、启动容器,就能访问一个功能完整的白板应用。但在生产环境,尤其是企业级部署中,几个关键问题立刻浮现:
这些问题的本质,是从“单体思维”转向“云原生架构”的范式迁移。我们需要重新思考两个核心层面:应用状态管理 和 基础设施编排。
Kubernetes 擅长管理无状态服务。而 Excalidraw 虽然前端完全无状态,其协作逻辑却依赖于运行时的连接上下文。如果多个 Pod 各自为政,用户 A 和用户 B 可能被路由到不同实例,导致消息无法广播。
解决办法只有一个:把状态外移。
我们引入 Redis 作为共享会话存储。所有 WebSocket 连接信息、房间成员列表、操作队列都集中存放在 Redis 中。每个 Pod 启动时订阅相同的频道,一旦收到新操作,立即转发给对应房间的所有客户端。
这样做的好处显而易见:
- 新增 Pod 实例不再影响现有会话;
- 单个 Pod 崩溃不会导致数据丢失;
- 支持横向扩展,轻松承载数百个并发房间。
当然,这需要对 Excalidraw 的后端进行轻微改造或使用社区增强版(如 excalidraw-room-server),使其支持外部状态存储。
# 示例:为 Deployment 添加 Redis 环境变量
env:
- name: REDIS_HOST
value: "redis-service"
- name: REDIS_PORT
value: "6379"
- name: USE_REDIS_PUBSUB
value: "true"
小贴士:如果你不想维护 Redis,也可以考虑 Firebase Realtime Database 或 Supabase,它们天然支持多客户端同步,适合中小团队快速上线。
想象一下:周一上午 10 点,全公司进入“战略规划周”,几十个会议室同时开启白板协作。你的 Excalidraw 服务瞬间面临百倍流量增长。如果没有弹性机制,结果只能是卡顿、断连、用户体验雪崩。
Kubernetes 的 HorizontalPodAutoscaler (HPA) 正是用来应对这种场景的利器。
虽然官方 HPA 主要基于 CPU 和内存指标,但对于 WebSocket 类服务,更合理的扩缩依据其实是 活跃连接数 或 消息吞吐量。幸运的是,我们可以借助 Prometheus + Custom Metrics 实现这一点。
在 Excalidraw 后端添加 /metrics 接口,输出当前活跃房间数、总连接数等信息:
# HELP excalidraw_active_rooms Number of active drawing rooms
# TYPE excalidraw_active_rooms gauge
excalidraw_active_rooms 23
# HELP excalidraw_websocket_connections Total number of WebSocket connections
# TYPE excalidraw_websocket_connections gauge
excalidraw_websocket_connections 156
配合 Prometheus 抓取,这些指标即可用于驱动扩缩决策。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: excalidraw-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: excalidraw-deployment
minReplicas: 2
maxReplicas: 15
metrics:
- type: Pods
pods:
metric:
name: excalidraw_websocket_connections
target:
type: AverageValue
averageValue: "10" # 每个 Pod 平均承载 10 个连接
这意味着:当总连接数达到 100 时,系统会自动扩容至 10 个 Pod;若降至 20,则缩回 2 个。整个过程无需人工干预。
经验值参考:普通服务器上,一个 Excalidraw Pod 可稳定支撑 8–15 个并发 WebSocket 连接(取决于画布复杂度)。建议初始设置目标值为 10,后续根据压测调整。
最终的生产级架构不再是简单的“前端+后端”,而是一个由多个微服务协同构成的系统。以下是典型拓扑结构:
graph TD
A[Client Browser] --> B[Ingress Controller]
B --> C[Service → Excalidraw Pod]
C --> D[(Redis Session Store)]
C --> E[(Persistent DB: Firebase/PostgreSQL)]
C --> F[AI Gateway Service]
F --> G[(LLM API: OpenAI, Claude, etc.)]
各组件职责如下:
/draw/*)、启用 WebSocket 升级头,并可集成 OAuth2 Proxy 实现登录保护。这个架构的关键优势在于:每个部分都可以独立伸缩与替换。例如,AI 请求量大时,单独扩容 AI Gateway;而主服务仍保持轻量。
光有理论不够,落地靠的是精准的资源配置。以下是一份经过生产验证的 Deployment 配置片段,兼顾性能与稳定性。
apiVersion: apps/v1
kind: Deployment
metadata:
name: excalidraw-deployment
labels:
app: excalidraw
version: v1.4
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # 确保至少有一个 Pod 在线
selector:
matchLabels:
app: excalidraw
template:
metadata:
labels:
app: excalidraw
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
spec:
containers:
- name: excalidraw
image: excalidraw/excalidraw:latest
ports:
- containerPort: 80
protocol: TCP
envFrom:
- configMapRef:
name: excalidraw-config
- secretRef:
name: excalidraw-secrets
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 10
periodSeconds: 5
几点说明:
maxUnavailable: 0 是为了保障协作连续性——哪怕牺牲一点发布速度,也不能让用户突然断开。/healthz 和 /ready 应由后端实现,前者检测进程存活,后者判断是否已完成初始化(如连接 Redis 成功)。很多团队只关注“能不能用”,却忽略了“安不安全”和“出了问题怎么查”。
公开部署 Excalidraw 相当于开放了一个自由书写空间,极易被滥用。建议采取以下措施:
/admin, /export)做细粒度 RBAC 控制(需自定义中间件)。没有监控的服务就像盲飞。必须建立三层可观测体系:
/metrics,Grafana 展示连接数、错误率、延迟分布;一个实用的 Grafana 面板应包含:
- 当前活跃连接趋势图
- 每秒广播消息数量
- Redis 延迟 P99
- HPA 当前副本数 vs 目标值
把 Excalidraw 部署在 Kubernetes 上,表面上看是一次基础设施升级,实则推动了组织协作文化的进化。
过去,画图是“设计师的事”;现在,每个人都能用“说一句,生成一张图”的方式参与设计。产品经理描述业务流程,AI 自动生成泳道图;工程师口述系统模块,立刻得到一份可编辑的架构草图。这种“低门槛表达”极大降低了沟通成本。
而背后那套自动伸缩、自我修复的 K8s 编排系统,则让运维团队得以“隐身”。他们不再需要半夜爬起来扩容实例,也不必担心某次发布搞崩了协作环境——一切交给平台自动处理。
这正是云原生的魅力所在:让复杂的事情变简单,让简单的事情变得可靠。
未来,随着更多 AI 原语融入协作工具,我们将看到“意图→图表”、“语音→原型”的转化越来越流畅。而今天搭建的这套可扩展架构,正是通往那个智能协作时代的坚实跳板。