AI摘要 本文详细介绍了Kubernetes中的灰度发布策略，包括灰度发布的概念、优势、实现方案和最佳实践。文章通过示例代码展示了基于Service+Deployment标签选择、Ingress Controller和Istio Service Mesh的灰度发布实现方法，并提供了监控配置、发布策略、自动化回滚和用户细分策略等最佳实践。最后，文章讨论了常见问题及其解决方案，强调了灰度发布在现代应用部署中的重要性。 此内容根据文章生成，仅用于文章内容的解释与总结 Kubernetes灰度发布实战指南：让你的应用更新更安全在微服务架构盛行的今天，应用的频繁更新已经成为常态。然而，如何在保证业务稳定的前提下，安全地发布新版本，一直是运维和开发团队面临的重要挑战。今天我们来深入探讨Kubernetes中的灰度发布策略，让你的应用更新更加安全可控。什么是灰度发布？灰度发布（Canary Deployment），也称为金丝雀发布，是一种渐进式的部署策略。它的核心思想是先将新版本部署到一小部分用户或服务器上，观察其运行情况，如果一切正常，再逐步扩大新版本的覆盖范围，直到完全替换旧版本。这种策略的名称来源于矿工使用金丝雀检测矿井中有毒气体的做法——如果金丝雀出现异常，矿工就知道环境有危险。同样，如果新版本在小范围内出现问题，我们可以及时发现并回滚，避免影响全部用户。为什么选择灰度发布？1. 降低风险传统的蓝绿部署虽然可以快速切换，但如果新版本有问题，影响范围是100%。而灰度发布可以将风险控制在可接受范围内。2. 实时监控可以通过监控小部分用户的反馈来评估新版本的性能和稳定性。3. 快速回滚一旦发现问题，可以立即停止流量导向新版本，将用户请求重新路由到稳定版本。4. 用户体验优化可以根据用户反馈来调整新版本，确保最终发布的版本质量更高。Kubernetes中的灰度发布实现方案方案一：基于Service + Deployment的标签选择这是最基础的灰度发布方式，通过控制不同版本Pod的数量来实现流量分配。# 稳定版本 Deployment apiVersion:apps/v1 kind:Deployment metadata: name:app-stable spec: replicas:9 selector: matchLabels: app:myapp version:stable template: metadata: labels: app:myapp version:stable spec: containers: -name:app image:myapp:v1.0 ports: -containerPort:8080 --- # 金丝雀版本 Deployment apiVersion:apps/v1 kind:Deployment metadata: name:app-canary spec: replicas:1 selector: matchLabels: app:myapp version:canary template: metadata: labels: app:myapp version:canary spec: containers: -name:app image:myapp:v2.0 ports: -containerPort:8080 --- # Service 配置 apiVersion:v1 kind:Service metadata: name:app-service spec: selector: app:myapp ports: -port:80 targetPort:8080 type: ClusterIP在这个配置中，Service会将流量分发到所有带有app: myapp标签的Pod上。由于稳定版本有9个副本，金丝雀版本有1个副本，所以大约10%的流量会被分发到新版本。方案二：使用Ingress Controller实现更精细的流量控制对于需要更精确流量控制的场景，可以使用Ingress Controller（如Nginx Ingress）的高级功能。# 主要的Ingress规则 apiVersion:networking.k8s.io/v1 kind:Ingress metadata: name:app-ingress annotations: nginx.ingress.kubernetes.io/canary:"false" spec: rules: -host:myapp.example.com http: paths: -path:/ pathType:Prefix backend: service: name:app-stable-service port: number:80 --- # 金丝雀Ingress规则 apiVersion:networking.k8s.io/v1 kind:Ingress metadata: name:app-canary-ingress annotations: nginx.ingress.kubernetes.io/canary:"true" nginx.ingress.kubernetes.io/canary-weight:"10" # 也可以基于请求头进行路由 # nginx.ingress.kubernetes.io/canary-by-header: "canary" # nginx.ingress.kubernetes.io/canary-by-cookie: "canary" spec: rules: -host:myapp.example.com http: paths: -path:/ pathType:Prefix backend: service: name:app-canary-service port: number: 80方案三：使用Istio Service MeshIstio提供了更强大的流量管理能力，可以实现基于请求头、Cookie、用户ID等多种维度的灰度发布。# DestinationRule 定义不同版本的subset apiVersion:networking.istio.io/v1alpha3 kind:DestinationRule metadata: name:app-destination spec: host:app-service subsets: -name:stable labels: version:stable -name:canary labels: version:canary --- # VirtualService 定义流量分发规则 apiVersion:networking.istio.io/v1alpha3 kind:VirtualService metadata: name:app-virtual-service spec: hosts: -app-service http: -match: -headers: canary: exact:"true" route: -destination: host:app-service subset:canary -route: -destination: host:app-service subset:stable weight:90 -destination: host:app-service subset:canary weight: 10灰度发布的最佳实践1. 设置合适的监控指标在进行灰度发布时，必须设置完善的监控体系：# 示例：Prometheus监控配置 apiVersion: v1 kind: ConfigMap metadata: name: app-monitoring data: prometheus.yml: | global: scrape_interval: 15s scrape_configs: - job_name: 'app-canary' static_configs: - targets: ['app-canary-service:8080'] metrics_path: /metrics - job_name: 'app-stable' static_configs: - targets: ['app-stable-service:8080'] metrics_path: /metrics关键监控指标包括：• 错误率（Error Rate）• 响应时间（Response Time）• 吞吐量（Throughput）• 系统资源使用率（CPU/Memory）2. 制定明确的发布策略# 灰度发布脚本示例 #!/bin/bash # 阶段1：部署金丝雀版本（5%流量） kubectl apply -f canary-deployment.yaml kubectl scale deployment app-canary --replicas=1 kubectl scale deployment app-stable --replicas=19 # 等待5分钟观察 sleep 300 # 检查监控指标 if check_metrics; then echo"阶段1通过，进入阶段2" # 阶段2：增加到20%流量 kubectl scale deployment app-canary --replicas=4 kubectl scale deployment app-stable --replicas=16 else echo"阶段1失败，执行回滚" kubectl scale deployment app-canary --replicas=0 exit 1 fi3. 实现自动化回滚# 使用Helm实现自动回滚 apiVersion: v1 kind: ConfigMap metadata: name: rollback-script data: rollback.sh: | #!/bin/bash ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=error_rate" | jq '.data.result[0].value[1]') if (( $(echo "$ERROR_RATE > 0.05" | bc -l) )); then echo "错误率超过5%，执行回滚" helm rollback myapp kubectl scale deployment app-canary --replicas=0 fi4. 用户细分策略可以根据不同的用户群体进行更精细的灰度发布：# 基于用户ID的灰度发布 apiVersion:networking.istio.io/v1alpha3 kind:VirtualService metadata: name:user-based-canary spec: hosts: -app-service http: -match: -headers: user-id: regex:".*[0-4]$"# 用户ID以0-4结尾的用户 route: -destination: host:app-service subset:canary -route: -destination: host:app-service subset: stable常见问题及解决方案问题1：流量分配不均匀原因： Kubernetes的负载均衡算法可能导致流量分配不够精确。解决方案： 使用Session Affinity或者更精确的负载均衡策略。apiVersion: v1 kind:Service metadata: name:app-service spec: selector: app:myapp ports: -port:80 targetPort:8080 sessionAffinity: ClientIP问题2：数据库兼容性问题原因： 新版本的数据库schema变更可能导致兼容性问题。解决方案： 采用向后兼容的数据库变更策略，或者使用数据库版本控制工具。问题3：监控延迟原因： 监控系统的数据收集和处理可能存在延迟。解决方案： 设置合适的观察窗口期，不要过早判断发布结果。总结灰度发布是现代应用部署的重要策略，Kubernetes提供了多种实现方案，从简单的基于副本数量的流量分配，到复杂的基于Istio的精细化流量控制。选择合适的方案需要根据具体的业务需求、技术栈和团队能力来决定。记住灰度发布的核心原则：小步快跑，快速验证，及时回滚。通过完善的监控体系和自动化流程，可以显著提升应用发布的安全性和可靠性。在实际应用中，建议从简单的方案开始，逐步完善监控和自动化能力，最终建立起适合自己团队的灰度发布体系。
AI摘要 Kubernetes调度器负责将Pod放置到合适的节点上，以便节点上的Kubelet能够运行这些Pod。调度器通过监测机制发现未调度的Pod，并根据资源需求、节点选择器、节点亲和性、Pod亲和/反亲和性等原则进行调度。kube-scheduler是Kubernetes集群的默认调度器，负责选择最佳节点运行Pod。调度器的调度决策考虑因素包括资源请求、硬件/软件/策略限制、亲和及反亲和要求、数据局部性和负载间的干扰等。用户可以通过节点标签、节点隔离/限制、nodeSelector、亲和性与反亲和性、nodeName和Pod拓扑分布约束等方法来控制Pod的调度。 此内容根据文章生成，仅用于文章内容的解释与总结 调度概述在 Kubernetes 中，调度是指将 Pod 放置到合适的节点上，以便对应节点上的 Kubelet 能够运行这些 Pod。调度概览调度器通过 Kubernetes 的监测（Watch）机制来发现集群中新创建且尚未被调度到节点上的 Pod。 调度器会将所发现的每一个未调度的 Pod 调度到一个合适的节点上来运行。 调度器会依据下文的调度原则来做出调度选择。如果你想要理解 Pod 为什么会被调度到特定的节点上， 或者你想要尝试实现一个自定义的调度器，这篇文章将帮助你了解调度。当多个调度规则同时存在时，Kubernetes 会按照以下优先级顺序处理：资源需求：CPU/内存请求是最基本的筛选条件节点选择器（nodeSelector）：简单的标签匹配节点亲和性（required）：必须满足的节点条件Pod 亲和/反亲和性（required）：必须满足的 Pod 关系条件kube-schedulerkube-scheduler 是 Kubernetes 集群的默认调度器，并且是集群 控制面 的一部分。 如果你真的希望或者有这方面的需求，kube-scheduler 在设计上允许你自己编写一个调度组件并替换原有的 kube-scheduler。Kube-scheduler 选择一个最佳节点来运行新创建的或尚未调度（unscheduled）的 Pod。 由于 Pod 中的容器和 Pod 本身可能有不同的要求，调度程序会过滤掉任何不满足 Pod 特定调度需求的节点。 或者，API 允许你在创建 Pod 时为它指定一个节点，但这并不常见，并且仅在特殊情况下才会这样做。在一个集群中，满足一个 Pod 调度请求的所有节点称之为可调度节点。 如果没有任何一个节点能满足 Pod 的资源请求， 那么这个 Pod 将一直停留在未调度状态直到调度器能够找到合适的 Node。调度器先在集群中找到一个 Pod 的所有可调度节点，然后根据一系列函数对这些可调度节点打分， 选出其中得分最高的节点来运行 Pod。之后，调度器将这个调度决定通知给 kube-apiserver，这个过程叫做绑定。在做调度决定时需要考虑的因素包括：单独和整体的资源请求、硬件/软件/策略限制、 亲和以及反亲和要求、数据局部性、负载间的干扰等等。kube-scheduler 中的节点选择kube-scheduler 给一个 Pod 做调度选择时包含两个步骤：过滤打分过滤阶段会将所有满足 Pod 调度需求的节点选出来。 例如，PodFitsResources 过滤函数会检查候选节点的可用资源能否满足 Pod 的资源请求。 在过滤之后，得出一个节点列表，里面包含了所有可调度节点；通常情况下， 这个节点列表包含不止一个节点。如果这个列表是空的，代表这个 Pod 不可调度。在打分阶段，调度器会为 Pod 从所有可调度节点中选取一个最合适的节点。 根据当前启用的打分规则，调度器会给每一个可调度节点进行打分。最后，kube-scheduler 会将 Pod 调度到得分最高的节点上。 如果存在多个得分最高的节点，kube-scheduler 会从中随机选取一个。支持以下两种方式配置调度器的过滤和打分行为：调度策略 允许你配置过滤所用的 断言（Predicates） 和打分所用的 优先级（Priorities）。调度配置 允许你配置实现不同调度阶段的插件， 包括：QueueSort、Filter、Score、Bind、Reserve、Permit 等等。 你也可以配置 kube-scheduler 运行不同的配置文件。将 Pod 指派给节点你可以约束一个 Pod 以便限制其只能在特定的节点上运行， 或优先在特定的节点上运行。有几种方法可以实现这点， 推荐的方法都是用标签选择算符来进行选择。 通常这样的约束不是必须的，因为调度器将自动进行合理的放置（比如，将 Pod 分散到节点上， 而不是将 Pod 放置在可用资源不足的节点上等等）。但在某些情况下，你可能需要进一步控制 Pod 被部署到哪个节点。例如，确保 Pod 最终落在连接了 SSD 的机器上， 或者将来自两个不同的服务且有大量通信的 Pod 被放置在同一个可用区。你可以使用下列方法中的任何一种来选择 Kubernetes 对特定 Pod 的调度：与节点标签匹配的 nodeSelector亲和性与反亲和性nodeName 字段Pod 拓扑分布约束节点标签与很多其他 Kubernetes 对象类似，节点也有标签。 你可以手动地添加标签。 Kubernetes 也会为集群中所有节点添加一些标准的标签。说明：这些标签的取值是取决于云提供商的，并且是无法在可靠性上给出承诺的。 例如，kubernetes.io/hostname 的取值在某些环境中可能与节点名称相同， 而在其他环境中会取不同的值。节点隔离/限制通过为节点添加标签，你可以准备让 Pod 调度到特定节点或节点组上。 你可以使用这个功能来确保特定的 Pod 只能运行在具有一定隔离性、安全性或监管属性的节点上。如果使用标签来实现节点隔离，建议选择节点上的 kubelet 无法修改的标签键。 这可以防止受感染的节点在自身上设置这些标签，进而影响调度器将工作负载调度到受感染的节点。NodeRestriction 准入插件防止 kubelet 使用 node-restriction.kubernetes.io/ 前缀设置或修改标签。要使用该标签前缀进行节点隔离：确保你在使用节点鉴权机制并且已经启用了 NodeRestriction 准入插件。将带有 node-restriction.kubernetes.io/ 前缀的标签添加到 Node 对象， 然后在节点选择算符中使用这些标签。 例如，example.com.node-restriction.kubernetes.io/fips=true 或 example.com.node-restriction.kubernetes.io/pci-dss=true。nodeSelectornodeSelector 是节点选择约束的最简单推荐形式。你可以将 nodeSelector 字段添加到 Pod 的规约中设置你希望目标节点所具有的节点标签。 Kubernetes 只会将 Pod 调度到拥有你所指定的每个标签的节点上。进一步的信息可参见将 Pod 指派给节点。亲和性与反亲和性nodeSelector 提供了一种最简单的方法来将 Pod 约束到具有特定标签的节点上。 亲和性和反亲和性扩展了你可以定义的约束类型。使用亲和性与反亲和性的一些好处有：亲和性、反亲和性语言的表达能力更强。nodeSelector 只能选择拥有所有指定标签的节点。 亲和性、反亲和性为你提供对选择逻辑的更强控制能力。你可以标明某规则是“软需求”或者“偏好”，这样调度器在无法找到匹配节点时仍然调度该 Pod。你可以使用节点上（或其他拓扑域中）运行的其他 Pod 的标签来实施调度约束， 而不是只能使用节点本身的标签。这个能力让你能够定义规则允许哪些 Pod 可以被放置在一起。亲和性功能由两种类型的亲和性组成：节点亲和性功能类似于 nodeSelector 字段，但它的表达能力更强，并且允许你指定软规则。Pod 间亲和性/反亲和性允许你根据其他 Pod 的标签来约束 Pod。节点亲和性节点亲和性概念上类似于 nodeSelector， 它使你可以根据节点上的标签来约束 Pod 可以调度到哪些节点上。 节点亲和性有两种：requiredDuringSchedulingIgnoredDuringExecution： 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector， 但其语法表达能力更强。preferredDuringSchedulingIgnoredDuringExecution： 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点，调度器仍然会调度该 Pod。说明：在上述类型中，IgnoredDuringExecution 意味着如果节点标签在 Kubernetes 调度 Pod 后发生了变更，Pod 仍将继续运行。你可以使用 Pod 规约中的 .spec.affinity.nodeAffinity 字段来设置节点亲和性。例如，考虑下面的 Pod 规约：pods/pod-with-node-affinity.yamlapiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - antarctica-east1 - antarctica-west1 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: another-node-label-key operator: In values: - another-node-label-value containers: - name: with-node-affinity image: registry.k8s.io/pause:2.0在这一示例中，所应用的规则如下：节点必须包含一个键名为 topology.kubernetes.io/zone 的标签， 并且该标签的取值必须为 antarctica-east1 或 antarctica-west1。节点最好具有一个键名为 another-node-label-key 且取值为 another-node-label-value 的标签。你可以使用 operator 字段来为 Kubernetes 设置在解释规则时要使用的逻辑操作符。 你可以使用 In、NotIn、Exists、DoesNotExist、Gt 和 Lt 之一作为操作符。阅读操作符了解有关这些操作的更多信息。NotIn 和 DoesNotExist 可用来实现节点反亲和性行为。 你也可以使用节点污点 将 Pod 从特定节点上驱逐。说明：如果你同时指定了 nodeSelector 和 nodeAffinity，两者必须都要满足， 才能将 Pod 调度到候选节点上。如果你在与 nodeAffinity 类型关联的 nodeSelectorTerms 中指定多个条件， 只要其中一个 nodeSelectorTerms 满足（各个条件按逻辑或操作组合）的话，Pod 就可以被调度到节点上。如果你在与 nodeSelectorTerms 中的条件相关联的单个 matchExpressions 字段中指定多个表达式， 则只有当所有表达式都满足（各表达式按逻辑与操作组合）时，Pod 才能被调度到节点上。参阅使用节点亲和性来为 Pod 指派节点， 以了解进一步的信息。节点亲和性权重你可以为 preferredDuringSchedulingIgnoredDuringExecution 亲和性类型的每个实例设置 weight 字段，其取值范围是 1 到 100。 当调度器找到能够满足 Pod 的其他调度请求的节点时，调度器会遍历节点满足的所有的偏好性规则， 并将对应表达式的 weight 值加和。最终的加和值会添加到该节点的其他优先级函数的评分之上。 在调度器为 Pod 作出调度决定时，总分最高的节点的优先级也最高。例如，考虑下面的 Pod 规约：pods/pod-with-affinity-preferred-weight.yamlapiVersion: v1 kind: Pod metadata: name: with-affinity-preferred-weight spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: label-1 operator: In values: - key-1 - weight: 50 preference: matchExpressions: - key: label-2 operator: In values: - key-2 containers: - name: with-node-affinity image: registry.k8s.io/pause:2.0如果存在两个候选节点，都满足 preferredDuringSchedulingIgnoredDuringExecution 规则， 其中一个节点具有标签 label-1:key-1，另一个节点具有标签 label-2:key-2， 调度器会考察各个节点的 weight 取值，并将该权重值添加到节点的其他得分值之上，说明：如果你希望 Kubernetes 能够成功地调度此例中的 Pod，你必须拥有打了 kubernetes.io/os=linux 标签的节点。逐个调度方案中设置节点亲和性特性状态： Kubernetes v1.20 [beta]在配置多个调度方案时， 你可以将某个方案与节点亲和性关联起来，如果某个调度方案仅适用于某组特殊的节点时， 这样做是很有用的。 要实现这点，可以在调度器配置中为 NodeAffinity 插件的 args 字段添加 addedAffinity。例如：apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration profiles: - schedulerName: default-scheduler - schedulerName: foo-scheduler pluginConfig: - name: NodeAffinity args: addedAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: scheduler-profile operator: In values: - foo这里的 addedAffinity 除遵从 Pod 规约中设置的节点亲和性之外， 还适用于将 .spec.schedulerName 设置为 foo-scheduler。 换言之，为了匹配 Pod，节点需要满足 addedAffinity 和 Pod 的 .spec.NodeAffinity。由于 addedAffinity 对最终用户不可见，其行为可能对用户而言是出乎意料的。 应该使用与调度方案名称有明确关联的节点标签。说明：DaemonSet 控制器为 DaemonSet 创建 Pod， 但该控制器不理会调度方案。 DaemonSet 控制器创建 Pod 时，默认的 Kubernetes 调度器负责放置 Pod， 并遵从 DaemonSet 控制器中设置的 nodeAffinity 规则。Pod 间亲和性与反亲和性Pod 间亲和性与反亲和性使你可以基于已经在节点上运行的 Pod 的标签来约束 Pod 可以调度到的节点，而不是基于节点上的标签。Pod 间亲和性与反亲和性的类型Pod 间亲和性与反亲和性的格式为“如果 X 上已经运行了一个或多个满足规则 Y 的 Pod， 则这个 Pod 应该（或者在反亲和性的情况下不应该）运行在 X 上”。 这里的 X 可以是节点、机架、云提供商可用区或地理区域或类似的拓扑域， Y 则是 Kubernetes 尝试满足的规则。你通过标签选择算符 的形式来表达规则（Y），并可根据需要指定选关联的名字空间列表。 Pod 在 Kubernetes 中是名字空间作用域的对象，因此 Pod 的标签也隐式地具有名字空间属性。 针对 Pod 标签的所有标签选择算符都要指定名字空间，Kubernetes 会在指定的名字空间内寻找标签。你会通过 topologyKey 来表达拓扑域（X）的概念，其取值是系统用来标示域的节点标签键。 相关示例可参见常用标签、注解和污点。说明：Pod 间亲和性和反亲和性都需要相当的计算量，因此会在大规模集群中显著降低调度速度。 我们不建议在包含数百个节点的集群中使用这类设置。说明：Pod 反亲和性需要节点上存在一致性的标签。换言之， 集群中每个节点都必须拥有与 topologyKey 匹配的标签。 如果某些或者所有节点上不存在所指定的 topologyKey 标签，调度行为可能与预期的不同。与节点亲和性类似，Pod 的亲和性与反亲和性也有两种类型：requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution例如，你可以使用 requiredDuringSchedulingIgnoredDuringExecution 亲和性来告诉调度器， 将两个服务的 Pod 放到同一个云提供商可用区内，因为它们彼此之间通信非常频繁。 类似地，你可以使用 preferredDuringSchedulingIgnoredDuringExecution 反亲和性来将同一服务的多个 Pod 分布到多个云提供商可用区中。要使用 Pod 间亲和性，可以使用 Pod 规约中的 .affinity.podAffinity 字段。 对于 Pod 间反亲和性，可以使用 Pod 规约中的 .affinity.podAntiAffinity 字段。调度行为在调度新 Pod 时，Kubernetes 调度器会根据当前集群状态评估 Pod 的亲和性/反亲和性规则：硬约束（节点过滤）：podAffinity.requiredDuringSchedulingIgnoredDuringExecution 和 podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution：调度器基于现有 Pod，确保新 Pod 被分配到满足这些必需的亲和性和反亲和性规则的节点上。软约束（评分）：podAffinity.preferredDuringSchedulingIgnoredDuringExecution 和 podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution：调度器根据节点满足这些优选的亲和性和反亲和性规则的程度来评分，以优化 Pod 的放置。忽略的字段：现有 Pod 的 podAffinity.preferredDuringSchedulingIgnoredDuringExecution：在为新 Pod 做调度决策时，不会考虑这些优选的亲和性规则。现有 Pod 的 podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution：同样，在调度时会忽略现有 Pod 的优选反亲和性规则。调度一组具有 Pod 间亲和性的 Pod如果当前正被调度的 Pod 在具有自我亲和性的 Pod 序列中排在第一个， 那么只要它满足其他所有的亲和性规则，它就可以被成功调度。 这是通过以下方式确定的：确保集群中没有其他 Pod 与此 Pod 的名字空间和标签选择算符匹配； 该 Pod 满足其自身定义的条件，并且选定的节点满足所指定的所有拓扑要求。 这确保即使所有的 Pod 都配置了 Pod 间亲和性，也不会出现调度死锁的情况。Pod 亲和性示例考虑下面的 Pod 规约：pods/pod-with-pod-affinity.yamlapiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: topology.kubernetes.io/zone podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: topology.kubernetes.io/zone containers: - name: with-pod-affinity image: registry.k8s.io/pause:2.0本示例定义了一条 Pod 亲和性规则和一条 Pod 反亲和性规则。Pod 亲和性规则配置为 requiredDuringSchedulingIgnoredDuringExecution，而 Pod 反亲和性配置为 preferredDuringSchedulingIgnoredDuringExecution。亲和性规则规定，只有节点属于特定的区域 且该区域中的其他 Pod 已打上 security=S1 标签时，调度器才可以将示例 Pod 调度到此节点上。 例如，如果我们有一个具有指定区域（称之为 "Zone V"）的集群，此区域由带有 topology.kubernetes.io/zone=V 标签的节点组成，那么只要 Zone V 内已经至少有一个 Pod 打了 security=S1 标签， 调度器就可以将此 Pod 调度到 Zone V 内的任何节点。相反，如果 Zone V 中没有带有 security=S1 标签的 Pod， 则调度器不会将示例 Pod 调度给该区域中的任何节点。反亲和性规则规定，如果节点属于特定的区域 且该区域中的其他 Pod 已打上 security=S2 标签，则调度器应尝试避免将 Pod 调度到此节点上。 例如，如果我们有一个具有指定区域（我们称之为 "Zone R"）的集群，此区域由带有 topology.kubernetes.io/zone=R 标签的节点组成，只要 Zone R 内已经至少有一个 Pod 打了 security=S2 标签， 调度器应避免将 Pod 分配给 Zone R 内的任何节点。相反，如果 Zone R 中没有带有 security=S2 标签的 Pod， 则反亲和性规则不会影响将 Pod 调度到 Zone R。查阅设计文档 以进一步熟悉 Pod 亲和性与反亲和性的示例。你可以针对 Pod 间亲和性与反亲和性为其 operator 字段使用 In、NotIn、Exists、DoesNotExist 等值。阅读操作符了解有关这些操作的更多信息。原则上，topologyKey 可以是任何合法的标签键。出于性能和安全原因，topologyKey 有一些限制：对于 Pod 亲和性而言，在 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 中，topologyKey 不允许为空。对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 Pod 反亲和性， 准入控制器 LimitPodHardAntiAffinityTopology 要求 topologyKey 只能是 kubernetes.io/hostname。如果你希望使用其他定制拓扑逻辑， 你可以更改准入控制器或者禁用之。除了 labelSelector 和 topologyKey，你也可以指定 labelSelector 要匹配的名字空间列表，方法是在 labelSelector 和 topologyKey 所在层同一层次上设置 namespaces。 如果 namespaces 被忽略或者为空，则默认为 Pod 亲和性/反亲和性的定义所在的名字空间。名字空间选择算符特性状态： Kubernetes v1.24 [stable]用户也可以使用 namespaceSelector 选择匹配的名字空间，namespaceSelector 是对名字空间集合进行标签查询的机制。 亲和性条件会应用到 namespaceSelector 所选择的名字空间和 namespaces 字段中所列举的名字空间之上。 注意，空的 namespaceSelector（{}）会匹配所有名字空间，而 null 或者空的 namespaces 列表以及 null 值 namespaceSelector 意味着“当前 Pod 的名字空间”。matchLabelKeys特性状态： Kubernetes v1.33 [stable] (enabled by default: true)说明：matchLabelKeys 字段是一个 Beta 级别的字段，在 Kubernetes 1.33 中默认被启用。 当你想要禁用此字段时，你必须通过 MatchLabelKeysInPodAffinity 特性门控禁用它。Kubernetes 在 Pod 亲和性或反亲和性中包含一个可选的 matchLabelKeys 字段。 此字段指定了应与传入 Pod 的标签匹配的标签键，以满足 Pod 的（反）亲和性。这些键用于从 Pod 的标签中查找值；这些键值标签与使用 labelSelector 字段定义的匹配限制组合（使用 AND 操作）。 这种组合的过滤机制选择将用于 Pod（反）亲和性计算的现有 Pod 集合。注意：不建议在 matchLabelKeys 中使用可能会直接在 Pod 上更新的标签。即使你编辑直接在 matchLabelKeys 中指定的 Pod 的标签 （也就是说，不是通过 Deployment 进行更新）， kube-apiserver 也不会将这种标签的更新反映到合并后的 labelSelector 上。一个常见的用例是在 matchLabelKeys 中使用 pod-template-hash （设置在作为 Deployment 的一部分进行管理的 Pod 上，其中每个版本的值是唯一的）。 在 matchLabelKeys 中使用 pod-template-hash 允许你定位与传入 Pod 相同版本的 Pod， 确保滚动升级不会破坏亲和性。apiVersion: apps/v1 kind: Deployment metadata: name: application-server ... spec: template: spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - database topologyKey: topology.kubernetes.io/zone # 只有在计算 Pod 亲和性时，才考虑指定上线的 Pod。 # 如果你更新 Deployment，替代的 Pod 将遵循它们自己的亲和性规则 # （如果在新的 Pod 模板中定义了任何规则）。 matchLabelKeys: - pod-template-hashmismatchLabelKeys特性状态： Kubernetes v1.33 [stable] (enabled by default: true)说明：mismatchLabelKeys 字段是一个 Beta 级别的字段，在 Kubernetes 1.33 中默认被禁用。 当你想要禁用此字段时，你必须通过 MatchLabelKeysInPodAffinity 特性门控禁用它。Kubernetes 为 Pod 亲和性或反亲和性提供了一个可选的 mismatchLabelKeys 字段。 此字段指定了在满足 Pod（反）亲和性时，不应与传入 Pod 的标签匹配的键。注意：不建议在 matchLabelKeys 中使用可能会直接在 Pod 上更新的标签。即使你编辑直接在 matchLabelKeys 中指定的 Pod 的标签 （也就是说，不是通过 Deployment 进行更新）， kube-apiserver 也不会将这种标签的更新反映到合并后的 labelSelector 上。一个示例用例是确保 Pod 进入指定的拓扑域（节点、区域等），在此拓扑域中只调度来自同一租户或团队的 Pod。 换句话说，你想要避免在同一拓扑域中同时运行来自两个不同租户的 Pod。apiVersion: v1 kind: Pod metadata: labels: # 假设所有相关的 Pod 都设置了 “tenant” 标签 tenant: tenant-a ... spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 确保与此租户关联的 Pod 落在正确的节点池上 - matchLabelKeys: - tenant topologyKey: node-pool podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 确保与此租户关联的 Pod 不能调度到用于其他租户的节点上 - mismatchLabelKeys: - tenant # 无论此 Pod 的 “tenant” 标签的值是什么， # 如果节点池中有来自别的租户的任何 Pod 在运行， # 都会阻碍此 Pod 被调度到这些节点池中的节点上 labelSelector: # 我们必须有一个 labelSelector，只选择具有 “tenant” 标签的 Pod， # 否则此 Pod 也会与来自 DaemonSet 的 Pod 产生反亲和性， # 例如，这些 Pod 不应该具有 “tenant” 标签 matchExpressions: - key: tenant operator: Exists topologyKey: node-pool更实际的用例Pod 间亲和性与反亲和性在与更高级别的集合（例如 ReplicaSet、StatefulSet、 Deployment 等）一起使用时，它们可能更加有用。 这些规则使得你可以配置一组工作负载，使其位于所定义的同一拓扑中； 例如优先将两个相关的 Pod 置于相同的节点上。以一个三节点的集群为例。你使用该集群运行一个带有内存缓存（例如 Redis）的 Web 应用程序。 在此例中，还假设 Web 应用程序和内存缓存之间的延迟应尽可能低。 你可以使用 Pod 间的亲和性和反亲和性来尽可能地将该 Web 服务器与缓存并置。在下面的 Redis 缓存 Deployment 示例中，副本上设置了标签 app=store。 podAntiAffinity 规则告诉调度器避免将多个带有 app=store 标签的副本部署到同一节点上。 因此，每个独立节点上会创建一个缓存实例。apiVersion: apps/v1 kind: Deployment metadata: name: redis-cache spec: selector: matchLabels: app: store replicas: 3 template: metadata: labels: app: store spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - store topologyKey: "kubernetes.io/hostname" containers: - name: redis-server image: redis:3.2-alpine下例的 Deployment 为 Web 服务器创建带有标签 app=web-store 的副本。 Pod 亲和性规则告诉调度器将每个副本放到存在标签为 app=store 的 Pod 的节点上。 Pod 反亲和性规则告诉调度器决不要在单个节点上放置多个 app=web-store 服务器。apiVersion: apps/v1 kind: Deployment metadata: name: web-server spec: selector: matchLabels: app: web-store replicas: 3 template: metadata: labels: app: web-store spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - web-store topologyKey: "kubernetes.io/hostname" podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - store topologyKey: "kubernetes.io/hostname" containers: - name: web-app image: nginx:1.16-alpine创建前面两个 Deployment 会产生如下的集群布局，每个 Web 服务器与一个缓存实例并置， 并分别运行在三个独立的节点上。node-1node-2node-3webserver-1webserver-2webserver-3cache-1cache-2cache-3总体效果是每个缓存实例都非常可能被在同一个节点上运行的某个客户端访问， 这种方法旨在最大限度地减少偏差（负载不平衡）和延迟。你可能还有使用 Pod 反亲和性的一些其他原因。 参阅 ZooKeeper 教程 了解一个 StatefulSet 的示例，该 StatefulSet 配置了反亲和性以实现高可用， 所使用的是与此例相同的技术。nodeNamenodeName 是比亲和性或者 nodeSelector 更为直接的形式。nodeName 是 Pod 规约中的一个字段。如果 nodeName 字段不为空，调度器会忽略该 Pod， 而指定节点上的 kubelet 会尝试将 Pod 放到该节点上。 使用 nodeName 规则的优先级会高于使用 nodeSelector 或亲和性与非亲和性的规则。使用 nodeName 来选择节点的方式有一些局限性：如果所指代的节点不存在，则 Pod 无法运行，而且在某些情况下可能会被自动删除。如果所指代的节点无法提供用来运行 Pod 所需的资源，Pod 会失败， 而其失败原因中会给出是否因为内存或 CPU 不足而造成无法运行。在云环境中的节点名称并不总是可预测的，也不总是稳定的。警告：nodeName 旨在供自定义调度器或需要绕过任何已配置调度器的高级场景使用。 如果已分配的 Node 负载过重，绕过调度器可能会导致 Pod 失败。 你可以使用节点亲和性或 nodeselector 字段将 Pod 分配给特定 Node，而无需绕过调度器。下面是一个使用 nodeName 字段的 Pod 规约示例：apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx nodeName: kube-01上面的 Pod 只能运行在节点 kube-01 之上。Pod 拓扑分布约束你可以使用 拓扑分布约束（Topology Spread Constraints） 来控制 Pod 在集群内故障域之间的分布， 故障域的示例有区域（Region）、可用区（Zone）、节点和其他用户自定义的拓扑域。 这样做有助于提升性能、实现高可用或提升资源利用率。阅读 Pod 拓扑分布约束 以进一步了解这些约束的工作方式。操作符下面是你可以在上述 nodeAffinity 和 podAffinity 的 operator 字段中可以使用的所有逻辑运算符。操作符行为In标签值存在于提供的字符串集中NotIn标签值不包含在提供的字符串集中Exists对象上存在具有此键的标签DoesNotExist对象上不存在具有此键的标签以下操作符只能与 nodeAffinity 一起使用。操作符行为Gt字段值将被解析为整数，并且该整数小于通过解析此选择算符命名的标签的值所得到的整数Lt字段值将被解析为整数，并且该整数大于通过解析此选择算符命名的标签的值所得到的整数说明：Gt 和 Lt 操作符不能与非整数值一起使用。 如果给定的值未解析为整数，则该 Pod 将无法被调度。 另外，Gt 和 Lt 不适用于 podAffinity。
Ingress-Nginx 基本概念与核心功能Ingress-Nginx 是 Kubernetes 生态中最流行的 Ingress Controller 实现之一，用于管理集群外部到内部服务的 HTTP (S) 流量。它本质上是一个基于 Nginx 的负载均衡器，通过 Kubernetes 的 Ingress 资源进行配置。1. 基本概念1.1 Ingress vs Ingress ControllerIngress：Kubernetes 的 API 对象，定义了外部访问集群内服务的规则（如域名、路径、TLS 配置等）。Ingress Controller：具体实现这些规则的组件（如 Nginx、Traefik、HAProxy 等），负责将流量转发到后端服务。1.2 Ingress-Nginx 的角色作为 Kubernetes 集群的 "前门"，接收所有外部 HTTP (S) 流量。根据 Ingress 资源的配置，将请求路由到对应的后端 Service。提供负载均衡、SSL 终止、路径重写、访问控制等功能。2. 流程逻辑2.1 组件交互流程客户端请求 → 负载均衡器（如云厂商 LB 或 NodePort） → Ingress-Nginx Pod → 根据 Ingress 规则 → 后端 Service → Pod2.2 关键步骤详解部署 Ingress-Nginx：在集群中部署 Ingress-Nginx Controller（通常作为 DaemonSet 或 Deployment）。创建 Service（类型为 LoadBalancer 或 NodePort）暴露 Controller。定义 Ingress 规则：yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: rules: - host: example.com http: paths: - path: /api pathType: Prefix backend: service: name: backend-service port: number: 8080规则生效：Ingress-Nginx 监控 Ingress 资源的变化，动态更新 Nginx 配置。当请求到达时，根据 host 和 path 匹配规则，转发到对应 Service。3. 使用场景3.1 域名路由将不同域名的请求路由到不同服务：yamlspec: rules: - host: api.example.com http: ... # 路由到 API 服务 - host: www.example.com http: ... # 路由到前端服务3.2 路径前缀路由根据 URL 路径将请求分发到不同服务：yamlspec: rules: - host: example.com http: paths: - path: /api backend: { service: { name: api-service } } - path: /web backend: { service: { name: web-service } }3.3 SSL/TLS 终止在 Ingress 层处理 HTTPS 请求，卸载 SSL 证书管理：yamlspec: tls: - hosts: - example.com secretName: tls-secret # 包含证书和私钥的 Secret3.4 负载均衡与流量控制通过 Ingress-Nginx 实现请求限流、重试策略、加权负载均衡等。3.5 微服务网关作为微服务架构的统一入口，处理认证、授权、API 聚合等功能。4. 优势与最佳实践4.1 优势声明式配置：通过 Ingress 资源定义规则，无需直接修改 Nginx 配置。动态更新：配置变更实时生效，无需重启服务。扩展性：支持丰富的注解（Annotations）扩展功能。5.Ingress-Nginx部署5.1部署Ingress-Nginx下面配置内容是已经替换好的（可以直接CV使用），在 K8S 主节点上创建ingress-deploy.yaml文件内容，内容如下，然后进行kubectl apply -f ingress-deploy.yaml 就可以了！[root@k8s-master01 k8s-demo]# cat ingress-deploy.yaml apiVersion: v1 kind: Namespace metadata: labels: app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx name: ingress-nginx --- apiVersion: v1 automountServiceAccountToken: true kind: ServiceAccount metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx namespace: ingress-nginx --- apiVersion: v1 kind: ServiceAccount metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx namespace: ingress-nginx rules: - apiGroups: - "" resources: - namespaces verbs: - get - apiGroups: - "" resources: - configmaps - pods - secrets - endpoints verbs: - get - list - watch - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - networking.k8s.io resources: - ingresses verbs: - get - list - watch - apiGroups: - networking.k8s.io resources: - ingresses/status verbs: - update - apiGroups: - networking.k8s.io resources: - ingressclasses verbs: - get - list - watch - apiGroups: - coordination.k8s.io resourceNames: - ingress-nginx-leader resources: - leases verbs: - get - update - apiGroups: - coordination.k8s.io resources: - leases verbs: - create - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - list - watch - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission namespace: ingress-nginx rules: - apiGroups: - "" resources: - secrets verbs: - get - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets - namespaces verbs: - list - watch - apiGroups: - coordination.k8s.io resources: - leases verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - networking.k8s.io resources: - ingresses verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - networking.k8s.io resources: - ingresses/status verbs: - update - apiGroups: - networking.k8s.io resources: - ingressclasses verbs: - get - list - watch - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - list - watch - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission rules: - apiGroups: - admissionregistration.k8s.io resources: - validatingwebhookconfigurations verbs: - get - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx namespace: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: ingress-nginx subjects: - kind: ServiceAccount name: ingress-nginx namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission namespace: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: ingress-nginx-admission subjects: - kind: ServiceAccount name: ingress-nginx-admission namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ingress-nginx subjects: - kind: ServiceAccount name: ingress-nginx namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ingress-nginx-admission subjects: - kind: ServiceAccount name: ingress-nginx-admission namespace: ingress-nginx --- apiVersion: v1 data: allow-snippet-annotations: "false" kind: ConfigMap metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-controller namespace: ingress-nginx --- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-controller namespace: ingress-nginx spec: externalTrafficPolicy: Local ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - appProtocol: http name: http port: 80 protocol: TCP targetPort: http - appProtocol: https name: https port: 443 protocol: TCP targetPort: https selector: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx type: LoadBalancer --- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-controller-admission namespace: ingress-nginx spec: ports: - appProtocol: https name: https-webhook port: 443 targetPort: webhook selector: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-controller namespace: ingress-nginx spec: minReadySeconds: 0 revisionHistoryLimit: 10 selector: matchLabels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx strategy: rollingUpdate: maxUnavailable: 1 type: RollingUpdate template: metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 spec: hostNetwork: true #与宿主机共享网络 tolerations: #设置能在master上部署 - key: node-role.kubernetes.io/master operator: Exists nodeName: k8s-master01 containers: - args: - /nginx-ingress-controller - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller - --election-id=ingress-nginx-leader - --controller-class=k8s.io/ingress-nginx - --ingress-class=nginx - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller - --validating-webhook=:8443 - --validating-webhook-certificate=/usr/local/certificates/cert - --validating-webhook-key=/usr/local/certificates/key env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: LD_PRELOAD value: /usr/local/lib/libmimalloc.so image: bitnami/nginx-ingress-controller:1.9.1 imagePullPolicy: IfNotPresent lifecycle: preStop: exec: command: - /wait-shutdown livenessProbe: failureThreshold: 5 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: controller ports: - containerPort: 80 name: http protocol: TCP - containerPort: 443 name: https protocol: TCP - containerPort: 8443 name: webhook protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: requests: cpu: 100m memory: 90Mi securityContext: allowPrivilegeEscalation: true capabilities: add: - NET_BIND_SERVICE drop: - ALL runAsUser: 101 volumeMounts: - mountPath: /usr/local/certificates/ name: webhook-cert readOnly: true dnsPolicy: ClusterFirst nodeSelector: kubernetes.io/os: linux serviceAccountName: ingress-nginx terminationGracePeriodSeconds: 300 volumes: - name: webhook-cert secret: secretName: ingress-nginx-admission --- apiVersion: batch/v1 kind: Job metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission-create namespace: ingress-nginx spec: template: metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission-create spec: containers: - args: - create - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc - --namespace=$(POD_NAMESPACE) - --secret-name=ingress-nginx-admission env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace image: dyrnq/kube-webhook-certgen:v20230407 imagePullPolicy: IfNotPresent name: create securityContext: allowPrivilegeEscalation: false nodeSelector: kubernetes.io/os: linux restartPolicy: OnFailure securityContext: fsGroup: 2000 runAsNonRoot: true runAsUser: 2000 serviceAccountName: ingress-nginx-admission --- apiVersion: batch/v1 kind: Job metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission-patch namespace: ingress-nginx spec: template: metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission-patch spec: containers: - args: - patch - --webhook-name=ingress-nginx-admission - --namespace=$(POD_NAMESPACE) - --patch-mutating=false - --secret-name=ingress-nginx-admission - --patch-failure-policy=Fail env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace image: dyrnq/kube-webhook-certgen:v20230407 imagePullPolicy: IfNotPresent name: patch securityContext: allowPrivilegeEscalation: false nodeSelector: kubernetes.io/os: linux restartPolicy: OnFailure securityContext: fsGroup: 2000 runAsNonRoot: true runAsUser: 2000 serviceAccountName: ingress-nginx-admission --- apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: nginx spec: controller: k8s.io/ingress-nginx --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission namespace: ingress-nginx spec: egress: - {} podSelector: matchLabels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx policyTypes: - Ingress - Egress --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.9.1 name: ingress-nginx-admission webhooks: - admissionReviewVersions: - v1 clientConfig: service: name: ingress-nginx-controller-admission namespace: ingress-nginx path: /networking/v1/ingresses failurePolicy: Fail matchPolicy: Equivalent name: validate.nginx.ingress.kubernetes.io rules: - apiGroups: - networking.k8s.io apiVersions: - v1 operations: - CREATE - UPDATE resources: - ingresses sideEffects: None注意：按照上述部署完毕后其实有个问题，我们需要保证ingress-nginx-controller部署在 Master 节点上，否则无法进行正确的访问，所以还需要修改Ingress部署配置文件的一处位置，让其部署在主节点上：5.2 验证Ingress-Nginx等待一会儿，通过 kubectl get pods -A 查看，发现 Ingress-Nginx 成功部署完毕！[root@k8s-master01 k8s-demo]# kubectl get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE ingress-nginx ingress-nginx-admission-create-rf2f6 0/1 Completed 0 6h6m ingress-nginx ingress-nginx-admission-patch-k5nqw 0/1 Completed 1 6h6m ingress-nginx ingress-nginx-controller-647479f4f9-jzrjg 1/1 Running 0 6h6m
KubeSphere简介个人感觉推荐：学习使用kubesphere，企业使用rancherKubeSphere 是一款功能强大的容器管理平台，以下是其简介：基本信息开源项目：基于 Apache-2.0 授权协议开源，由 Google Go、Groovy、HTML/CSS 和 Shell 等多种编程语言开发。基础架构：以 Kubernetes 为内核，架构具有即插即用特性，可运行在私有云、公有云、混合云等多种环境，支持多云与多集群的统一管理。功能特性全栈 IT 自动化：提供从 Kubernetes 集群搭建到运维的全栈 IT 自动化能力，支持在线和离线安装、升级与扩容。可视化资源管理：提供可视化的 Kubernetes 资源管理界面，用户可通过向导式界面轻松创建和管理各种 K8s 资源。强大的 DevOps 功能：内置基于 Jenkins 的 DevOps 系统，支持图形化和脚本两种方式的 CI/CD 流水线构建，还提供 S2I 和 B2I 等 CD 工具。微服务治理出色：基于 Istio 提供可视化无代码侵入的灰度发布、熔断、流量治理等功能，同时支持分布式 Tracing。多租户管理：提供基于角色的细粒度统一认证，支持对接企业 LDAP/AD，实现多层级的权限管理。可观察性强：提供集群、工作负载、Pod、容器等多维度的监控，支持基于多租户的日志查询与日志收集，提供节点与应用层级的告警与通知功能。基础设施管理全面：支持 Kubernetes 节点管理、节点扩容与集群升级，支持对接多种存储系统，提供可视化运维管理 PVC、StorageClass 的功能，并支持 CSI 插件对接云平台存储。网络管理灵活：提供租户网络隔离与 K8s NetworkPolicy 管理功能，支持 Calico、Flannel 等多种网络插件，并提供 Porter LB 用于暴露物理环境 K8s 集群的 LoadBalancer 服务。支持 GPU 资源管理：可运行 TensorFlow 等 ML 框架，为 AI 和大数据应用提供支持。技术架构：采用前后端分离设计，后端各个功能组件可通过 REST API 对接外部系统，这种设计让其能灵活运行在各种 Kubernetes、私有云、公有云、VM 或物理环境之上。应用场景助力业务数字化转型：帮助企业一步升级容器架构，适应数字化转型需求。降低运维复杂度：通过多维管控 Kubernetes，让运维工作更加轻松。推动企业 DevOps 落地：实现敏捷开发与自动化运维，提升开发和运维效率。升级云原生架构：提供灵活的微服务解决方案，助力企业构建云原生架构。释放硬件最大效能：基于物理环境构建全栈容器架构，充分利用硬件资源。主机名ip角色k8s-master01100.100.157.10k8s-master01/nfs-serverk8s-work01100.100.157.11k8s-work01/nfs-clientk8s-work02100.100.157.12k8s-work02/nfs-client一、NFS安装1、所有服务器节点安装NFS服务参考nfs安装手册2、配置KubeSphere共享的目录#步骤一：创建共享目录 mkdir -p /root/hxy/nfs/data/kubesphere #步骤二：在/etc/exports文件中加入下面的行 /root/hxy/nfs/data/kubesphere *(insecure,rw,sync,no_root_squash) #步骤三：重启NFS服务 systemctl restart rpcbind && systemctl enable rpcbind systemctl restart nfs && systemctl enable nfs #步骤四：查看配置是否生效 exportfs -r exportfs #步骤五：其他集群节点上查看配置是否生效 showmount -e 100.100.157.103、部署NFS Subdir External Provisioner 插件作用：因为NFS没有可以提供动态卷供应的能力，安装NFS Subdir External Provisioner 插件，NFS 能为 KubeSphere 提供动态卷供应能力。当有新的 PersistentVolumeClaim（PVC）创建时，系统可自动根据 StorageClass 的配置，在 NFS 服务器上创建对应的存储卷并挂载到需要的容器中，提高了存储资源的分配效率和灵活性。3.1 安装步骤#步骤一：创建安装目录 mkdir -p /opt/k8s/kubesphere && cd /opt/k8s/kubesphere #步骤二：下载压缩包 wget https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/archive/refs/tags/nfs-subdir-external-provisioner-4.0.18.zip #步骤三：下载后解压 unzip nfs-subdir-external-provisioner-4.0.18.zip #步骤四：进入文件目录 cd nfs-subdir-external-provisioner-nfs-subdir-external-provisioner-4.0.18 #步骤五：创建命名空间（Namespace）方便管理 kubectl create ns nfs-system #步骤六：替换部署文件中的命名空间名称 sed -i'' "s/namespace:.*/namespace: nfs-system/g" ./deploy/rbac.yaml ./deploy/deployment.yaml #步骤七：替换部署文件中的命名空间为nfs-system cd /opt/k8s/kubesphere/nfs-subdir-external-provisioner-nfs-subdir-external-provisioner-4.0.18 sed -i'' "s/namespace:.*/namespace: nfs-system/g" ./deploy/rbac.yaml ./deploy/deployment.yaml grep "namespace:" ./deploy/* #验证是否替换成功 #步骤八：创建RBAC资源 cd /opt/k8s/kubesphere/nfs-subdir-external-provisioner-nfs-subdir-external-provisioner-4.0.18/deploy kubectl apply -f rbac.yaml #步骤九：检查NFS客户端Provisioner部署是否成功 #检查 ServiceAccount输出中是否包含 nfs-client-provisioner，确认 ServiceAccount 已经正确创建 kubectl get serviceaccount -n nfs-system|grep nfs-client-provisioner #检查RBAC配置，确认ClusterRole和ClusterRoleBinding 是否已创建： kubectl get clusterrole | grep nfs-client-provisioner-runner kubectl get clusterrolebinding | grep run-nfs-client-provisioner #步骤十： #1）配置deployment.yaml将nfs-subdir-external-provisioner:v4.0.2的镜像地址改为自己的私有镜像地址（注：nfs-subdir-external-provisioner:v4.0.2镜像GitHub上获取网络受阻，可以先找到资源上传到自己的私有仓库中，可参考的源有：k8s-sigs.io/nfs-subdir-external-provisioner） #2）修改NFS_SERVER和NFS_PATH为NFS主机对应的IP和共享的目录 #3）修改volumes中的server和path为NFS主机的IP和NFS共享的目录 #如下： apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: nfs-system 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: k8s-sigs.io/nfs-subdir-external-provisioner imagePullPolicy: IfNotPresent volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner - name: NFS_SERVER value: 100.100.157.10 - name: NFS_PATH value: /root/hxy/nfs/data/kubesphere volumes: - name: nfs-client-root nfs: server: 100.100.157.10 path:/root/hxy/nfs/data/kubesphere #步骤十一：执行/nfs-subdir-external-provisioner部署命令 kubectl apply -f deployment.yaml #步骤十二：验证插件是否部署成功 kubectl get deployment,pods -n nfs-system #步骤十三：部署StorageClass kubectl apply -f class.yaml #检查StorageClass是否部署成功 kubectl get sc 3.2 检查Provisioner、ClusterRole、ClusterRoleBinding是否部署成功3.3 检查nfs-client-provisioner是否部署成功二、部署Kubesphere1. 安装核心组件Kubesphere core通过helm安装核心组件Kubesphere core，成功后终端会输出user/passowrd/urlhelm upgrade --install -n kubesphere-system --create-namespace ks-core https://charts.kubesphere.com.cn/main/ks-core-1.1.3.tgz --debug --wait \ --set global.imageRegistry=swr.cn-southwest-2.myhuaweicloud.com/ks \ --set extension.imageRegistry=swr.cn-southwest-2.myhuaweicloud.com/ks \ --set hostClusterName=k8s-paco2. 验证
K8S 的资源清单参数名类型字段说明apiVersionStringK8S APl 的版本，可以用 kubectl api versions 命令查询kindStringyam 文件定义的资源类型和角色metadataObject元数据对象，下面是它的属性metadata.nameString元数据对象的名字，比如 pod 的名字metadata.namespaceString元数据对象的命名空间SpecObject详细定义对象spec.containers[]list定义 Spec 对象的容器列表spec.containers[].nameString为列表中的某个容器定义名称spec.containers[].imageString为列表中的某个容器定义需要的镜像名称spec.containers[].imagePullPolicystring定义镜像拉取策略，有 Always、Never、IfNotPresent 三个值可选 - Always（默认）：意思是每次都尝试重新拉取镜像 - Never：表示仅适用本地镜像 - IfNotPresent：如果本地有镜像就使用本地镜像，没有就拉取在线镜像。spec.containers[].command[]list指定容器启动命令，因为是数组可以指定多个，不指定则使用镜像打包时使用的启动命令。spec.containers[].args[]list指定容器启动命令参数，因为是数组可以指定多个。spec.containers[].workingDirstring指定容器的工作目录spec.containers[].volumeMounts[]list指定容器内部的存储卷配置spec.containers[].volumeMounts[].namestring指定可以被容器挂载的存储卷的名称spec.containers[].volumeMounts[].mountPathstring指定可以被容器挂载的存储卷的路径spec.containers[].volumeMounts[].readOnlystring设置存储卷路径的读写模式，ture 或者 false，默认是读写模式spec.containers[].ports[]list指定容器需要用到的端口列表spec.containers[].ports[].namestring指定端口的名称spec.containers[].ports[].containerPortstring指定容器需要监听的端口号spec.containers[].ports[].hostPortstring指定容器所在主机需要监听的端口号，默认跟上面 containerPort 相同，注意设置了 hostPort 同一台主机无法启动该容器的相同副本（因为主机的端口号不能相同，这样会冲突）spec.containers[].ports[].protocolstring指定端口协议，支持 TCP 和 UDP，默认值为 TCPspec.containers[].env[]list指定容器运行前需设置的环境变量列表spec.containers[].env[].namestring指定环境变量名称spec.containers[].env[].valuestring指定环境变量值spec.containers[].resourcesObject指定资源限制和资源请求的值（这里开始就是设置容器的资源上限）spec.containers[].resources.limitsObject指定设置容器运行时资源的运行上限spec.containers[].resources.limits.cpustring指定 CPU 的限制，单位为 Core 数，将用于 docker run –cpu-shares 参数spec.containers[].resources.limits.memorystring指定 mem 内存的限制，单位为 MIB、GiBspec.containers[].resources.requestsObject指定容器启动和调度时的限制设置spec.containers[].resources.requests.cpustringCPU请求，单位为core数，容器启动时初始化可用数量spec.containers[].resources.requests.memorystring内存请求，单位为MIB、GiB，容器启动的初始化可用数量spec.restartPolicystring定义 pod 的重启策略，可选值为 Always、OnFailure、Never，默认值为 Always。 - Always：pod 一旦终止运行，则无论容器是如何终止的，kubelet 服务都将重启它。 - OnFailure：只有 pod 以非零退出码终止时，kubelet 才会重启该容器。如果容器正常结束（退出码为0），则 kubectl 将不会重启它。 - Never：Pod 终止后，kubelet 将退出码报告给 master，不会重启该 podspec.nodeSelectorObject定义 Node 的 label 过滤标签，以 key：value 格式指定spec.imagePullSecretsObject定义 pull 镜像时使用 secret 名称，以 name：secretkey 格式指定spec.hostNetworkBoolean定义是否使用主机网络模式，默认值为 false。设置 true 表示使用宿主机网络，不使用 docker 网桥，同时设置了 true将无法在同一台宿主机上启动第二个副本k8s的资源类型资源类型缩写别名clusters componentstatusescsconfigmapscmdaemonsetsdsdeploymentsdeployendpointsepeventevhorizontalpodautoscalershpaingressesingjobs limitrangeslimitsnamespacesnsnetworkpolicies nodesnostatefulsets persistentvolumeclaimspvcpersistentvolumespvpodspopodsecuritypoliciespsppodtemplates replicasetsrsreplicationcontrollersrcresourcequotasquotacronjob secrets serviceaccountsaservicessvcstorageclasses thirdpartyresources
Harbor私有镜像仓库无坑搭建一、介绍Docker容器应用的开发和运行路不开可靠的镜像管理，虽然Docker官方也提供了公共的镜像仓库，但是从安全和效率等方面考虑，部署我们私有环境的Registry也是非常必要的。 Harbor是由VMware公司开源的企业级的Docker Registry管理项目，它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。二、组件用于部署 Harbor 的 Docker Compose 模板位于 /Deployer/docker-compose.yml. 打开这个模板文件，会发现 Harbor 由 5 个容器组成：proxy：由 Nginx 服务器构成的反向代理。registry：由 Docker 官方的开源 registry 镜像构成的容器实例。ui：即架构中的 core services, 构成此容器的代码是 Harbor 项目的主体。mysql：由官方 MySql 镜像构成的数据库容器。log: 运行着 rsyslogd 的容器，通过 log-driver 的形式收集其他容器的日志。这几个容器通过 Docker link 的形式连接在一起，这样，在容器之间可以通过容器名字互相访问。对终端用户而言，只需要暴露 proxy (即 Nginx)的服务端口。三、工作原理假设我们将 Harbor 部署在主机名为 registry.abcdocker.com 的虚机上。用户通过 docker login 命令向这个 Harbor 服务发起登录请求:docker login registry.abcdocker.com当用户输入所需信息并点击回车后，Docker 客户端会向地址“registry.abcdocker.com/v2/” 发出 HTTP GET 请求。Harbor 的各个容器会通过以下步骤处理：(1)Docker login(a) 首先，这个请求会由监听 80 端口的 proxy 容器接收到。根据预先设置的匹配规则，容器中的 Nginx会将请求转发给后端的 registry 容器；(2) 在 registry 容器一方，由于配置了基于 token 的认证，registry 会返回错误代码 401，提示 Docker客户端访问 token 服务绑定的 URL。在 Harbor 中，这个 URL 指向 Core Services；(3) Docker 客户端在接到这个错误代码后，会向token服务的URL发出请求，并根据HTTP协议的BasicAuthentication 规范，将用户名密码组合并编码，放在请求头部(header)；(4)类似地，这个请求通过 80 端口发到 proxy 容器后，Nginx 会根据规则把请求转发给 ui 容器，ui 容器监听 token 服务网址的处理程序接收到请求后，会将请求头解码，得到用户名、密码；(5) 在得到用户名、密码后，ui 容器中的代码会查询数据库，将用户名、密码与 mysql 容器中的数据进行比对(注:ui 容器还支持 LDAP 的认证方式，在那种情况下 ui 会试图和外部 LDAP 服务进行通信并校验用户名/密码)。比对成功，ui 容器会返回表示成功的状态码， 并用密钥生成 token，放在响应体中返回给 Docker 客户端。这个过程中组件间的交互过程如下图所示三、安装环境ip主机名harbor-server100.100.157.10k8s-master01harbor-client100.100.157.11k8s-work01harbor-client100.100.157.12k8s-work02Harbor 2种安装方式1.离线安装 wget https://github.com/goharbor/harbor/releases/download/v2.12.1/harbor-offline-installer-v2.12.1.tgz tar xf harbor-offline-installer-v2.12.1.tgz 2.在线安装 $ wget https://storage.googleapis.com/harbor-releases/harbor-online-installer-v1.5.2.tgz $ tar xf harbor-online-installer-v1.5.2.tgz[root@harbor harbor]# head harbor.yml需：cp harbor.yml.tmpl harbor.yml修改hostname ：ip地址修改port：默认端口号注释https本次我们使用离线安装，安装包在上面$ tar xf harbor-offline-installer-v2.12.1.tgz cd harbor/ 执行 prepare 命令来准备启动环境。这个过程会检查并准备相关的环境设置。 ./prepare 完成准备后，运行以下命令来安装并启动 Harbor。这个过程会下载并运行 7 个镜像。 ./install.sh 默认端口为80，需要修改端口请修改docker-compose.yaml对应服务的映射这里修改的端口为50003.1访问Harbor访问：100.100.157.10:5000Harbor 的默认用户名是 admin，默认密码是 Harbor12345docker push 需要项目路径，需要Harbor 创建项目 k8s3.2客户端配置免https[root@k8s-work01 ~]# cat /etc/docker/daemon.json { "registry-mirrors": [ "https://docker.1panel.dev", "https://docker.foreverlink.love", "https://dytt.online", "https://func.ink", "https://lispy.org", "https://docker.xiaogenban1993.com", "https://docker.xn--6oq72ry9d5zx.cn", "https://docker.zhai.cm", "https://docker.5z5f.com", "https://a.ussh.net", "https://docker.cloudlayer.icu", "https://docker.linkedbus.com", "https://docker.m.daocloud.io" ], "insecure-registries": [ "100.100.157.10:5000" ], "exec-opts": ["native.cgroupdriver=systemd"] } [root@k8s-work01 ~]# systemctl reset-failed docker.service [root@k8s-work01 ~]# systemctl restart docker如果不配置，客户端使用时候会报错： Error response from daemon: Get https:// 172.16.1.146:5000/v1/\_ping: http: server gaveHTTP response to HTTPS client3.3客户端登陆docker login 需单独创建一个用户，否则push不了[root@k8s-work01 ~]# docker login 100.100.157.10:5000 Username: hxy Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded四、管理镜像4.1下拉镜像docker pull nginx4.2打标签docekr tag 镜像名称:标签 你的IP:端口/harbor项目名称/镜像名称:标签 docker tag nginx:latest 100.100.157.10:5000/k8s/nginx:latest4.3上传 docker push 你的IP:端口/harbor项目名称/镜像名称:标签 docker push 100.100.157.10:5000/k8s/nginx:latest4.4下拉docker pull 100.100.157.10:5000/k8s/nginx:latest
深入了解 Kubernetes Pod 的状态背景：在 Kubernetes 中，Pod 是部署和管理应用的最小单位。理解 Pod 的各种状态、它们的意义以及如何排查异常状态，对于我们日常运维和故障排查至关重要。在这篇文章中，我们将介绍 Kubernetes Pod 的各种状态，结合具体实例，帮助大家更好地理解和排查 Pod 异常。一、Pod的常见状态Kubernetes 中，Pod 通过不同的状态反映其生命周期中的不同阶段。下面是 Kubernetes 中 Pod 的常见状态：Pending(待定)状态描述：Pod 被创建但还没有被调度到某个节点上，或者它的容器还没有完全启动。通常出现这个状态的原因是资源不足（如内存、CPU）或者调度问题。常见原因：1、节点资源不足，导致 Pod 无法调度。2、调度器（Scheduler）还未选择节点来运行 Pod。3、Pod 的镜像在节点上尚未拉取完毕。查看pending状态的podkubectl get pods --field-selector=status.phase=Pending排查方法：1、查看pod事件信息： kubectl describe pod pod-name -n namespace 2、查看集群资源是否足够： kubectl describe node node-nameRunning(运行中)状态描述：Pod 已经被调度到节点并且至少有一个容器正在运行。这个状态意味着 Pod 已经在正常运行状态，可以处理请求。常见原因：这是 Pod 生命周期中的正常状态，表示 Pod 的容器已经成功启动并处于运行状态排查方法：1、使用以下命令查看 Pod 是否在 Running 状态 kubectl get pods 2、如果 Pod 处于 Running 状态但应用出现问题，可以通过 kubectl logs 查看容器日志： kubectl logs <pod-name>Succeeded(成功)状态描述：Pod 中的所有容器都已成功运行并且正常退出。当所有容器的退出状态码为 0 时，Pod 会进入 Succeeded 状态。常见原因：pod中的容器已经完成它的工作并且退出，通常用于一次性任务（如批处理任务）排除方法：1、如果 Pod 处于 Succeeded 状态，但你期望它仍在运行，可以通过查看容器的退出码来判断： kubectl describe pod <pod-name> 查看容器的退出码和日志，判断是否是由于应用异常导致提前退出。 failed（失败）状态描述：Pod 中的容器遇到错误并且退出，退出码不为 0。Pod 在运行期间发生了错误或者容器无法启动，因此进入 Failed 状态。常见原因：1、容器在启动时发生错误，通常是由于配置问题、依赖问题或应用崩溃等。2、容器多次重启并且超过了重启限制。排查原因：1、查看 Pod 事件： kubectl describe pod <pod-name> 查找是否有错误事件，比如镜像拉取失败、资源不足等。 2、查看容器日志： kubectl logs <pod-name> 查找容器退出时的日志信息，定位容器崩溃的原因。 3、查看 Pod 的重启次数： kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].restartCount}' 如果重启次数过多，说明容器不断崩溃，可以尝试查看容器日志以排查问题。crashloopbackoff（崩溃循环）状态描述：Pod 中的容器崩溃后尝试重启，但一直处于重启失败的状态，进入 CrashLoopBackOff 状态。常见原因：1、容器内的应用崩溃，容器无法正常启动。2、容器的启动命令或配置存在错误。3、容器的依赖环境没有准备好，比如数据库连接失败、网络问题等。排查方法： 1、查看 Pod 事件： kubectl describe pod <pod-name> 查看 Pod 的事件日志，看看是否有关于容器重启失败的错误信息。 2、查看容器日志： kubectl logs <pod-name> 查看容器崩溃时的日志信息，查找异常原因。 3、临时进入 Pod 调试： kubectl exec -it <pod-name> -- /bin/bash 如果容器启动失败，可以进入容器内部查看配置文件、运行环境等，进一步排查。unknown（未知）状态描述：Pod 的状态无法被 Kubernetes 控制平面确定，通常发生在节点无法与控制平面通信时。这个状态意味着集群的某个组件无法获取 Pod 的状态。常见原因：1、节点的网络或状态与控制平面断开连接，导致 Pod 的状态无法同步。2、控制平面出现问题，无法从节点获取状态信息。二、Pod异常状态排查方法总结1、查看pod的事件日志2、查看容器日志3、查看pod的重启次数4、调试pod的内部环境
前言Helm的官方网站、Helm的github地址在没有使用Helm之前，向kubernetes部署应用，我们依次需要编写deployment、service、ingress等yaml文件，然后还需要依次进行部署，步骤比较繁琐。随着项目的微服务化，复杂的应用在容器中部署以及管理显得较为复杂。因此Helm通过打包的方式生成Char模板，然后install Char模板生成release，支持发布的版本管理和控制，很大程度上简化了kubernetes应用的部署和管理。Helm简介Helm的本质就是让k8s的应用管理（Deployment、Service）可配置，能够动态生成。通过动态生成k8s资源清单文件，然后调用kubectl命令自动执行k8s资源部署。我们可以将Helm看作Kubernetes下的apt-get/yum。Helm是Deis 开发的一个用于kubernetes的包管理器。每个包称为一个Chart，一个Chart是一个目录（一般情况下会将目录进行打包压缩，形成name-version.tgz格式的单一文件，方便传输和存储）。对于应用发布者而言，可以通过Helm打包应用，管理应用依赖关系，管理应用版本并发布应用到软件仓库。对于使用者而言，使用Helm后不用需要了解Kubernetes的yaml语法并编写应用部署文件，可以通过Helm下载并在kubernetes上安装需要的应用，同时进行少量的配置即可。除此以外，Helm还提供了kubernetes上的软件部署，删除，升级，回滚应用的强大功能。Helm还可以结合Jenkins进行CI、CD进行自动化、流水线构建项目，可以将我们大量重复的步骤省略，节约时间。Helm的作用有以下几点：快速安装常用应用：许多大公司都有helm仓库，为我们提供了许多优质的应用，可以直接拉取安装，如快速部署Redis集群、安装Jenkins等。多环境部署：通常我们需要多套环境，如开发环境、测试环境、生产环境等，helm可以通模板+变量的形式实现快速部署。运维与开发隔离：运维人员治理k8s资源，写部署模板及默认设置；开发职员只需要提供少量设置即可，把精力主要集中在开发上。Helm的基本原理Helm中有四大基本概念：helm客户端、Char、Repository、Releasehelm客户端：主要是命令行，负责管理本地的Charts、repositories，发送Chart，实例安装、查询、卸载等操作。Chart：是创建一个应用的信息集合，包括各种Kubernetes对象的配置模板、参数定义、依赖关系、文档说明等，形成一个压缩包.tar。Char是应用部署的自包含逻辑单元。可以将Chart想象成apt、yum中的软件安装包，同时Char模板可以发布到专门的repository。Repository: Chart仓库。类似于docker的镜像仓库，可以使用Harbor作为Chart的仓库。Release：release是Chart运行的实例，使用helm install命令在Kubernetes集群中部署的Chart就生成了一个Release。一个Chart能够多次安装到同一个集群，每次安装都是一个Release。Release基于名称空间进行隔离。Helm安装方法 1：通过脚本自动安装（推荐）curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh说明：此脚本会自动下载最新 Helm 二进制文件并安装到 /usr/local/bin 目录。适用于 Linux/macOS 系统。方法 2：手动下载二进制文件从 Helm GitHub Release 下载对应系统的二进制包（如 helm-v3.x.x-linux-amd64.tar.gz）。解压并移动到可执行路径：tar -zxvf helm-v3.x.x-linux-amd64.tar.gz sudo mv linux-amd64/helm /usr/local/bin/helm验证安装：helm version，输出类似 version.BuildInfo{Version:"v3.x.x"} 表示成功。配置 Helm 仓库（添加一个就行，阿里云就好）添加官方仓库：helm repo add stable https://charts.helm.sh/stable国内镜像加速helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts更新仓库索引helm repo update验证Helm功能搜索 Chart 包：helm search repo nginx # 查找 Nginx 相关 Chart注意事项权限要求：确保 kubectl 已配置并具有集群管理员权限，Helm 通过 kubeconfig 文件与集群通信版本兼容性：Helm v3 支持 Kubernetes 1.20+，建议使用最新稳定版离线安装：若服务器无法访问 GitHub，可手动下载二进制文件并复制到 /usr/local/bin卸载 Helmsudo rm /usr/local/bin/helm # 删除二进制文件 # 清除 Helm 配置 rm -rf ~/.helm
什么是 Rancher？参考：官方文档教程Rancher 是一个 Kubernetes 管理工具，让你能在任何地方和任何提供商上部署和运行集群。Rancher 可以创建来自 Kubernetes 托管服务提供商的集群，创建节点并安装 Kubernetes，或者导入在任何地方运行的现有 Kubernetes 集群。Rancher 基于 Kubernetes 添加了新的功能，包括统一所有集群的身份验证和 RBAC，让系统管理员从一个位置控制全部集群的访问。此外，Rancher 可以为集群和资源提供更精细的监控和告警，将日志发送到外部提供商，并通过应用商店（Application Catalog）直接集成 Helm。如果你拥有外部 CI/CD 系统，你可以将其与 Rancher 对接。没有的话，你也可以使用 Rancher 提供的 Fleet 自动部署和升级工作负载。Rancher 是一个 全栈式 的 Kubernetes 容器管理平台，为你提供在任何地方都能成功运行 Kubernetes 的工具。在 Kubernetes 集群上安装/升级 Rancher备注本安装指南假定你使用的是 Helm 3。要设置 Rancher：添加 Helm Chart 仓库为 Rancher 创建命名空间选择 SSL 配置安装 cert-manager（除非你自带证书，否则 TLS 将在负载均衡器上终止）使用 Helm 和你选择的证书选项安装 Rancher验证 Rancher Server 是否部署成功保存选项1. 添加 Helm Chart 仓库[](https://ranchermanager.docs.rancher.com/zh/getting-started/installation-and-upgrade/install-upgrade-on-a-kubernetes-cluster#1-%E6%B7%BB%E5%8A%A0-helm-chart-%E4%BB%93%E5%BA%93 "标题的直接链接")执行 helm repo add 命令，以添加包含安装 Rancher 的 Chart 的 Helm Chart 仓库。有关如何选择仓库，以及哪个仓库最适合你的用例，请参见选择 Rancher 版本。Latest：建议用于试用最新功能helm repo add rancher-latest https://releases.rancher.com/server-charts/latestStable：建议用于生产环境helm repo add rancher-stable https://releases.rancher.com/server-charts/stableAlpha：即将发布的实验性预览。helm repo add rancher-alpha https://releases.rancher.com/server-charts/alpha注意：不支持升级到 Alpha 版、从 Alpha 版升级或在 Alpha 版之间升级。2. 为 Rancher 创建命名空间[](https://ranchermanager.docs.rancher.com/zh/getting-started/installation-and-upgrade/install-upgrade-on-a-kubernetes-cluster#2-%E4%B8%BA-rancher-%E5%88%9B%E5%BB%BA%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4 "标题的直接链接")你需要定义一个 Kubernetes 命名空间，用于安装由 Chart 创建的资源。这个命名空间的名称为 cattle-system：kubectl create namespace cattle-system3.安装rancher使用以下命令安装 Rancher：# 创建一个命名空间 kubectl create namespace cattle-system # 安装 Rancher helm install rancher rancher-stable/rancher --namespace cattle-system --set hostname=rancher.your-domain.com说明：首先创建一个名为 cattle-system 的命名空间，以便 Rancher 在这个命名空间下运行。然后，通过 Helm 安装 Rancher，hostname 是你希望将 Rancher 绑定到的域名。4.验证rancher安装可以通过以下命令检查 Rancher 的状态：# 检查 Rancher Pod 状态 kubectl -n cattle-system rollout status deploy/rancher 说明：这个命令会显示 Rancher 的 Pod 是否已成功启动并运行。5.访问rancher控制面板如果 Rancher 已成功运行，你可以通过浏览器访问管理界面，输入你在步骤 3 中设置的域名