“放在容器上,Kubernetes 不就都自动处理了吗?”
许多开发者初次接触 Kubernetes 时常有的误解
>
🎯 本文涵盖内容
- 在 Kubernetes 上部署数据库的条件以及不应部署的原因
- 为什么日志收集工具(Fluent Bit, Loki 等)可以配置为容器
- 将生产数据库与 Kubernetes 分离的实际原因
- 日志数据的法律保留义务(基于韩国法律)
- 实践中常用的配置模式和示例
📌 引言 / 背景
随着 Kubernetes 的普及,“一切皆容器!”的趋势日益增强。随之而来的自然问题是:“数据库也不能放在 Kubernetes 上吗?”
简短的回答是:“可以放。但在生产环境中需要谨慎。”
Kubernetes 是一个为无状态(stateless)工作负载优化的平台。像 Web 服务器、API 服务器这样接收请求并响应的应用程序,即使 Pod 宕机并重新启动,也不会有太大问题。但数据库不同。因为数据一旦丢失,就彻底完了。
那么日志(log)呢?日志收集代理和日志存储数据库与生产数据库的性质不同。而且,这里还牵涉到法律方面的考量。
接下来,我们将逐一探讨。
🔍 Kubernetes 的特性:为什么与数据库的兼容性如此棘手?
Kubernetes 是一个秉持“一次性”哲学的平台
Kubernetes 假定 Pod 可以随时终止并重新创建。这被称为Ephemeral(短暂性)特性。节点故障、扩缩容、滚动更新……在所有情况下,Pod 都可能随时消失。
数据库与这一哲学相冲突。数据库的核心是数据的持久性(Persistence)。
Kubernetes 为解决这个问题提供了 PV/PVC(Persistent Volume / Persistent Volume Claim),但这并非完美的解决方案。
将生产数据库移出 Kubernetes 的5个原因① 难以保证数据持久性
即使使用 PV,如果整个节点宕机或存储后端出现问题,仍存在数据丢失的风险。云托管数据库(如 AWS RDS、Azure Database 等)本身提供多可用区复制、自动备份和时间点恢复(PITR)。
② StatefulSet 的操作复杂性
要在 Kubernetes 上运行数据库,需要使用 StatefulSet。StatefulSet 为每个 Pod 分配唯一的 ID 和存储,以确保有序的部署/删除。然而,直接管理 MySQL InnoDB Cluster、PostgreSQL HA、MongoDB ReplicaSet 等的集群、故障转移、主节点选举逻辑,会带来相当大的操作负担。
# StatefulSet 示例 — 在 K8s 上运行数据库时
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres"
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
volumeMounts:
- name: pgdata
mountPath: /var/lib/postgresql/data
volumeClaimTemplates: # 为每个 Pod 创建单独的 PVC
- metadata:
name: pgdata
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
仅看上述配置就已很复杂。如果再加上备份 CronJob、监控 Exporter、网络策略、安全上下文,运维团队的负担将倍增。
③ 网络延迟和存储 I/O 性能
Kubernetes 的网络通过覆盖网络(CNI)运行。数据库的核心是高速 I/O 和低延迟,而容器化带来的网络开销和存储抽象层可能会影响性能。特别是与直接访问 NVMe SSD 的裸金属数据库相比,可能会出现性能差异。
④ 安全隔离的难度
容器共享操作系统内核。如果同一节点上的其他容器通过漏洞访问节点,数据库数据也可能面临风险。托管数据库服务在专用基础设施中隔离运行。
⑤ 许可证和操作工具兼容性
Oracle、MS SQL Server 等商业数据库在容器环境下的许可证策略复杂,官方支持水平通常低于裸金属环境。
🪵 那么日志(Log)数据库可以部署在 Kubernetes 上吗?
日志收集架构的特点
日志系统主要分为三个层次:
| 层级 | 职责 | 示例工具 |
| 收集代理 | 从每个 Pod/Node 收集日志 | Fluent Bit, Filebeat |
| 聚合/处理 | 解析、过滤、路由 | Fluentd, Logstash |
| 存储/查询 | 存储和搜索日志 | Loki, Elasticsearch, ClickHouse |
收集代理 — 以容器方式运行是自然的
像 Fluent Bit 这样的日志收集代理,通常以 DaemonSet 的方式部署是标准模式。DaemonSet 会在每个节点上部署一个 Pod。这是因为它的职责是访问节点级别的日志文件(/var/log/containers/)并收集日志。
# Fluent Bit DaemonSet 核心部分
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
app: fluent-bit
template:
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:2.2
volumeMounts:
- name: varlog
mountPath: /var/log # 挂载主机日志目录
readOnly: true
- name: containers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/lib/docker/containers
代理本身不存储状态。即使 Pod 宕机,重新启动后也能从该时间点开始收集日志(可能会有轻微的收集空白,但并非致命)。
日志存储数据库 — 部署位置取决于需求
将日志存储数据库(例如:Loki, Elasticsearch)部署在 Kubernetes 上,其可接受范围比生产数据库更广。
原因如下:
- ✅ 日志即使部分丢失,通常也不会对业务造成致命影响
- ✅ 日志数据并非不可再生的原始数据(源头在应用程序中)
- ✅ Loki 和 Elasticsearch 都提供官方 Helm Chart,支持 Kubernetes 环境
- ✅ Grafana + Loki + Fluent Bit 堆栈是 Kubernetes 原生日志记录的事实标准
但是,如果日志具有法律保留义务,情况就不同了。下一节将详细讨论。
⚖️ 法律问题 — 如何存储日志?
这部分在实践中容易被忽视,但非常重要。
韩国主要法律的日志保留义务
| 法律法规 | 对象 | 保留项目 | 保留期限 |
| 个人信息保护法 | 所有个人信息处理者 | 个人信息处理系统访问记录 | 至少6个月(1万名以上或敏感信息:2年) |
| 信息通信网法 | 信息通信服务提供者 | 个人信息处理者访问记录 | 至少6个月 |
| 电子金融交易法 | 金融机构、电子金融业者 | 电子金融交易记录 | 5年 |
| 电子商务法 | 在线购物中心等 | 合同·申请记录、支付记录等 | 5年(合同),3年(投诉处理) |
| 医疗法 | 医疗机构 | 诊疗记录、诊疗相关电算记录 | 10年(以诊疗记录簿为准) |
> 📌 个人信息保护法实施令第30条:访问记录的保留·检查义务。处理1万名以上信息主体或处理唯一识别信息·敏感信息的情况下,至少保留2年并每月检查一次。
为什么具有法律保留义务的日志不应仅保存在 Kubernetes 中
Kubernetes 内部的 PV 存在因基础设施变更、集群迁移、操作失误而删除的风险。具有法律保留义务的日志必须满足以下条件:
- ✅ 防止删除·篡改:访问控制 + 不可变存储(WORM, Write Once Read Many)
- ✅ 长期保存:在义务期限内稳定保存
- ✅ 搜索和审计:在保留机构或调查机构要求时可立即提供
推荐架构:建议采用双重结构,将从 Kubernetes 收集的日志长期保存在云对象存储(AWS S3、Azure Blob Storage、NCP Object Storage)中,而 Kubernetes 内部的日志数据库仅用于短期查询目的。
[Pod 로그]
→ Fluent Bit (DaemonSet, K8s 내)
→ Loki or Elasticsearch (K8s 내, 단기 조회용: 30~90일)
→ S3 / Azure Blob (장기 보관용, WORM 설정: 법정 기간)
💻 实践示例:Fluent Bit → S3 双重输出配置
# fluent-bit.conf — 同时将日志发送到 Loki(用于查询)和 S3(用于长期存储)
[SERVICE]
Flush 5
Daemon Off
Log_Level info
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
Refresh_Interval 5
# 输出 1: Loki (用于短期查询)
[OUTPUT]
Name loki
Match kube.*
Host loki.monitoring.svc.cluster.local
Port 3100
Labels job=fluentbit
# 输出 2: S3 (用于法律合规存储,长期)
[OUTPUT]
Name s3
Match kube.*
bucket my-log-archive-bucket
region ap-northeast-2
s3_key_format /logs/%Y/%m/%d/$TAG[4].%H%M%S.gz
compression gzip
use_put_object On
total_file_size 100M # 以 100MB 为单位打包存储
upload_timeout 600 # 每 10 分钟强制上传
⚠️ 注意事项 / 常见错误
① PV 删除失误
一个 kubectl delete pvc 命令就可能删除数据库卷。务必检查 reclaimPolicy: Retain 设置。
apiVersion: v1
kind: PersistentVolume
spec:
persistentVolumeReclaimPolicy: Retain # ← 必须设置为 Retain
② 赋予日志收集代理过多权限
向 Fluent Bit 授予 cluster-admin 权限存在安全风险。请根据最小权限原则,仅授予必要的 RBAC 权限。
③ 仅将法律保留日志保存在 K8s 集群内部
如果集群被删除或 PV 丢失,将无法进行审计响应。务必配置上述的双重存储结构。
④ 未确认日志是否包含个人信息
如果 API 请求日志、错误日志中包含姓名、电子邮件、IP 地址等个人信息,那么该日志本身就属于个人信息处理。必须根据个人信息保护法明确定义处理目的、保留期限和销毁标准。
✅ 总结 / 结束语

分类 Kubernetes 上运行 推荐替代方案
| 分类 | 在 Kubernetes 上运行 | 推荐替代方案 |
| 生产数据库 | ⚠️ 可能,但运维负担大 | 托管数据库服务(RDS, Azure DB 等) |
| 日志收集代理 | ✅ 推荐(DaemonSet 模式) | — |
| 日志存储数据库(短期) | ✅ 可能(Loki, ES) | — |
| 法律保留义务日志 | ❌ 仅在 K8s 上存储有风险 | 对象存储 + WORM 并行 |
核心摘要:
- 🐳 生产数据库:与 Kubernetes 分离。利用托管服务。
- 🪵 日志代理:以 DaemonSet 方式部署在 Kubernetes 上是标准做法。
- 📦 日志存储数据库:短期查询用在 K8s 内部;具有法律保留义务的日志单独存储在对象存储中。
- ⚖️ 法律义务:查阅相关法律(如个人信息保护法、电子金融交易法),遵守保留期限和方式。
下一步,建议您尝试使用 Helm 直接配置 Grafana + Loki + Fluent Bit 堆栈。

发表回复