Kubernetes Pod和容器设计模式
1 定义pod资源
1.1 关于pod
什么是Pod?
- 一个或多个容器的集合,因而也可称为容器集,但却是Kubernetes调度、部署和运行应用的原子单元
- 另外封装的内容:可被该组容器共享的存储资源、网络协议栈及容器的运行控制策略等
- 依赖于pause容器事先创建出可被各应用容器共享的基础环境,它默认共享Network、IPC和UTS名称空间给各容器,PID名称空间也可以共享,但需要用户显式定义
Pod的组成形式有两种
- 单容器Pod:仅含有单个容器
- 多容器Pod:含有多个具有“超亲密”关系的容器
- 同一Pod内的所有容器都将运行于由Scheduler选定的同一个节点上
1.2 Pod资源规范的基础框架
一个极简的Pod定义,仅需要为其指定一个要运行的容器即可
- 给出该容器的名称和使用的Image
- pause容器无需定义
- 下面是一个简单的Pod资源示例
1.3 了解Pod的运行状况
- 打印Pod完整的资源规范,通过status字段了解
- kubectl get TYPE NAME -o yaml|json
- 例如
- kubectl get pods demoapp -o yaml
- kubectl get pods demoapp -o json
- 打印Pod资源的详细状态
- kubectl describe TYPE NAME
- 例如
- kubectl describe pods demoapp
- 获取Pod中容器应用的日志
- kubectl logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]
- 例如
- kubectl logs demoapp -c demoapp
1.4 Pod的phase和重启策略
Pod的相位
- Pending (待决中):Pod 已经被 Kubernetes 控制平面接受,但它的容器还没有开始创建。这通常表示资源尚未分配到节点上,或卷、网络等相关资源还没有准备好。
- 状态:Pod 已经提交到 API server,等待调度器将 Pod 分配到某个节点,可能在等待卷、网络、节点资源等。
- Running (运行中):Pod 已经被调度到一个节点,并且所有的容器都已经创建。至少有一个容器正在运行,或者正在启动或重启中。
- 状态:Pod 已经成功分配到一个节点上,至少有一个容器正在运行或处于准备运行的状态。
- Succeeded (成功):Pod 中的所有容器都已经成功终止,并且不会再重新启动。通常用于执行一次性任务(如 Job)的 Pod。
- 状态:所有容器已成功完成并正常退出,pod 进入此状态后,意味着任务已完成且没有失败。
- Failed (失败):Pod 中的所有容器已经终止,但其中至少有一个容器以非零状态退出,表明容器运行失败。
- 状态:至少有一个容器非正常终止,退出码不为 0。Pod 已经停止运行且不会被重新启动(除非使用了重启策略)。
- Unknown (未知):由于某些原因,Kubernetes 无法获取到 Pod 的状态信息,通常是因为无法与节点通信。
- 状态:控制平面无法与 Pod 所在的节点通信,Pod 的实际状态无法确定,可能是由于网络问题或节点失联。
- 状态:控制平面无法与 Pod 所在的节点通信,Pod 的实际状态无法确定,可能是由于网络问题或节点失联。
容器的状态
- Waiting (等待中):容器已经被创建,但尚未启动或运行。此状态表示容器正在等待一些条件满足,才能开始运行。
- 常见原因:
- 镜像拉取:正在从镜像仓库中拉取镜像。
- 资源不足:节点上资源不足,无法启动容器。
- 配置错误:如启动命令错误、镜像路径错误等。
- 调试方法:可以使用 kubectl describe pod
查看具体的等待原因。
- 常见原因:
- Running (运行中):容器已经成功启动,并且正在运行中。此状态表示容器中的应用程序正在正常处理任务。
- 特点:容器已经分配了必要的资源,并处于工作状态,可以对外提供服务。
- Terminated (已终止):容器已经停止运行。终止状态表示容器已经完成了其任务或由于某种原因停止了。
- 特点:
- 容器可能是正常退出(例如任务完成)或异常退出(例如错误或命令失败)。
- 终止状态会伴随着一个退出状态码:
- 0 表示正常退出。
- 非 0 表示由于错误退出。
- 调试方法:检查 reason 字段和退出状态码来确定容器终止的原因。
- 特点:
- Unknown (未知):由于某些原因,Kubernetes 无法获取到容器的当前状态。通常,这是因为与运行容器的节点的通信出现了问题。
- 常见原因:
- 节点失联:Kubernetes 无法与节点通信,无法获取容器状态。
- 网络问题:网络连接问题导致无法查询容器的实际状态。
- 调试方法:检查节点的健康状态,确保节点和控制平面的网络连接正常
- 常见原因:
Pod的重启策略:决定了容器终止后是否应该重启
- Always:无论何种exit code,都要重启容器
- OnFailure:仅在exit code为非0值(即错误退出)时才重启容器
- Never:无论何种exit code,都不重启容器
pod容器拉取策略
Image Pull Policy:
- Always:总是拉取镜像。无论本地是否已经存在该镜像,每次启动 Pod 时,都会尝试从指定的镜像仓库中拉取最新版本的镜像。
- IfNotPresent:本地没有要使用Image时才去Pull,但Tag为latest的Image除外,这种将自动使用Always策略;
- Never:从不拉取镜像。无论本地是否存在镜像,Kubernetes 都不会尝试从镜像仓库中拉取镜像。如果本地不存在该镜像,Pod 将无法启动。
pod容器的command和args
- Command
指定容器启动时要执行的命令。如果未设置 command,容器将使用镜像中定义的默认启动命令。 - Args
args:指定传递给 command 的参数。如果 args 未设置,容器将使用镜像中定义的默认参数。
#范例:
containers:
- name: my-container
image: busybox
command: ["sleep"]
args: ["3600"]
#在这个例子中,容器将运行 sleep 3600 命令,也就是让容器休眠一小时。
#默认行为
#- 如果只指定了 command 而没有指定 args,则容器仅运行指定的 command,没有任何附加参数。
#- 如果只指定了 args 而没有指定 command,则 args 会被传递给镜像中的默认启动命令。
#- 如果 command 和 args 都未指定,容器将运行镜像中的默认启动命令及其默认参数。
2 配置pod
2.1 通过环境变量向容器传递参数
环境变量是容器化应用的常用配置方式之一
在容器上嵌套使用env字段
- 每个环境变量需要通过name给出既定的名称
- 传递的值则定义在value字段上
示例:
2.2 应用监控
容器式运行的应用类似于“黑盒”,为了便于平台对其进行监测,云原生应用应该输出用于监视自身API
- 包括健康状态、指标、分布式跟踪和日志等
- 至少应该提供用于健康状态监测的API
- Process Health (进程健康状态)
- 定义:指容器内运行的应用程序进程是否正常运行。这通常通过 liveness 探针或 readiness 探针来检测。
- API 采集的内容:API 可以查询容器内应用进程的状态,判断其是否处于 Running 状态。如果进程异常终止或挂起,Kubernetes 可以根据设定的策略进行重启或其他操作。
- Readiness (就绪状态检测)
- 定义:指容器是否已经准备好处理外部请求。Readiness 探针用于检测容器的就绪状态,当容器处于“就绪”状态时,Pod 才会被加入到服务的负载均衡中。
- API 采集的内容:Kubernetes 通过 API 调用容器内部的健康检查端点(如 HTTP 或 TCP),以判断容器是否准备好接受请求。如果容器未通过就绪检查,它将不会接收流量。
- Liveness (存活状态检测)
- 定义:指容器是否仍然存活和健康。Liveness 探针用于检测容器是否在正常运行。如果存活检查失败,Kubernetes 会认为容器不再健康,并可能会重新启动它。
- API 采集的内容:Kubernetes 会定期通过 API 调用设定的端点(如执行命令或访问 URL)来检查容器的存活状态。如果检查失败,容器将被重新启动。
- Metrics (指标)
- 定义:指收集和监控容器和应用程序的性能指标,如 CPU 使用率、内存使用量、请求延迟等。
- API 采集的内容:Kubernetes 通过 Metrics Server 或其他监控工具(如 Prometheus)采集这些指标。应用程序也可以通过暴露特定的指标端点供监控系统采集和分析。
- Tracing (分布式链路跟踪信息)
- 定义:指收集和追踪请求在分布式系统中的流转信息。通过链路跟踪,可以了解请求在各个服务之间的传播路径及其延迟。
- API 采集的内容:分布式跟踪系统(如 Jaeger 或 Zipkin)可以通过 API 采集并分析应用程序在多个服务之间的请求流,以帮助识别性能瓶颈和延迟来源。
- Logs (日志)
- 定义:指记录应用程序运行时的日志信息。日志是排查和解决问题的重要依据。
- API 采集的内容:Kubernetes 提供 API 用于访问容器的标准输出和错误输出的日志。日志系统(如 Fluentd 或 Elasticsearch)可以收集这些日志以进行分析和存储。
2.3 Pod的健康状态监测机制
2.3.1 Pod支持的监测类型
- startup Probe
- 定义:用于检测容器启动是否成功,一旦探测成功后停止执行。startup Probe 通常用于那些启动时间较长的应用程序,以防止 Kubernetes 在容器尚未完全启动时将其标记为失败并重新启动。
- 用途:startup Probe 是为了延迟其他探针(如 liveness Probe 和 readiness Probe)的启动,直到应用程序完全启动。这确保了应用在真正启动之前不会被误判为不可用。
- liveness Probe
- 定义:用于检测容器是否处于健康运行状态。如果 liveness Probe 检测失败,Kubernetes 会认为该容器已经挂掉并将其重启。
- 用途:liveness Probe 确保容器在运行期间保持健康,如果出现死锁或其他严重问题导致容器不可用,探针会触发重启。
- readiness Probe
- 定义:用于检测容器是否已准备好接受请求。如果 readiness Probe 检测失败,Kubernetes 会将该 Pod 从服务的负载均衡中移除,直到检测通过为止。
- 用途:readiness Probe 确保只有在容器准备好处理流量时,才会接收外部请求,防止请求被发送到尚未准备好的容器。
典型场景:
在一个运行 Tomcat 的应用程序中,livenessProbe 和 readinessProbe 可以配置来分别检测 JVM 和应用程序的状态。以下是一个典型的场景:
- JVM 启动成功但应用程序未完全启动的场景
livenessProbe 成功:
- 检测内容:livenessProbe 可以配置为检查 JVM 是否已经成功启动,例如通过检测某个端口是否打开,或者检查一个简单的 HTTP 响应。
- 成功条件:一旦 JVM 启动并开始监听某个端口(如 8080),livenessProbe 会认为容器是健康的,因此检测成功。
readinessProbe 失败:
- 检测内容:readinessProbe 可以配置为检查应用程序是否已经完全启动并准备好处理请求。通常,这可以通过访问应用程序的某个特定路径(如 /healthz 或 /ready)来实现,该路径会返回应用程序的准备状态。
- 失败条件:即使 JVM 已经启动,Tomcat 可能还在加载应用程序、初始化资源或连接到数据库等。在这些过程中,应用程序可能还没有准备好处理外部请求,readinessProbe 会失败。
注意:
- Liveness Probe检测失败,会将容器重启,过程中,Pod 的状态可能会短暂变为 Terminating,然后变为Running。
- ReadinessProbe失败时,Pod 的状态仍然是 Running, Ready 状态标记为 False,这意味着该 Pod 不会再接收新的流量。例如,服务会将这个 Pod 从负载均衡的目标列表中移除,直到 readinessProbe 再次成功。
2.3.2 监测机制
- Exec Action:根据指定命令的结果状态码判定
- 状态码:
- 0:表示命令执行成功,探针通过。
- 非 0:表示命令执行失败,探针未通过。
- 适用场景:用于在容器内运行特定命令以检测应用程序的状态。例如,运行自定义脚本来检查应用程序的健康状况。
- 状态码:
- TcpSocket Action:根据相应TCP套接字连接建立状态判定
- 判定方式:
- 成功建立连接:探针通过。
- 无法建立连接:探针未通过。
- 适用场景:用于检查 TCP 服务(如数据库服务、消息队列等)是否能够正常接受连接。
- 判定方式:
- HTTPGet Action:根据指定https/http服务URL的响应结果判定
- 判定方式:
- 响应状态码在 200 到 399 之间:探针通过。
- 其他状态码:探针未通过。
- 适用场景:适用于 Web 服务,通过 HTTP/HTTPS 端点来检查服务是否正常运行。
- 判定方式:
2.3.3 配置参数
-
initialDelaySeconds
- 定义:在容器启动后,等待的初始时间(以秒为单位)再开始执行探针。
- 用途:确保探针不会在容器刚启动时立即执行,给应用程序足够的启动时间。
-
periodSeconds
- 定义:探针执行的周期(以秒为单位)。每隔 periodSeconds 时间,探针会被执行一次。
- 用途:控制探针的执行频率。
-
timeoutSeconds
- 定义:探针执行的超时时间(以秒为单位)。如果探针在 timeoutSeconds 时间内未返回结果,则探针视为失败。
- 用途:防止探针执行时间过长而影响容器的正常运行。
-
successThreshold
- 定义:探针连续成功的次数。只有当探针连续成功达到 successThreshold 次数时,探针才被认为通过。
- 用途:用于确保探针的稳定性,防止偶然的成功导致不准确的探针结果。
-
failureThreshold
- 定义:探针连续失败的次数。只有当探针连续失败达到 failureThreshold 次数时,探针才被认为未通过。
- 用途:用于设置探针对失败的容忍度,防止偶然的失败导致不必要的容器重启或标记为不可用。
2.3.4 健康探针配置示例
同时定义了三种探针:
startup使用了Exec Action
liveness和readiness使用HTTPGet Action
测试效果
liveness: URL “/livez” 支持以POST方法为livez参数设定不同值,非OK值都以5xx响应码响应;
readiness: URL “/readyz” 支持以POST方法为readyz参数设定不同值,非OK值都以5xx响应码响应;
2.3.5 liveness范例
范例:Exec Action
[root@k8s-master01 pods]#cat liveness-exec-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
#command: ['/bin/sh', '-c', '[ "$(curl -s 127.0.0.1/livez)" == "OK" ]']
command: ['/bin/sh', '-c', '[ "$(/usr/bin/curl -s http://127.0.0.1/livez)" == "OK" ]']
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 5
#应用yaml文件
[root@k8s-master01 pods]#kubectl apply -f liveness-exec-demo.yaml
pod/liveness-exec-demo created
使用kubectl describe查看pod详细信息,发现首次探测失败,未达到失败阈值3次不会自动重启
查看pod的ip,使用POST方法修改值为非ok
修改为非ok后,再次查看发现容器重启
使用kubectl get发现重启次数为1
再次执行curl发现重启后结果为ok
范例:TcpSocket Action
[root@k8s-master01 pods]#cat liveness-tcpsocket-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcpsocket-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
securityContext:
capabilities:
add:
- NET_ADMIN
livenessProbe:
tcpSocket:
port: http
periodSeconds: 5
initialDelaySeconds: 5
[root@k8s-master01 pods]#kubectl apply -f liveness-tcpsocket-demo.yaml
pod/liveness-tcpsocket-demo unchanged
使用kubectl get podes -o wide查看pod地址,使用curl命令发起请求测试
kubectl describe pods liveness-tcpsocket-demo发现启动成功
使用iptables规则手动禁止访问80端口
使用kubectl describe再次查看发现连接80端口拒绝,尝试重启容器。因为网络协议栈都是在pause容器定义的,故重启也无法解决
范例:HTTPGet Action
[root@k8s-master01 pods]#cat liveness-httpget-demo.yaml
# Maintainer: MageEdu <mage@magedu.com>
# URL: http://www.magedu.com
# ---
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-demo
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: '/livez'
port: 80
scheme: HTTP
initialDelaySeconds: 5
[root@k8s-master01 pods]#kubectl apply -f liveness-httpget-demo.yaml
pod/liveness-httpget-demo created
后续测试同Exec Action,修改livez的值,状态码为506,再使用kubectl describe查看Events
2.3.6 readiness范例
范例
[root@k8s-master01 pods]#cat readiness-httpget-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-demo
namespace: default
labels:
name: readiness-httpget-demo
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
path: '/readyz'
port: 80
scheme: HTTP
initialDelaySeconds: 15
timeoutSeconds: 2
periodSeconds: 5
failureThreshold: 3
restartPolicy: Always
#生成一个Service 的 YAML 文件,将生成的文件内容追加到 readiness-httpget-demo.yaml 中
[root@k8s-master01 pods]#kubectl create service clusterip readiness-httpget-demo --tcp=80:80 --dry-run=client -o yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: readiness-httpget-demo
name: readiness-httpget-demo
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: readiness-httpget-demo
type: ClusterIP
status:
loadBalancer: {}
[root@k8s-master01 pods]#kubectl create service clusterip readiness-httpget-demo --tcp=80:80 --dry-run=client -o yaml >> readiness-httpget-demo.yaml
#使用vim编辑追加后的文件,删除不必要的字段
[root@k8s-master01 pods]#vim readiness-httpget-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-demo
namespace: default
labels:
name: readiness-httpget-demo
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
path: '/readyz'
port: 80
scheme: HTTP
initialDelaySeconds: 15
timeoutSeconds: 2
periodSeconds: 5
failureThreshold: 3
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app: readiness-httpget-demo
name: readiness-httpget-demo
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
name: readiness-httpget-demo
type: ClusterIP
apply创建pod和service,get查看pod初始化未完成时为未就绪状态,查看service的Endpoints为空,并未将其加入到可用后端列表中的端点
pod就绪后,再次查看service的Endpoints显示pod的ip地址和端口
手动修改readyz的值,让readiness状态不再就绪
events事件中发现pod就绪探测失败
查看serivce可用后端又为空
将值改为ok后,service将后端重新加回去了
2.3.7 startup范例
2.4 Security Context
2.4.1 Pod及容器的安全上下文
- 一组用来决定容器是如何创建和运行的约束条件,这些条件代表创建和运行容器时使用的运行时参数
- 给了用户为Pod或容器定义特权和访问控制机制
Pod和容器的安全上下文设置主要包括以下几个方面:
- 自主访问控制DAC
- 容器进程运行身份及资源访问权限
- 定义:指容器内的进程以何种用户身份运行,以及它们对资源的访问权限。这可以通过设置 runAsUser 和 runAsGroup 等参数来控制。
- 作用:例如,通过设置 runAsUser,可以指定容器内进程以特定的用户 ID 运行,而不是默认的 root 用户。这有助于降低潜在的安全风险。
- Linux Capabilities
- 定义:Linux Capabilities 是 Linux 内核中的一种特性,它将传统的 root 权限分解为更细粒度的权限,可以只赋予进程所需的特定权限,而不是所有 root 权限。
- 作用:可以通过安全上下文设置 capabilities 字段来增加或删除容器进程的权限。比如,可以赋予容器特定的能力,如绑定到端口,但不赋予完全的 root 权限。
- seccomp
- AppArmor
- SELinux
- Privileged Mode
- Privilege Escalation
Kubernetes支持在Pod及容器级别分别使用安全上下文
Linux Capabilities:https://man7.org/linux/man-pages/man7/capabilities.7.html
2.4.1.1 Linux Capabilities
范例1: add: ["NET_ADMIN"]
上图进入pod容器中执行iptbales命令提示权限被拒绝(你必须是root),是因为容器中运行的 root 用户并不是真正的宿主机 root 用户,而是一个受限的 root 用户。这是因为容器技术通过隔离机制(如命名空间和 cgroups)来实现容器的隔离,确保容器内的操作不会直接影响到宿主机的安全性和稳定性,需要容器内也能执行该操作需要配置Security Context。
示例如下:
apiVersion: v1
kind: Pod
metadata:
name: demoapp
spec:
containers:
- name: demoapp
image: ikubernetes/demoapp:v1.0
securityContext:
capabilities:
add: ["NET_ADMIN"]
范例2:drop ["CHOWN"]
执行chown修改属主数组提示不允许操作
2.4.1.2 指定容器进程运行身份
范例:
默认容器以root身份运行,使用runAsUser指定进程运行用户
2.5 资源需求(requests)和限制(limits)
资源需求(requests)
- 定义需要系统预留给该容器使用的资源最小可用值
- 容器运行时可能用不到这些额度的资源,但用到时必须确保有相应数量的资源可用
- 资源需求的定义会影响调度器的决策
资源限制(limits)
- 定义该容器可以申请使用的资源最大可用值,超出该额度的资源使用请求将被拒绝
- 该限制需要大于等于requests的值,但系统在其某项资源紧张时,会从容器那里回收其使用的超出其requests值的那部分
requests和limits定义在容器级别,主要围绕cpu、memory和hugepages三种资源
范例:
#对cpu和内存进行资源需求和资源限制配置
[root@k8s-master01 pods]#cat resource-requests-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: stress-pod
spec:
containers:
- name: stress
image: ikubernetes/stress-ng
command: ["/usr/bin/stress-ng", "-c 1", "-m 1", "--metrics-brief"]
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "400m"
[root@k8s-master01 pods]#cat resource-limits-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: memleak-pod
labels:
app: memleak
spec:
containers:
- name: simmemleak
image: ikubernetes/simmemleak
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "64Mi"
cpu: "1"
limits:
memory: "64Mi"
cpu: "1"
3 pod设计模式
3.1 容器设计模式
3.1.1 基于容器的分布式系统中常用的3类设计模式
- 单容器模式:单一容器形式运行的应用
- 特点:
- 容器之间是松耦合的。
- 适合微服务架构,每个服务可以独立扩展和管理。
- 运维简单,容易调试和监控。
- 示例:
- MySQL数据库服务:一个 MySQL 数据库服务可以在一个独立的容器中运行,提供数据库服务给其他应用使用。
- 特点:
- 单节点模式:由强耦合的多个容器协同共生
- 特点:
- 容器间紧密耦合,通常需要一起部署和升级。
- 适用于需要高效的进程间通信或共享资源的场景。
- 可能涉及容器之间的依赖管理和协调。
- 示例:
- ELK 堆栈(Elasticsearch, Logstash, Kibana):在这个模式下,Elasticsearch、Logstash 和 Kibana 可以部署在同一个节点上。它们协同工作,Elasticsearch 负责存储和索引数据,Logstash 处理数据输入,Kibana 提供数据的可视化。这些服务之间的通信频繁且高效,因此放在同一节点上是一个典型的选择。
- LAMP 堆栈(Linux, Apache, MySQL, PHP):可以将 Apache Web 服务器、PHP 应用程序和 MySQL 数据库放在同一个节点上的多个容器中运行,以确保它们之间的低延迟和高效通信。
- 特点:
- 多节点模式:基于特定部署单元(Pod)实现分布式算法
- 特点:
- 适合分布式系统,提供高可用性、容错和弹性扩展。
- 容器之间通过网络通信,相对松散耦合。
- 复杂度高,需要分布式协调机制(如分布式锁、共识算法)。
- 示例:
- Redis Cluster:Redis Cluster 是 Redis 的分布式实现,它允许将数据分布在多个节点上,以实现水平扩展、数据分片和高可用性。Redis Cluster 通过分片(sharding)机制将数据分布在多个节点(Node)中,并且每个节点可以有一个或多个副本(replica)来提高容错能力。
- 特点:
3.1.2 单节点多容器模式
- 一种跨容器的设计模式
- 目的是在单个节点之上同时运行多个共生关系的容器,因而容器管理系统需要由将它们作为一个原子单位进行统一调度
- Pod概念就是这个设计模式的实现之一
3.1.3 单节点多容器模式的常见实现
Sidecar模式
- Pod中的应用由主应用程序(通常是基于HTTP协议的应用程序)以及一个Sidecar容器组成
- 辅助容器用于为主容器提供辅助服务以增强主容器的功能,是主应用程序是必不可少的一部分,但却未必非得运行为应用的一部分
Ambassador模式
- Pod中的应用由主应用程序和一个Ambassador容器组成
- 辅助容器代表主容器发送网络请求至外部环境中,因此可以将其视作主容器应用的“大使”
- 应用场景:云原生应用程序需要诸如断路、路由、计量和监视等功能,但更新已有的应用程序或现有代码库以添加这些功能可能很困难,甚至难以实现,进程外代理便成了一种有效的解决方案
Adapter模式
- Pod中的应用由主应用程序和一个Adapter容器组成
- Adapter容器为主应用程序提供一致的接口,实现了模块重用,支持标准化和规范化主容器应用程序的输出以便于外部服务进行聚合
Init Container模式
- 一个Pod中可以同时定义多个Init容器
- Init容器负责以不同于主容器的生命周期来完成那些必要的初始化任务,包括在文件系统上设置必要的特殊权限、数据库模式设置或为主应用程序提供初始数据等,但这些初始化逻辑无法包含在应用程序的镜像文件中,或者出于安全原因,应用程序镜像没有执行初始化活动的权限等等
- Init容器需要串行运行,且在所有Init容器均正常终止后,才能运行主容器
3.1.3.1 Sidecar范例:
Sidecar 模式是将一个或多个辅助容器与主应用容器一起部署在同一个 Pod 中。这些辅助容器通常提供与主应用容器紧密相关的支持功能,如日志收集、监控、代理、数据备份等。
[root@k8s-master01 pods]#cat sidecar-container-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: sidecar-container-demo
namespace: default
spec:
containers:
- name: proxy #Sidecar辅助容器
image: nginx:1.24-alpine
- name: demo #主容器
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
env:
- name: HOST
value: "127.0.0.1"
- name: PORT
value: "8080"
[root@k8s-master01 pods]#kubectl apply -f sidecar-container-demo.yaml
pod/sidecar-container-demo created
进入proxy容器中手动创建nginx代理文件,注释默认的default.conf文件,使用curl访问测试能成功代理到demo容器的8080端口
3.1.3.2 Ambassador范例
Ambassador 模式 是一种在同一个 Pod 内运行多个容器的设计模式,其中一个容器(即“大使”或“ambassador”容器)代理另一个容器的网络请求或其他外部通信。这种模式常用于将网络流量路由到主应用程序容器,处理复杂的网络任务,如负载均衡、服务发现、协议转换等。
[root@k8s-master01 pods]#cat ambassador-container-demo.yaml
# Create By: "MageEdu <mage@magedu.com>"
# Site: www.magedu.com
apiVersion: v1
kind: Pod
metadata:
name: ambassador-container-demo
spec:
containers:
- name: curl #主容器
image: ikubernetes/admin-box:v1.2
command: ["sleep", "999999"]
- name: ambassador #大使容器,它会代理请求并将其转发到 Kubernetes API 服务器。
image: bitnami/kubectl:latest
command: ["/bin/sh","-c","kubectl proxy"] #ambassador 容器通过 kubectl proxy 命令充当代理,它会将外部请求转发到 Kubernetes API 服务器(地址为 https://kubernetes.default.svc)。
args:
# 传递给 kubectl proxy 的选项,若需要改变默认监听的tcp/8001端口,可以额外附加“--port=NUM”选项;
- --server="https://kubernetes.default.svc"
- --certificate-authority="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
- --token="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
- --accept-paths='^.\*'
#在这个示例中,curl容器本身是不能直接访问 API 服务器的,ambassador 容器作为代理,将对 Kubernetes API 的请求路由到实际的 API 服务器。这种设置使得 curl 容器可以通过 ambassador 容器间接访问 Kubernetes API,而不需要直接与 API 服务器通信
3.1.3.3 Adapter范例
Adapter 模式用于将主应用容器的输出或数据格式转换为另一种格式或接口,使其能够与外部系统或其他服务进行交互。Adapter 容器通常与主应用容器一起部署,以处理数据转换、协议适配等任务。
[root@k8s-master01 pods]#cat adapter-container-demo.yaml
# Create By: "MageEdu <mage@magedu.com>"
# Site: www.magedu.com
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
default.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
---
apiVersion: v1
kind: Pod
metadata:
name: adapter-container-demo
spec:
containers:
- name: nginx #主容器
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d/
name: nginx-conf
readOnly: true
- name: adapter # adapter容器将nginxnginx的status的指标转换为prometheus兼容格式并暴露出去,供prometheus采集
image: nginx/nginx-prometheus-exporter:latest
args: ["-nginx.scrape-uri","http://localhost/nginx_status"]
ports:
# nginx-prometheus-exporter默认监听tcp/9113端口
- name: exporter
containerPort: 9113
volumes:
- name: nginx-conf
configMap:
name: nginx-conf
items:
- key: default.conf
path: default.conf
使用curl命令请求9113端口的metrics路径可以获取到值
3.1.3.4 Init Container范例
Init Container 是在主应用容器启动之前运行的容器,通常用于执行一些初始化任务,如配置文件生成、数据库迁移、依赖下载等。Init Container 完成后,主应用容器才会启动。
[root@k8s-master01 pods]#cat init-container-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-container-demo
namespace: default
spec:
initContainers: #init容器使用特殊字段
- name: iptables-init #初始容器
image: ikubernetes/admin-box:latest
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c'] #使用iptables命令添加一条nat策略,将目标端口是8080的请求转给80端口
args: ['iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80']
securityContext:
capabilities:
add:
- NET_ADMIN
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
查看端口仅监听了80端口,使用curl测试8080端口能收到响应
因为未给demo主容器capabilities权限,所以进入该容器中也无法执行iptables命令查看规则
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了