当前位置 : 首页 » 文章分类 :  开发  »  Kubernetes/K8S

Kubernetes/K8S

Kubernetes/K8S 使用笔记

Kubernetes 官方文档
https://kubernetes.io/docs/home/
https://kubernetes.io/zh/docs/home/
学习 Kubernetes 最权威的文档。Kubernetes 官网源码和文档本身就是在 GitHub 开源的,中文版文档由国内的大神在维护,翻译的还不错。默认查看的是最新版文档,一些老版本文档可能没有中文版。

《Docker — 从入门到实践》 – docker 中文白皮书
https://yeasy.gitbooks.io/docker_practice/content/
https://github.com/yeasy/docker_practice

Kubernetes Handbook——Kubernetes中文指南/云原生应用架构实践手册 - Jimmy Song(宋净超)云原生布道师
https://jimmysong.io/kubernetes-handbook/

从Docker到Kubernetes进阶 - 阳明的博客
https://www.qikqiak.com/k8s-book/

kubernetes | 中文社区
https://www.kubernetes.org.cn/

k8s 快速尝试:
https://www.katacoda.com/courses/kubernetes


概述

Kubernetes 是 Google 开源容器集群管理系统,提供应用部署、维护、 扩展机制等功能,利用 Kubernetes 能方便地管理跨机器运行容器化的应用,其主要功能如下:

  • 使用 Docker 对应用程序包装 (package)、实例化 (instantiate)、运行 (run)。
  • 以集群的方式运行、管理跨机器的容器。
  • 解决 Docker 跨机器容器之间的通讯问题。
  • Kubernetes 的自我修复机制使得容器集群总是运行在用户期望的状态。包括容器的自动启动、自动重调度以及自动备份。

Kubernetes 是为生产环境而设计的容器调度管理系统,对于负载均衡、服务发现、高可用、滚动升级、自动伸缩等容器云平台的功能要求有原生支持。

一个 K8S 集群是由分布式存储(etcd)、 Node 节点和 Master 节点构成的。所有的集群状态都保存在etcd中,Master节点上则运行集群的管理控制模块。

Node 节点是真正运行应用容器的主机节点,在每个 Node 节点上都会运行一个 Kubelet 代理,控制该节点上的容器、镜像和存储卷等。

基础组件功能

etcd
一个高可用的K/V键值对存储和服务发现系统
保存了整个集群的状态;

flannel
实现夸主机的容器网络的通信

apiserver
提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制;

controller manager
负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;

scheduler
负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上;

kubelet
负责维护容器的生命周期,同时也负责Volume(CSI)和网络(CNI)的管理;
kubelet 是工作节点执行操作的 agent,负责具体的容器生命周期管理,根据从数据库中获取的信息来管理容器,并上报 pod 运行状态等;

container runtime
负责镜像管理以及Pod和容器的真正运行(CRI);

kube-proxy
负责为 Service 提供 cluster 内部的服务发现和负载均衡;
kube-proxy 是一个简单的网络访问代理,同时也是一个 Load Balancer。它负责将访问到某个服务的请求具体分配给工作节点上的 Pod(同一类标签)。

K8S中一些基本概念

Service 服务

Kubernetes 中 Pod 是随时可以消亡的(节点故障、容器内应用程序错误等原因)。如果使用 Deployment 运行您的应用程序,Deployment 将会在 Pod 消亡后再创建一个新的 Pod 以维持所需要的副本数。每一个 Pod 有自己的 IP 地址,然而,对于 Deployment 而言,对应 Pod 集合是动态变化的。

一组 pod 可以组成一个 Service,对外提供统一的访问地址(Service ip 或 dns),对内转发请求到不同的 pod

在 K8s 集群中,客户端需要访问的服务就是 Service 对象。每个 Service 会对应一个集群内部有效的虚拟IP,该虚拟IP通过IPVS规则,自动轮询访问后端 Pod。在K8s集群中微服务的负载均衡是由 Kube-proxy 实现的。

Namespace

通过将系统内部的对象分配到不同的 Namespace 中,这些 namespace 之间可以完全隔离,也可以通过某种方式,让一个 namespace 中的 service 可以访问到其他的 namespace 中的服务。

Volume

Volume 是 Pod 中能够被多个容器访问的共享目录。

DaemonSet

确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除DaemonSet 将会删除它创建的所有 Pod。

ConfigMap

ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。ConfigMap 可以更方便地处理不包含敏感信息的字符串。

Kubernetes对象之ConfigMap
https://www.jianshu.com/p/cf8705a93c6b

HPA
Horizontal Pod Autoscaling,顾名思义,使Pod水平自动缩放。

service和pod

service:服务,是一个虚拟概念,逻辑上代理后端pod。
pod生命周期短,状态不稳定,pod异常后新生成的pod ip会发生变化,之前pod的访问方式均不可达。通过service对pod做代理,service有固定的ip和port,ip:port组合自动关联后端pod,即使pod发生改变,kubernetes内部更新这组关联关系,使得service能够匹配到新的pod。
这样,通过service提供的固定ip,用户再也不用关心需要访问哪个pod,以及pod是否发生改变,大大提高了服务质量。
如果pod使用rc创建了多个副本,那么service就能代理多个相同的pod,通过kube-proxy,实现负载均衡

K8S三种IP及端口

Node IP: 节点设备的IP,如物理机,虚拟机等容器宿主的实际IP。
Node Port:服务对外(gateway)暴露的端口。
Pod IP: Pod 的IP地址,是根据网络组件的IP段进行分配的。
Pod Port:应用程序启动时监听的端口,即Tomcat或undertow容器监听端口,例如8080。
Service IP: Service的IP,是一个虚拟IP,仅作用于service对象,由k8s 管理和分配,需要结合service port才能使用,单独的IP没有通信功能,集群外访问需要一些修改。
Service Port:服务内部(K8S内部)使用的端口。
在K8S集群内部,node ip 、pod ip、 service ip的通信机制是由k8s制定的路由规则,不是IP路由,即K8S的Pod ip、 Service ip与外界网络不通。

使用K8S的好处

降低成本:利用docker的隔离机制,一个node上可以部署多个pod
方便接入:新项目接入不用单独申请ec2资源,由SE根据集群资源使用情况扩缩容;使用docker镜像,不用安装依赖
自动化运维:k8s自动检测pod的heath状态,检测不通后自动从service上摘除节点;pod崩溃后自动重启;node宕机后pod自动漂移;pod部署为滚动部署,理论上无宕机时间


Kubernetes对象

Understanding Kubernetes Objects 理解 Kubernetes 对象
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/
https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/kubernetes-objects/

Kubernetes 对象是 “目标性记录” ———— 旦创建对象,Kubernetes 系统将持续工作以确保对象存在。 通过创建对象,本质上是在告知 Kubernetes 系统,所需要的集群工作负载看起来是什么样子的, 这就是 Kubernetes 集群的 期望状态(Desired State)。

也就是说 Kubernetes 对象描述的是一种要达到的目标状态

操作 Kubernetes 对象 —— 无论是创建、修改,或者删除 —— 需要使用 Kubernetes API。 比如,当使用 kubectl 命令行接口时,CLI 会执行必要的 Kubernetes API 调用, 也可以在程序中使用 客户端库直接调用 Kubernetes API。

对象规约(spec)与对象状态(status)

对象规约 spec 描述了希望对象达到的状态,即期望状态(Desired State)
对象状态 status 描述了对象的 当前状态(Current State),它是由 Kubernetes 系统和组件 设置并更新的。在任何时刻,Kubernetes 控制平面(control plane) 都一直积极地管理着对象的实际状态,以使之与期望状态相匹配。

使用yaml描述对象

创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态, 以及关于对象的一些基本信息(例如名称)。 当使用 Kubernetes API 创建对象时(或者直接创建,或者基于kubectl), API 请求必须在请求体中包含 JSON 格式的信息。 大多数情况下,需要在 .yaml 文件中为 kubectl 提供这些信息。 kubectl 在发起 API 请求时,将这些信息转换成 JSON 格式。

比如下面的 yaml 配置描述了一个类型为 Deployment 的对象

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

使用类似于上面的 .yaml 文件来创建 Deployment 的一种方式是使用 kubectl 命令行接口(CLI)中的 kubectl apply 命令, 将 .yaml 文件作为参数。
例如
kubectl apply -f https://k8s.io/examples/application/deployment.yaml --record
输出类似如下这样:

deployment.apps/nginx-deployment created

必须字段

在想要创建的 Kubernetes 对象对应的 .yaml 文件中,需要配置如下的字段:

  • apiVersion 创建该对象所使用的 Kubernetes API 的版本
  • kind 想要创建的对象的类别
  • metadata 帮助唯一标识对象的一些数据,包括一个 name 字符串、UID 和可选的 namespace

你也需要提供对象的 spec 字段。 对象 spec 的精确格式对每个 Kubernetes 对象来说是不同的,包含了特定于该对象的嵌套字段。

Kubernetes API 参考 能够帮助我们找到任何我们想创建的对象的 spec 格式。
例如
pod spec 参数
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#podspec-v1-core

deployment spec 参数
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#deploymentspec-v1-apps


Node 节点

nodeSelector节点选择

nodeSelector 是节点选择约束的最简单推荐形式。nodeSelector 是 PodSpec 的一个字段。 它包含键值对的映射。为了使 pod 可以在某个节点上运行,该节点的标签中必须包含这里的每个键值对(它也可以具有其他标签)。

nodeSelector 提供了一种非常简单的方法来将 pod 约束到具有特定标签的节点上。

亲和与反亲和

节点亲和

节点亲和概念上类似于 nodeSelector,它使你可以根据节点上的标签来约束 pod 可以调度到哪些节点。

目前有两种类型的节点亲和,分别为 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution。你可以视它们为“硬”和“软”,意思是,前者指定了将 pod 调度到一个节点上必须满足的规则(就像 nodeSelector 但使用更具表现力的语法),后者指定调度器将尝试执行但不能保证的偏好。名称的“IgnoredDuringExecution”部分意味着,类似于 nodeSelector 的工作原理,如果节点的标签在运行时发生变更,从而不再满足 pod 上的亲和规则,那么 pod 将仍然继续在该节点上运行。


Label 标签

Labels and Selectors 标签和选择算符
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/labels/

Label(标签)是 Kubernetes 系统中另外一个核心概念。一个Label是一个 key=value 的键值对,其中key与value由用户自己指定。Label可以被附加到各种资源对象上,例如Node、Pod、Service、RC等,一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上。Label通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。

标签(Labels) 是附加到 Kubernetes 对象(比如 Pods)上的键值对。

一个对象可以有多个标签,一个标签也可以附加到多个对象上,但每个 key 对于给定对象必须是唯一的

给某个资源定义一个标签,随后可以通过 label 进行查询和筛选 ,deployment 与 service 之间通过 label 来关联。

标签的语法和字符集

标签 是键值对。

有效的标签键有两个段:可选的前缀和名称,用斜杠(/)分隔。 名称段是必需的,必须小于等于 63 个字符,以字母数字字符([a-z0-9A-Z])开头和结尾, 带有破折号(-),下划线(_),点( .)和之间的字母数字。 前缀是可选的,如果指定,前缀必须是 DNS 子域:由点(.)分隔的一系列 DNS 标签,总共不超过 253 个字符, 后跟斜杠(/)。

