K8s基础知识
- K8S系列
- 2024-03-27
- 1162热度
- 0评论
ConfigMap和secret的区别
基础信息
ConfigMap 和 Secret 都是用来将配置数据与应用程序镜像分离的 Kubernetes 对象,它们的核心目的都是实现应用的配置解耦和可移植性。
重点:这2个都是一种资源对象,目的相同,只不过实现的方式不一样
|
特性
|
ConfigMap
|
Secret
|
|
用途
|
存储非敏感配置数据(如配置文件、环境变量)
|
存储敏感数据(如密码、令牌、证书)
|
|
数据编码
|
明文存储(Base64 编码仅用于传输)
|
强制Base64 编码(非加密)
|
|
安全性
|
无加密,适合公开配置
|
有基本的访问控制,非加密存储,但可配合加密插件(如 KMS)
|
|
使用方式
|
环境变量、命令行参数、挂载为文件
|
同 ConfigMap,也可用于镜像拉取凭证
|
|
类型
|
无类型限制
|
有多种类型(如Opaque、kubernetes.io/dockerconfigjson、tls等)
|
|
大小限制
|
1MB(默认 etcd 限制)
|
同 ConfigMap
|
重点说明
- Secret 并不是加密的:默认只是使用 Base64 编码了,etcd 中仍是明文。要真正加密,需启用 Encryption at Rest。
- ConfigMap 不适合存密码:即使不是加密,也不应该将敏感信息放入 ConfigMap。
- Pod 使用方式类似:都可以通过环境变量或卷挂载使用。
总结来说就是:ConfigMap保存公开的配置,Secret存机密配置信息;但是Secret 只是“稍微藏了一下”(base64),并不是“加密”。
详细说明
ConfigMap:
- 数据内容一般是:配置文件(如 .json, .properties, .xml),环境变量值,命令行参数等。
- 示例:应用的服务端口号、日志级别、功能开关、外部 API 的 URL。
Secret:
- 数据内容一般是:密码、数据库连接字符串、API 密钥、TLS 证书、SSH 私钥、OAuth tokens 等。
- 示例:MySQL 数据库的 root 密码、访问 AWS S3 的 access_key 和 secret_key。
数据编码与安全性
ConfigMap:
- 数据以纯文本形式存储。
- kubectl get configmap <name> -o yaml 命令中,你可以直接看到数据的原始内容。
Secret:
- 数据默认以 Base64 编码的形式存储。
- kubectl get secret <name> -o yaml 命令中,data 字段下的值是 Base64 编码后的字符串。
Base64 是一种编码方式,而非加密方式。它可以被轻松地解码还原为原始数据。因此,Secret 本身并不提供强大的安全保证。它更像是一种“障眼法”,防止敏感信息被无意中看到。
# echo -n 'SGVsbG8gV29ybGQh' | base64 -d #直接输出# base64 -d <<< 'SGVsbG8gV29ybGQh' > output.txt #输出到文件 使用一些简单的命令,就可以直接看到原始的数据
使用方式
两者在使用方式上高度相似,都可以通过以下方式挂载到 Pod 中:
- 环境变量:valueFrom.configMapKeyRef / valueFrom.secretKeyRef
- 卷挂载:将整个 ConfigMap 或 Secret 作为文件或目录挂载到容器中。
当作为卷挂载时,Secret 的每个 data 键值对会被解码为明文文件,而 ConfigMap 的文件内容就是原始明文。
【pod使用示例】
【ConfigMap内容】
# cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
data:
# 像配置文件一样的内容
app.properties: |
feature.x.enabled=true
log.level=INFO
# 简单的键值对
database.url: "jdbc:mysql://prod-db-host:3306/myapp"
# kubectl create -f configmap.yaml
# kubectl get configmap my-app-config -o yaml
# 你会看到 database.url 的值是清晰的明文。
【Secret内容】
# echo -n "MySuperSecretPassword123!" | base64
# 输出:TXlTdXBlclNlY3JldFBhc3N3b3JkMTIzIQ==
# cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: my-app-secret
type: Opaque # 通用类型
data:
database.password: TXlTdXBlclNlY3JldFBhc3N3b3JkMTIzIQ==
# kubectl create -f secret.yaml
# kubectl get secret my-app-secret -o yaml
# 你会看到 database.password 的值是 Base64 编码后的字符串。
上面创建ConfigMap和Secret之后,接下来在Pod中使用它们
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: app
image: my-app:latest
env:
- name: DB_URL # 来自 ConfigMap
valueFrom:
configMapKeyRef:
name: my-app-config
key: database.url
- name: DB_PASSWORD # 来自 Secret
valueFrom:
secretKeyRef:
name: my-app-secret
key: database.password
volumeMounts:
- name: config-volume
mountPath: "/etc/app"
volumes:
- name: config-volume
configMap:
name: my-app-configr
这个configmap除了环境变量的方式,还使用了mount挂载的方式,那么挂载之后的效果是:
- 不是生成/etc/app/config-volume 这样的文件,这是错误的理解,要注意
- 在容器内部,/etc/app这个目录下会生成2个文件
/etc/app/
├── app.properties
└── database.url
这2个文件的内容分别是上面configmap中定义的
特别注意,在挂载secret的时候,也是和configmap一样会生成这些文件,但是Secret 中的 Base64 编码数据在挂载时会自动解码为原始数据
也就是说,如果这里挂载的my-app-secret,那么
/etc/app/
└── database.password
# cat database.password
MySuperSecretPassword123!
k8s的服务发现
Kubernetes服务发现是集群内服务间动态寻址和通信的核心机制,它主要解决了Pod IP地址动态变化导致的服务访问问题。下面这个表格汇总了其核心机制与组件:
|
机制/组件 🛠️
|
核心原理 🔍
|
适用场景 📋
|
|
Service
|
为一组Pod提供
稳定的虚拟IP
(ClusterIP)和端口
|
集群内部服务间通信
|
|
DNS解析
|
集群内置的
CoreDNS
为Service生成DNS记录(格式:
..svc.cluster.local),通过域名访问服务
|
推荐方式,集群内服务发现
|
|
kube-proxy
|
运行在每个节点上,通过iptables或IPVS规则,将发往Service虚拟IP的流量负载均衡到后端Pod
|
流量转发与负载均衡
|
|
Endpoints
|
动态维护与Service关联的
健康Pod的IP和端口列表
|
服务后端详情,供kube-proxy使用
|
工作流程详解
当你创建一个Deployment和与之关联的Service时,服务发现的完整流程便启动了:
1、Pod注册:你的Pod实例被调度到节点上,kubelet会将其IP和端口等信息注册到API Server。
2、Service与Endpoints:你定义的Service通过标签选择器(Label Selector)匹配后端Pod。Kubernetes会自动创建并维护一个同名的Endpoints对象,其中包含所有健康Pod的IP和端口列表。当Pod发生增减或重启时,Endpoints会动态更新。
3、DNS记录发布:集群的DNS组件(如CoreDNS)会监测Service的创建,并为其生成一条DNS记录。例如,一个名为 user-service 在 default 命名空间的服务,其完整域名就是 user-service.default.svc.cluster.local。
4、流量转发:当集群内其他Pod(例如 api-gateway)试图通过上述域名访问 user-service 时:
- 请求首先被发送到CoreDNS进行解析,得到Service的ClusterIP。
- 请求随后被发往该ClusterIP。
- kube-proxy在节点上配置的网络规则(如iptables)会拦截到目标为ClusterIP的流量,并根据负载均衡算法(如轮询)将其转发到Endpoints中记录的某个具体Pod。
核心服务类型
Service有多种类型,以适应不同访问需求:
- ClusterIP:默认类型。为服务分配一个仅在集群内部可以访问的虚拟IP,用于服务间内部通信。
- NodePort:在ClusterIP基础上,在每个Node节点上开放一个静态端口(范围:30000-32767)。通过 <NodeIP>:<NodePort> 可以从集群外部访问服务。
- LoadBalancer:通常与云提供商(如AWS、GCP)的负载均衡器集成,为服务分配一个外部负载均衡器的IP地址,使服务能够直接从外部互联网访问。
- Headless Service:一种特殊类型的服务,通过设置 clusterIP: None 来创建。它没有集群IP,DNS查询会直接返回后端所有Pod的IP地址列表。这对于有状态应用(如Kafka、Elasticsearch集群)或需要直接与特定Pod通信的场景非常有用。
高级模式与选择建议
- 服务网格(Service Mesh):对于复杂的微服务架构,可以考虑使用服务网格(如Istio)。它通过在每个Pod边注入一个Sidecar代理,提供了更细粒度的流量管理、安全的服务间通信、可观测性和弹性能力。
- 多集群服务发现:当服务需要跨多个Kubernetes集群时,可以使用像Submariner或KubeFed这样的方案,它们可以同步集群间的服务信息。
选择服务发现方式的简单指引:
- 绝大多数集群内部服务通信:使用 Service + DNS 的方式。
- 需要直接获取所有后端Pod地址(如数据库集群、自定义负载均衡):使用 Headless Service。
- 需要从外部访问服务:根据环境选择 NodePort(本地测试)或 LoadBalancer(云环境生产部署)。
- 需要高级流量管理、链路追踪、熔断等:考虑引入 服务网格。
容器化底层知识
CRI
docker
namespace
context
cgroup
k8s基本概念和术语
pause容器作用
k8s必知必会的知识点
service是怎么和pod关联的
cpu的0.1是绝对值,不是相对值,只是表示0.1个cpu,不管是单核还是多核cpu
关于endpooint
首先,要知道不是所有 Pod 都会有对应的 Endpoint。
只有满足下面两个条件,Pod 的 IP 才会被写进 Endpoints(或 EndpointSlice):
- 存在带有 spec.selector 的 Service;
- 该 Pod 的标签完全匹配这个 selector,并且处于 Ready 状态(除非 Service 显式设置了 publishNotReadyAddresses: true)。
没有 Service,或者标签对不上,Pod 就不会出现在任何 Endpoint 记录里。
因此,“有没有 Endpoint”取决于 Service 的 selector 是否选中了它,而不是 Pod 本身
在 Kubernetes 里,Endpoint 对象并不是“手动”写出来的,而是由集群里的一个专门控制器——EndpointController——持续、自动地“填充”出来的。
它的数据源确实是 Service 的配置(spec.selector),但“产生”过程是控制器监听 Pod 变化后把匹配的 Pod IP+端口写进同名 Endpoint 对象,而不是 Service 一创建就一次性生成。下面把整条链路拆开说明。
谁负责“产生”Endpoint
- 组件kube-controller-manager 里的 **EndpointControllerEndpointController(以及 1.21+ 并启用了 EndpointSlice 时的 EndpointSliceController)。
工作方式:
- List/Watch 所有 Service 和 Pod;
- 每 10s 全量同步一次(可配),同时监听增量事件;
- 对每条 Service,计算 spec.selector 匹配的 Pod;
- 把 Pod 的 podIP + containerPort(或 targetPort)写进同名 Endpoints 对象;
- 如果 Pod 新增、删除、IP 变、就绪态变,控制器立即 patch 对应的 Endpoints
- 这里还有后续:
- kube-proxy / CNI Ingress / Service Mesh 等组件 Watch Endpoints
- 生成 iptables/IPVS/eBPF/Envoy 规则
- 集群内外流量按规则负载均衡到后端 Pod。
与 Service 配置
- selector 是“筛选条件”:Service 通过 spec.selector 告诉控制器“哪些 Pod 是我的后端”。
- 无 selector 的 Service(例如你想手动指向外部数据库,或引用另一个 Service)不会产生任何 Endpoint 记录;这时需要用户自己创建同名的 Endpoints(或 EndpointSlice)对象,把外部 IP+端口写进去。
- 端口映射规则:
- Service 的 spec.ports[].targetPort 决定 Endpoints 里保存的容器端口号;
- 如果 Pod 里同名端口不存在,Endpoints 对象仍旧会被生成,只是里面保存的 IP:port 实际上在 Pod 侧没有进程在监听;
一句话回答
Endpoint 是根据Endpoint 是根据 Service 的 selector 配置由 EndpointController 持续监听 Pod 后自动创建/更新的;
没有 selector 的 Service 不会自动产生 Endpoint,需要用户手动维护。
安装部署
启动参数
核心组件
apiserver
etcd
coredns
kubelet
kube-proxy
control-manager
scheduler
ingress
k8s网络
iptables
ipvs
kube-proxy转发过程
各网络插件
k8s安全设置
ssl/tls证书
serviceaccount
secret
configmap
RBAC
k8s的卷和存储
k8s的自动扩缩容
如何用k8s的statefulset部署有状态服务
如何自定义crd
k8s的API
client-go
informer
list、watch机制
k8s的监控报警
cAdvisor监控
p8s+grafana
设计k8s高可用架构
k8s常见故障处理
k8s常见运维操作
1、运维工具
kubectl什么的
2、版本升级
3、重启服务注意事项
4、亲和性设置
5、集群扩缩容
6、节点故障处理
7、node的隔离和恢复
企业生产环境实战
对GPU的支持
ebpf
资源配额,limitrange和resourcequota
k8s的资源管理
CRD扩展
CRD资源对象定义和CRD控制器
Isito
service mesh
