K8s Secret 认证失败:echo 换行符陷阱

2025-09-08

“一切看起来都对,但它就是不对!”
如果你在 K8s 中遇到了令人抓狂的 AuthenticationFailed (认证失败) 错误,并且发誓你的用户名密码绝不可能错,那么恭喜你,你可能遇到了今天的主角——一个由 echo 命令悄悄塞进你密码里的“隐形刺客”。

案发现场 🕵️‍♂️

你信心满满地创建了一个 Secret,准备给你的 MongoDB 提供认证信息。

第一步:生成 Base64 密码
你熟练地敲下命令:

echo username | base64
# 输出: dXNlcm5hbWUK

echo admin | base64
# 输出: YWRtaW4K

看起来完美无缺。

第二步:创建 Secret YAML
你把这些值填入 secret.yamldata 字段:

apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
data:
  mongo-root-username: dXNlcm5hbWUK  # <-- 看起来没问题
  mongo-root-password: YWRtaW4K     # <-- 看起来也没问题

第三步:启动应用,然后… 💥
你的应用日志开始疯狂报错:

MongoServerError: Authentication failed.```
你用 `kubectl exec` 潜入 MongoDB Pod 内部,用你记忆中的密码 `admin` 手动连接,依然失败!

## 真凶揭秘:隐形的换行符 `\n` 🔪

问题就出在 `echo` 命令上。默认情况下,`echo` 在输出你给它的字符串后,会非常“贴心”地在末尾**追加一个换行符 (`\n`)**。

所以,你进行 Base64 编码的真实内容其实是:
- `"username\n"`
- `"admin\n"`

当 MongoDB Pod 第一次启动时,它忠实地将自己的用户名和密码设置成了带有换行符的版本。而之后,无论是你的应用还是你手动连接,提供密码时都只输入了 `"admin"`。

在计算机眼中,`"admin"` 和 `"admin\n"` 是两个截然不同的字符串,就像你的通行证上写的是“张三 ”(多一个空格),而你报的名字是“张三”,门卫(MongoDB)自然不会放你进去!

## 解决方案:如何正确“亮证” ✅

### 方案一:使用 `stringData` (👑 王者之选,强烈推荐)

Kubernetes 提供了一个完美的字段 `stringData`,让你彻底告别手动编码的烦恼。你只需要提供明文字符串,K8s 会在后台帮你进行**正确的、不带换行符的** Base64 编码。

**【正确示例】**
```yaml
apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
stringData:  # <-- 使用 stringData,而不是 data
  mongo-root-username: "username"  # <-- 直接写明文,所见即所得
  mongo-root-password: "admin"

优点

  • 直观:配置清晰易读,维护方便。
  • 安全:避免了所有手动编码的坑。
  • 优雅:这才是 K8s 推荐的正确姿势。

方案二:手动修正 echo 命令

如果你坚持要手动编码,请务必给 echo 命令加上 -n 参数。-n 的意思就是 “do not output the trailing newline”(不要输出结尾的换行符)。

【正确命令】

echo -n username | base64
## 输出: dXNlcm5hbWU= (注意,和之前的不一样了!)

echo -n admin | base64
## 输出: YWRtaW4=

然后将这些正确的值填入 data 字段。

🚨 重要:如何“清理现场”并重启

仅仅修正并 apply Secret 是不够的!因为 MongoDB 的初始化脚本 (MONGO_INITDB_*) 只在数据库第一次创建时运行。你需要一次彻底的“重启”:

  1. 删除旧资源kubectl delete 掉旧的 Deployment, Service, Secret。
  2. 💥 删除持久化数据 (最关键一步!):如果你的 MongoDB 绑定了 PVC (PersistentVolumeClaim),必须删除它,否则旧的、带错误密码的数据会一直存在。
    kubectl delete pvc <your-mongodb-pvc-name>
  3. 重新部署:使用修正后(推荐 stringData 版本)的 YAML 文件,重新 kubectl apply

✨ 总结

  • 警惕 echo:在管道符 | 前使用 echo 时,永远先问自己:“我要不要那个换行符?” 大多数时候,你都应该使用 echo -n
  • 拥抱 stringData:在编写 Secret 时,stringData 应该是你的第一选择。它能让你从 Base64 的泥潭中解放出来。

记住这个小坑,下次再遇到类似问题,你就能像个老手一样,一眼看穿这个“隐形刺客”的把戏了!