K8s基础知识

 

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