如果省略前缀,则假定标签键对用户是私有的。 向最终用户对象添加标签的自动系统组件(例如 kube-scheduler、kube-controller-manager、 kube-apiserver、kubectl 或其他第三方自动化工具)必须指定前缀。

kubernetes.io/ 前缀是为 Kubernetes 核心组件保留的。

有效标签值必须为 63 个字符或更少,并且必须为空或以字母数字字符([a-z0-9A-Z])开头和结尾, 中间可以包含破折号(-)、下划线(_)、点(.)和字母或数字。

标签选择运算符

API 目前支持两种类型的选择算符:基于等值的 和 基于集合的。 标签选择算符可以由逗号分隔的多个 需求 组成。 在多个需求的情况下,必须满足所有要求,因此逗号分隔符充当逻辑 与 && 运算符。

等值运算符

基于等值 或 基于不等值 的需求允许按标签键和值进行过滤。 匹配对象必须满足所有指定的标签约束,尽管它们也可能具有其他标签。
可接受的运算符有 =, ==!= 三种。 前两个表示 相等(并且只是同义词),而后者表示 不相等。

例如:
environment = production 选择所有 environment 是 production 的资源。
tier != frontend 选择所有 tier 不是 frontend 的资源。
environment=production,tier!=frontend 选择 production 环境中 tier 不是 frontend 的资源。

等值选择经常用于给 Pod 指定运行的 node, 例如下面这个 pod 配置中用 nodeSelector 指定必须运行在 accelerator 是 nvidia-tesla-p100 的 node 上。

apiVersion: v1
kind: Pod
metadata:
  name: cuda-test
spec:
  containers:
    - name: cuda-test
      image: "k8s.gcr.io/cuda-vector-add:v0.1"
      resources:
        limits:
          nvidia.com/gpu: 1
  nodeSelector:
    accelerator: nvidia-tesla-p100

集合运算符

基于集合 的标签需求允许你通过一组值来过滤键。 支持三种操作符:in, notinexists (只可以用在 key 标识符上)。

例如:
environment in (production, qa) 选择 environment 是 production 或 qa 的资源。
tier notin (frontend, backend) 选择 tier 不是 frontend 或 backend 的资源,以及所有没有 tier 标签的资源
partition 选择所有带有 partition 标签的资源,不校验 partition 标签的值。
!partition 选择所有不带 partition 标签的资源,不校验 partition 标签的值。
partition, environment notin (qa) 选择带有 partition 标签,且 environment 不是 qa 的资源。

其实等值运算符都可以用集合运算符来代替,比如 environment=production 等于 environment in (production)
集合运算符和等值运算符可以一起使用,比如 partition in (customerA, customerB),environment!=qa

预定义系统标签

kubernetes.io/hostname
示例 kubernetes.io/hostname=ip-172-20-114-199.ec2.internal
用于:Node
Kubelet 用 hostname 值来填充该标签。注意:可以通过向 kubelet 传入 –hostname-override 参数对 “真正的” hostname 进行修改。


Pod 容器组

Pods 容器组
https://kubernetes.io/docs/concepts/workloads/pods/
https://kubernetes.io/zh/docs/concepts/workloads/pods/

Pod(中文官方叫法是“容器组”)是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod 是 Kubernetes 创建及管理的最小的可部署的计算单元,一个 Pod 由一个或者多个容器组成,这些容器共享内存,网络以及运行容器的方式。

Pod和容器

在 kubernetes 里面,Pod 实际上正是 kubernetes 项目为你抽象出来的一个可以类比为进程组的概念。

一个 Pod 中可以有一个或多个容器
1、一个 Pod 中运行一个容器。“每个 Pod 中一个容器” 的模式是最常见的用法;在这种使用方式中,你可以把 Pod 想象成是单个容器的封装,kuberentes 管理的是 Pod 而不是直接管理容器。
2、在一个 Pod 中同时运行多个容器。一个 Pod 中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。这些在同一个 Pod 中的容器可以互相协作成为一个 service 单位 —— 一个容器共享文件,另一个 “sidecar” 容器来更新这些文件。Pod 将这些容器的存储资源作为一个实体来管理。

使用Pod

通常不需要直接创建 Pod,甚至单实例 Pod。 相反,你会使用诸如 Deployment 或 Job 这类工作负载资源 来创建 Pod。如果 Pod 需要跟踪状态, 可以考虑 StatefulSet 资源。

Pod的几种状态

Pod 遵循一个预定义的生命周期,起始于 Pending 阶段,如果至少 其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded 或者 Failed 阶段。

pending
Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。

running
Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。

succeeded
Pod 中的所有容器都已成功终止,并且不会再重启。

failed
Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。

unknown
因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。


容器探针

在Kubernetes上下文中存活探针和就绪探针被称作健康检查。这些容器探针是一些周期性运行的小进程,这些探针返回的结果(成功,失败或者未知)反映了容器在Kubernetes的状态。基于这些结果,Kubernetes会判断如何处理每个容器,以保证弹性,高可用性和更长的正常运行时间。

针对运行中的容器,kubelet 可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:
livenessProbe 存活探针,指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success。

readinessProbe 就绪探针,指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。

就绪探针旨在让Kubernetes知道你的应用是否准备好为请求提供服务。Kubernetes只有在就绪探针通过才会把流量转发到Pod。如果就绪探针检测失败,Kubernetes将停止向该容器发送流量,直到它通过。

startupProbe 启动探针,指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success。


Init容器

Init Containers Init 容器
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
https://kubernetes.io/zh/docs/concepts/workloads/pods/init-containers/

Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行,可以包括一些应用镜像中不存在的实用工具和安装脚本。

每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。

Init 容器与普通的容器非常像,除了如下两点:

  • 它们总是运行到完成。
  • 每个都必须在下一个启动之前成功完成。

所以:

  • Init 容器不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe, 因为它们必须在 Pod 就绪之前运行完成。
  • 如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。

如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。 然而,如果 Pod 对应的 restartPolicy 值为 Never,Kubernetes 不会重新启动 Pod。

为 Pod 设置 Init 容器需要在 Pod 的 spec 中添加 initContainers 字段, 该字段以 Container 类型对象数组的形式组织,和应用的 containers 数组同级相邻。 Init 容器的状态在 status.initContainerStatuses 字段中以容器状态数组的格式返回 (类似 status.containerStatuses 字段)。

为什么需要init容器?

因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:

  • Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。 例如,没有必要仅为了在安装过程中使用类似 sed、awk、python 或 dig 这样的工具而去 FROM 一个镜像来生成一个新的镜像。
  • Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
  • 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
  • Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可以访问 应用容器不能访问的 Secret 的权限。
  • 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器 提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 一旦前置条件满足,Pod 内的所有的应用容器会并行启动。

init容器使用示例

1、等待一个 Service 完成创建,创建一个包含如下 shell 命令的 init 容器:

