docker-manifest: https://gitee.com/reed_chi/docker-manifest.git
k8s-manifest: https://gitee.com/reed_chi/k8s-manifest
git clone https://gitee.com/reed_chi/k8s-manifest
一、Pod
1. 初体验
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
owner: lxf
env: dev
spec:
containers:
- image: nginx:1.22.1
name: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
# 涉及的命令
kubectl apply -f nginx.yaml
kubectl get pod
kubectl get pod --show-labels
kubectl get pod -l owner=lxf
kubectl get pod -owide
2. 在yaml中为容器定义变量
apiVersion: v1
kind: Pod
metadata:
name: busy-pod
labels:
owner: xxhf
env: dev
region: beijing
tier: back
spec:
containers:
- image: busybox:latest
name: busy
imagePullPolicy: IfNotPresent
env:
- name: name
value: "lxf"
- name: address
value: "beijing"
command:
- /bin/echo
args:
- "NAME=$(name), ADDRESS=$(address)"
restartPolicy: OnFailure
kubectl logs busy-pod
kubectl exec -it busy-pod -- sh
3. pause 容器(Pause Container)
在 Kubernetes 中,初始化容器(Init Container)和 pause 容器(Pause Container)都是与主要业务容器(主容器)相关的辅助容器,但它们的作用和功能略有不同。
- pause 容器是每个 Pod 都会包含的一个特殊容器,它负责管理 Pod 网络命名空间和存储卷,并维持整个 Pod 的生命周期。
- pause 容器在 Pod 启动时首先创建,并在其他容器启动之前一直运行。
- 主要作用是为了让其他容器可以共享网络命名空间,通过 localhost 进行通信,并提供一个持久的进程以维持整个 Pod 的生命周期。
4. 初始化容器(Init Container)
-
初始化容器是一种特殊类型的容器,它会在 Pod 中的主要业务容器启动之前被依次执行。
-
初始化容器主要用于在主容器启动之前完成一些初始化任务,比如数据准备、环境设置、配置检查等。
-
每个初始化容器必须成功运行完毕后,才会依次执行下一个初始化容器或者主容器。如果初始化容器中任何一个失败,Pod 将会被重新启动。
正确
apiVersion: v1
kind: Pod
metadata:
name: init-pod1
labels:
app: init
spec:
containers:
- name: init-container
image: busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'until nslookup www.baidu.com; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox
command: ['sh', '-c', 'until nslookup www.163.com ; do echo waiting for mydb; sleep 2; done;']
模拟初始化容器错误
#第一次,将init-myservice中 nslookup 的地址修改成错误的。比如www.baidu.commmmmmm,发现Pod的状态一直卡在 Init 0/2;
#第二次,将init-mydb中 nslookup 的地址修改成错误的,比如www.163.commmmmm发现Pod的状态一直卡在 Init 1/2;
该Pod 包含了一个主容器和两个初始化容器 initContainers ,每个容器都使用了 busybox 镜像。
具体配置内容解释如下:
- 主容器 init-container 使用 busybox 镜像,并定义了一个命令,即打印 "The app is running!" 并休眠 3600 秒。
- 初始化容器 init-myservice 使用 busybox 镜像,并定义了一个循环命令,不断执行 nslookup www.baidu.com 命令直到成功为止。在每次查询失败时,会打印 "waiting for myservice" 的提示信息,并等待 2 秒后重试。
- 初始化容器 init-mydb 也使用 busybox 镜像,并且定义了类似的循环命令,不断执行 nslookup www.163.com 命令直到成功为止。同样地,在每次查询失败时,会打印 "waiting for mydb" 的提示信息,并等待 2 秒后重试。
kubectl delete pod init-pod1 --grace-period=0
[root@master-01 04-pod]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
busy-pod 0/1 Completed 0 31m
busybox 1/1 Running 0 34m
init-pod1 0/1 Init:1/2 0 9s
nginx-pod 1/1 Running 0 45
4. 钩子
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx:1.22.1
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
该 pod 定义了两个生命周期事件处理:
-
lifecycle.postStart钩子:在容器启动后执行的操作。在这里,postStart 钩子使用 exec 类型的操作,在容器启动后执行一个命令,将 "Hello from the postStart handler" 写入到 "/usr/share/message" 文件中。
preStop 钩子:在容器终止之前执行的操作。在这里,preStop 钩子同样使用 exec 类型的操作,在容器终止之前执行一个命令,使用 "/usr/sbin/nginx -s quit" 命令来优雅地关闭 Nginx 服务。 -
lifecycle.postStart钩子:postStart 钩子会在容器启动后立即执行,而 preStop 钩子会在容器终止之前执行。这些钩子可以用来执行一些额外的操作,比如注册服务、清理资源等。
kubectl apply -f lifexycle-demo.yaml
kubectl exec -it lifcecle-demo -- sh
# cat /usr/share/message
5. 容器探针
在 Kubernetes 中,探针(Probes)是用于监测容器状态和健康状况的机制,有三种类型的探针:存活探针(Liveness Probe)、就绪探针(Readiness Probe)和启动探针(Startup Probe)。这些探针可以帮助 Kubernetes 系统确定何时应该重启容器、是否应该将流量引导到容器以及何时认为容器已准备好接收流量。
在Kubernets中,有三种类型的探针:
- 存活探针(Liveness Probe): 存活探针用来检查容器是否正在运行。如果存活探针失败,Kubernetes 将认为容器不再正常工作,并尝试重新启动容器。这有助于确保应用程序在发生故障时能够及时重启。
- 就绪探针(Readiness Probe): 就绪探针用来检查容器是否已准备好接收流量。如果就绪探针失败,Kubernetes 将停止将流量发送到该容器,直到就绪探针再次成功。这有助于避免向尚未完全启动或初始化的容器发送流量。
- 启动探针(Startup Probe): 启动探针用于检查容器是否已经启动并且可以接收流量。与存活探针和就绪探针不同,启动探针是在容器启动时执行的,只会在容器启动过程中使用。一旦启动探针成功,就不再被调用。
通过配置这些不同类型的探针,您可以更好地管理和监控容器的运行状态,确保应用程序在 Kubernetes 集群中高效稳定地运行。
在 Kubernetes 中,有几种常见的探针方式用于检测容器的健康状态:
- HTTP 探针: 使用 HTTP 探针时,Kubernetes 会向容器发送 HTTP 请求,并根据返回的状态码来判断容器的健康状态。您可以配置 HTTP 探针来检查应用程序是否正常响应请求。即连接端口并发送 HTTP GET 请求。
- TCP 探针: TCP 探针通过尝试建立到容器指定端口的 TCP 连接来检测容器的健康状态。如果连接成功建立,容器被认为是健康的;否则,容器被认为是不健康的。即使用 TCP 协议尝试连接容器的指定端口。
- Exec 探针: Exec 探针通过在容器内部执行特定命令并检查返回状态来检测容器的健康状态。如果执行成功,则容器被认为是健康的;否则,容器被认为是不健康的。即执行一个Linux命令,比如 ps、cat 等等,和 container的 command字段类似。

apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
default.conf: |
server {
listen 80;
location /ready {
return 200 'I am OK!';
}
}
---
apiVersion: v1
kind: Pod
metadata:
name: probe-pod
spec:
containers:
- name: my-container
image: nginx:1.22.1
livenessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 20
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 30
periodSeconds: 10
startupProbe:
tcpSocket:
port: 80
initialDelaySeconds: 10
periodSeconds: 10
volumeMounts:
- name: nginx-conf-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-conf-volume
configMap:
name: nginx-conf
该Pod定义了三个探针,分别代表:
livenessProbe : 存活探针 ,用于检测容器内的服务或应用程序是否处于运行状态。
httpGet:执行HTTP GET请求以检查容器的健康状态。path:指定用于检查健康状态的端点路径,例如"/healthz"。port:指定用于检查健康状态的端口,例如80。
initialDelaySeconds:容器启动后多久开始执行第一次探针检测的延迟时间(单位:秒)。periodSeconds:探针检测的执行周期,即每隔多少秒执行一次检测。
readinessProbe: 就绪探针,用于检测容器内的服务或应用是否准备好接收流量。
httpGet:执行HTTP GET请求以检查容器的就绪状态。path:指定用于检查就绪状态的端点路径,例如"/readiness"。port:指定用于检查就绪状态的端口,例如80。
startupProbe:启动探针,用于在容器启动过程中检测服务的可用性,确保容器已经成功启动并准备好接收流量。
tcpSocket:执行TCP套接字连接以检查容器的启动状态。port:指定用于检查启动状态的端口,例如80。initialDelaySeconds:容器启动后多久开始执行第一次探针检测的延迟时间(单位:秒)。periodSeconds:探针检测的执行周期,即每隔多少秒执行一次检测。
通过对这些探针进行配置,你可以确保容器在启动后、运行期间和接收流量之前都处于健康的状态,从而提高应用程序的可靠性和稳定性。
kubectl get pod -w
kubectl describe probe-pod
kubectl logs probe-pod
6. 资源限制
如果一个Kubernetes集群中的Pod没有设置资源限制,Pod中的进程可能会无限制吃资源,导致该容器占用了过多的资源,可能会导致以下几种情况发生:
- 节点资源耗尽:如果容器泄漏导致该Pod消耗了过多的资源,例如CPU和内存,这可能会导致宿主节点的资源耗尽。当节点上的资源耗尽时,其他Pod也会受到影响,可能无法正常工作。
- 其他Pod受影响:由于资源被过度消耗,其他正常运行的Pod可能会受到影响,它们可能会经历性能下降或者甚至崩溃,导致整个集群的可用性下降。
- 自动调度失败:如果节点上的资源被该Pod占用完毕,新的Pod可能无法在该节点上调度,导致调度失败或者延迟。
- 集群不可用:如果所有节点都受到影响,整个Kubernetes集群可能会变得不可用,导致服务中断和应用不可访问。
- 系统可能会触发节点上的Pod驱逐(Eviction)机制。Pod驱逐是Kubernetes的一种自我保护机制,用于在节点资源不足时,确保集群的稳定性和可用性。
因此设置合理的资源限制是必不可少的操作。当一个 Pod 的资源使用超过了设置的限制(limits)时,Kubernetes 会对该 Pod 执行以下操作之一:
- OOM (Out Of Memory) 杀死:如果 Pod 使用的内存超过了设置的内存限制,Linux 内核可能会触发 OOM 杀死机制,强制终止该 Pod 中的某些进程,以释放内存。这可能导致 Pod 中的应用程序意外终止。
- CPU Throttling:如果 Pod 使用的 CPU 超过了设置的 CPU 限制,Kubernetes 可能会对该 Pod 中的进程进行 CPU 限制,即降低其 CPU 使用率,以确保其他 Pod 能够获得足够的 CPU 资源。
apiVersion: v1
kind: Pod
metadata:
name: resource-pod
spec:
containers:
- name: nginx
image: nginx:1.22.1
resources:
limits:
memory: "200Mi"
cpu: "500m"
requests:
memory: "100Mi"
cpu: "250m"
上述文件中创建了一个名为 "resource-pod" 的 Pod,其中包含一个运行 nginx 镜像的容器 "nginx"。在容器的 resources 字段下,我们定义了对内存和 CPU 的限制和请求。
limits定义了对资源的最大限制:memory: "200Mi"表示最大可用内存为 200MiB。cpu: "500m"表示最大可用 CPU 为 500 毫核(0.5 核)。
requests定义了对资源的请求:memory: "100Mi"表示请求 100MiB 的内存。cpu: "250m"表示请求 250 毫核(0.25 核)的 CPU。
7. 服务质量等级
服务质量等级(Quality of Service,QoS)在 Kubernetes 中也起着重要作用。在 Kubernetes 中,Pod 根据其请求的资源量和使用的资源情况,被分为以下三个 QoS 等级:
-
Guaranteed:这个 QoS 等级的 Pod 具有最高优先级,它们声明了自己的资源需求,并且 Kubernetes 能够保证这些资源一直可用。这意味着 Guaranteed Pod 不会因为节点资源不足而被终止。
- Pod 中的每个容器必须有内存 limit 和内存 request。
- 对于 Pod 中的每个容器,内存 limit 必须等于内存 request。
- Pod 中的每个容器必须有 CPU limit 和 CPU request。
- 对于 Pod 中的每个容器,CPU limit 必须等于 CPU request。
-
Burstable:这个 QoS 等级的 Pod 通常没有明确声明自己的资源需求,但它们设置了资源限制。在节点资源充足时,这些 Pod 可以使用超出其请求的资源量,但当节点资源不足时,它们可能会受到影响。
- Pod 不满足针对 QoS 类
Guaranteed的判据。 - Pod 中至少一个容器有内存或 CPU 的 request 或 limit。
- Pod 不满足针对 QoS 类
-
BestEffort:这个 QoS 等级的 Pod 没有设置资源请求和限制,它们将竞争节点上的剩余资源。在节点资源不足时,这些 Pod 很可能被首先终止,以保证 Guaranteed 和 Burstable Pod 的正常运行。
如果 Pod 不满足
Guaranteed或Burstable的判据,则它的 QoS 类为BestEffort。 换言之,只有当 Pod 中的所有容器没有内存 limit 或内存 request,也没有 CPU limit 或 CPU request 时,Pod 才是BestEffort。Pod 中的容器可以请求(除 CPU 或内存之外的) 其他资源并且仍然被归类为BestEffort。
因此,当节点资源不足时,Kubernetes 将优先保证 Guaranteed Pod 的资源需求,然后是 Burstable Pod,最后是 BestEffort Pod。管理员可以根据应用的重要性和资源需求来设置 Pod 的 QoS 等级,以确保关键应用能够获得足够的资源,保障其服务质量。
二、Namespace
1. 使用命令行创建命令空间
kubectl create namespace my-ns1
或kubectl create ns my-ns1
2. 使用yaml文件创建命名空间
apiVersion: v1
kind: Namespace
metadata:
name: my-ns1
kubectl apply -f my-ns1.yaml
3. 将pod放在指定命名空间
默认情况是将资源创建在 default 命空间
apiVersion: v1
kind: Pod
metadata:
namespace: my-ns1
name: demo-pod
#namespace: default
labels:
env: dev
app: app-name
tier: front
region: bj
spec:
containers:
- name: nginx
image: nginx:1.22.1
- name: redis
image: redis:latest
kubectl get ns
kubectl get pod -n my-ns1
kubectl get all -n my-ns1
kubectl delete ns my-ns1
三、 标签
在 Kubernetes 中,标签(Labels)是用来标识和分类资源对象的键值对。标签可以附加到 Kubernetes 中的各种对象(例如 Pod、节点、服务等),并且具有以下作用:
- 选择器:标签可以用作选择器,通过标签选择器(Label Selectors)来筛选出一组具有特定标签的资源对象。这对于创建较为复杂的控制器、服务发现、负载均衡等功能十分重要。
- 分组和分类:通过给资源对象打上不同的标签,可以方便地对它们进行分类和分组。这有助于组织和管理大规模的部署。
- 目标定位:标签可以帮助确定资源对象的属性和用途,从而更轻松地识别和定位特定的资源。
- 策略控制:基于标签,可以实现不同资源对象的调度策略、访问控制、监控和日志记录等功能,从而更好地管理应用程序和资源。
- 动态配置:标签可以用于动态配置和控制应用程序的行为,或者根据标签的变化触发自动化操作。
在 Kubernetes 中,您可以使用 kubectl 命令行工具执行以下操作来管理节点的标签:增加、删除、改变和查询。
1. 增加标签
kubectl label nodes <node-name> <label-key>=<label-value>
kubectl label node master-01 owner=lxf
2. 查看标签
#查询所有节点上的标签
kubectl get nodes --show-labels
#将< lable-name >单独列出
kubectl get node -L < label-name >
#仅列出具有< lable-name >标签的节点
kubectl get node -L < label-name >
3. 删除标签
kubectl label nodes <node-name> <label-key>-
kubectl label node master-01 owner-
4. 修改标签
kubectl label nodes <node-name> <label-key>=<new-label-value> --
四、Job && CronJob
1. Job
Job一般用于在集群中处单次的任务,如数据处理作业,需要从存储中读取数据、进行处理,然后将结果写回到存储中。通过创建一个 Job,Kubernetes 将确保 Pod 启动并运行该数据处理任务,直到任务成功完成。
apiVersion: batch/v1
kind: Job
metadata:
name: sleep-job
spec:
activeDeadlineSeconds: 30
backoffLimit: 2
completions: 4
parallelism: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: echo-job
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- sleep $(($RANDOM % 10 + 1)) && echo done
上述文件是一个 Kubernetes Job 的 YAML 配置示例,具体字段含义如下:
activeDeadlineSeconds:这个字段指定了 Job 运行的总时间限制,以秒为单位。在本例中,这意味着如果 Job 的所有 Pod 在 30 秒内无法完成,它们将被终止。
backoffLimit: 2:这个字段表示在 Job 失败时重试的次数上限。如果 Job 中的 Pod 失败,并且未达到 backoffLimit 次数上限,Kubernetes 将尝试重新启动该 Pod。
completions: 4:指定了需要成功完成的 Pod 的数量。在本例中,Job 期望有 4 个 Pod 成功完成任务后才认为任务完成。
parallelism: 2:指定允许同时运行的 Pod 的数量。在本例中,最多可以同时运行 2 个 Pod。
template: 包含了 Pod 模板的定义,定义了要运行的容器。
restartPolicy: OnFailure:定义了 Pod 的重启策略。在本例中,设置为 OnFailure,表示只有当容器以失败状态退出时才会重启。- containers:定义了要运行的容器的相关信息。
name: echo-job:容器的名称。image: busybox:latest:容器所使用的镜像。imagePullPolicy: IfNotPresent:指定在本地不存在该镜像时才会从远程仓库拉取。command:定义了容器的启动命令。在本例中,容器会执行一个 shell 脚本命令,随机休眠一段时间后输出 "done"。
因此,这个配置文件定义了一个 Job,该 Job 会创建 4 个 Pod,每次并行运行 2 个 Pod,每个 Pod 中的容器将随机休眠一段时间后输出 "done"。如果有任何 Pod 在 30 秒内无法完成,它们将被终止;失败的 Pod 最多会重试 2 次。
2. CronJob
虽然 Kubernetes 本身没有原生的定时任务功能,但是可以使用 CronJob(基于 Job 的定时任务)来实现定时执行任务。
apiVersion: batch/v1
kind: CronJob
metadata:
name: echo-cj
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: echo-cj
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/echo"]
args: ["hello", "world"]
上述文件是一个 Kubernetes CronJob 的 YAML 配置示例,让我为您解释其中的字段含义:
schedule: 这里指定了 CronJob 的执行计划,即任务应该每隔一分钟执行一次。Cron 表达式中的五个部分依次表示:分钟、小时、日期、月份、星期几。jobTemplate:定义了要运行的 Job 模板。spec:定义了 Job 的规范。template:定义了 Pod 模板。spec:定义了 Pod 的规范。restartPolicy: OnFailure,指定了 Pod 的重启策略为在失败时重启。containers:定义了要运行的容器的相关信息。name: echo-cj:容器的名称。image: busybox:latest:容器所使用的镜像。imagePullPolicy: IfNotPresent:指定在本地不存在该镜像时才会从远程仓库拉取。command: ["/bin/echo"]:定义了容器的启动命令,这里是执行/bin/echo命令。args: ["hello", "world"]:指定了传递给容器的参数,这里是hello和world。这意味着容器启动后将执行/bin/echo hello world这个命令。
因此,这个配置文件定义了一个名为 "echo-cj" 的 CronJob,它会每分钟执行一个 Job,该 Job 创建一个 Pod,并在其中运行一个输出 "hello world" 的 echo 命令。这样就实现了每分钟打印一次 "hello world" 的效果。
五、ConfigMap & Secret
在Kubernetes中,ConfigMap 和 Secret 都是用来存储敏感信息或配置数据的资源对象,它们可以被挂载到 Pod 中作为卷(volume)来提供应用程序所需的配置信息。
- ConfigMap:ConfigMap 用于存储非敏感的配置数据,比如环境变量、配置文件等。您可以通过创建 ConfigMap 来将配置数据与 Pod 分离,这样可以使配置更易于管理和更新。Pod 中的容器可以将 ConfigMap 挂载为卷,然后读取其中的配置数据。
- Secret:Secret 用于存储敏感数据,例如密码、token 等机密信息。Secret 对象会对存储的数据进行 Base64 编码,但并不提供加密功能。同样地,Pod 中的容器可以将 Secret 挂载为卷,然后安全地访问其中的敏感数据。
1. 创建
ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: info
data:
count: '10'
debug: 'on'
path: '/etc/systemd'
greeting: |
say hello to kubernetes.
say hi to the World.
data 部分包含了要存储在 ConfigMap 中的键值对数据
count: '10':表示一个名为 "count" 的键,对应的值是字符串 "10"。greeting: |:表示一个名为 "greeting" 的键,后面的|表示接下来会有多行文本内容。
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
namespace: default
data:
default.conf: |
server {
listen 80;
location / {
default_type text/plain;
return 200
'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\ndate: $time_iso8601\n';
}
location /ping {
return 200 "pongggggggggggggggggggggggggg";
}
}
default.conf: | : 表示一个名为 “default.conf” ,后面的 | 表示接下来会有多行文本内容,然后是实际的配置内容。
Secret
apiVersion: v1
kind: Secret
metadata:
name: user
data:
username: bXktdXNlcg==
password: MTIzNDU2
db: bXlzcWw=
注意事项:Secret中存储的要求使用bases64进行编码后的值。
#编码
echo -n "your_text_to_encode" | base64
#解码
echo -n "my-username" | base64 --decode
[root@master-01 06-configmap-secret]# echo -n "my-user" |base64
bXktdXNlcg==
[root@master-01 06-configmap-secret]# echo -n "bXktdXNlcg==" |base64 --decode
my-user[root@master-01 06-configmap-secret]#
[root@master-01 06-configmap-secret]# echo -n "123456" |base64
MTIzNDU2
[root@master-01 06-configmap-secret]# echo -n "MTIzNDU2" |base64 --decode
123456[root@master-01 06-configmap-secret]#
2. 以环境变量的方式使用
apiVersion: v1
kind: Pod
metadata:
name: env-pod
labels:
owner: lxf
env: dev
spec:
containers:
- name: busy
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sleep", "3000"]
env:
- name: COUNT
valueFrom:
configMapKeyRef:
name: info
key: count
- name: DEBUG
valueFrom:
configMapKeyRef:
name: info
key: debug
- name: USERNAME
valueFrom:
secretKeyRef:
name: user
key: username
- name: PASSWORD
valueFrom:
secretKeyRef:
name: user
key: password
[root@master-01 06-configmap-secret]# kubectl exec -it env-pod -- sh
/ #
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
/ # echo "$COUNT"
10
/ # echo "$DEBUG"
on
/ # echo "$USERNAME"
my-user
/ # echo "$PASSWORD"
123456
3. 以卷的形式使用
apiVersion: v1
kind: Pod
metadata:
name: vol-pod
labels:
owner: xxhf
env: dev
spec:
volumes:
- name: cm-vol
configMap:
name: info
- name: sec-vol
secret:
secretName: user
containers:
- name: busy
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sleep", "3000"]
volumeMounts:
- mountPath: /tmp/configmap
name: cm-vol
- mountPath: /tmp/secret
name: sec-vol
[root@master-01 06-configmap-secret]# kubectl exec -it vol-pod -- sh
/ #
/ # cd /tmp/configmap/
/tmp/configmap # ls
count debug greeting path
/tmp/configmap # cat *
10onsay hello to kubernetes.
say hi to the World.
/etc/systemd/tmp/configmap #
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod-vol
labels:
env: dev
app: nginx
spec:
volumes:
- name: nginx-vol
configMap:
name: nginx-conf
containers:
- name: nginx-container
image: nginx:1.22.1
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: nginx-vol
[root@master-01 06-configmap-secret]# kubectl get pod nginx-pod-vol -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-pod-vol 1/1 Running 0 109s 10.20.171.26 worker-01 <none> <none>
[root@master-01 06-configmap-secret]# curl 10.20.171.26
srv : 10.20.171.26:80
host: nginx-pod-vol
uri : GET 10.20.171.26 /
date: 2024-03-27T02:32:20+00:00
[root@master-01 06-configmap-secret]# curl 10.20.171.26/ping
pongggggggggggggggggggggggggg[root@master-01 06-configmap-secret]#
4. 是否支持热更新
- 以环境变量形式使用的不支持热更新;
- 以卷的形式使用的支持热更新。
5. Secret的种类
在 Kubernetes 中,Secret 是用来存储敏感数据的对象,例如密码、API 密钥、证书等。Kubernetes 提供了几种不同类型的 Secret,以满足不同的使用场景和需求。以下是 Kubernetes 中常见的几种 Secret 类型:
- Opaque Secrets(不透明 Secrets):这是最常见的 Secret 类型,用于存储任意类型的密钥-值对。这些密钥-值对可以是任何二进制数据,例如用户名、密码等。
- Docker Registry Secrets(Docker 注册表 Secrets):用于存储 Docker 镜像仓库认证信息,通常用于拉取私有镜像。
- TLS Secrets(TLS Secrets):用于存储 TLS 证书和私钥,用于加密通信或进行 HTTPS 配置。
- Service Account Tokens(服务账号令牌):由 Kubernetes 自动创建的 Secrets,用于将 ServiceAccount 与 Pod 关联起来以访问 Kubernetes API。
- Generic Secrets(通用 Secrets):类似于 Opaque Secrets,但提供了更多的灵活性,可以指定数据编码格式。
- SSH Secrets(SSH Secrets):用于存储 SSH 私钥和公钥,用于安全连接到 Pod 或容器。
- Token Secrets(Token Secrets):用于存储访问令牌或 API 密钥,用于验证身份或进行授权。
| 内置类型 | 用法 |
|---|---|
Opaque | 用户定义的任意数据 |
kubernetes.io/service-account-token | 服务账号令牌 |
kubernetes.io/dockercfg | ~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson | ~/.docker/config.json 文件的序列化形式 |
kubernetes.io/basic-auth | 用于基本身份认证的凭据 |
kubernetes.io/ssh-auth | 用于 SSH 身份认证的凭据 |
kubernetes.io/tls | 用于 TLS 客户端或者服务器端的数据 |
bootstrap.kubernetes.io/token | 启动引导令牌数据 |
[root@master-01 06-configmap-secret]# kubectl get secret
NAME TYPE DATA AGE
default-token-qnqmx kubernetes.io/service-account-token 3 25h
user Opaque 3 33m
[root@master-01 06-configmap-secret]#
Kubernetes 中的每个 Pod 都会自动关联一个 Service Account,并且会分配一个 Service Account Token 给该 Pod。这个 Service Account Token 是用来访问 Kubernetes API 的凭证,允许 Pod 在集群内进行一些操作,比如查询 API 对象、创建其他对象、或者与其他组件进行交互。
默认情况下,Pod 在创建时都会自动挂载一个 Service Account Token,并且这个 Token 会被放置在特定的路径下(通常是 "/var/run/secrets/kubernetes.io/serviceaccount")。Pod 中的容器可以使用这个 Token 来向 Kubernetes API 发送请求,进行认证和授权。
这个默认的 Service Account Token 可以让 Pod 在不需要额外身份验证的情况下与 Kubernetes API 交互,但同时也需要确保 Pod 只能进行其被授权的操作,以维护集群的安全性。
在 Kubernetes 中,每个命名空间都包含一个名为 "default" 的 Service Account。当 Pod 在特定命名空间中创建时,如果没有显式指定使用其他 Service Account,它们将自动使用该命名空间中的 "default" Service Account。
当 Pod 使用 "default" Service Account 时,Kubernete·s 会自动为该 Pod 分配一个名为 "default-token" 的 Secret。这个 Secret 包含了用于与 Kubernetes API 进行认证和授权的 Service Account Token。
部署Wordpress
apiVersion: v1
kind: Namespace
metadata:
name: my-wp
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-cm
namespace: my-wp
data:
DATABASE: 'db_wordpress'
USER: 'wordpress'
PASSWORD: '123456'
ROOT_PASSWORD: '123456'
---
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
namespace: my-wp
labels:
app: wordpress
role: database
spec:
containers:
- name: wp-mysql
image: mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
envFrom:
- prefix: 'MYSQL_'
configMapRef:
name: mysql-cm
---
apiVersion: v1
kind: ConfigMap
metadata:
name: wp-cm
namespace: my-wp
data:
HOST: 'mysql-service'
USER: 'wordpress'
PASSWORD: '123456'
NAME: 'db_wordpress'
---
apiVersion: v1
kind: Pod
metadata:
name: wp-pod
namespace: my-wp
labels:
app: wordpress
role: website
spec:
containers:
- name: wp-pod
image: wordpress:6
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
envFrom:
- prefix: 'WORDPRESS_DB_'
configMapRef:
name: wp-cm
---
apiVersion: v1
kind: Service
metadata:
name: wordpress-service
namespace: my-wp
spec:
selector:
app: wordpress
role: website
ports:
- protocol: TCP
targetPort: 80
port: 80
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
name: mysql-service
namespace: my-wp
spec:
selector:
app: wordpress
role: database
ports:
- protocol: TCP
targetPort: 3306
port: 3306
[root@master-01 07-wordpress-deploy]# kubectl get all -n my-wp
NAME READY STATUS RESTARTS AGE
pod/mysql-pod 1/1 Running 0 21m
pod/wp-pod 1/1 Running 0 21m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/mysql-service ClusterIP 10.123.218.173 <none> 3306/TCP 18s
service/wordpress-service NodePort 10.112.55.57 <none> 80:32585/TCP 7m3s
[root@master-01 07-wordpress-deploy]#
浏览器访问: http://192.168.17.110:32585
六、Deployment
Deployment 是一种用于定义 Pod 模板和控制 Pod 副本数量的资源对象。Deployment 可以确保指定数量的 Pod 始终在运行,并且可以实现滚动更新和回滚操作,以便进行应用程序的无缝更新和版本管理。
以下是 Deployment 的主要特点和功能:
- Pod 模板:
- Deployment 定义了一个 Pod 模板,其中包含容器镜像、环境变量、卷挂载等信息。根据这个模板,Deployment 会创建并管理多个 Pod 实例。
- 副本控制:
- Deployment 控制着 Pod 的副本数量,可以确保始终有指定数量的 Pod 在运行。如果某个 Pod 意外终止,Deployment 会自动创建新的 Pod 来替代。
- 滚动更新:
- 通过 Deployment,可以实现应用程序的滚动更新。您可以更新 Deployment 的 Pod 模板,然后 Deployment 会逐步替换现有的 Pod 实例,确保应用程序在更新过程中保持可用性。
- 回滚操作:
- 如果更新导致问题或错误,您可以使用 Deployment 进行回滚操作。Deployment 允许您回退到先前的版本,恢复应用程序的稳定状态。
- 扩展和收缩:
- 通过调整 Deployment 的副本数量,可以实现应用程序的水平扩展和收缩。根据负载情况,您可以增加或减少 Pod 的数量来满足需求。
1. 初体验
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
spec:
replicas: 2
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- image: nginx:1.22.1
name: nginx
env:
- name: name
value: "lxf"
- name: address
value: "beijing"
replicas:指定了要创建的 Pod 的副本数量为 2 个。selector:指定了用于选择 Pod 的标签选择器,这里选择了标签 "app: nginx-dep" 的 Pod。
2. 滚动更新
更新 Deployment 的 Pod 模板或副本数量时,Kubernetes 将创建一个新的 ReplicaSet 来控制新版本的 Pod,并逐步增加新版本的 Pod 实例数量,同时逐步减少旧版本的 Pod 实例数量。这个过程称为滚动更新。
v1
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf-v1
data:
default.conf: |
server {
listen 80;
location /ready {
return 200 'I am V1!';
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rollout-deployment
annotations:
kubernetes.io/change-cause: version=v1
spec:
replicas: 4
minReadySeconds: 30
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-container
image: nginx:1.22.1
volumeMounts:
- name: nginx-conf-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-conf-volume
configMap:
name: nginx-conf-v1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
revisionHistoryLimit: 10
annontation: 注解信息,将体现在rollout history中。minReadySeconds: 表示新创建的 Pod 需要在变为 Ready 状态之前等待的秒数。strategy:定义了更新策略,这里是 RollingUpdate 类型,表示使用滚动更新的方式。rollingUpdate:滚动更新的具体设置,包括最大 Surge 和最大不可用的 Pod 数量。maxSurge:表示允许超过副本数量的 Pod 数量,这里设置为 1 个。maxUnavailable:表示在执行滚动更新时最大允许不可用的 Pod 数量,这里设置为 0 个。
type:指定了更新策略的类型,这里是 RollingUpdate,表示滚动更新。revisionHistoryLimit: 表示保存的历史版本数量限制,这里设置为 10 个。
[root@master-01 rollout-update]# kubectl get pod -owide |grep rollout-deploy
rollout-deployment-797db549bd-5ms52 1/1 Running 0 91s 10.20.171.16 worker-01 <none> <none>
rollout-deployment-797db549bd-7chs8 1/1 Running 0 91s 10.20.171.11 worker-01 <none> <none>
rollout-deployment-797db549bd-df852 1/1 Running 0 91s 10.20.171.17 worker-01 <none> <none>
rollout-deployment-797db549bd-qsfbg 1/1 Running 0 91s 10.20.171.21 worker-01 <none> <none>
[root@master-01 rollout-update]# curl 10.20.171.16/ready
I am V1![root@master-01 rollout-update]# kubectl rollout history deployment rollout-deployment
deployment.apps/rollout-deployment
REVISION CHANGE-CAUSE
1 version=v1
[root@master-01 rollout-update]#
v2
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf-v2
data:
default.conf: |
server {
listen 80;
location /ready {
return 200 'I am V2!';
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rollout-deployment
annotations:
kubernetes.io/change-cause: version=v2
spec:
replicas: 4
minReadySeconds: 30
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-container
image: nginx:1.23.1
volumeMounts:
- name: nginx-conf-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-conf-volume
configMap:
name: nginx-conf-v2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
revisionHistoryLimit: 10
v3
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
default.conf: |
server {
listen 80;
location /ready {
return 200 'I am V3!';
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rollout-deployment
annotations:
kubernetes.io/change-cause: version=v3
spec:
replicas: 4
minReadySeconds: 30
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-container
image: bitnami/nginx
volumeMounts:
- name: nginx-conf-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-conf-volume
configMap:
name: nginx-conf
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
revisionHistoryLimit: 10
kubectl get pod -w
kubectl describe deployment http-update
kubectl rollout pause deployment http-update
kubectl rollout resume deployment http-update
kubectl rollout history deployment http-update
[root@master-01 rollout-update]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
rollout-deployment-797db549bd-bggvf 1/1 Running 0 13s
rollout-deployment-797db549bd-hg7xq 1/1 Running 0 13s
rollout-deployment-797db549bd-hplxm 1/1 Running 0 13s
rollout-deployment-797db549bd-nr2j8 1/1 Running 0 13s
rollout-deployment-778588fc9c-t6t5m 0/1 Pending 0 0s
rollout-deployment-778588fc9c-t6t5m 0/1 Pending 0 0s
rollout-deployment-778588fc9c-t6t5m 0/1 ContainerCreating 0 0s
rollout-deployment-778588fc9c-t6t5m 0/1 ContainerCreating 0 1s
rollout-deployment-778588fc9c-t6t5m 1/1 Running 0 2s
rollout-deployment-797db549bd-bggvf 1/1 Terminating 0 57s
rollout-deployment-778588fc9c-fh88z 0/1 Pending 0 0s
rollout-deployment-778588fc9c-fh88z 0/1 Pending 0 0s
rollout-deployment-778588fc9c-fh88z 0/1 ContainerCreating 0 0s
rollout-deployment-797db549bd-bggvf 1/1 Terminating 0 57s
rollout-deployment-778588fc9c-fh88z 0/1 ContainerCreating 0 1s
rollout-deployment-778588fc9c-fh88z 1/1 Running 0 1s
rollout-deployment-797db549bd-bggvf 0/1 Terminating 0 58s
rollout-deployment-797db549bd-bggvf 0/1 Terminating 0 58s
rollout-deployment-797db549bd-bggvf 0/1 Terminating 0 58s
rollout-deployment-797db549bd-nr2j8 1/1 Terminating 0 88s
rollout-deployment-778588fc9c-4n7lc 0/1 Pending 0 0s
rollout-deployment-778588fc9c-4n7lc 0/1 Pending 0 0s
rollout-deployment-778588fc9c-4n7lc 0/1 ContainerCreating 0 0s
rollout-deployment-797db549bd-nr2j8 1/1 Terminating 0 88s
rollout-deployment-778588fc9c-4n7lc 0/1 ContainerCreating 0 1s
rollout-deployment-797db549bd-nr2j8 0/1 Terminating 0 90s
rollout-deployment-797db549bd-nr2j8 0/1 Terminating 0 90s
rollout-deployment-797db549bd-nr2j8 0/1 Terminating 0 90s
rollout-deployment-778588fc9c-4n7lc 1/1 Running 0 2s
rollout-deployment-797db549bd-hplxm 1/1 Terminating 0 2m
rollout-deployment-778588fc9c-5s9g4 0/1 Pending 0 0s
rollout-deployment-778588fc9c-5s9g4 0/1 Pending 0 0s
rollout-deployment-778588fc9c-5s9g4 0/1 ContainerCreating 0 0s
rollout-deployment-797db549bd-hplxm 1/1 Terminating 0 2m
rollout-deployment-797db549bd-hplxm 0/1 Terminating 0 2m
rollout-deployment-797db549bd-hplxm 0/1 Terminating 0 2m1s
rollout-deployment-797db549bd-hplxm 0/1 Terminating 0 2m1s
rollout-deployment-778588fc9c-5s9g4 0/1 ContainerCreating 0 1s
rollout-deployment-778588fc9c-5s9g4 1/1 Running 0 2s
rollout-deployment-797db549bd-hg7xq 1/1 Terminating 0 2m32s
rollout-deployment-797db549bd-hg7xq 1/1 Terminating 0 2m32s
rollout-deployment-797db549bd-hg7xq 0/1 Terminating 0 2m33s
rollout-deployment-797db549bd-hg7xq 0/1 Terminating 0 2m33s
rollout-deployment-797db549bd-hg7xq 0/1 Terminating 0 2m33s
[root@master-01 rollout-update]# kubectl describe deployment rollout-deployment
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 5m14s deployment-controller Scaled up replica set rollout-deployment-797db549bd to 4
Normal ScalingReplicaSet 2m36s deployment-controller Scaled up replica set rollout-deployment-778588fc9c to 1
Normal ScalingReplicaSet 2m34s deployment-controller Scaled down replica set rollout-deployment-797db549bd to 3
Normal ScalingReplicaSet 2m34s deployment-controller Scaled up replica set rollout-deployment-778588fc9c to 2
Normal ScalingReplicaSet 2m32s deployment-controller Scaled down replica set rollout-deployment-797db549bd to 2
Normal ScalingReplicaSet 2m32s deployment-controller Scaled up replica set rollout-deployment-778588fc9c to 3
Normal ScalingReplicaSet 2m30s deployment-controller Scaled down replica set rollout-deployment-797db549bd to 1
Normal ScalingReplicaSet 2m30s deployment-controller Scaled up replica set rollout-deployment-778588fc9c to 4
Normal ScalingReplicaSet 2m28s deployment-controller Scaled down replica set rollout-deployment-797db549bd to 0
[root@master-01 rollout-update]# kubectl get pod -owide |grep rollout-deploy
rollout-deployment-778588fc9c-4n7lc 1/1 Running 0 4m20s 10.20.171.37 worker-01 <none> <none>
rollout-deployment-778588fc9c-5s9g4 1/1 Running 0 3m48s 10.20.171.51 worker-01 <none> <none>
rollout-deployment-778588fc9c-fh88z 1/1 Running 0 4m51s 10.20.171.60 worker-01 <none> <none>
rollout-deployment-778588fc9c-t6t5m 1/1 Running 0 5m23s 10.20.171.58 worker-01 <none> <none>
[root@master-01 rollout-update]# curl 10.20.171.37/ready
I am V2![root@master-01 rollout-update]# kubectl rollout history deployment rollout-deployment
deployment.apps/rollout-deployment
REVISION CHANGE-CAUSE
1 version=v1
2 version=v2
[root@master-01 rollout-update]#
3. 回滚
Kubernetes 提供了回滚机制来管理应用程序的更新过程,并确保在出现问题时可以快速恢复到稳定的版本。具体来说,Kubernetes 支持 Deployment 的回滚操作,通过管理 ReplicaSet 来实现版本的切换和回滚。回滚操作可以理解为另一种滚动更新。
回滚到上一个版本
kubectl rollout undo deployment < your_deployment_name >
[root@master-01 rollout-update]# kubectl rollout undo deployment rollout-deployment
deployment.apps/rollout-deployment rolled back
[root@master-01 rollout-update]# kubectl rollout history deployment rollout-deployment
deployment.apps/rollout-deployment
REVISION CHANGE-CAUSE
2 version=v2
3 version=v1
[root@master-01 rollout-update]# kubectl get pod -owide |grep rollout-deploy
rollout-deployment-797db549bd-8xkb6 1/1 Running 0 118s 10.20.171.18 worker-01 <none> <none>
rollout-deployment-797db549bd-k7j2j 1/1 Running 0 118s 10.20.171.31 worker-01 <none> <none>
rollout-deployment-797db549bd-r5kfv 1/1 Running 0 53s 10.20.171.46 worker-01 <none> <none>
rollout-deployment-797db549bd-xnhdm 1/1 Running 0 118s 10.20.171.19 worker-01 <none> <none>
[root@master-01 rollout-update]# curl 10.20.171.18/ready
I am V1![root@master-01 rollout-update]#
回滚到指定版本
kubectl rollout undo deployment < your_deployment_name > --to-revision=< revision-number >
[root@master-01 rollout-update]# kubectl rollout history deployment rollout-deployment
deployment.apps/rollout-deployment
REVISION CHANGE-CAUSE
1 version=v1
2 version=v2
3 version=v3
[root@master-01 rollout-update]#kubectl rollout undo deployment rollout-deployment --to-revision=1
deployment.apps/rollout-deployment rolled back
七、DaemonSet
在 Kubernetes 中,DaemonSet 是一种控制器类型,常被用来在集群的每个节点上运行一组特定的 Pod 实例,以便执行一些系统级任务或者服务。它通常用于在整个集群中部署某些基础设施性质的服务或者代理程序,如日志收集器、监控代理、网络代理等。
-
确保在每个节点上运行特定的 Pod 实例: DaemonSet 会在集群中的每个节点上自动创建一个 Pod 副本,确保所指定的服务或者应用在整个集群中都能得到运行。
-
节点感知性: DaemonSet 可以感知节点的增加或减少,并自动调整 Pod 的数量,从而保证在每个节点上都有一个 Pod 实例运行。
-
系统级任务: 适用于需要在每个节点上运行的系统级任务,如日志收集、监控、安全代理等。DaemonSet 可以确保这些任务在整个集群中保持运行。
-
无需手动管理节点上的 Pod: 使用 DaemonSet 可以避免手动在每个节点上部署 Pod,简化了管理和部署的工作流程。
-
滚动更新和版本控制: 可以通过更新 DaemonSet 的 Pod 模板来实现滚动更新,同时保持每个节点上的实例处于最新状态。
1. 创建
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter-ds
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
containers:
- name: node-exporter
image: bitnami/node-exporter:1.6.1
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
对比Deployment控制器,DaemonSet没有replicas字段。
[root@master-01 09-daemonset]# kubectl get pod -owide |grep node-exporter
node-exporter-ds-k9c6n 1/1 Running 0 50s 10.18.184.77 master-01 <none> <none>
node-exporter-ds-m4b7v 1/1 Running 0 50s 10.20.171.36 worker-01 <none> <none>
[root@master-01 09-daemonset]#
如果节点上有污点,pod将无调度到该节点上,要保证pod可以调度到所有节点,按照下面的方法去除污点或者为pod设置容忍度(以去除污点为例)。
首先,要查看 Kubernetes 集群上的污点(Taints),您可以使用以下命令:
kubectl describe nodes <node-name>
在上面的命令中,将 <node-name> 替换为您要删除,将列出集群中指定节点的详细信息,包括节点上的污点。在输出中,您可以找到每个节点的 Taints 部分,其中列出了应用于该节点的任何污点。
另外,您也可以使用以下命令来直接获取节点和它们的 Taints 信息:
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
然后,去除节点
kubectl taint nodes <node-name> key-
在上面的命令中,将 <node-name> 替换为您要删除污点的节点名称,key 替换为要删除的污点键。通过在键后面加上 - 表示删除该键对应的污点
[root@master-01 09-daemonset]# kubectl describe node master-01 |grep -i taint
Taints: node-role.kubernetes.io/master:NoSchedule
[root@master-01 09-daemonset]# kubectl taint node master-01 node-role.kubernetes.io/master-
node/master-01 untainted
[root@master-01 09-daemonset]# kubectl describe node master-01 |grep -i taint
Taints: <none>
[root@master-01 09-daemonset]#
八、 StatefulSet
StatefulSet 是 Kubernetes 中的一种控制器类型,用于管理有状态应用程序的部署和运行。与 Deployment 控制器不同,StatefulSet 控制器为每个 Pod 分配一个唯一的标识符,并且对这些 Pod 进行有序部署和扩展。这使得 StatefulSet 特别适用于需要稳定的持久化存储、网络标识或稳定的网络主机名的应用程序,如数据库、消息队列等。
以下是 StatefulSet 的一些特点和优势:
-
稳定的网络标识和主机名: StatefulSet 为每个 Pod 提供了稳定的标识符,其名称基于其在 StatefulSet 中的索引。这使得应用程序可以依赖于特定的网络标识和主机名,有助于实现有状态应用程序的稳定性。
-
有序部署和扩展: StatefulSet 保证它管理的 Pod 按照定义的顺序进行部署和扩展,这对于需要有序启动或者有序扩展的应用程序非常重要,例如数据库集群。
-
持久化存储: StatefulSet 可以与持久卷 (Persistent Volume) 结合使用,为每个 Pod 提供稳定的、持久的存储。
-
有状态应用程序支持: StatefulSet 为部署和管理有状态应用程序提供了便利,使得在 Kubernetes 上部署像数据库、缓存系统、队列服务等有状态应用程序变得更加方便。
本案例使用本地存储的 pv 作为 sts 的数据持久化的存储卷,这样做就会使得 sts管理的 pod 调度到哪个节点,哪个节点上就会创建一个 pv 存储卷。
虽然 sts 为了保持一些持久性存储(如 PV)的稳定性以及保留一些应用程序级别的状态,确实提供了一些机制来尽量确保在 Pod 被删除或重新调度时,它们会尽可能地调度到原来的节点上。但并不保证在所有情况下都能将 Pod 调度到原来的节点上,这可能受到节点资源的限制、调度器的策略以及其他集群中的因素影响。而一旦 pod 调度到其他的节点,绑定一个新节点的 pv,就会读取不到之前 pv 的数据,不利于数据的管理和使用,也不符合 sts 作为有状态应用管理器的初衷。生产环境更推荐使用易于管理的网络存储,如 NFS、Ceph等等。
1. 创建文件
pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv-0
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/redis
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv-1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/redis
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-sts
spec:
serviceName: redis-service
replicas: 2
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: redis-pv
mountPath: /data
volumeClaimTemplates:
- metadata:
name: redis-pv
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
这是一个 StatefulSet 的 YAML 配置文件,用于部署 Redis 实例。让我逐个解释每个字段的含义:
-
apiVersion: apps/v1:指定要使用的 Kubernetes API 版本。 -
kind: StatefulSet:指定要创建的资源类型,这里是 StatefulSet,用于运行有状态的应用程序。 -
metadata:元数据字段,用于定义资源的元数据信息,如名称等。name: redis-sts:StatefulSet 的名称。
-
spec:规范字段,用于定义 StatefulSet 的规范。-
serviceName: redis-service:指定用于该 StatefulSet 中 Pods 的 Service 的名称。 -
replicas: 2:指定要创建的 Pod 的副本数,这里是 2 个。 -
selector:选择器,用于选择要控制的 Pod。-
matchLabels:匹配标签,选择具有指定标签的 Pod。app: redis:选择具有标签app=redis的 Pod。
-
-
template:模板字段,用于定义要创建的 Pod 的模板。-
metadata:Pod 的元数据信息。-
labels:标签,用于识别 Pod。app: redis:指定 Pod 的标签为app=redis。
-
-
spec:Pod 的规范信息。-
containers:容器列表,定义要在 Pod 中运行的容器。-
name: redis:容器的名称。 -
image: redis:5-alpine:容器使用的镜像名称及版本。 -
ports:容器暴露的端口列表。containerPort: 6379:容器监听的端口号,这里是 Redis 默认端口 6379。
-
volumeMounts:挂载到容器中的存储卷列表。-
name: redis-pv:指定要挂载的持久卷的名称。 -
mountPath: /data:指定挂载到容器中的路径,这里是/data目录。
-
-
-
-
-
volumeClaimTemplates:持久卷声明模板列表,用于定义 StatefulSet 中 Pods 所需的持久卷声明模板。-
metadata:持久卷声明模板的元数据信息。name: redis-pv:持久卷声明模板的名称。
-
spec:持久卷声明模板的规范信息。-
accessModes: [ "ReadWriteOnce" ]:指定持久卷的访问模式,这里是 ReadWriteOnce,表示可以被单个节点挂载为读写模式。 -
resources:资源请求字段,用于定义持久卷的资源请求。-
requests:资源请求列表。storage: 1Gi:指定持久卷的存储容量为 1GB。
-
-
-
-
注意事项:
- volumeMount.name 字段和 volumeClaimTemplates.name 字段要保持一致;
- sts 有两个副本,每个副本中声明的 pvc 都要有一个相对应的 pv。
九、Service
1. 简介
Service 是一种抽象,用于定义一组 Pod 的逻辑集合以及访问这些 Pod 的策略。Service 提供了一种稳定的方式来访问一组具有相同功能的 Pod,而不必关心 Pod 的具体 IP 地址或者在集群中的位置。
具体来说,Kubernetes 中的 Service 具有以下几个主要作用和特点:
-
服务发现和负载均衡:Service 提供了一个抽象的访问点,通过 Service 名称,其他应用程序可以轻松地访问到后端 Pod,而不必关心这些 Pod 的 IP 地址。当有多个副本的 Pod 提供同一种服务时,Service 还可以自动进行负载均衡,将请求分发到不同的 Pod 上,从而提高服务的可用性和性能。
-
稳定的网络端点:Service 提供了一个虚拟 IP 地址(或者 DNS 名称),这个 IP 地址是稳定的,即使后端 Pod 发生变化,比如被重新调度或者扩展,Service 的 IP 地址也不会改变,确保了对服务的持续访问。
-
多种服务类型:Kubernetes 中的 Service 支持多种类型,包括 ClusterIP、NodePort、LoadBalancer 等。每种类型都有不同的访问方式和适用场景,可以满足不同的需求。
-
标签选择器:Service 通过标签选择器来确定哪些 Pod 属于同一个服务。通过标签选择器,用户可以灵活地定义 Service 所代表的后端 Pod,而不必手动维护 Pod 的列表。
apiVersion: v1
kind: Service
metadata:
name: my-service # Service 的名称
spec:
selector:
app: my-app # 标签选择器,选择属于 "my-app" 应用程序的 Pod
ports:
- protocol: TCP # 端口协议,TCP 或 UDP
port: 80 # Service 暴露的端口
targetPort: 8080 # Pod 真实监听的端口
type: ClusterIP # Service 类型,可以是 ClusterIP、NodePort、LoadBalancer 等
2. 类型
ClusterIP:
- ClusterIP 是默认的 Service 类型。
- 它为服务创建了一个虚拟的 ClusterIP 地址,该地址仅在集群内部可访问。
- 这意味着只有集群内的其他 Pod 可以通过 ClusterIP 地址来访问该服务。
- 这种模式适用于需要在集群内部进行服务发现和访问的情况。
NodePort:
- NodePort 模式通过在集群中的每个节点上开放一个固定端口(范围为 30000-32767),将外部流量引导到 Service 中的一个 Pod。
- 对外暴露的端口会被转发到 Service 中定义的端口,从而允许外部流量访问 Service。
- 外部客户端可以通过访问任何节点的 IP 地址和 NodePort 来访问 Service。
- 这种模式适用于需要从集群外部直接访问服务的情况。
LoadBalancer:
- LoadBalancer 模式使用云平台提供的负载均衡器服务(如AWS ELB、Google Cloud Load Balancer等),为 Service 分配一个外部可访问的 IP 地址。
- 该负载均衡器会自动将流量分发到后端 Pod,并可以实现健康检查等功能。
- 这种模式适用于需要对外暴露服务并且需要负载均衡能力的情况。
ExternalName :
- ExternalName 是Kubernetes 中一个特殊的 service 类型,它不需要指定 selector 去选择哪些 Pod 实例提供服务,而是使用 DNS CNAME 机制把自己 CNAME 到你指定的另外一个域名上,可以实现跨命名空间的访问你可以提供集群内的名字,比如mysql.db.svc 这样的建立在db命名空间内的 MySQL 服务,也可以指定 http://www.baidu.com 这样的外部真实域名。
3. 基于 NodePort 的 Nginx 服务
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx-dep
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-dep
spec:
replicas: 1
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- name: nginx
image: nginx:1.22.1
ports:
- containerPort: 80
3. 无头服务
无头服务(Headless Service)是 Kubernetes 中的一种特殊类型的服务,它与普通服务(ClusterIP、NodePort、LoadBalancer)不同。在定义无头服务时,您需要将 Service 的 spec.clusterIP 字段设置为 None。
无头服务的特点包括:
- 没有 ClusterIP 地址:无头服务不会分配 ClusterIP 地址,这意味着它不提供负载均衡或代理功能。
- 每个 Pod 都有自己的 DNS 记录:对于无头服务中的每个 Pod,Kubernetes 会为其创建一个 DNS 记录,这个 DNS 记录的格式通常为
<pod-name>.<service-name>.<namespace>.svc.cluster.local。 - 适用于需要直接访问每个 Pod 的场景:无头服务适用于需要直接访问每个 Pod 的情况,例如数据库集群、状态存储等。
通过使用无头服务,您可以实现以下功能:
- 直接通过 Pod 的 IP 地址访问每个 Pod,而不经过 Service 的负载均衡。
- 通过 DNS 记录来实现 Pod 的发现和直接访问。
apiVersion: v1
kind: Service
metadata:
name: redis-headless-svc
spec:
selector:
app: redis-svc
clusterIP: None
ports:
- port: 6379
targetPort: 6379
protocol: TCP
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-dep
spec:
replicas: 1
selector:
matchLabels:
app: redis-dep
template:
metadata:
labels:
app: redis-dep
spec:
containers:
- name: redis
image: redis:5-alpine
ports:
- containerPort: 6379
[root@master-01 09-Service]# kubectl get svc -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.112.0.1 <none> 443/TCP 45d <none>
nginx-svc NodePort 10.120.13.160 <none> 80:31312/TCP 15m app=nginx-dep
redis-svc ClusterIP None <none> 6379/TCP 7m53s app=redis-svc
十、Ingress
Ingress 允许公开 HTTP 和 HTTPS 服务,并基于主机名(域名)或路径将流量路由到不同的 Service 中。通过使用 Ingress,您可以实现基于 URL 的流量控制、负载均衡和 TLS 终止等功能。
Ingress和IngressClass和Service之间的联系:

IngressController:

Ingress 的优势:
- 流量路由:通过定义 Ingress 规则,您可以指定不同的主机名和路径与不同的 Service 相关联,从而实现流量的精确路由。
- 负载均衡:Ingress Controller 负责监视 Ingress 资源的变化,并配置负载均衡器(如 Nginx、HAProxy 等)以实现流量的均衡分发。
- TLS 终止:Ingress 支持通过 TLS 密钥和证书对传入的 HTTPS 请求进行解密,可以实现端到端的加密通信。
- 虚拟主机:可以使用不同的主机名(即域名)来访问集群中的不同服务,从而实现多个服务共享同一个 IP 地址的能力。
- 灵活性:Ingress 提供了灵活的配置选项,可以根据需要定义多个规则和设置各种参数,满足不同场景下的流量控制需求。
Ingress 资源通常由三个核心组成部分组成:Ingress 、Ingress Controller 和 Ingress Class。
IngressClass实现了Ingres和IngressController的解耦,允许一个集群中使用多个IngressController。
Ingress通过Ingress.spec.IngressClassName字段定义要使用的IngresscClass;IngressClass通过IngreesClass.spec.controller字段定义要使用的IngressController。
- Ingress 规则(Ingress 资源清单):
- Ingress 规则定义了如何将外部的 HTTP 和 HTTPS 请求路由到集群内部的服务。每个 Ingress 规则通常包含一个或多个主机和路径的映射规则,指定了请求应该被路由到哪个后端服务。
- Ingress Controller:
- Ingress Controller 是负责实现 Ingress 规则定义的组件,它会监视集群中的 Ingress 对象,根据规则配置负载均衡器等网络设备,以确保外部流量正确地路由到内部服务。不同的 Ingress Controller 可能支持不同的功能和配置选项。
- Ingress Class:
- Ingress Class 是用来标识 Ingress Controller 的类别和配置的对象。通过 Ingress Class,您可以将特定的 Ingress 资源与指定的 Ingress Controller 关联起来,确保正确的控制器处理相应的规则。Ingress Class 通常包含了指定的 Controller 名称和可能的参数配置。
1. 部署Ingress Controller
本文以Ingress Nginx 控制器为例。
Ref:https://kubernetes.github.io/ingress-nginx/deploy/#quick-start
Ref:https://github.com/kubernetes/ingress-nginx
1.1 下载 IngressController 的 资源清单
wget -O deploy.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
注意事项:要根据 k8s 的版本选择合适的 controller 版本,因为本文 k8s 是1.23.15版本,因此安装1.6.4版本的controller。

安装和 k8s 不适配的版本可能会出现如下报错:
[root@master-01 10-Ingress]# kubectl -n ingress-nginx logs ingress-nginx-controller-56cc97cf59-5dzgx
F0510 14:06:38.716461 7 main.go:64] port 80 is already in use. Please check the flag --http-port
-------------------------------------------------------------------------------
NGINX Ingress controller
Release: v1.10.0
Build: 71f78d49f0a496c31d4c19f095469f3f23900f8a
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.25.3
-------------------------------------------------------------------------------
1.2 修改资源清单
vim deploy.yaml
34 ---
335 apiVersion: v1
336 kind: Service
337 metadata:
338 labels:
339 app.kubernetes.io/component: controller
340 app.kubernetes.io/instance: ingress-nginx
341 app.kubernetes.io/name: ingress-nginx
342 app.kubernetes.io/part-of: ingress-nginx
343 app.kubernetes.io/version: 1.10.0
344 name: ingress-nginx-controller
345 namespace: ingress-nginx
346 spec:
347 externalTrafficPolicy: Local
348 ipFamilies:
349 - IPv4
350 ipFamilyPolicy: SingleStack
351 ports:
352 - appProtocol: http
353 name: http
354 port: 80
355 nodePort: 30080 #30080表示外部可以通过集群中任意节点的30080端口访问该Service的端口80。
356 protocol: TCP
357 targetPort: http
358 - appProtocol: https
359 name: https
360 port: 443
361 nodePort: 30443 #同理,若不加 Kubernetes在30000到32767之间为NodePort随机分配
362 protocol: TCP
363 targetPort: https
364 selector:
365 app.kubernetes.io/component: controller
366 app.kubernetes.io/instance: ingress-nginx
367 app.kubernetes.io/name: ingress-nginx
368 type: NodePort #将LoadBalancer修改为NodePort
1.3 运行Controller
kubectl apply -f deploy.yaml
2. 创建Ingress
cm
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
default.conf: |
server {
listen 80;
location / {
default_type text/plain;
return 200
'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\ndate: $time_iso8601\n';
}
}
dep
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
spec:
replicas: 2
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
volumes:
- name: nginx-conf-vol
configMap:
name: nginx-conf
containers:
- image: nginx:1.22.1
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: nginx-conf-vol
svc
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx-dep
ports:
- port: 80
targetPort: 80
protocol: TCP
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ing
spec:
ingressClassName: nginx
rules:
- host: nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- path: /shop/
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- path: /tea/
pathType: Exact
backend:
service:
name: nginx-svc
port:
number: 80
这个 Ingress 资源定义了如何将外部的 HTTP 请求路由到 Kubernetes 集群内的服务。让我解释一下其中的每个部分:
-
apiVersion: networking.k8s.io/v1: 这指定了 Ingress 资源的 Kubernetes API 版本。 -
kind: Ingress: 这表示定义了一个 Ingress 资源。 -
metadata: 这是元数据部分,用于指定 Ingress 资源的名称等信息。name: nginx-ing: 这是 Ingress 资源的名称。
-
spec: 这是 Ingress 规则的规范部分,其中定义了如何路由请求。-
ingressClassName: nginx: 这指定了使用的 Ingress 类别名称。 -
rules: 这是路由规则的列表。-
host: nginx.example.com: 这指定了匹配的主机名。当请求的主机名为 nginx.example.com 时,将会应用下面定义的路径规则。 -
http: 这表示匹配 HTTP 请求。-
paths: 这是路径规则的列表,指定了如何匹配和路由请求的路径。-
path: /: 这是一个路径规则,指定了根路径/的匹配。-
pathType: Prefix: 这指定了路径匹配类型为前缀匹配,即以/开头的所有路径都会匹配到这个规则。 -
backend: 这是后端服务的定义,指定了当请求匹配到这个规则时要转发到哪个后端服务。-
service: 这是服务的定义,指定了要转发到的服务名称。-
name: nginx-svc: 这是要转发到的服务的名称,即名为nginx-svc的服务。 -
port: 这是服务的端口定义。number: 80: 这是要转发到的服务的端口号,即服务监听的 HTTP 端口号。
-
-
-
-
path: /shop/: 这是另一个路径规则,指定了匹配/shop/路径的请求。-
pathType: Prefix: 这同样指定了路径匹配类型为前缀匹配。 -
backend: 这是后端服务的定义,与上面类似。
-
-
path: /tea/: 这是第三个路径规则,指定了匹配/tea/路径的请求。-
pathType: Exact: 这指定了路径匹配类型为精确匹配,即只有当请求的路径与/tea/完全匹配时才会应用这个规则。 -
backend: 这同样是后端服务的定义,与上面类似。
-
-
-
-
-
综上所述,这个 Ingress 资源定义了三个路径规则,分别匹配根路径、/shop/ 路径和 /tea/ 路径,并将匹配到的请求转发到名为 nginx-svc 的服务的 80 端口。
注意事项:宿主机通过 Ingress 的 IP 地址访问时候是不通的。
集群内部访问
[root@master-01 10-Ingress]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-dep-b4bfd684c-7kt5h 1/1 Running 0 14m 10.20.171.1 worker-01 <none> <none>
nginx-dep-b4bfd684c-ds6n8 1/1 Running 0 14m 10.18.184.100 master-01 <none> <none>
[root@master-01 10-Ingress]# kubectl get ingress -owide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ing nginx nginx.example.com 10.118.167.100 80 12m
[root@master-01 10-Ingress]# kubectl describe ingress nginx-ing
Name: nginx-ing
Labels: <none>
Namespace: default
Address: 10.118.167.100
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
nginx.example.com
/ nginx-svc:80 (10.18.184.100:80,10.20.171.1:80)
/shop/ nginx-svc:80 (10.18.184.100:80,10.20.171.1:80)
/tea/ nginx-svc:80 (10.18.184.100:80,10.20.171.1:80)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 12m (x2 over 12m) nginx-ingress-controller Scheduled for sync
[root@master-01 10-Ingress]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.17.110 master-01
192.168.17.120 worker-01
10.118.167.100 nginx.example.com
[root@master-01 10-Ingress]# curl nginx.example.com
srv : 10.18.184.100:80
host: nginx-dep-b4bfd684c-ds6n8
uri : GET nginx.example.com /
date: 2024-05-13T15:27:47+00:00
[root@master-01 10-Ingress]#
集群外部访问
Ingress 中我们设置了服务的域名是nginx.example.com
nginx-controller的svc生产环境一般使用云厂商的LoadBalacer,本实验采用的是NodePort
生产环境也可以使用NodePort的方式,将域名解析到虚IP,虚IP反向代理K8S集群节点IP的31005端口,来实现高可用。
例如,
| 类型 | IP地址 | 端口 |
|---|---|---|
| VIP | 192.168.17.200 | 80 |
| RIP1 | 192.168.17.110 | 31005 |
| RIP1 | 192.168.17.120 | 31005 |
[root@master-01 ~]# kubectl -n ingress-nginx get svc ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.118.167.100 <none> 80:31005/TCP,443:32278/TCP 119m
[root@master-01 ~]#
集群外部的访问链路:
- 浏览器输入nginx.example.com:31005
(nginx.example.com对应的是集群的任一节点IP,尽量不要用主节点,可能会报错,原因不详) - 转到10.118.167.100:80(IngressController-nginx的地址)
- 然后根据INgress规则转到相应的svc
- svc转到相应的pod
首先,宿主机hosts文件配置一条记录:C:\Windows\System32\drivers\etc\hosts
……
192.168.17.120 nginx.example.com
……
然后,浏览器访问: nginx.example.com:31005

3. 为Ingress配置TLS加密
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ing
spec:
ingressClassName: nginx
rules:
- host: nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- path: /shop/
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- path: /tea/
pathType: Exact
backend:
service:
name: nginx-svc
port:
number: 80
tls:
- hosts:
- nginx.example.com
secretName: tls-secret
在这个示例中,我们在 spec 下增加了一个 tls 字段,用来指定 TLS 配置。其中:
hosts指定了需要应用 TLS 的域名列表。secretName指定了用于存储 TLS 证书和密钥的 Secret 对象的名称。
请注意,这里的 tls-secret 应该是一个已经创建好的 Secret 对象,其中包含了 TLS 证书和密钥的信息。
在Kubernetes中创建一个TLS证书的Secret可以通过以下步骤完成。
首先,你需要将TLS证书和私钥文件准备好,然后使用kubectl命令行工具来创建Secret。
假设你有一个名为tls.crt的TLS证书文件和一个名为tls.key的私钥文件,你可以使用以下命令将它们创建为一个Secret:
kubectl create secret tls tls-secret --cert=tls.crt --key=tls.key
4. IngressClass
使用 nginx 作为IngressController 的时候,默认创建了一个名为 nginx 的 IngressClass。
在Kubernetes中,可以通过定义IngressClass来指定特定的Ingress控制器,然后在创建Ingress资源时将其与特定的IngressClass相关联。这使得你可以为不同的Ingress资源选择不同的控制器进行处理。
以下是一个简单的IngressClass定义示例:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: nginx.org/ingress-controller
parameters:
apiGroup: networking.k8s.io
kind: IngressClassParameters
name: nginx
在这个示例中,我们定义了一个名为"nginx"的IngressClass,并指定了与之相关联的控制器名称为"nginx.org/ingress-controller"。
一旦你定义了IngressClass,你就可以在创建Ingress资源时指定使用的IngressClass,例如:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
...
十一、存储
在Kubernetes中,PV(PersistentVolume)和PVC(PersistentVolumeClaim)是用来实现持久化存储的机制。PV表示集群中的一个持久化存储资源,而PVC则是对PV的申请和使用。下面简单介绍一下它们的概念和用法:
PV(PersistentVolume):
- PersistentVolume(PV) 是集群中的一块独立的存储资源,可以由管理员预先配置好,供应用程序使用。
- PV 可以是物理存储资源,也可以是云存储服务(例如 AWS EBS、Azure Disk)等。
- PV 有不同的访问模式(Access Modes),如ReadWriteOnce、ReadOnlyMany和ReadWriteMany,用于定义多个Pod之间如何访问这个PV。
- PV 通常由集群管理员进行配置和管理,应用程序开发者只需要创建PVC来请求使用PV。
PVC(PersistentVolumeClaim):
- PersistentVolumeClaim(PVC) 是应用程序对存储资源(PV)的申请和使用声明。
- 应用程序开发者通过创建PVC来请求存储资源,并指定所需的存储容量和访问模式。
- Kubernetes会根据PVC的要求匹配合适的PV,并将其绑定到PVC上,使应用程序可以使用该PV提供的存储功能。
- 当应用程序不再需要存储资源时,可以删除对应的PVC,PV会被释放并可以供其他应用程序使用。
1. 创建本地存储(Local Storage)
- 本地存储是直接连接到宿主机上的物理存储资源,通常是宿主机的本地硬盘或SSD。
- 本地存储具有较高的性能和低延迟,适合对性能要求较高的应用程序,如大数据处理、高性能计算等。
- 本地存储通常只能被单个节点上的Pod访问,不适合需要跨节点访问的应用程序。
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: standard
hostPath:
path: /data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx:1.22.1
volumeMounts:
- mountPath: "/data"
name: my-volume
volumes:
- name: my-volume
persistentVolumeClaim:
claimName: my-pvc
在这个示例中,我们定义了一个PV(my-pv),它使用HostPath作为持久化存储,容量为1Gi,并且定义了访问模式为ReadWriteOnce。然后,我们创建了一个PVC(my-pvc),请求1Gi的存储容量和ReadWriteOnce的访问模式,以便绑定到PV上供应用程序使用。
Pod的volumeMounts部分中,我们将名为my-volume的卷挂载到/data目录上。然后在volumes部分中,我们指定了my-volume卷与名为my-pvc的PVC绑定。
2. 创建网络存储(Network Storage)
- 网络存储是通过网络连接到集群节点的存储资源,通常由外部存储提供商(如云服务商或存储解决方案提供商)提供支持。
- 网络存储包括各种类型,如网络文件系统(NFS)、块存储(如AWS EBS、Azure Disk)和对象存储(如AWS S3、MinIO)等。
- 网络存储可以动态地进行扩展和收缩,适用于需要跨节点访问的应用程序,如数据库、共享文件系统等。
- Kubernetes中的PersistentVolume(PV)和PersistentVolumeClaim(PVC)机制可以方便地管理和使用网络存储。
本文以NFS为例:
安装NFS服务端
yum install -y nfs-utils rpcbind
mkdir /data/nfs
echo "/data/k8s 192.168.17.132.0/24(rw,sync,no_subtree_check,no_root_squash,insecure)" >> /etc/exports
systemctl restart nfs
安装NFS客户端
yum -y install nfs-utils
showmount -e 192.168.17.132
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-5g-pv
spec:
storageClassName: nfs
accessModes:
- ReadWriteMany
capacity:
storage: 5Gi
nfs:
path: /data/nfs/5g-pv
server: 172.17.0.93 #nfs server端的地址
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-static-pvc
spec:
storageClassName: nfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
spec:
replicas: 1
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
volumes:
- name: nfs-pvc-vol
persistentVolumeClaim:
claimName: nfs-static-pvc
containers:
- image: nginx:1.22.1
name: nginx
volumeMounts:
- name: nfs-pvc-vol
mountPath: /tmp
3. 动态创建PV
PV 还是需要人工管理,必须要由系统管理员手动维护各种存储设备,再根据开发需求逐个创建 PV,而且 PV 的大小也很难精确控制,容易出现空间不足或者空间浪费的情况。
在我们的这个实验环境里,只有很少的 PV 需求,管理员可以很快分配 PV 存储卷,但是在一个大集群里,每天可能会有几百几千个应用需要 PV 存储,如果仍然用人力来管理分配存储,管理员很可能会忙得焦头烂额,导致分配存储的工作大量积压。
那么能不能让创建 PV 的工作也实现自动化呢?或者说,让计算机来代替人类来分配存储卷呢?
这个在 Kubernetes 里就是“动态存储卷”的概念,它可以用 StorageClass 绑定一个 Provisioner 对象,而这个 Provisioner 就是一个能够自动管理存储、创建 PV 的应用,代替了原来系统管理员的手工劳动。
有了“动态存储卷”的概念,前面我们讲的手工创建的 PV 就可以称为“静态存储卷”。
目前,Kubernetes 里每类存储设备都有相应的 Provisioner 对象,对于 NFS 来说,它的 Provisioner 就是“NFS subdir external provisioner”,你可以在 GitHub 上找到这个项目。
Ref:nfs-subdir-external-provisioner
部署该项目的时候,只需要把项目中的deploy目录下的deployment.yaml和rbac.yaml部署到集群中即可。
部署nfs-subdir-external-provisioner
rabc.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.17.132
- name: NFS_PATH
value: /data/k8s
volumes:
- name: nfs-client-root
nfs:
server: 192.168.17.132
path: /data/k8s
上面的案例中,NFS 服务端 IP 地址为 192.168.17.132 ; 共享的目录为 /data/k8s
创建 PVC
storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client-retained
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
onDelete: "retain"
关键字段是 provisioner,它指定了应该使用哪个 Provisioner。另一个字段 parameters 是调节 Provisioner 运行的参数,需要参考文档来确定具体值,在这里的 onDelete: "retain" 暂时保留分配的存储,之后再手动删除。
pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-dynamic-pvc
spec:
storageClassName: nfs-client-retained
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Mi
[root@master-01 11-PV+PVC]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-dynamic-pvc Bound pvc-7e2dbd6e-1879-4d14-8f4d-3b3148dbcea6 10Mi RWX nfs-client-retained 25m
[root@master-01 11-PV+PVC]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-7e2dbd6e-1879-4d14-8f4d-3b3148dbcea6 10Mi RWX Delete Bound default/nfs-dynamic-pvc nfs-client-retained 25m
[root@master-01 11-PV+PVC]#
自动依据 pvc 来创建 pv
4. 回收策略
在Kubernetes中,PersistentVolume(PV)的回收策略是通过PV的persistentVolumeReclaimPolicy字段来定义的。这个字段指定了当与PV绑定的PersistentVolumeClaim(PVC)被删除后,Kubernetes应该如何处理PV的回收。
persistentVolumeReclaimPolicy字段有以下三种可选的回收策略:
- Retain:保留策略会保留PV的数据,不会删除PV,需要管理员手动处理已释放的PV。数据不会被自动清除,可以手动进行清理和管理。
- Delete:删除策略会删除PV,并清除其存储资源,释放存储空间以供其他PV使用。一旦与PV绑定的PVC被删除,PV将被自动删除和清理。
- Recycle:回收策略将尝试清除PV中的数据,以便可以重新使用PV。这种策略已经在Kubernetes v1.12版本中被弃用,建议使用其他更可靠的回收策略。
部署Wordpress
1.mysql
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-cm
data:
DATABASE: 'db_wordpress'
USER: 'wordpress'
PASSWORD: '123456'
ROOT_PASSWORD: '123456'
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: wp-mysql
labels:
app: wordpress
role: database
spec:
serviceName: wp-mysql-svc
volumeClaimTemplates:
- metadata:
name: wp-mysql-pvc
spec:
storageClassName: nfs-client-retained
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Mi
replicas: 1
minReadySeconds: 30
selector:
matchLabels:
app: wp-mysql
template:
metadata:
labels:
app: wp-mysql
spec:
containers:
- name: wp-mysql
image: mysql:5.7
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1
memory: 2048Mi
requests:
cpu: 500m
memory: 500Mi
startupProbe:
periodSeconds: 15
tcpSocket:
port: 3306
livenessProbe:
periodSeconds: 10
tcpSocket:
port: 3306
readinessProbe:
periodSeconds: 15
tcpSocket:
port: 3306
ports:
- containerPort: 3306
envFrom:
- prefix: 'MYSQL_'
configMapRef:
name: mysql-cm
volumeMounts:
- name: wp-mysql-pvc
mountPath: /var/lib/mysql
---
apiVersion: v1
kind: Service
metadata:
name: wp-mysql-svc
labels:
spec:
selector:
app: wp-mysql
ports:
- port: 3306
targetPort: 3306
protocol: TCP
name: http
2. wordpress
apiVersion: v1
kind: ConfigMap
metadata:
name: wp-cm
data:
HOST: 'wp-mysql-svc'
USER: 'wordpress'
PASSWORD: '123456'
NAME: 'db_wordpress'
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wp-dep
labels:
app: wp-dep
spec:
replicas: 1
minReadySeconds: 30
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: wp-dep
template:
metadata:
labels:
app: wp-dep
spec:
containers:
- name: wordpress
image: wordpress:6
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1
memory: 1024Mi
requests:
cpu: 200m
memory: 500Mi
startupProbe:
periodSeconds: 5
tcpSocket:
port: 80
livenessProbe:
periodSeconds: 10
tcpSocket:
port: 80
readinessProbe:
periodSeconds: 15
tcpSocket:
port: 80
ports:
- containerPort: 80
envFrom:
- prefix: 'WORDPRESS_DB_'
configMapRef:
name: wp-cm
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wp-ingress
spec:
ingressClassName: nginx
rules:
- host: wp.xinxianghf.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wp-dep-svc
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
name: wp-dep-svc
labels:
spec:
selector:
app: wp-dep
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
十二、调度
1. 节点亲和性与反亲和性
亲和性
在 Kubernetes 中,节点亲和性(Node Affinity) 是一种机制,用于控制 Pod 被调度到哪些节点上。它通过节点的标签(labels)来实现。节点上的标签允许您将特定的属性附加到节点上,例如节点的地理位置、硬件规格等。
节点亲和性规则基于节点的标签来筛选可用于调度 Pod 的节点。您可以定义节点亲和性规则,使 Pod 被调度到具有特定标签的节点上,或者倾向于被调度到具有某些标签的节点上。
节点标签:节点标签是键值对形式的元数据,附加到 Kubernetes 集群中的节点上。这些标签可以根据您的需求进行自定义,并且可以用来描述节点的特征、属性或约束。
节点亲和性规则:
-
requiredDuringSchedulingIgnoredDuringExecution:这种规则指定了 Pod 必须满足的节点标签条件,否则该 Pod 将无法被调度。 -
preferredDuringSchedulingIgnoredDuringExecution:这种规则指定了 Pod 偏好的节点标签条件,即指定了节点标签的优先级。如果有多个节点符合 Pod 的偏好条件,那么这些节点将被赋予不同的权重,Pod 将更倾向于被调度到权重较高的节点上。如果没有节点符合偏好条件,Pod 仍然可以被调度到其他节点上。
apiVersion: v1
kind: Pod
metadata:
name: node-pa-pod
spec:
containers:
- name: my-container
image: nginx:1.22.1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: custom.node.label
operator: In
values:
- value-1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: custom.node.label
operator: In
values:
- value-2
根据给定的节点亲和性规则配置,这个 Pod 将会被调度到以下类型的节点上:
必要条件:Pod 必须被调度到具有 custom.node.label 标签且值为 value-1 的节点上。这是一个必须满足的条件,如果没有符合这个条件的节点,Pod 将无法被调度。
偏好条件:Pod 偏好被调度到具有 custom.node.label 标签且值为 value-2 的节点上。这是一个偏好条件,权重为 1,表示系统更倾向于满足这个条件。但如果没有符合偏好条件的节点,Pod 仍然可以被调度到符合必要条件的节点上(即具有 custom.node.label 标签且值为 value-1 的节点)。
kubectl label nodes master-01 custom.node.label=value-1
kubectl get node master-01 |grep -i taint
反亲和性
在 Kubernetes 中,除了节点亲和性(Node Affinity)外,还存在节点反亲和性(Node Anti-Affinity)的概念,用于指定 Pod 不应该被调度到具有特定标签的节点上。
节点反亲和性可以通过 nodeAntiAffinity 字段来定义,其规则包括:
requiredDuringSchedulingIgnoredDuringExecution:
requiredDuringSchedulingIgnoredDuringExecution表示在调度期间必须满足的条件,即禁止将 Pod 调度到满足指定标签规则的节点上。- 类似于节点亲和性中的
requiredDuringSchedulingIgnoredDuringExecution规则,但是这里是为了阻止 Pod 被调度到特定的节点。
preferredDuringSchedulingIgnoredDuringExecution:
preferredDuringSchedulingIgnoredDuringExecution表示优先级设置,即尽量避免将 Pod 调度到满足指定标签规则的节点上。- 类似于节点亲和性中的
preferredDuringSchedulingIgnoredDuringExecution规则,但是这里是为了降低将 Pod 调度到特定节点的优先级。
2. Pod亲和性与反亲和性
亲和性
Pod 亲和性(Affinity)是 Kubernetes 中一种调度策略,用于指定 Pod 应该被调度到具有特定标签的节点上的规则。通过定义 Pod 亲和性,可以控制 Pod 的调度行为,确保相关的 Pod 被部署在一起或者避免被部署在同一节点上。如应用和数据库。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: "kubernetes.io/hostname"
containers:
- name: nginx
image: nginx:1.22.1
resources:
limits:
memory: 1Gi
cpu: 1
requests:
memory: 256Mi
cpu: 100m
-
podAffinity: 指定了 Pod 亲和性规则, 要求 Pod 被调度到**具有app标签且值为redis的 Pod **所在的节点上。 -
topologyKey : "kubernetes.io/hostname": 指定了拓扑键,用于确定 Pod 之间关系的拓扑域。
Pod反亲和性
同node反亲和性
3. 将Pod指派给节点
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
在这个示例中,nodeSelector 字段指定了要将 Pod 调度到具有 disktype: ssd 标签的节点上。这样,Kubernetes 调度器会尝试将该 Pod 调度到符合条件的节点上运行。
4. 污点
在 Kubernetes 中,污点(Taints)是一种机制,用于影响 Pod 被调度到节点上的行为。通过给节点添加污点,可以限制哪些 Pod 能够被调度到该节点上。这种机制可以帮助集群管理员控制 Pod 的调度行为,例如将特定类型的工作负载调度到专门用途的节点上,或者限制某些节点上不适合运行特定类型的 Pod。
每个节点可以有零个或多个污点,每个污点由一个键值对组成,分别是键(key)、值(value)和效果(effect)。键表示污点的名称,值表示污点的值,而效果表示当 Pod 与该污点匹配时的行为。效果通常包括如下几种:
- NoSchedule: 当节点上存在该污点时,不会调度任何未匹配该污点的 Pod 到该节点上。
- PreferNoSchedule: 当节点上存在该污点时,会尽量避免调度未匹配该污点的 Pod 到该节点上,但不是强制的。
- NoExecute: 当节点上添加了该污点后,所有已经存在的不匹配该污点的 Pod 将被驱逐出节点。
Pod 可以通过容忍(Tolerations)来声明可以容忍的污点,从而在调度时考虑污点的影响。
总的来说,污点是 Kubernetes 中一种用于限制 Pod 调度行为的机制,可以帮助管理员根据需求对集群中的节点和 Pod 进行灵活的调度控制。
添加污点
要在节点上添加污点,可以使用以下命令:
kubectl taint nodes <node-name> key=value:effect
其中,<node-name> 是节点的名称,key=value:effect 是要添加的污点的键值对和效果。例如:
kubectl taint nodes node-1 app=prod:NoSchedule
这个命令会在名为 node-1 的节点上添加一个名为 app,值为 prod,效果为 NoSchedule 的污点。
移除污点
要在节点上移除污点,可以使用以下命令:
kubectl taint nodes <node-name> key-
其中,<node-name> 是节点的名称,key- 表示要移除的污点的键。例如:
kubectl taint nodes node-1 app-
这个命令会在名为 node-1 的节点上移除名为 app 的污点。
5. 容忍度
在 Kubernetes 中,容忍度(tolerations)是一种用于定义 Pod 可以“容忍”哪些节点上的污点(taint)的机制。污点是节点上的标记,用于表示该节点上可能存在的限制,例如只能运行特定类型的工作负载或者需要特定条件才能运行。通过容忍度,你可以指定哪些 Pod 允许在具有特定污点的节点上运行。
容忍度由 Pod 的规范(spec)中的 tolerations 字段定义。每个容忍度规则由以下字段组成:
key:指定要容忍的污点的键。operator:指定匹配规则的操作符,通常为Equal、Exists或DoesNotExist。value:指定要匹配的污点的值。effect:指定对匹配的污点采取的操作,例如NoSchedule、PreferNoSchedule或NoExecute。
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
containers:
- name: gpu-container
image: gpu-image
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
在上面的示例中,tolerations 字段指定了容忍度规则,告诉 Kubernetes 系统允许 gpu-pod 在具有 key1=value1:NoSchedule 污点的节点上运行。这样一来,当调度 Pod 时,Kubernetes 将考虑节点的污点和 Pod 的容忍度规则,并确保只有匹配的 Pod 被调度到相应的节点上。
十三、网络
Kubernetes 的网络原理是一个相当复杂的话题。在 Kubernetes 中,每个 Pod 都有自己的 IP 地址,并且可以通过这个 IP 地址与其他 Pod 进行通信。
-
Pod 网络: 在 Kubernetes 中,每个 Pod 都分配了一个唯一的 IP 地址。这意味着即使 Pod 被部署到不同的节点上,它们之间仍然可以直接通信。
-
Service: Service 是一个抽象概念,用于定义一组 Pod,并为它们提供统一的访问入口。Service 有自己的虚拟 IP 地址,可以负载均衡流量到后端的 Pod 上。
-
Cluster 内部通信: Kubernetes 使用一个叫做 CNI(Container Network Interface)的标准来管理容器间的网络连接。CNI 插件负责为 Pod 分配 IP 地址,并配置网络规则来允许 Pod 之间的通信。
-
Cluster 外部访问: 对外部流量的访问通常通过 Service 和 Ingress 资源来管理。Ingress 资源定义了从集群外部进入集群的 HTTP 和 HTTPS 路由规则,允许对集群中的 Service 进行访问和负载均衡。
-
网络插件: 在 Kubernetes 中,可以使用各种网络插件来实现 Pod 之间的通信,比如 Flannel、Calico、Cilium 等。这些插件可以通过不同的方式来实现 Pod 网络,比如覆盖网络、VXLAN、BGP 等技术。
Calico
1. 同一个Pod中的容器
依赖pause容器创建的网络命名空间,这些容器在同一个网络空间中。这意味着每个 Pod 内的容器在网络上看起来就像运行在同一台主机上的不同进程一样。当容器需要和本地主机上的其他进程或容器进行通信时,它们可以直接通过 localhost 来进行通信,就像在单个主机上的不同进程之间一样。
2. 同节点不同Pod的容器
在 Calico 中, 每生成一个新的Pod,那么在Node上都会根据插件来生成一个新的虚拟网卡如vethxxxx或者calixxxx,这个网卡会对应到Pod里的eth0。一个端口连接到容器的网络命名空间,另一个端口连接到宿主机的网络命名空间或者 Linux bridge 上。当同一节点上的不同 Pod 中的容器需要进行通信时,Calico 会通过 veth 对实现这种通信。数据包会从一个容器的 veth 对发送到宿主机的网络命名空间或 Linux bridge,然后再通过目标容器的 veth 对传输到目标容器的网络命名空间,从而完成容器之间的通信。
3. 不同节点的容器
Calico 的 IP in IP模式:
- 从字面来理解,就是把一个 IP 数据包又套在一个 IP 包里,即把 IP 层封装到 IP 层的一个 tunnel,看起来似乎是浪费,实则不然。
- 它的作用其实基本上就相当于一个基于 IP 层的网桥!
- 一般来说,普通的网桥是基于 mac 层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。
- ipip 的源代码在内核 net/ipv4/ipip.c 中可以找到。
IP 包进入 IP 隧道设备之后,就会被 Linux 内核的 IPIP 驱动接管。IPIP 驱动会将这个 IP 包直接封装在一个宿主机网络的 IP 包中,如下所示:

IP 包进入 IP 隧道设备之后,就会被 Linux 内核的 IPIP 驱动接管。IPIP 驱动会将这个 IP 包直接封装在一个宿主机网络的 IP 包中,如下所示:

在 Calico 的 IP in IP 模式中,具体来说,IP-in-IP 模式在 Calico 中的流程如下:
- 源节点上的容器发送数据包到目标节点上的容器。
- 数据包首先到达源节点的 Calico 数据面,Calico 数据面将数据包封装在一个外部 IP 包中,外部 IP 包的目的地址是目标节点的 IP 地址。
- 外部 IP 包通过底层网络传输到目标节点。
- 目标节点的 Calico 数据面接收到外部 IP 包后,解析出内部的数据包,并将其传递给目标节点上的容器。
补充:veth 对和 tunl0区别
veth 对和 tunl0 是在 Linux 网络中用于不同类型通信的两种不同接口,各自具有不同的特点和用途:
-
veth 对(Virtual Ethernet Pair)是一对虚拟的以太网设备,通常成对出现,一端连接到容器的网络命名空间,另一端连接到宿主机的网络命名空间或者 Linux bridge。veth 对可以用于在同一台主机上不同网络命名空间之间进行通信,例如容器和宿主机之间、不同容器之间等。通过 veth 对,数据包可以在宿主机和容器之间进行传输。
-
tunl0 是 Linux 内核提供的一种隧道接口,用于在网络层对数据包进行封装和解封装,实现不同网络之间的通信。通常用于实现跨网络的通信,例如在 Calico 中用于跨节点的容器通信,通过 tunl0 接口可以将数据包封装在另一个 IP 数据包中进行传输。
因此,veth 对主要用于同一台主机上不同网络命名空间之间的通信,而 tunl0 主要用于实现不同网络之间的通信,例如跨节点的通信。
总的来说,veth 对是用于本地通信的虚拟以太网设备,而 tunl0 是用于实现隧道通信的接口。
BGP模式
BGP 网络相比较 IPIP 网络,最大的不同之处就是没有了隧道设备 tunl0。前面介绍过 IPIP 网络 pod 之间的流量发送 tunl0,然后 tunl0 发送对端设备。BGP 网络中,pod 之间的流量直接从网卡发送目的地,减少了 tunl0 这个环节。

- 边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议。
- 它通过维护 IP 路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。
- BGP 不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。
- BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单 IP,BGP 机房的优点:服务器只需要设置一个 IP 地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。
- BGP 网络相比较 IPIP 网络,最大的不同之处就是没有了隧道设备 tunl0。
十四、安全
Kubernetes API 的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及准入控制(Admission Control)等。
1. 认证(Authentication):
在请求到达 Kubernetes API 服务器时,首先进行认证,验证请求的身份是否合法。认证可以通过不同的方式实现,如基于证书的 TLS 认证、令牌认证、用户名密码认证等。只有成功通过认证的请求才能继续后续的流程。
2.授权(Authorization):
认证通过后,请求将被送往授权模块进行授权判断。授权会验证请求的发起者是否有执行该操作的权限。在 Kubernetes 中,主要通过 RBAC(基于角色的访问控制)来实现授权,根据用户或实体的角色和权限来确定是否允许执行请求的操作。
2.1 创建 Service Account :
通过以下命令在指定的 Namespace 中创建一个 Service Account
kubectl create serviceaccount <service-account-name> -n <namespace>
其中,<service-account-name> 是你想要创建的 Service Account 的名称,<namespace> 是 Service Account 所属的 Namespace。
2.2 创建Role或 ClusterRole :
Role:
- 作用域:Role 对象是针对单个 Namespace 的。它定义了一组权限规则,可以授予在特定 Namespace 内对资源的操作权限。
- 规则范围:在创建 Role 时,规则只适用于特定 Namespace 内的资源。
ClusterRole:
- 作用域:ClusterRole 对象是集群级别的,它定义了一组权限规则,可用于授予对集群范围内资源的操作权限。
- 规则范围:ClusterRole 可以用于控制对整个集群中的资源的操作权限,而不限于单个 Namespace。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: <namespace>
name: sa-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "create", "delete"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: custom-cluster-role
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "create", "update", "delete"]
2.2 创建 RoleBinding 或 ClusterRoleBinding :
创建 RoleBinding 或 ClusterRoleBinding 将 Service Account 与角色或者 ClusterRole 绑定起来
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sa-role-binding
namespace: <namespace>
subjects:
- kind: ServiceAccount
name: <service-account-name>
namespace: <namespace>
roleRef:
kind: Role
name: sa-role
apiGroup: rbac.authorization.k8s.io
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: <cluster-role-binding-name>
subjects:
- kind: ServiceAccount
name: <service-account-name>
namespace: <namespace>
roleRef:
kind: ClusterRole
name: <cluster-role-name>
apiGroup: rbac.authorization.k8s.io
2.4 获取 Service Account 的 Token:
get secret <service-account-token-secret> -n <namespace> -o=jsonpath='{$.data.token}' | base64 --decode
其中,<service-account-token-secret> 是 Service Account 的 Token Secret 名称,一般格式为 <service-account-name>-token-<random-string>。
2.5创建 kubeconfig 文件 :
使用以下模板创建 kubeconfig 文件,替换 <cluster-name>, <server-url>, <ca-cert-data>, <token> 为实际值:
apiVersion: v1
kind: Config
clusters:
- name: <cluster-name>
cluster:
server: <server-url>
certificate-authority-data: <ca-cert-data>
contexts:
- name: <context-name>
context:
cluster: <cluster-name>
user: <user-name>
current-context: <context-name>
users:
- name: <user-name>
user:
token: <token>
3. 准入控制(Admission Control):
当请求通过了认证和授权之后,将被送往准入控制模块进行进一步处理。准入控制器是 Kubernetes API 服务器的一个插件机制,用于对请求进行审查和修改,确保请求符合集群的策略和规范。准入控制可用于应用特定的安全策略、限制资源的创建或更新等。
评论区