资讯动态

Kubernetes Secret 核心用法与 CKAD 考试实战解析

发布时间:2026/9/16 23:40:35 来源:尧图企业网站定制
CKAD-CN 备考系列走到第 12 篇终于轮到 Secret 这个高频对象。如果你已经跟着前面的内容把 Pod、Deployment、Service、ConfigMap 都练得差不多了Secret 应该是接下来投资回报率最高的一小块知识点。它本身不难结构也不复杂但考试里很少单独出题而是经常作为 Deployment、Ingress、ServiceAccount 这些综合任务里的“隐蔽环节”出现给 Deployment 注入数据库密码、给 Ingress 挂载 TLS 证书、给私有镜像仓库配置拉取凭据全都绕不开 Secret。更关键的是Secret 一旦出错丢的不只是一个对象的分而是整道多步骤应用题的分。之前看过不少备考者的反馈说看到 Secret 的 YAML 第一反应是“这不就是 ConfigMap 套了一层 base64 吗”我备考时也这么想过但真正上手做题才发现创建命令的多参数写法、dry-run 的输出格式、挂载进 Pod 后的权限表现都和 ConfigMap 有明显区别。这篇我先把“是什么、怎么建、怎么用”讲透再给一道贴近真实考试风格的模拟题带你走完整链路。内容按计划拆成两篇本篇是 Secret - 1下一篇再处理 docker-registry、TLS、ServiceAccount 令牌以及更多进阶场景。1. 为什么 Secret 在 CKAD-CN 里算“送分题”又总有人在细节上丢分1.1 Secret 与 ConfigMap 的本质边界不是简单编码很多教程会把 Secret 描述成“加密版的 ConfigMap”这个说法不能说错但很容易误导人。Secret 的数据字段确实要求填 base64 编码后的字符串但 base64 只是一种编码方式不是加密任何人拿到这份 YAML 都能用一条命令解出来。真正的安全边界来自三个方面RBAC 权限控制、etcd 中的存储策略、节点上的存放方式。考试不会要求你配置 etcd 加密但你得清楚 Secret 和 ConfigMap 在使用语义上的差别。举一个实际区别ConfigMap 里的data可以直接写明文Secret 里的data必须写 base64但 Secret 额外提供了stringData字段写 YAML 时可以直接填明文kubectl 会在提交时帮你编码。另一个区别是节点存储ConfigMap 挂载到 Pod 后就是普通文件Secret 挂载后 kubelet 通常将它放到 tmpfs 内存文件系统里不会直接落到宿主机磁盘。这也是为什么 Secret 适合放密码、令牌、证书ConfigMap 适合放 nginx.conf、application.yml 这类非敏感配置。对比项ConfigMapSecret典型用途配置文件、环境变量等非敏感数据密码、密钥、证书、镜像仓库凭据data 字段明文Base64 编码后的内容stringData 字段不支持支持写 YAML 更方便节点存储普通文件优先 tmpfs 内存文件系统命名空间隔离有有Pod 引用方式env / volumeenv / volume1.2 考试中的出现方式单独出题少嵌套任务多从真题分布来看纯粹考“创建一个 Secret”的题目并不多见更常见的是这种多步骤任务在指定命名空间创建 Deployment镜像用 nginx:1.25要求从已有 Secretdb-secret中读取DB_PASSWORD作为环境变量注入容器。这类题目考察的不只是 Secret 本身还有你对 Pod 字段、Deployment 层级、命名空间参数的熟练程度。所以备考 Secret 时别只背创建命令一定要把“创建 Secret → 在 Pod 中引用 → 验证效果”整条链路练熟。我在模拟环境里见过有人花两分钟就把 Secret 建好了却在写 Pod 的env.valueFrom.secretKeyRef时把secretKeyRef拼错成configMapKeyRef整题白做。细节决定这题是送分还是送命。2. Secret 类型连着出题先把 Opaque 之外的类型分清2.1 内置类型一览与各自的 data 结构Secret 不是只有一种“花名册式”的存放格式它按使用场景分成好几种内置类型考试里最常出现的是下面四个Secret 类型用途data 里常见的键Opaque任意敏感键值密码、API Token 等任意自定义键kubernetes.io/dockerconfigjson私有镜像仓库登录凭据.dockerconfigjsonkubernetes.io/tlsTLS 证书常用于 Ingresstls.crt、tls.keykubernetes.io/service-account-tokenServiceAccount 的令牌token、ca.crt、namespaceOpaque是默认类型也是你在kubectl create secret generic里创建的那个。它没有固定结构想放什么键都行适合“用户名密码”“API keysecret key”这类自定义组合。kubernetes.io/tls固定要求tls.crt和tls.key这两个键给 Ingress 用。kubernetes.io/dockerconfigjson则把 Docker 的~/.docker/config.json内容整体塞进.dockerconfigjson字段里供 Pod 的imagePullSecrets引用。Service Account 令牌这个类型比较特殊大多数情况下是系统自动创建的你不需要手工写出这个 Secret。但你要知道它的存在当集群为 ServiceAccount 分配长期令牌时会生成一个对应类型的 Secret里面包含ca.crt和token。新版 Kubernetes 里这种行为已经在发生变化考试如果涉及 ServiceAccount 相关概念建议顺便看下当前版本对自动创建 Secret 的策略。2.2 怎么快速判断题目需要哪种类型做题时最容易纠结的是“应该用 generic 还是 docker-registry 还是 tls”。我的判断方法是看题目给的信息结构题目说“创建 Secret包含 username 和 password” → 用generic题目说“配置 imagePullSecret 拉取私有镜像” → 用docker-registry题目说“给 Ingress 创建 TLS Secret” → 用tls这三类对应三套不同命令命令参数差异很大。generic用--from-literal或--from-filedocker-registry用--docker-server、--docker-username、--docker-passwordtls用--cert和--key。如果你把docker-registry的命令参数用在generic上kubectl 会直接报未知参数。反过来如果在私有仓库场景用了 generic又容易因为.dockerconfigjson格式不对导致拉取镜像失败。所以拿到题目先判断类型再动手。3. 创建 Secret 的三条路线命令、文件、YAML考场怎么选3.1 命令式创建和 --dry-run 的组合拳CKAD-CN 考试允许使用 kubectl而且不限制你用命令式还是声明式。我的经验是Secret 这种数据量小、键值结构清晰的对象用命令式创建效率最高但最好配合--dry-runclient -o yaml输出一份 YAML 再应用这样既能留下“审计痕迹”也方便在出错时检查。kubectl create secret generic db-secret \ --from-literalusernameadmin \ --from-literalpasswordS3curePass \ -n dev --dry-runclient -o yaml | kubectl apply -f -这条命令的逻辑是先用kubectl create生成一个 Client 端的 YAML不真正提交到集群然后通过管道直接kubectl apply。很多人会问为什么不直接kubectl create secret ...因为直接 create 也可以但一旦题目要求“将 YAML 保存到 /opt/xxx.yaml”你就需要 dry-run 输出到文件kubectl create secret generic db-secret \ --from-literalpwdK8s#2024 \ -n dev --dry-runclient -o yaml secret.yaml kubectl apply -f secret.yaml如果你有多个键值对可以连续写多个--from-literal。如果密码里包含$、#、空格这些特殊字符务必用单引号包起来防止 shell 解析。3.2 声明式 YAMLdata 与 stringData 的取舍当你需要把 Secret 写进考试提供的 YAML 文件或者想控制immutable等字段时手写声明式 YAML 更稳妥。基本结构如下apiVersion: v1 kind: Secret metadata: name: db-secret namespace: dev type: Opaque data: username: YWRtaW4 password: UzNjcmVQYXNzdata下的值必须是 base64。如果你想在 YAML 里直接写明文用stringDataapiVersion: v1 kind: Secret metadata: name: db-secret namespace: dev type: Opaque stringData: username: admin password: S3curePassstringData是写给人看的真正提交后kubectl 会把它转换成data字段并 base64 编码你可以用kubectl get secret db-secret -n dev -o yaml看到转换结果。注意同一个 Secret 中data和stringData不建议对同一个键重复指定后者的优先级会覆盖前者容易让你困惑到底最终值是什么。3.3 一个命令创建多组键值对时最容易错的字段命令式创建有几种数据来源需要分清--from-literal直接给键值对适合少量手动输入--from-file从文件读取内容文件名作为键文件内容作为值--from-env-file从一个多行键值文件批量导入实际考试中--from-file的坑在文件名会自动成为键名。比如你执行kubectl create secret generic ssh-secret --from-file~/.ssh/id_rsa生成的 Secret 键名是id_rsa不是你想当然的ssh-privatekey。如果需要自定义键名要写成--from-filessh-privatekey~/.ssh/id_rsa这种格式冒号或等号前的部分才是键名。这个问题很多人直到kubectl exec进容器里发现找不到文件才意识到。4. Pod 中使用 Secret 的两种方式环境变量和挂载卷4.1 secretKeyRef 精确抽取与 envFrom 批量注入考试里最常见的用法是环境变量注入。单个键的精确引用写法如下apiVersion: v1 kind: Pod metadata: name: secret-pod namespace: dev spec: containers: - name: app image: nginx:1.25 env: - name: DB_USERNAME valueFrom: secretKeyRef: name: db-secret key: usernamesecretKeyRef里的name指向 Secret 对象名key指向 Secret 里的数据键。这里有个容易写错的地方name是 Secret 的名称不是容器的名称也不是 namespace。如果你的 Secret 不在 Pod 同一个 namespacePod 根本起不来因为 Secret 是命名空间隔离的对象。如果 Secret 里有十几个键你想一次性全部注入环境变量用envFrom更省事envFrom: - secretRef: name: db-secretenvFrom会把每个键直接映射成环境变量名键名就是变量名。但它有个局限如果键名不合规比如包含短横线my-key它不能直接作为环境变量名这部分键会被跳过。因此当你想严格控制注入哪些变量、变量名跟键名不一致时老老实实用secretKeyRef逐个映射。4.2 挂载成文件items、defaultMode 与只读控制Secret 也可以挂载成文件对应用来说就像读配置文件一样自然。声明方式是在 Pod 的spec.volumes里声明 Secret 卷再在容器里volumeMountsspec: volumes: - name: secret-volume secret: secretName: db-secret defaultMode: 0400 items: - key: username path: db-user containers: - name: app image: nginx:1.25 volumeMounts: - name: secret-volume mountPath: /etc/app-secret readOnly: true这里有几个关键点不写items时Secret 里的每个键都会变成mountPath下的一个文件文件名就是键名。写items可以挑选键并用path自定义文件名。defaultMode控制文件权限默认是 0644。如果你希望容器内其他用户不能读取这些敏感文件设置成0400或0440。卷声明里用secret.secretName不是在 volumeMount 里指定 Secret 名称。4.3 环境变量不热更新、挂载卷会热更新这个差异是考点这是 Secret 在学习中最容易忽略、也最容易在综合题验证环节踩坑的地方。通过环境变量注入到容器里的 Secret 值在 Pod 运行期间不会随 Secret 更新而改变。你有两个选择重新创建 Pod或者干脆不要在更新 Secret 后傻等。考试时如果你修改了 Secret然后kubectl exec进同一个 Pod 看环境变量发现还是旧值别怀疑自己写错了这是设计行为。挂载成文件的 Secret 则会由 kubelet 定期同步更新默认周期大概在一分钟左右。只要 Secret 变了过一会儿容器里对应文件的内容也会变。但这个热更新有个例外如果你用了subPath单独挂载某个文件这个文件不会自动更新。考试里一般不会考到 subPath 这个层级但如果你在练习中遇到“文件内容没更新”的问题先检查是不是 subPath。另外引用不存在的 Secret 会导致 Pod 无法正常创建会停在CreateContainerConfigError。如果题目允许缺失可以给引用加optional: trueenv: - name: DB_USERNAME valueFrom: secretKeyRef: name: maybe-not-exist key: username optional: true加上optional后即使 Secret 不存在Pod 也能启动。5. 我在练习中踩过的真实坑位从 Base64 误解到命名空间5.1 Base64 不是加密但考纲确实喜欢测编解码kubectl create secret generic在生成 YAML 时会自动把--from-literal的值 base64 编码所以你用 dry-run 导出的 Secret YAML 里看到的值是一串结尾带的字符串不要以为是乱码。反过来如果你想手动改 YAMLdata 字段不填合法 base64apply 的时候 API Server 会直接报a valid base64 encoded data。验证实际值时最常用的命令是kubectl get secret db-secret -n dev \ -o jsonpath{.data.username} | base64 -d这个组合在考试验证阶段非常实用。我建议你在练习环境里多敲几遍别只会kubectl describe secret。kubectl describe只展示键名不会展示值这是刻意的安全设计但也意味着它不适合你验证值到底对不对。用jsonpath配合base64 -d才能看到明文。5.2 1MiB 限制背后的设计逻辑Secret 在 API Server 侧有大小限制单个 Secret 对象不适合存放过大的数据。如果你试图把几 MB 的配置文件塞进 Secret创建会失败因为底层存储 etcd 对单个对象的体积有限制默认请求体大小约为 1.5MiBSecret 官方建议也控制在 1MiB 以内。这个限制反过来提醒你Secret 不是给你塞大文件的它最适合存放几百字节到几 KB 的密码、令牌、证书。考试里遇到“把某个配置文件转成 Secret”的需求注意看题目给的配置文件到底有多大如果异常大可能是题目故意挖坑让你思考到底该用 ConfigMap 还是 Secret。5.3 命名空间、dry-run 输出和 ServiceAccount 自动生成的混淆练习时最容易出现的问题之一是命名空间对不上。你用kubectl apply -f secret.yaml时没有指定-n当前 context 的 namespace 又不是题目要求的 namespace那么 Secret 就建错了地方。Pod 引用它的时候会找不到对象。我的习惯是要么在 YAML 的metadata.namespace里显式写要么每条命令都带-n不依赖默认 namespace。还有一个容易混淆的点新版本集群里 ServiceAccount 会自动生成或按需生成对应的 Secret名字看起来很长一串。你可能会在kubectl get secrets输出里看到一堆sa-token-xxxxx如果正在做的是普通 Opaque Secret 的题目别去动这些自动生成的 Secret也不要删删除可能导致 ServiceAccount 异常。你需要创建时用kubectl create secret重新起个新名字两者互不干扰。6. 一道贴近真实考试难度的 Secret 综合任务6.1 题目要求创建 Secret 并注入 Pod 环境变量和卷下面这道题是我按照 CKAD-CN 真题风格整理出来的综合练习建议先别看答案自己在模拟环境里做一遍题目内容创建命名空间ckad-secret在该命名空间下创建名为app-secret的 Secret类型为 Opaque包含以下键值DB_USERadminDB_PASSK8s#2024创建 Pod 名为secret-consumer镜像nginx:1.25将DB_USER注入为环境变量USERNAME将DB_PASS注入为环境变量PASSWORD将整个 Secret 挂载到容器的/etc/app-secret目录只读文件权限设为0400这个题目很典型它同时考察了 Secret 创建、命名空间、环境变量精确映射、卷挂载、权限控制五个点。你能独立跑通说明 Secret 的基本操作已经过关。6.2 我推荐的答题顺序和验证命令我的作答顺序是先创建 Secret再准备 Pod因为 Pod 引用 Secret 时要求对象必须存在虽然先写 Pod YAML 再创建 Secret 也不会出错但按依赖关系排序排查问题更顺手。第一步创建命名空间和 Secretkubectl create ns ckad-secret kubectl create secret generic app-secret -n ckad-secret \ --from-literalDB_USERadmin \ --from-literalDB_PASSK8s#2024第二步生成 Pod 的骨架 YAMLkubectl run secret-consumer --imagenginx:1.25 \ -n ckad-secret --dry-runclient -o yaml pod.yaml第三步编辑pod.yaml添加 env 和 volumeapiVersion: v1 kind: Pod metadata: name: secret-consumer namespace: ckad-secret spec: volumes: - name: app-secret-volume secret: secretName: app-secret defaultMode: 0400 containers: - name: secret-consumer image: nginx:1.25 env: - name: USERNAME valueFrom: secretKeyRef: name: app-secret key: DB_USER - name: PASSWORD valueFrom: secretKeyRef: name: app-secret key: DB_PASS volumeMounts: - name: app-secret-volume mountPath: /etc/app-secret readOnly: true注意kubectl run生成的名字是secret-consumer容器名默认跟 Pod 名一致这里即使手写 YAML命名也要保持一致避免不必要的困惑。第四步应用并验证kubectl apply -f pod.yaml kubectl get pod -n ckad-secret kubectl exec -n ckad-secret secret-consumer -- env | grep -E USERNAME|PASSWORD kubectl exec -n ckad-secret secret-consumer -- ls -l /etc/app-secret kubectl exec -n ckad-secret secret-consumer -- cat /etc/app-secret/DB_USER如果环境变量里能看到USERNAMEadmin、PASSWORDK8s#2024挂载目录下有DB_USER和DB_PASS两个文件且权限是-r--------这题就稳了。你还可以尝试往里写文件应该会得到 Permission denied说明只读和权限都生效了。6.3 做完这题给下一篇 Secret 留下哪些进阶问题这道模拟题覆盖了 Opaque Secret 的灵魂内容但 CKAD-CN 的 Secret 考点远不止这些。下一篇我会重点展开docker-registry类型 Secret 的真实格式以及imagePullSecrets是怎么被 Deployment 使用的kubernetes.io/tls类型 Secret 在 Ingress 里的挂法证书和私钥的常见错误ServiceAccount 自动令牌 Secret 在新版 Kubernetes 中的变化immutable: true对 Secret 更新策略的影响如何通过 RBAC 控制 Secret 的读取权限以及为什么 Secret 默认不等于绝对安全最后说个备考心得Secret 本身不难难点是别把它当 ConfigMap 用。建议你在自己的练习环境里把同一个 Secret 分别用环境变量和卷各挂载一次观察更新后两者的表现差异。这种对比式练习远比背十遍命令更管用。等你把这些都跑熟了再看到“给 Deployment 注入数据库密码”这类题目基本就是看一眼就能动手的状态。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价