for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; exit 1`

dig 目标 service 成功后 init 容器完成,再继续执行后续当前容器的启动。

2、注册这个 Pod 到远程服务器,通过在命令中调用 API,类似如下:

curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register \
  -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'

3、在启动应用容器之前等一段时间,使用类似命令 sleep 60

4、克隆 Git 仓库到卷中。

5、将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。 例如,在配置文件中存放 POD_IP 值,并使用 Jinja 生成主应用配置文件。

下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动, 第二个等待 mydb 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动 spec 节中的应用容器。

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

pause容器

我们检查 node 节点的时候会发现每个node上都运行了很多的pause容器

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES
55f9851b66d6        79dd6d6368e2            "/opt/bin/flanneld -…"   3 days ago          Up 3 days                               k8s_kube-flannel_kube-flannel-ds-sfw7f_kube-system_466fe793-8578-4993-a3d3-d9215aeeb96c_287
cbb1745cd369        k8s.gcr.io/kube-proxy   "/usr/local/bin/kube…"   5 days ago          Up 5 days                               k8s_kube-proxy_kube-proxy-lpbnl_kube-system_fa15d31f-83d5-4bfa-93f3-fb4386116e79_0
a18a3f092784        k8s.gcr.io/pause:3.2    "/pause"                 5 days ago          Up 5 days                               k8s_POD_kube-proxy-lpbnl_kube-system_fa15d31f-83d5-4bfa-93f3-fb4386116e79_0
642b8c79bd6c        k8s.gcr.io/pause:3.2    "/pause"                 5 days ago          Up 5 days                               k8s_POD_kube-flannel-ds-sfw7f_kube-system_466fe793-8578-4993-a3d3-d9215aeeb96c_0

kubernetes 中的 pause 容器主要为每个业务容器提供以下功能:
1、在pod中担任Linux命名空间共享的基础;
2、启用pid命名空间,开启init进程。

Pause容器
https://jimmysong.io/kubernetes-handbook/concepts/pause-container.html


ReplicationController 副本控制器

ReplicationController 副本控制器
https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/
https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicationcontroller/

注意:Kubernetes 1.2 之后,推荐使用配置 ReplicaSet 的 Deployment 来进行 Pod 编排。

ReplicationController 确保在任何时候都有特定数量的 Pod 副本处于运行状态。 换句话说,ReplicationController 确保一个 Pod 或一组同类的 Pod 总是可用的。

当 Pod 数量过多时,ReplicationController 会终止多余的 Pod。当 Pod 数量太少时,ReplicationController 将会启动新的 Pod。 与手动创建的 Pod 不同,由 ReplicationController 创建的 Pod 在失败、被删除或被终止时会被自动替换。 例如,在中断性维护(如内核升级)之后,你的 Pod 会在节点上重新创建。 因此,即使你的应用程序只需要一个 Pod,你也应该使用 ReplicationController 创建 Pod。 ReplicationController 类似于进程管理器,但是 ReplicationController 不是监控单个节点上的单个进程,而是监控跨多个节点的多个 Pod。

在讨论中,ReplicationController 通常缩写为 “rc”,并作为 kubectl 命令的快捷方式。

定义RC

与所有其它 Kubernetes 对象配置一样,ReplicationController 需要 apiVersion、kind 和 metadata 字段。
此外,RC 定义必须包含以下几部分:
.spec.replicas Pod 副本个数
Pod 期待的副本数量。如果你没有指定 .spec.replicas, 那么它默认是 1。

.spec.selector Pod 选择器
用于筛选目标 Pod 的 Label Selector。ReplicationController 将管理标签与选择算符匹配的所有 Pod。
它不区分是它自己创建的还是其他进程创建的 Pod。
如果指定了 .spec.template.metadata.labels, 它必须和 .spec.selector 相同,否则它将被 API 拒绝。
如果没有指定 .spec.selector, 它将默认为 .spec.template.metadata.labels

注意:最好不要出现创建了多个控制器并且其选择算符之间存在重叠的情况,否则结果可能无法预料。

.spec.template Pod 模板
当 Pod 的副本数量小于预期数量时,用于创建新 Pod 的模板。
.spec.template 是 RC 的 spec 的唯一必需字段。
.spec.template 是一个 Pod 模板。 它的模式与 Pod 完全相同,只是它是嵌套的,没有 apiVersion 或 kind 属性。
除了 Pod 所需的字段外,ReplicationController 中的 Pod 模板必须指定适当的标签和适当的重新启动策略。


ReplicaSet 副本集

ReplicaSet 副本集
https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicaset/

ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本(实例)的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。

ReplicaSet 副本集的主要几个字段有:

  • selector 确定哪些 Pod 属于该副本集
  • replicas 副本集应该维护几个 Pod 副本(实例)
  • template Pod 的定义

副本集将通过创建、删除 Pod 容器组来确保符合 selector 选择器的 Pod 数量等于 replicas 指定的数量。当符合 selector 选择器的 Pod 数量不够时,副本集通过使用 template 中的定义来创建 Pod。

在 Kubernetes 中,并不建议您直接使用 ReplicaSet,推荐使用 Deployment,由 Deployment 创建和管理 ReplicaSet。

ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 然而,Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,我们建议使用 Deployment 而不是直接使用 ReplicaSet,除非您需要自定义更新业务流程或根本不需要更新。

这实际上意味着,您可能永远不需要操作 ReplicaSet 对象:而是使用 Deployment,并在 spec 部分定义您的应用。


Deployment 部署

Deployments 部署
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/

Deployment 是 Kubernetes 在 1.2 版本中引入的新概念,用于更好地解决Pod的编排问题,Deployment+ReplicaSet 用于替换之前的 ReplicationController(RC)

Deployment 是最常用的用于部署无状态服务的方式。Deployment 控制器使得您能够以声明的方式更新 Pod(容器组)和 ReplicaSet(副本集)。

Deployment 为 Pod 提供声明式更新。只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和 ReplicaSet 的实际状态改变到您的目标状态。可以滚动升级和回滚应用,扩容和缩容。

以“声明”的方式管理 Pod 和 ReplicaSet,其本质是将一些特定场景的一系列运维步骤固化下来,以便快速准确无误的执行。


kube-proxy

kube-proxy 作为 Kubernetes 集群中的网络代理和负载均衡器,其作用是将发送到Service的请求转发到具体的后端。
Kubernetes从1.8开始为kube-proxy组件引入了IPVS模式,并在Kubernetes 1.11进入GA,在Kubernetes 1.12成为kube-proxy的默认代理模式。

当前Kubernetes kube-proxy的负载均衡支持以下三种代理模式:

userspace

userspace:这种模式下kube-proxy进程在用户空间监听一个本地端口,iptables规则将流量转发到这个本地端口,然后kube-proxy在其内部应用层建立到具体后端的连接,即在其内部进行转发,这是在用户空间的转发,虽然比较稳定,但效率不高。userspace模式是kube-proxy早期(Kubernetes 1.0)的模式,早就不推荐使用,也不会被我们使用。

iptables

iptables:这种模式是从Kubernetes 1.2开始并在Kubernetes 1.12之前的默认方式。
在这种模式下kube-proxy监控Kubernetes对Service、Endpoint对象的增删改操作。监控到Service对象的增删改,将配置iptables规则,截获到Service的ClusterIp和端口的流量并将其重定向到服务的某个后端;监控到Endpoint对象的增删改,将更新具体到某个后端的iptables规则。iptables模式基于netfilter,但因为流量的转发都是在Kernel Space,所以性能更高且更加可靠。 这种模式的缺点是,对于超大规模集群,当集群中服务数量达到一定量级时,iptables规则的添加将会出现很大延迟,因为规则的更新出现kernel local,所以此时将会出现性能问题

ipvs

ipvs:这种模式从Kubernetes 1.11进入GA,并在Kubernetes 1.12成为kube-proxy的默认代理模式。
ipvs模式也是基于netfilter,对比iptables模式在大规模Kubernetes集群有更好的扩展性和性能,支持更加复杂的负载均衡算法(如:最小负载、最少连接、加权等),支持Server的健康检查和连接重试等功能。ipvs依赖于iptables,使用iptables进行包过滤、SNAT、masquared。ipvs将使用ipset需要被DROP或MASQUARED的源地址或目标地址,这样就能保证iptables规则数量的固定,我们不需要关心集群中有多少个Service了。

IPVS(IP Virtual Server)是lvs项目的一部分,作为Linux内核的一部分,提供4层负载均衡器的功能,即传输层负载均衡。ipvs运行在主机内核中,作为真是服务器集群前的负载均衡器,将到对服务的请求转发到真实的服务器上,并将多个ip的真实服务器集群的服务显示为单个ip的虚拟机服务。

Kubernetes 从1.10到1.11升级记录(续):Kubernetes kube-proxy开启IPVS模式
https://blog.frognew.com/2018/10/kubernetes-kube-proxy-enable-ipvs.html

k8s ipvs 长连接 Connection reset by peer问题

查看 tcp keepalive 的内核参数

$ sysctl net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_probes net.ipv4.tcp_keepalive_intvl
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75

net.ipv4.tcp_keepalive_time 是连接时长,当超过这个时间后,每隔 net.ipv4.tcp_keepalive_intvl 的时间间隔会发送keepalive数据包,net.ipv4.tcp_keepalive_probe 是发送keepalived数据包的频率。

使用 ipvsadm 命令查看k8s节点上ipvs的超时时间:

ipvsadm -l --timeout
Timeout (tcp tcpfin udp): 900 120 300

经过上面的分析可以看出,各个k8s节点上tcp keepalive超时是7200秒(即2小时),ipvs超时是900秒(15分钟),这就出现如果客户端或服务端在15分钟内没有应答时,ipvs会主动将tcp连接终止,而客户端服务还傻傻以为是2个小时呢。 很明显net.ipv4.tcp_keepalive_time不能超过ipvs的超时时间。

Kubernetes IPVS模式下服务间长连接通讯的优化,解决Connection reset by peer问题
https://blog.frognew.com/2018/12/kubernetes-ipvs-long-connection-optimize.html


Kubernetes API

Kubernetes API 总览
https://kubernetes.io/zh/docs/reference/using-api/api-overview/

Kubernetes API v1.19 参考手册
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/


常用k8s集群部署工具

kops

kops 是官方出的 Kubernetes Operations,适合生产级 K8s 的安装、升级和管理。
https://github.com/kubernetes/kops

可以看做是适用于集群的 kubectl,kops 可帮助您从命令行创建,销毁,升级和维护生产级,高可用性的 Kubernetes 集群。

目前正式支持AWS(Amazon Web Services),其中 GCE 和 OpenStack 处于 beta 测试阶段,而 VMware vSphere 处于 alpha 阶段,并且计划其他平台。

可见,它对云平台结合紧密而提供独特功能,如果未来预见只使用某个云平台,那么相比 kubespray 是更好的选择。

kubeadm

kubeadm 官方维护的为了给创建 Kubernetes 集群提供最佳实践的一个工具,涉及集群生命周期管理等知识。

通过 kubeadm 命令来管理,kubeadm < init | join | upgrade | reset >

Minikube

All-in-one的k8s单节点环境,主要用作实验学习,k8s的quickstart入口
https://kubernetes.io/docs/tutorials/hello-minikube/#create-a-minikube-cluster

kubespray

https://github.com/kubernetes-incubator/kubespray

Kubespray 是由K8S社区孵化的,一个基于Ansible的 K8S 部署工具。

kubespray 是部署生产环境就绪的 Kubernetes 集群的工具。kubernetes-sigs 组织维护。

特点是通过 Ansible 部署,所以相比 kops 方式,kubespray 是 OS 级别通用的部署方式(可以是裸机 或者 云)。

另外 kubespray 2.8 以上版本推荐用 kubeadm 创建集群,以便从中使用生命周期管理的实践 并 卸载其中 OS 配置的东西。

相当于结合了 kubeadm 以及自身的优点。

[K8s] Kubernetes 集群部署管理方式对比, kops, kubeadm, kubespray
https://www.cnblogs.com/farwish/p/12747887.html

Kubo

kubo 是 bosh 用来部署 kubernetes 的一个 release,可以管理 K8S 集群的全生命周期。现在已经被改名为 Cloud Foundry’s Container Runtime。
Bosh 是 Cloud Foundry 的部署工具,不过它也可以用来部署其他分布式系统。 Pivotal 和 Google 公司合作发布的 Kubo(现已改名为CFCR) 项目,就可以让用户通过 Bosh 来部署 Kubernetes 集群。


使用kubeadm安装部署k8s v1.19

kubeadm 是 Kubernetes 官方提供的用于快速安装 Kubernetes 集群的工具箱,比单独安装各个 k8s 组件要方便,还不用担心 k8s 组件之间的版本不兼容问题。
https://kubernetes.io/docs/reference/setup-tools/kubeadm/

参考文档

推荐通过 kubeadm 安装 k8s 集群,英文原版的官方文档最准确,但有些细节和坑没说清楚,有时候遇到问题不知如何解决。
Installing kubeadm(安装kubeadm/kubelet/kubectl)
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
Creating a cluster with kubeadm(初始化k8s集群、安装网络插件、添加node、清理)
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

如果按照网上的博客文章安装的话,一定要看好博客中的 k8s 版本,不同版本的配置项差别还是挺大的。

我安装的是 k8s 2020.9.6 最新版 v1.19,一开始参考 v1.10 的安装文档就走了好多弯路,比如设置在开着 swap 的情况下也可以启动 kubelet 的配置时,多数文章中的老方法都不起作用。比如多数文章中的 Helm 都是 V2 版本,还需要安装服务端 Tiller,其实 Helm V3 版本已经不需要 Tiller 这个组件了。

下面列几篇我主要参考的博客文章:

使用kubeadm安装Kubernetes v1.15
https://www.kubernetes.org.cn/5551.html
这篇文章参考价值比较大,里面有正确的开着swap启动kubelet的配置方法,Ingress等应用都是通过Helm部署的,但Helm是v2版本的

Kubernetes(一) 跟着官方文档从零搭建K8S v1.15
https://juejin.im/post/6844903943051411469
这篇文章中网络插件用的是 calico,且是系列文章。

用 kubeadm 搭建集群环境 - 阳明的博客 v1.10
https://www.qikqiak.com/k8s-book/docs/16.%E7%94%A8%20kubeadm%20%E6%90%AD%E5%BB%BA%E9%9B%86%E7%BE%A4%E7%8E%AF%E5%A2%83.html

使用 kubeadm 部署 kubernetes - 《Docker — 从入门到实践》 v1.10
https://yeasy.gitbook.io/docker_practice/setup/kubeadm


Linux系统配置

系统信息

共两台机器,都是 CentOS 7 系统,都是 1vCPU 2GB 内存

lightsail 是 centos 7.6

$ cat /etc/centos-release
CentOS Linux release 7.6.1810 (Core)
$ uname -a
Linux lightsail 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 29 14:49:43 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

linode 是 centos 7.8

$ cat /etc/centos-release
CentOS Linux release 7.8.2003 (Core)
$ uname -a
Linux linode 3.10.0-1127.el7.x86_64 #1 SMP Tue Mar 31 23:36:51 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

linode 当做 master 节点,lightsail 当做 worker 节点

前提条件

k8s 安装前提条件

  • CentOS 7 及以上系统
  • 2GB 及以上内存
  • 2 核及以上 CPU
  • 多节点之间需要完全网络连通,端口开放
  • 保证各个节点的 mac 地址和 product_uuid 是唯一的
  • 必须禁用 linux swap 交换空间,否则 kubelet 报错无法启动。

Before you begin
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin


内核参数配置

下面网络内核参数是为了保证 iptables 能看到 bridge 流量

1、确保 br_netfilter 模块已加载到 linux 内核
lsmod | grep br_netfilter 有结果就是已加载
如果没加载,执行 sudo modprobe br_netfilter 加载 br_netfilter 模块到内核

2、为了保证 iptables 能看到 bridge 流量,需要确保两个内核参数 net.bridge.bridge-nf-call-ip6tablesnet.bridge.bridge-nf-call-iptables 的值为 1
我两台机器上默认都是 1

$ sysctl net.bridge.bridge-nf-call-ip6tables net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

如果不是,执行下面命令

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

也就是先把内核配置参数保存到自定义的 /etc/sysctl.d/k8s.conf 配置文件中(注意这个文件是自己新建的,之前没有),然后 sudo sysctl --system 命令会加载 /etc/sysctl.d/*.conf 目录中的配置文件(具体可以去了解下 sudo sysctl --system 命令原理)


修改hostname

1、保证两台机器的 hostname 不一样就行了,我这里为了便于识别,设置成了方便记忆的名字。

sudo hostnamectl set-hostname linode
sudo hostnamectl set-hostname lightsail

2、编辑本机 DNS 配置 /etc/hosts, 写入两台机器的 hostname 和 ip 映射关系

192.168.1.1 linode
192.168.1.2 lightsail

关闭firewalld防火墙

CentOS7 中用 firewalld 防火墙代替了 iptables 防火墙,关闭它。
sudo systemctl stop firewalld 关闭 firewalld 防火墙
sudo firewall-cmd --state 查看 firewalld 运行状态,结果是 not running

如果使用的 vps 提供商有其他防火墙配置,也要关闭防火墙或开启对应的接口,比如 aws 需要在web页面上做对应配置。

关闭SELinux访问控制

setenforce 0 将 SELinux 设为 permissive 模式,只告警不限制执行。
getenforce 获取 SELinux 运行状态,结果应该是 Permissive 或 Disabled

关闭swap交换空间

swapoff -a 关闭所有交换空间。
我没有执行这一步,我机器只有 2GB 内存,关闭交换空间后其他应用都没法跑了,我只能开着交换空间,然后修改 kubelet 参数让他在有交换空间的系统上也能启动。


配置各节点互相免密登录

在各个节点上 ssh-keygen 生成密钥对,并把各自的公钥贴到其他节点的 ~/.ssh/authorized_keys 文件(没有则新建)中。
不想手动的话就使用 ssh-copy-id 命令自动考过去。
最终实现各个节点上可以互相免密登录。

lightsail 节点上
1 ssh-keygen -f linode 生成密钥 linode 和 linode.pub
2 拷贝 linode.pub 内容贴到 linode 节点的 ~/.ssh/authorized_keys 文件中。
3 编辑 ~/.ssh/config 文件(没有则新建),配置快速登录

Host linode
    HostName xx.xx.xx.xx
    IdentityFile ~/.ssh/linode
    User linodeuser

保存后直接 ssh linode 即可免密登录到 linode 节点

linode 节点上
1 ssh-keygen -f lightsail 生成密钥 lightsail 和 lightsail.pub
2 拷贝 lightsail.pub 内容到 lightsail 节点的 ~/.ssh/authorized_keys 文件中。
3 编辑 ~/.ssh/config 文件(没有则新建),配置快速登录

Host lightsail
    HostName xx.xx.xx.xx
    IdentityFile ~/.ssh/lightsail
    User lightsailuser

保存后直接 ssh lightsail 即可免密登录到 lightsail 节点


安装docker(或其他容器运行时)

为了在 pod 上运行容器,k8s 需要 容器运行时(Container runtimes),常用的容器运行时有

  • docker 最流行的容器引擎。
  • containerd containerd 是 docker 的一部分,后来单独从 docker 中分离出来开源了。
  • CRI-O 一个实现了 OCI(Open Container Initiative) 开放容器标准 和 k8s CRI(Container Runtime Interface) 容器交互接口的容器运行时。可作为一个轻量级的容器运行时代替 docker 引擎。

k8s 使用 CRI(Container Runtime Interface)容器运行时接口 和我们选择的容器运行时进行交互。

kubeadm 会通过扫描 UDS(Unix Domain Socket) 自动检测已安装的容器引擎,比如

  • Docker /var/run/docker.sock
  • containerd /run/containerd/containerd.sock
  • CRI-O /var/run/crio/crio.sock

docker 18.09 之后,安装 docker 也就自动安装了 containerd 容器运行时,所以会同时检测到这两个容器运行时,这时会优先选择 docker

总之,绝大多数情况下我们直接安装 docker 就好了。

docker 安装参考笔记 Docker
我两台机器上之前都已经在用 docker, 版本分别是:

$ docker -v
Docker version 19.03.5, build 633a0ea
$ docker -v
Docker version 19.03.12, build 48a66213fe

docker 版本 和 k8s 版本之间的兼容性看官方文档:
https://kubernetes.io/docs/setup/production-environment/container-runtimes/#docker


安装kubeadm/kubelet/kubectl

kubeadm 是启动 k8s 集群的命令工具
kubelet 是用于管理容器生命周期,或者说管理 pod 的
kubectl 是命令行工具,相当于和 k8s 交互的客户端

1 把 kubernetes.repo yum 源中的镜像地址替换为阿里云的

$ cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

2 安装 kubelet, kubeadm 和 kubectl
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
版本 v1.19


配置和启动kubelet

安装后 kubelet 会注册成为一个系统服务 /usr/lib/systemd/system/kubelet.service
内容如下:

[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target

设置开机启动kubelet

sudo systemctl enable kubelet 设置开启启动 kubelet
systemctl list-unit-files |grep kube 查看是否开机启动,结果是 enabled 表示开机启动。


解决k8s必须关闭swap交换空间

Kubernetes 1.8 开始要求关闭系统的 Swap,如果不关闭,默认配置下 kubelet 将无法启动。。
原因主要是为了性能考虑,如果一个 pod 开了交换空间,可能被认为有很多剩余资源,从而被分配较多的实例。
所以关闭 swap 主要是为了性能考虑。

可以通过 kubelet 的启动参数 --fail-swap-on=false 更改这个限制。
kubelet --help 帮助文件中是这么说的

--fail-swap-on Makes the Kubelet fail to start if swap is enabled on the node. (default true) (DEPRECATED: This parameter should be set via the config file specified by the Kubelet’s –config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)

Kubelet/Kubernetes should work with Swap Enabled #53533
https://github.com/kubernetes/kubernetes/issues/53533
[ERROR Swap]: running with swap on is not supported. Please disable swap #610
https://github.com/kubernetes/kubeadm/issues/610
Error while executing and initializing kubeadm
https://stackoverflow.com/questions/47094861/error-while-executing-and-initializing-kubeadm

网上多数 k8s 安装文档都说是在 systemd 的 conf 文件中加这个配置,比如:

cd /etc/systemd/system
sudo mkdir kubelet.service.d
cd kubelet.service.d
sudo vim 20-allow-swap.conf

填入

[Service]
Environment="KUBELET_EXTRA_ARGS=--fail-swap-on=false"

然后

sudo systemctl daemon-reload
kubeadm init --ignore-preflight-errors=Swap

但是这个方法在 v1.19 版本上并不好用,启动 kubelet 还是报错:

9月 06 20:12:40 linode kubelet[10613]: F0906 20:12:40.680096   10613 server.go:265] failed to run Kubelet: running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: [Filename                                Type                Size        Used        Priority /swapfile1                              file                4194300        440        -2]

在 v1.11+ 以上版本中,真正起作用的是配置 /etc/sysconfig/kubelet 这个文件,里面默认就有个 KUBELET_EXTRA_ARGS= 配置项,改为下面这样:

KUBELET_EXTRA_ARGS=--fail-swap-on=false

然后重启 kubelet,成功在开着 swap 的情况下启动 kubelet

使用kubeadm安装Kubernetes 1.15
https://www.kubernetes.org.cn/5551.html


配置cgroup driver

用 yum 源的方式安装的 kubelet 生成的配置文件将参数 --cgroup-driver 改成了 systemd, 而 docker 的 cgroup-driver 是 cgroupfs, 这二者必须一致。
查看 docker 的 cgroup driver

$ docker info |grep Cgroup
 Cgroup Driver: cgroupfs

官方建议将 cgroup driver 改为 systemd, 因为对于使用systemd作为init system的Linux的发行版,使用systemd作为docker的cgroup driver可以确保服务器节点在资源紧张的情况更加稳定。

创建或修改 /etc/docker/daemon.json

{
  "exec-opts": ["native.cgroupdriver=systemd"]
}

重启docker:

systemctl restart docker

docker info | grep Cgroup
Cgroup Driver: systemd

使用kubeadm安装Kubernetes 1.15
https://www.kubernetes.org.cn/5551.html


启动 kubelet

sudo systemctl start kubelet 启动 kubelet 服务,如果启动后发现进程不存在,可以通过 sudo journalctl -xefu kubelet 查看 kubelet 的启动错误日志。

failed to load Kubelet config file /var/lib/kubelet/config.yaml

1、master 节点上,第一次启动 kubectl 报错,说找不到 /var/lib/kubelet/config.yaml 这个配置文件

9月 05 18:25:42 linode systemd[1]: Started kubelet: The Kubernetes Node Agent.
9月 05 18:25:42 linode kubelet[8144]: F0905 18:25:42.524694    8144 server.go:198] failed to load Kubelet config file /var/lib/kubelet/config.yaml, error failed to read kubelet config file "/var/lib/kubelet/config.yaml", error: open /var/lib/k

官方文档说这个配置文件是 kubeadm init 命令生成的,先执行 kubeadm init 生成此配置文件后再启动 kubectl 即可。

2、worker 节点上,第一次启动 kubectl 也报这个错,也找不到 /var/lib/kubelet/config.yaml 配置文件。
注意:不需要手动创建 /var/lib/kubelet/config.yaml 配置文件,通过命令 kubadm join 加入 master 节点上初始化的 k8s 集群后,会自动生成此配置文件


kubeadm init初始化master节点

自定义kubeadm配置文件

kubeadm config print init-defaults 可以打印集群初始化默认使用的配置,我们将其保存为 ~/kubeadm.yaml,然后修改一些参数后使用这个配置文件来执行 kubeadm init

保存默认配置到 ~/kubeadm-init.yaml
kubeadm config print init-defaults > ~/kubeadm-init.yaml

默认配置如下:

apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 1.2.3.4
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  name: linode
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.19.0
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
scheduler: {}

修改:
1、将 advertiseAddress: 1.2.3.4 修改为 master 节点的地址
2、使用 kubeadm 默认配置初始化的集群,会在 master 节点打上 node-role.kubernetes.io/master:NoSchedule 的污点,阻止 master 节点接受调度运行工作负载。我这里只有两个节点,需要在 master 也参与调度,所以将这个 taint 修改为 node-role.kubernetes.io/master:PreferNoSchedule
见 The NodeRegistration.Taints field is omitted when marshalling kubeadm configuration
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/
3、如果服务器在国内,无法从默认的 imageRepository 拉取镜像的话,可以把镜像仓库地址替换为阿里云的 imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers,我这里不需要。

整个修改的部分如下

localAPIEndpoint:
  advertiseAddress: 5.6.7.8
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  name: linode
  taints:
  - effect: PreferNoSchedule
    key: node-role.kubernetes.io/master

忽略cpu和swap检测错误

不加任何参数执行 sudo kubeadm init 报错:

$ sudo kubeadm init
W0905 21:15:10.516741   14272 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.19.0
[preflight] Running pre-flight checks
    [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
    [WARNING Hostname]: hostname "linode" could not be reached
    [WARNING Hostname]: hostname "linode": lookup linode on x.x.x.x:53: no such host
error execution phase preflight: [preflight] Some fatal errors occurred:
    [ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
    [ERROR Swap]: running with swap on is not supported. Please disable swap
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

有两个硬件相关的错误:
1、只有一个 cpu,k8s 安装最少需要 2 个 cpu。可以跳过cpu个数检查 kubeadm init --ignore-preflight-errors=NumCPU
2、我机器只有 2GB 内存,必须开 swap 交换空间才能跑一堆服务,安装 k8s 要求必须关闭 swap,可以跳过 swap 检查 kubeadm init --ignore-preflight-errors=Swap
kubadm init error CPUs 1 is less than required 2(解决cpu问题)
https://stackoverflow.com/questions/60804280/kubadm-init-error-cpus-1-is-less-than-required-2
Error while executing and initializing kubeadm(解决swap问题)
https://stackoverflow.com/questions/47094861/error-while-executing-and-initializing-kubeadm

或者可以直接 --ignore-preflight-errors=all 忽略所有错误。

重复执行kubeadm init报错

假如之前执行过 kubeadm init,改了参数后再次执行时在 preflight 阶段会检查 端口占用 和 要生成的几个配置文件是否已存在并报错,如下:

$ sudo kubeadm init --config kubeadm.yaml
W0906 21:45:26.948291   26488 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.19.0
[preflight] Running pre-flight checks
    [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
error execution phase preflight: [preflight] Some fatal errors occurred:
    [ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
    [ERROR Port-6443]: Port 6443 is in use
    [ERROR Port-10259]: Port 10259 is in use
    [ERROR Port-10257]: Port 10257 is in use
    [ERROR FileAvailable--etc-kubernetes-manifests-kube-apiserver.yaml]: /etc/kubernetes/manifests/kube-apiserver.yaml already exists
    [ERROR FileAvailable--etc-kubernetes-manifests-kube-controller-manager.yaml]: /etc/kubernetes/manifests/kube-controller-manager.yaml already exists
    [ERROR FileAvailable--etc-kubernetes-manifests-kube-scheduler.yaml]: /etc/kubernetes/manifests/kube-scheduler.yaml already exists
    [ERROR FileAvailable--etc-kubernetes-manifests-etcd.yaml]: /etc/kubernetes/manifests/etcd.yaml already exists
    [ERROR Swap]: running with swap on is not supported. Please disable swap
    [ERROR Port-10250]: Port 10250 is in use
    [ERROR Port-2379]: Port 2379 is in use
    [ERROR Port-2380]: Port 2380 is in use
    [ERROR DirAvailable--var-lib-etcd]: /var/lib/etcd is not empty
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

可以 kubeadm reset 回滚,也可以直接 --ignore-preflight-errors=all 忽略所有错误。

kubeadm reset删除k8s集群

集群安装过程中遇到了其他问题,可以使用下面的命令来进行重置:

$ kubeadm reset
$ ifconfig cni0 down && ip link delete cni0
$ ifconfig flannel.1 down && ip link delete flannel.1
$ rm -rf /var/lib/cni/

Clean up
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#tear-down

kubeadm init成功执行的结果

在开始初始化集群之前可以使用 kubeadm config images pull 预先在各个节点上拉取所 k8s 需要的 docker 镜像,当然也可以不预先拉取,init 中会自动拉取,主要是为了快。

最终,执行 sudo kubeadm init --config ~/kubeadm.yaml --ignore-preflight-errors=all

结果如下:

$ sudo kubeadm init --config kubeadm.yaml --ignore-preflight-errors=all
[sudo] linode 的密码:
W0906 21:51:36.922560   27585 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.19.0
[preflight] Running pre-flight checks
    [WARNING NumCPU]: the number of available CPUs 1 is less than the required 2
    [WARNING Port-6443]: Port 6443 is in use
    [WARNING Port-10259]: Port 10259 is in use
    [WARNING Port-10257]: Port 10257 is in use
    [WARNING FileAvailable--etc-kubernetes-manifests-kube-apiserver.yaml]: /etc/kubernetes/manifests/kube-apiserver.yaml already exists
    [WARNING FileAvailable--etc-kubernetes-manifests-kube-controller-manager.yaml]: /etc/kubernetes/manifests/kube-controller-manager.yaml already exists
    [WARNING FileAvailable--etc-kubernetes-manifests-kube-scheduler.yaml]: /etc/kubernetes/manifests/kube-scheduler.yaml already exists
    [WARNING FileAvailable--etc-kubernetes-manifests-etcd.yaml]: /etc/kubernetes/manifests/etcd.yaml already exists
    [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
    [WARNING Swap]: running with swap on is not supported. Please disable swap
    [WARNING Port-10250]: Port 10250 is in use
    [WARNING Port-2379]: Port 2379 is in use
    [WARNING Port-2380]: Port 2380 is in use
    [WARNING DirAvailable--var-lib-etcd]: /var/lib/etcd is not empty
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Using existing ca certificate authority
[certs] Using existing apiserver certificate and key on disk
[certs] Using existing apiserver-kubelet-client certificate and key on disk
[certs] Using existing front-proxy-ca certificate authority
[certs] Using existing front-proxy-client certificate and key on disk
[certs] Using existing etcd/ca certificate authority
[certs] Using existing etcd/server certificate and key on disk
[certs] Using existing etcd/peer certificate and key on disk
[certs] Using existing etcd/healthcheck-client certificate and key on disk
[certs] Using existing apiserver-etcd-client certificate and key on disk
[certs] Using the existing "sa" key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/admin.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/scheduler.conf"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 0.027423 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.19" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node linode as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node linode as control-plane by adding the taints [node-role.kubernetes.io/master:PreferNoSchedule]
[bootstrap-token] Using token: abcdef.0123456789abcdef
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.5:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:a5bf274e7bfc185bdeff3654c0194959112e2bcc65147e3492a2aae5e303ddb5

出现 Your Kubernetes control-plane has initialized successfully! 就是成功了。

kubeadm init 的过程划分了各个 phase 阶段,如下:
[kubelet-start] 生成kubelet的配置文件 /var/lib/kubelet/config.yaml
[certs] 生成相关的各种证书
[kubeconfig] 生成相关的kubeconfig文件
[control-plane] 使用/etc/kubernetes/manifests目录中的yaml文件创建apiserver、controller-manager、scheduler的静态pod
[bootstraptoken] 生成token记录下来,后边使用kubeadm join往集群中添加节点时会用到

为了使非root用户也能正常使用 kubectl 命令,使用非 root 账户执行
To start using your cluster, you need to run the following as a regular user:
中的命令,这几个命令是为了可以使用 kubectl 工具访问集群

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

注意:最后给出了将节点加入集群的命令 kubeadm join ...,在 worker 节点上执行此命令可以加入 k8s 集群。
其中的 token 只有 24 小时有效期,过期后需要重新生成。

scheduler和controller-manager是Unhealthy状态

执行 kubectl get cs 查看 k8s 集群状态

$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS      MESSAGE                                                              ERROR
controller-manager   Unhealthy   Get "http://127.0.0.1:10252/healthz": dial tcp 127.0.0.1:10252: connect: connection refused
scheduler            Unhealthy   Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused
etcd-0               Healthy     {"health":"true"}

原因是 /etc/kubernetes/manifests 目录下的 kube-controller-manager.yaml 和 kube-scheduler.yaml 设置的默认端口是0,在文件中注释掉就可以了
在配置项 spec.containers.command.--port 前加 # 号注释掉,两个配置中都是这个配置项。
然后 sudo systemctl restart kubelet.service 重启 kubelet
再次执行 kubectl get cs 查看 k8s 集群状态

$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-0               Healthy   {"health":"true"}

kubectl get nodes 查看节点状态

$ kubectl get nodes
NAME     STATUS     ROLES    AGE   VERSION
linode   NotReady   master   13d   v1.19.0

当前只有一个 master 节点,状态是 NotReady 是因为网络还没配置。

解决kubernetes:v1.18.6 get cs127.0.0.1 connection refused错误
https://juejin.im/post/6860672181060403214


安装Pod Network

为了使 pod 之间可以互相通信,必须安装 Container Network Interface (CNI) 网络插件(network add-on)
常用的网络插件有 flannel 和 calico

k8s集群安装flannel网络插件

以 flannel 网络插件为例。

1、下载 flannel 配置文件
在 master 节点执行

$ cd ~
$ wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

2、kubectl apply -f kube-flannel.yml 安装 flannel 网络插件。

$ kubectl apply -f kube-flannel.yml
podsecuritypolicy.policy/psp.flannel.unprivileged created
Warning: rbac.authorization.k8s.io/v1beta1 ClusterRole is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRole
clusterrole.rbac.authorization.k8s.io/flannel created
Warning: rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleBinding
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

3、验证所有 Pod 都处于 Running 状态

$ kubectl get pods -A
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE
kube-system   coredns-f9fd979d6-8l6f2          1/1     Running   0          13d
kube-system   coredns-f9fd979d6-bmbnt          1/1     Running   0          13d
kube-system   etcd-linode                      1/1     Running   0          13d
kube-system   kube-apiserver-linode            1/1     Running   0          13d
kube-system   kube-controller-manager-linode   1/1     Running   0          12d
kube-system   kube-flannel-ds-4n9pq            1/1     Running   0          3m1s
kube-system   kube-proxy-mlls6                 1/1     Running   0          13d
kube-system   kube-scheduler-linode            1/1     Running   0          12d

安装网络插件之前,两个 coredns pod 是 Pending 状态,现在是 Running 状态了。

查看 node 状态,发现 master 节点也已经成为 Ready 状态。

$ kubectl get nodes
NAME     STATUS   ROLES    AGE   VERSION
linode   Ready    master   13d   v1.19.0

k8s集群安装calico网络插件

这个文档中使用的是 calico 网络插件
Kubernetes(一) 跟着官方文档从零搭建K8S
https://juejin.im/post/6844903943051411469


向k8s集群中添加node节点

注意:从开头到 “配置和启动kubelet” 的所有步骤都要在master节点和所有worker节点上执行(worker节点加入k8s集群前kubelet启动会失败),init master节点 和安装 Pod Network 只在master节点执行。

worker 节点上执行

$ sudo kubeadm join 172.105.221.57:6443 --ignore-preflight-errors=all --token d4kxk1.nnzgnb4vnz8qntb6 \
     --discovery-token-ca-cert-hash sha256:a5bf274e7bfc185bdeff3654c0194959112e2bcc65147e3492a2aae5e303ddb5

加入集群成功后输出如下,可以看到 kubeadm 会从 k8s 集群读取配置并写入 /var/lib/kubelet/config.yaml 文件,这个配置文件就是 worker 节点启动 kubelet 报错提示缺少的配置文件。然后还会自动启动 kubelet。

[preflight] Running pre-flight checks
    [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
    [WARNING Swap]: running with swap on is not supported. Please disable swap
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

注意:
1、必须以 root 用户执行 kubeadm join 命令,否则报错

error execution phase preflight: [preflight] Some fatal errors occurred:
    [ERROR IsPrivilegedUser]: user is not running as root

2、如果没关闭 swap 交换空间 preflight 检查无法通过,可以通过加参数 --ignore-preflight-errors=all 忽略

error execution phase preflight: [preflight] Some fatal errors occurred:
    [ERROR Swap]: running with swap on is not supported. Please disable swap
[preflight] If you know what you are doing, you can make a check non-fatal with --ignore-preflight-errors=...

3、官方推荐将 cgroup driver 改为 systemd, docker 默认的是 cgroupfs,不过不改也行

[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/

在 master 查看集群节点状态

$ kubectl get nodes
NAME        STATUS   ROLES    AGE     VERSION
lightsail   Ready    <none>   3m28s   v1.19.0
linode      Ready    master   14d     v1.19.0

可以看到 worker 节点已加入 k8s 集群。

初始化master节点生成的token只有24小时有效期

master 节点上 kubeadm init 生成的 token 只有 24 小时有效期(sha值是永久有效的),过期后在 worker 节点执行 kubeadm join 命令时报错:

error execution phase preflight: couldn't validate the identity of the API Server: could not find a JWS signature in the cluster-info ConfigMap for token ID "abcdef"
To see the stack trace of this error execute with --v=5 or higher

解决方法是在 master 节点上重新生成 token

重新生成token

在master节点执行
kubeadm token create 重新生成 token

$ kubeadm token create
W0920 21:47:42.350232   20277 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
d4kxk1.nnzgnb4vnz8qntb6

查看token

在master节点执行
如果没保存 token 值,通过 kubeadm token list 命令可以查看 token

$ kubeadm token list
TOKEN                     TTL         EXPIRES                     USAGES                   DESCRIPTION                                                EXTRA GROUPS
d4kxk1.nnzgnb4vnz8qntb6   23h         2020-09-21T21:47:42+08:00   authentication,signing   <none>                                                     system:bootstrappers:kubeadm:default-node-token

查看sha值

在master节点执行
如果没保存 sha256 值,通过下面的命令可以查看 sha256 值

openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
   openssl dgst -sha256 -hex | sed 's/^.* //'

Joining your nodes
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#join-nodes


从k8s集群删除node节点

假如从集群中移除 node2 节点

1、在 master 节点上执行:

kubectl drain node2 --delete-local-data --force --ignore-daemonsets
kubectl delete node node2

2、在 node2 上执行:

$ kubeadm reset
$ ifconfig cni0 down && ip link delete cni0
$ ifconfig flannel.1 down && ip link delete flannel.1
$ rm -rf /var/lib/cni/

3、在其他 node 上执行:

kubectl delete node node2

安装k8s包管理工具Helm v3.3.3

Helm 是最流行的 k8s 包管理工具,后续其他服务都通过 Helm 安装部署。

参考笔记 Helm
注意:Helm V3 及之后,只需安装一个客户端命令行工具 helm,不再需要在 k8s 集群中安装 tiller 了


Ingress

Ingress
https://kubernetes.io/docs/concepts/services-networking/ingress/
kubernetes / ingress-nginx
https://github.com/kubernetes/ingress-nginx/

Ingress 用于将集群中的服务暴露到集群外部,类似一个路由转发的组件,可以让外界访问 Kubernetes 内部的 Service。

Ingress 可以给 service 提供集群外部访问的 URL、负载均衡、SSL、HTTP 路由等。为了配置这些 Ingress 规则,集群管理员需要部署一个 Ingress controller,它监听 Ingress 和 service 的变化,并根据规则配置负载均衡并提供访问入口。

Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上。一个 Ingress 对象的主要内容,就类似 Nginx 的配置文件描述,对应的转发规则就是 ingressRule。

Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service。

Kubernetes 并没有自带 Ingress Controller,它只是一种标准,具体实现有多种,需要自己单独安装,业界常用的反向代理项目有:Nginx、HAProxy、Envoy、Traefik。

四层负载均衡与七层负载均衡

四层负载均衡:在 TCP/IP 层做,或者说只能依靠 ip:port 做转发。
七层负载均衡:在 应用层做,可以实现根据 http url路径进行转发。Nginx 是一个典型的七层负载均衡器。
四层负载均衡不识别域名,七层负载均衡识别域名

kubernetes 自带的 service 概念只有四层代理,即表现形式为IP:Port
如果需要实现七层负载均衡,需要使用 ingress 插件。

将k8s服务暴露到外部的几种方式

1、通过 port-forward 转发, 操作方便、适合调试时使用, 不适用于生产环境.
2、通过 NodePort, 此时集群中每一个节点(Node)都会监听指定端口, 我们通过任意节点的端口即可访问到指定服务. 但过多的服务会开启大量端口难以维护.
3、通过 LoadBalance 来暴露服务. LoadBalance(负载均衡 LB)通常由云服务商提供, 如果云环境中不提供LB服务, 我们通常直接使用Ingress, 或使用MetalLB来自行配置LB.
4、通过 Ingress 公开多个服务。 Ingress公开了从群集外部到群集内 services 的HTTP和HTTPS路由. 流量路由由Ingress资源上定义的规则控制. 在云服务商不提供LB服务的情况下, 我们可以直接使用Ingress来暴露服务. (另外, 使用LB + Ingress的部署方案可以避免过多LB应用带来的花费).

ingress原理

Ingress Controller 是一个以 pod 形式运行的反向代理程序,解析 ingress 的 yaml 格式的路由转发策略,并动态地按照策略生成配置文件(nginx.conf)

ingress-controller 应部署在边缘节点。所谓的边缘节点即集群内部用来向集群外暴露服务能力的节点,集群外部的服务通过该节点来调用集群内部的服务。

ingress的几种部署方式

kubernetes系列(十) - 通过Ingress实现七层代理
https://www.cnblogs.com/baoshu/p/13255909.html#head21


ingress-nginx 和 nginx-ingress 的区别

注意:ingress-nginx 和 nginx-ingress 都是 ingress controller 实现,但两者不是同一个应用

区别如下:
1、nginx-ingress 是 Nginx 维护的一个 ingress controller 实现,GitHub上的项目叫 kubernetes-ingress
官网 https://www.nginx.com/products/nginx/kubernetes-ingress-controller/
GitHub https://github.com/nginxinc/kubernetes-ingress

2、ingress-nginx 是 kubernetes 维护的一个 ingress controller 实现。
官网 https://kubernetes.github.io/ingress-nginx/
GitHub https://github.com/kubernetes/ingress-nginx

3、star对比
ingress-nginx 的 GitHub star 是 kubernetes-ingress 的 3 倍左右(2020.9)

4、功能对比见下面这篇官方文档
Differences Between nginxinc/kubernetes-ingress and kubernetes/ingress-nginx Ingress Controllers
https://github.com/nginxinc/kubernetes-ingress/blob/master/docs/nginx-ingress-controllers.md

见异思迁:K8s 部署 Nginx Ingress Controller 之 kubernetes/ingress-nginx
https://www.cnblogs.com/dudu/p/12334613.html


Helm3部署ingress-nginx

注意:网上多数博客部署的都是 nginx-ingress, 我这里是 ingress-nginx

0、ingress-controller 应部署在边缘节点上,将 linode 作为边缘节点,给 linode node 打上 edge label
kubectl label node linode node-role.kubernetes.io/edge=
执行后查看 nodes

$ kubectl get nodes
NAME        STATUS   ROLES         AGE     VERSION
lightsail   Ready    <none>        7d23h   v1.19.0
linode      Ready    edge,master   22d     v1.19.0

1、添加 ingress-nginx 的 chart 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
添加后查看如下

$ helm repo list
NAME             URL
ingress-nginx    https://kubernetes.github.io/ingress-nginx

2、搜索 ingress-nginx 包

$ helm search repo ingress-nginx
NAME                           CHART VERSION    APP VERSION    DESCRIPTION
ingress-nginx/ingress-nginx    3.3.0            0.35.0         Ingress controller for Kubernetes using NGINX a...

3、拉取 chart 包并解压

$ cd ~/helm
$ helm pull ingress-nginx/ingress-nginx --untar

helm pull 最后的 --untar=true 表示下载 chart 包后自动解压,会在当前目录下创建 ingress-nginx 目录并解压到此目录中。或者拉取下来后 tar -zxvf 手动解压 tgz 包。

解压后如下

$ ll ingress-nginx/
总用量 48
-rw-r--r--. 1 linode linode   466 9月  29 20:21 Chart.yaml
drwxr-xr-x. 2 linode linode  4096 9月  29 20:21 ci
-rw-r--r--. 1 linode linode    61 9月  29 20:21 OWNERS
-rw-r--r--. 1 linode linode  9535 9月  29 20:21 README.md
drwxr-xr-x. 3 linode linode  4096 9月  29 20:21 templates
-rw-r--r--. 1 linode linode 20045 9月  29 20:21 values.yaml

3、安装
helm install ingress-nginx ingress-nginx/ingress-nginx
helm install 后面第一个参数是安装后 release 的名字,自己任意指定,第二个参数是 chart 包的名字。

Installation Guide - NGINX Ingress Controller
https://kubernetes.github.io/ingress-nginx/deploy/#using-helm


dashboard

kubectl apply部署dashboard

可以参考官方文档直接使用 kubectl apply 部署
Web UI (Dashboard)
https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/
kubernetes / dashboard
https://github.com/kubernetes/dashboard

Helm3部署dashboard v2.7.1

这里使用 helm 部署,参考 Helm Hub 中 kubernetes-dashboard 页面的说明文档
https://hub.helm.sh/charts/k8s-dashboard/kubernetes-dashboard

1、添加repo
helm repo add k8s-dashboard https://kubernetes.github.io/dashboard
搜索查看 kubernetes-dashboard 版本

$ helm search repo kubernetes-dashboard
NAME                                  CHART VERSION    APP VERSION    DESCRIPTION
k8s-dashboard/kubernetes-dashboard    2.7.1            2.0.4          General-purpose web UI for Kubernetes clusters

2、拉取 chart 包并解压

$ mkdir helm && cd helm
$ helm pull k8s-dashboard/kubernetes-dashboard --untar=true

解压后如下

$ ll
总用量 44
drwxr-xr-x. 3 linode linode  4096 9月  22 15:44 charts
-rw-r--r--. 1 linode linode   447 9月  22 15:44 Chart.yaml
-rw-r--r--. 1 linode linode 15563 9月  22 15:44 README.md
-rw-r--r--. 1 linode linode   245 9月  22 15:44 requirements.lock
-rw-r--r--. 1 linode linode   163 9月  22 15:44 requirements.yaml
drwxr-xr-x. 2 linode linode  4096 9月  22 15:44 templates
-rw-r--r--. 1 linode linode  8191 9月  22 15:44 values.yaml

3、自定义配置文件 values.yaml
默认使用 values.yaml 这个配置文件,我们拷贝一份后修改,然后指定配置文件启动 chart. 拷贝一份命名为 values-my.yaml

kubernetes系列(十七) - 通过helm安装dashboard详细教程
https://www.cnblogs.com/baoshu/p/13326480.html

Helm 安装部署Kubernetes的dashboard
https://www.cnblogs.com/hongdada/p/11284534.html


kubectl

kubectl reference docs
https://kubernetes.io/docs/reference/kubectl/kubectl/

kubectl get

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#get

kubectl get cs

查看 k8s 集群状态

$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-0               Healthy   {"health":"true"}

kubectl get nodes

查看 k8s 集群中的节点信息

$ kubectl get nodes
NAME     STATUS     ROLES    AGE   VERSION
linode   NotReady   master   11d   v1.19.0

kubectl get pods -A

-A, --all-namespaces 查看所有命名空间的 pod

$ kubectl get pods -A
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE
kube-system   coredns-f9fd979d6-8l6f2          0/1     Pending   0          11d
kube-system   coredns-f9fd979d6-bmbnt          0/1     Pending   0          11d
kube-system   etcd-linode                      1/1     Running   0          11d
kube-system   kube-apiserver-linode            1/1     Running   0          11d
kube-system   kube-controller-manager-linode   1/1     Running   0          10d
kube-system   kube-proxy-mlls6                 1/1     Running   0          11d
kube-system   kube-scheduler-linode            1/1     Running   0          10d

kubectl create 创建资源

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#create
从文件或标准输入创建资源,这里的资源可以是 Service, Pod, ConfigMap 等等。
kubectl create -f FILENAME

例如
kubectl create -f helm-rbac.yaml 根据配置文件 helm-rbac.yaml 创建资源。

kubectl apply 应用配置文件

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#apply
应用指定的配置文件,如果指定的资源不存在会自动创建,相当于 kubectl create
kubectl apply (-f FILENAME | -k DIRECTORY)

--record 记录这条 kubectl 命令到资源注解中,默认是 false 不记录。

例如
kubectl apply -f helm-rbac.yaml 根据配置文件创建资源


kubectl run

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#run
在 pod 中运行指定的镜像


kubectl label 给资源打标签

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#label
更新资源的标签。

kubectl label node master node-role.kubernetes.io/edge= 给 master node 打上 edge label


kubectl drain

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#drain

从 k8s 集群删除节点

kubectl delete

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#delete

根据文件名、标签等删除资源


第三方工具

Kuboard

eip-work / kuboard-press
https://github.com/eip-work/kuboard-press

Kuboard for K8S
https://kuboard.cn/

Kuboard 是基于 Kubernetes 的微服务管理界面。同时提供 Kubernetes 免费中文教程,入门教程,最新版本的 Kubernetes v1.18 安装手册

Kuboard 这个项目的官网上有最新版的 k8s 安装文档以及学习资料,很不错。

sealos

fanux / sealos
https://github.com/fanux/sealos

sealyun 专注于kubernetes安装
https://sealyun.com/

kubernetes高可用安装(kubernetes install)工具,一条命令,离线安装,包含所有依赖,内核负载不依赖haproxy keepalived,纯golang开发,99年证书,支持v1.16 v1.15 v1.17 v1.18 v1.19

kubesphere

kubesphere / kubesphere
https://github.com/kubesphere/kubesphere

KubeSphere 是在 Kubernetes 之上构建的面向云原生应用的 容器混合云,支持多云与多集群管理,提供全栈的 IT 自动化运维的能力,简化企业的 DevOps 工作流。KubeSphere 提供了运维友好的向导式操作界面,帮助企业快速构建一个强大和功能丰富的容器云平台。KubeSphere 愿景是打造一个基于 Kubernetes 的云原生分布式操作系统,它的架构可以很方便地与云原生生态进行即插即用(plug-and-play)的集成。


k8s发布

k8s滚动更新机制

为了应用升级部署时候 k8s 不停服达到用户无感知,Kubernetes支持称为滚动更新的功能。此功能允许您按顺序更新pod,一次更新一个(按照配置比例),而不是一次停止/更新整个pod。使发布版本更新和回滚而不会中断服务


k8s服务发现

kubernetes 服务发现支持 Service环境变量 和 DNS 两种模式

环境变量

同一个 namespace 里的 Pod 启动时,k8s 会把集群中所有当前可用的 service 的 ip 和 port 会以环境变量的形式注入到pod里,在pod中的服务可以通过环境变量来知晓当前集群中的其他服务地址
比如pod创建时有一个redis-master服务,服务ip地址是10.0.0.11,port是6379,则会把下面一系列环境变量注入到pod里,通过这些环境变量访问redis-master服务。

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379

注:其中服务名和端口名转为大写,连字符转换为下划线。

限制:
1)Pod和Service的创建顺序是有要求的,Service必须在Pod创建之前被创建,否则环境变量不会设置到Pod中。
2)Pod只能获取同Namespace中的Service环境变量。

service ip

可以通过 service 的虚拟 IP 去访问,比如说刚创建的 my-service 这个服务,通过 kubectl get svc 或者 kubectl discribe service 都可以看到它的虚拟 IP 地址是 172.29.3.27,端口是 80,然后就可以通过这个虚拟 IP 及端口在 pod 里面直接访问到这个 service 的地址。

通过DNS解析服务名访问

K8s集群会内置一个dns服务器,service创建成功后,会在dns服务器里导入一些记录。
依靠 DNS 解析,同一个 namespace 里 pod 可以直接通过 service 的名字去访问到刚才所声明的这个 service。不同的 namespace 里面,我们可以通过 service 名字加“.”,然后加 service 所在的哪个 namespace 去访问这个 service,例如我们直接用 curl 去访问,就是 my-service:80 就可以访问到这个 service。

注:DNS需要下载DNS插件来提供服务。

例如下面是我们测试环境 k8s 集群中的服务

$ env|grep -i service|sort
KUBERNETES_SERVICE_HOST=192.168.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
UDS_AFTER_SALES_DOCKER_SERVICE_HOST=192.168.132.0
UDS_AFTER_SALES_DOCKER_SERVICE_PORT=8001
UDS_AFTER_SALES_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_APOLLO_FE_DOCKER_SERVICE_HOST=192.168.56.33
UDS_APOLLO_FE_DOCKER_SERVICE_PORT=8082
UDS_APOLLO_FE_DOCKER_SERVICE_PORT_HTTP_8082=8082
UDS_APOLLO_WEB_DOCKER_SERVICE_HOST=192.168.134.179
UDS_APOLLO_WEB_DOCKER_SERVICE_PORT=8081
UDS_APOLLO_WEB_DOCKER_SERVICE_PORT_HTTP_8081=8081
UDS_APPROACH_DOCKER_SERVICE_HOST=192.168.127.84
UDS_APPROACH_DOCKER_SERVICE_PORT=8001
UDS_APPROACH_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_ARES_DOCKER_SERVICE_HOST=192.168.73.119
UDS_ARES_DOCKER_SERVICE_PORT=8001
UDS_ARES_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_ARTHUR_FE_DOCKER_SERVICE_HOST=192.168.58.169
UDS_ARTHUR_FE_DOCKER_SERVICE_PORT=8081
UDS_ARTHUR_FE_DOCKER_SERVICE_PORT_HTTP_8081=8081
UDS_AZKABAN_WEB_SERVER_DOCKER_SERVICE_HOST=192.168.133.44
UDS_AZKABAN_WEB_SERVER_DOCKER_SERVICE_PORT=8081
UDS_AZKABAN_WEB_SERVER_DOCKER_SERVICE_PORT_HTTP_8081=8081
UDS_CALENDAR_DOCKER_SERVICE_HOST=192.168.97.231
UDS_CALENDAR_DOCKER_SERVICE_PORT=8080
UDS_CALENDAR_DOCKER_SERVICE_PORT_HTTP_8080=8080
UDS_CANAL_DOCKER_SERVICE_HOST=192.168.171.92
UDS_CANAL_DOCKER_SERVICE_PORT=8001
UDS_CANAL_DOCKER_SERVICE_PORT_HTTP_11110=11110
UDS_CANAL_DOCKER_SERVICE_PORT_HTTP_11112=11112
UDS_CANAL_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_CANAL_DOCKER_SERVICE_PORT_HTTP_8089=8089
UDS_CANAL_DOCKER_SERVICE_PORT_TCP_11111=11111
UDS_CODEX_DOCKER_SERVICE_HOST=192.168.224.175
UDS_CODEX_DOCKER_SERVICE_PORT=8001
UDS_CODEX_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_CONFIG_SERVER_DOCKER_SERVICE_HOST=192.168.18.112
UDS_CONFIG_SERVER_DOCKER_SERVICE_PORT=8001
UDS_CONFIG_SERVER_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_COUPON_DOCKER_SERVICE_HOST=192.168.164.23
UDS_COUPON_DOCKER_SERVICE_PORT=8001
UDS_COUPON_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_CRAWLER_DOCKER_SERVICE_HOST=192.168.227.144
UDS_CRAWLER_DOCKER_SERVICE_PORT=8001
UDS_CRAWLER_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_CREDITS_BLOCK_DOCKER_SERVICE_HOST=192.168.186.148
UDS_CREDITS_BLOCK_DOCKER_SERVICE_PORT=8001
UDS_CREDITS_BLOCK_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_CREDITS_DOCKER_SERVICE_HOST=192.168.37.137
UDS_CREDITS_DOCKER_SERVICE_PORT=8001
UDS_CREDITS_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_DASHBOARD_DOCKER_SERVICE_HOST=192.168.192.38
UDS_DASHBOARD_DOCKER_SERVICE_PORT=8001
UDS_DASHBOARD_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_DRIVE_DOCKER_SERVICE_HOST=192.168.77.252
UDS_DRIVE_DOCKER_SERVICE_PORT=8001
UDS_DRIVE_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_FEEDBACK_DOCKER_SERVICE_HOST=192.168.66.9
UDS_FEEDBACK_DOCKER_SERVICE_PORT=8001
UDS_FEEDBACK_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_FELLOW_DOCKER_SERVICE_HOST=192.168.185.40
UDS_FELLOW_DOCKER_SERVICE_PORT=8001
UDS_FELLOW_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_GATEWAY_DOCKER_SERVICE_HOST=192.168.4.237
UDS_GATEWAY_DOCKER_SERVICE_PORT=80
UDS_GATEWAY_DOCKER_SERVICE_PORT_HTTP_80=80
UDS_GATEWAY_DOCKER_SERVICE_PORT_HTTP_81=81
UDS_GATEWAY_DOCKER_SERVICE_PORT_TCP_443=443
UDS_GATEWAY_INT_DOCKER_SERVICE_HOST=192.168.82.41
UDS_GATEWAY_INT_DOCKER_SERVICE_PORT=80
UDS_GATEWAY_INT_DOCKER_SERVICE_PORT_TCP_443=443
UDS_GATEWAY_INT_DOCKER_SERVICE_PORT_TCP_80=80
UDS_HADES_DOCKER_SERVICE_HOST=192.168.71.22
UDS_HADES_DOCKER_SERVICE_PORT=8001
UDS_HADES_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_IM_DOCKER_SERVICE_HOST=192.168.174.150
UDS_IM_DOCKER_SERVICE_PORT=8001
UDS_IM_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_LEO_DOCKER_SERVICE_HOST=192.168.241.9
UDS_LEO_DOCKER_SERVICE_PORT=8001
UDS_LEO_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_LEO_FE_DOCKER_SERVICE_HOST=192.168.237.122
UDS_LEO_FE_DOCKER_SERVICE_PORT=7633
UDS_LEO_FE_DOCKER_SERVICE_PORT_TCP_7633=7633
UDS_LOKI_SERVICE_HOST=192.168.249.180
UDS_LOKI_SERVICE_PORT=8089
UDS_LOKI_SERVICE_PORT_HTTP_8089=8089
UDS_MEDUSA_DOCKER_SERVICE_HOST=192.168.138.222
UDS_MEDUSA_DOCKER_SERVICE_PORT=8001
UDS_MEDUSA_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_MYCROFT_SERVICE_HOST=192.168.3.245
UDS_MYCROFT_SERVICE_PORT=9119
UDS_MYCROFT_SERVICE_PORT_HTTP_9119=9119
UDS_NAT_DOCKER_SERVICE_HOST=192.168.163.167
UDS_NAT_DOCKER_SERVICE_PORT=8001
UDS_NAT_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_NIC_DOCKER_SERVICE_HOST=192.168.121.219
UDS_NIC_DOCKER_SERVICE_PORT=8001
UDS_NIC_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_NSP_DOCKER_SERVICE_HOST=192.168.89.146
UDS_NSP_DOCKER_SERVICE_PORT=8001
UDS_NSP_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_NSP_FE_DOCKER_SERVICE_HOST=192.168.225.168
UDS_NSP_FE_DOCKER_SERVICE_PORT=8501
UDS_NSP_FE_DOCKER_SERVICE_PORT_HTTP_8501=8501
UDS_NUP_SERVICE_HOST=192.168.56.161
UDS_NUP_SERVICE_PORT=9089
UDS_NUP_SERVICE_PORT_TCP_9089=9089
UDS_OPEN_APOLLO_API_SERVICE_HOST=192.168.184.74
UDS_OPEN_APOLLO_API_SERVICE_PORT=16831
UDS_OPEN_APOLLO_API_SERVICE_PORT_HTTP_16831=16831
UDS_OPEN_APOLLO_SERVICE_HOST=192.168.50.99
UDS_OPEN_APOLLO_SERVICE_PORT=9119
UDS_OPEN_APOLLO_SERVICE_PORT_HTTP_9119=9119
UDS_RANKS_DOCKER_SERVICE_HOST=192.168.62.190
UDS_RANKS_DOCKER_SERVICE_PORT=8001
UDS_RANKS_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_RED_PACKET_DOCKER_SERVICE_HOST=192.168.48.45
UDS_RED_PACKET_DOCKER_SERVICE_PORT=8001
UDS_RED_PACKET_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_RELATION_DOCKER_SERVICE_HOST=192.168.73.204
UDS_RELATION_DOCKER_SERVICE_PORT=8001
UDS_RELATION_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_SALES_DOCKER_SERVICE_HOST=192.168.228.4
UDS_SALES_DOCKER_SERVICE_PORT=8001
UDS_SALES_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_SHERLOCK_DOCKER_SERVICE_HOST=192.168.15.119
UDS_SHERLOCK_DOCKER_SERVICE_PORT=8001
UDS_SHERLOCK_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_SNOWFLAKE_SERVER_DOCKER_SERVICE_HOST=192.168.154.29
UDS_SNOWFLAKE_SERVER_DOCKER_SERVICE_PORT=8080
UDS_SNOWFLAKE_SERVER_DOCKER_SERVICE_PORT_TCP_8080=8080
UDS_USER_DOCKER_SERVICE_HOST=192.168.73.10
UDS_USER_DOCKER_SERVICE_PORT=8001
UDS_USER_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_USER_PROFILE_SERVICE_HOST=192.168.197.253
UDS_USER_PROFILE_SERVICE_PORT=8001
UDS_USER_PROFILE_SERVICE_PORT_HTTP_8001=8001
UDS_USER_VALUE_SERVICE_DOCKER_PORT=tcp://192.168.4.111:8001
UDS_USER_VALUE_SERVICE_DOCKER_PORT_8001_TCP=tcp://192.168.4.111:8001
UDS_USER_VALUE_SERVICE_DOCKER_PORT_8001_TCP_ADDR=192.168.4.111
UDS_USER_VALUE_SERVICE_DOCKER_PORT_8001_TCP_PORT=8001
UDS_USER_VALUE_SERVICE_DOCKER_PORT_8001_TCP_PROTO=tcp
UDS_USER_VALUE_SERVICE_DOCKER_SERVICE_HOST=192.168.4.111
UDS_USER_VALUE_SERVICE_DOCKER_SERVICE_PORT=8001
UDS_USER_VALUE_SERVICE_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_VEHICLE_DOCKER_SERVICE_HOST=192.168.86.238
UDS_VEHICLE_DOCKER_SERVICE_PORT=8001
UDS_VEHICLE_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_VEHICLE_MALL_DOCKER_SERVICE_HOST=192.168.136.225
UDS_VEHICLE_MALL_DOCKER_SERVICE_PORT=8001
UDS_VEHICLE_MALL_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_WATSON_DOCKER_SERVICE_HOST=192.168.92.133
UDS_WATSON_DOCKER_SERVICE_PORT=8001
UDS_WATSON_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_WEAVER_DOCKER_SERVICE_HOST=192.168.39.137
UDS_WEAVER_DOCKER_SERVICE_PORT=8001
UDS_WEAVER_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_ZEUS_BACKEND_DOCKER_SERVICE_HOST=192.168.176.55
UDS_ZEUS_BACKEND_DOCKER_SERVICE_PORT=8001
UDS_ZEUS_BACKEND_DOCKER_SERVICE_PORT_HTTP_8001=8001
UDS_ZEUS_FE_DOCKER_SERVICE_HOST=192.168.127.34
UDS_ZEUS_FE_DOCKER_SERVICE_PORT=8360
UDS_ZEUS_FE_DOCKER_SERVICE_PORT_HTTP_8360=8360

问题

upstream connect error or disconnect/reset before headers. reset reason connection failure

k8s 的 Istio 网关报的这个错

Istio DestinationRule gives upstream connect error or disconnect/reset before headers
https://stackoverflow.com/questions/53103984/istio-destinationrule-gives-upstream-connect-error-or-disconnect-reset-before-he


上一篇 Pinpoint

下一篇 Prometheus监控

阅读
评论
19,625
阅读预计86分钟
创建日期 2019-10-05
修改日期 2020-10-20
类别
目录
  1. 概述
    1. 基础组件功能
    2. K8S中一些基本概念
      1. Service 服务
      2. Namespace
      3. Volume
      4. DaemonSet
      5. ConfigMap
    3. service和pod
    4. K8S三种IP及端口
    5. 使用K8S的好处
  2. Kubernetes对象
    1. 对象规约(spec)与对象状态(status)
    2. 使用yaml描述对象
    3. 必须字段
  3. Node 节点
    1. nodeSelector节点选择
    2. 亲和与反亲和
      1. 节点亲和
  4. Label 标签
    1. 标签的语法和字符集
    2. 标签选择运算符
      1. 等值运算符
      2. 集合运算符
    3. 预定义系统标签
  5. Pod 容器组
    1. Pod和容器
    2. 使用Pod
    3. Pod的几种状态
    4. 容器探针
    5. Init容器
      1. 为什么需要init容器?
      2. init容器使用示例
    6. pause容器
  6. ReplicationController 副本控制器
    1. 定义RC
  7. ReplicaSet 副本集
  8. Deployment 部署
  9. kube-proxy
    1. userspace
    2. iptables
    3. ipvs
    4. k8s ipvs 长连接 Connection reset by peer问题
  10. Kubernetes API
  11. 常用k8s集群部署工具
    1. kops
    2. kubeadm
    3. Minikube
    4. kubespray
    5. Kubo
  12. 使用kubeadm安装部署k8s v1.19
    1. 参考文档
    2. Linux系统配置
      1. 系统信息
      2. 前提条件
      3. 内核参数配置
      4. 修改hostname
      5. 关闭firewalld防火墙
      6. 关闭SELinux访问控制
      7. 关闭swap交换空间
      8. 配置各节点互相免密登录
    3. 安装docker(或其他容器运行时)
    4. 安装kubeadm/kubelet/kubectl
    5. 配置和启动kubelet
      1. 设置开机启动kubelet
      2. 解决k8s必须关闭swap交换空间
      3. 配置cgroup driver
      4. 启动 kubelet
      5. failed to load Kubelet config file /var/lib/kubelet/config.yaml
    6. kubeadm init初始化master节点
      1. 自定义kubeadm配置文件
      2. 忽略cpu和swap检测错误
      3. 重复执行kubeadm init报错
      4. kubeadm reset删除k8s集群
      5. kubeadm init成功执行的结果
      6. scheduler和controller-manager是Unhealthy状态
    7. 安装Pod Network
      1. k8s集群安装flannel网络插件
      2. k8s集群安装calico网络插件
    8. 向k8s集群中添加node节点
      1. 初始化master节点生成的token只有24小时有效期
      2. 重新生成token
      3. 查看token
      4. 查看sha值
      5. 从k8s集群删除node节点
    9. 安装k8s包管理工具Helm v3.3.3
  13. Ingress
    1. 四层负载均衡与七层负载均衡
    2. 将k8s服务暴露到外部的几种方式
    3. ingress原理
    4. ingress的几种部署方式
    5. ingress-nginx 和 nginx-ingress 的区别
    6. Helm3部署ingress-nginx
  14. dashboard
    1. kubectl apply部署dashboard
    2. Helm3部署dashboard v2.7.1
  15. kubectl
    1. kubectl get
      1. kubectl get cs
      2. kubectl get nodes
      3. kubectl get pods -A
    2. kubectl create 创建资源
    3. kubectl apply 应用配置文件
    4. kubectl run
    5. kubectl label 给资源打标签
    6. kubectl drain
    7. kubectl delete
  16. 第三方工具
    1. Kuboard
    2. sealos
    3. kubesphere
  17. k8s发布
    1. k8s滚动更新机制
  18. k8s服务发现
    1. 环境变量
    2. service ip
    3. 通过DNS解析服务名访问
  19. 问题
    1. upstream connect error or disconnect/reset before headers. reset reason connection failure

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论