目录:
(1)k8s指南-概述
(2)k8s指南-架构
(3)k8s指南-工作负载(1)
(4)k8s指南-工作负载(2)
(5)k8s指南-工作负载(3)
(6)k8s指南-工作负载(4)
(7)k8s指南-Service
(8)k8s指南-Ingress
(9)k8s指南-DNS与服务发现
(10)K8S指南-平滑升级与自动扩缩容


Kubernetes是一个可移植的,可扩展的开源平台,用于管理容器化的工作负载和服务,为声明式配置和自动化带来了巨大便利。它拥有着巨大而快速增长的生态系统,其相关的服务和工具得到了广泛的应用。


Kubernetes是什么

一个kuberbetes集群由一个控制平面组件和一系列节点组成。

Going back in time

让我们回顾一下历史,看看部署方式的发展历程:
在这里插入图片描述

传统部署时代

早期的应用程序一般都部署在物理节点上,这带来的问题是没办法界定物理资源的边界,容易出现机器资源分配问题。比如说,当有多个应用运行在同一台物理机上时,如果某个应用占用了机器的大部分资源,就会导致其他应用无法运行。解决办法是让不同的应用跑在不同的机器上,但这又会导致机器资源利用不充分,而且会产生高昂的成本。

虚拟化部署时代

为了解决传统部署方式中存在的问题,虚拟化技术出现了。虚拟化部署允许用户在一个物理机cpu上跑多个虚拟机,虚拟机中的应用程序是相互隔离的。一个应用不能随意地访问另外一个应用,这在某种程度上提供了一定的安全性保证。

虚拟化技术能够很好地利用物理服务器上的资源,并且可以很方便地添加或者更新应用程序,从而实现更好的伸缩性,降低硬件成本。每一个虚拟机就是一台完整的计算器,在虚拟化硬件的基础上运行所有组件,包括操作系统。

容器化部署时代

容器与虚拟机有点类似,但它们有着更为宽松的隔离性,以便能够共享操作系统,也因此更为轻量级。与虚拟机类似的是,容器拥有自己的文件系统,cpu,内存,进程空间等。由于容器与底层基础设施是解藕的,所以可以方便地在云和云之间,操作系统和操作系统之间进行移植。

容器之所以变得如此受欢迎,是因为它具有很多的优点,比如:

  • 快捷的应用创建和部署:与使用虚拟机镜像相比,容器镜像使用起来更为方便和高效。
  • 持续地开发 、集成和部署:通过快速、简单的回滚(由于镜像的不可变性),支持可靠、频繁的镜像构建和部署。
  • 关注开发和运维的分离:在构建/发布阶段而不是部署阶段创建应用容器镜像,从而将应用程序和基础架构分离开。
  • 可观察行:不仅可以显示操作系统级别的信息和指标,还可以显示应用程序的运行情况和其他指标信息。
  • 跨开发、测试和生产的环境一致性:在不同的计算机和不同的环境中,能够保证应用程序及其运行的环境是相同的。
  • 跨云和操作系统的可移植性:可在Ubuntu,CoreOS,本地,Google Kubernetes Engine和其他任何地方运行。
  • 以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行OS到使用逻辑资源在OS上运行应用程序。
  • 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分,并且可以动态部署和管理-而不是在一台大型单机上整体运行。
  • 资源隔离:可预测的应用程序性能。
  • 资源利用:高效率和高密度。

kubernetes能做什么

容器是打包和运行应用程序的好方式。在生产环境中,你需要管理运行应用程序的容器,并确保不会停机。例如,如果一个容器发生故障,则需要启动另一个容器。如果由系统来处理这种情况,会不会变得更容易?这就是Kubernetes解决此类问题的方法。k8s提供了一个可弹性运行分布式系统的框架,能够满足你的扩展、故障转移、部署模式等需求。

Kubernetes为你提供:

  • 服务发现和负载均衡

k8s可以使用DNS名称或者自己的ip地址公开容器,如果进入容器的流量很大,k8s可以负载均衡并分配网络流量,从而使部署稳定。

  • 存储编排

k8s允许你自动挂载你选择的存储系统,例如本地存储,公有云存储等。

  • 自动部署和回滚

你可以使用k8s描述已部署容器的所需状态,k8s会以受控的速率将实际状态更改为期望状态。例如,你可以让k8s为你的部署创建新容器,删除现有容器并将它们所有的资源用于新容器。

  • 自动装箱计算

Kubernetes 允许你指定每个容器所需 CPU 和内存(RAM)。 当容器指定了资源请求时,Kubernetes 可以做出更好的决策来管理容器的资源。

  • 自愈

重新启动失败的容器,在节点不可用时,替换和重新调度节点上的容器,对用户定义的健康检查不响应的容器会被中止,并且在容器准备好服务之前不会将其向客户端广播。

  • 密钥与配置管理

k8s允许存储和管理敏感信息,例如密码、OAuth令牌和ssh密钥。你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置。

Kubernetes组件

当你部署完 Kubernetes, 即拥有了一个完整的集群。

一个 Kubernetes 集群由一组被称作节点的机器组成,Kubernetes 所管理的容器化应用就在这些节点上运行。每个集群具有至少一个工作节点。

工作负载组件,也就是pods,托管在集群中的工作节点上,而控制平面负责管理所有的工作节点和pods。通常在生产环境中,控制平面和集群是分布式的,跨主机和跨节点的,以此来实现故障转移和高可用。

下面是一个k8s集群的组件图:
在这里插入图片描述

控制平面

控制平台组件负责为集群做全局决策,比如任务调度,同时还能检测和响应集群事件,例如当pod数量不满足replicas指定的数量时,负责启动新的pod。

控制平面组件可以在集群中的任何节点上运行。但是为了简单起见,设置脚本通常会选择一台机器来启动所有的控制平面组件,并且这台机器不会跑任何用户容器。

kube-apiserver

API Server是控制平面中用于对外暴露k8s API接口的,它是控制平面的前端。

API Server的主要实现是kube-apiserver,是可以水平伸缩的。也就是说,它可通过部署多个实例进行伸缩。你可以运行kube-apiserver的多个实例,并在这些实例之间做负载均衡。

etcd

etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库。通常来说,etcd数据库需要有备份计划。

kube-scheduler

kube-scheduler负责监控新创建但还没有指定运行节点的pods,然后选择合适的节点让pod运行。

调度决策考虑的因素有很多,包括单个pod和pod集合的资源需求、硬件/软件/策略约束、亲和性和反亲和性规范、数据位置、工作负载间的干扰和最后时限。

kube-controller-manager

kube-controller-manager是控制器进程管理器。

从逻辑上来讲,每个控制器都是一个单独的进程,但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行。

这些控制器包括:

  • 节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应
  • 任务控制器(Job controller): 监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
  • 端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 与 Pod)
  • 服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌

cloud-controller-manager

云控制器管理器是指嵌入特定云的控制逻辑的控制平面组件。通过云控制器管理器,你可以将你的集群连接到云提供商的API, 并将云平台交互组件和你的集群交互组件隔离开来。
注意,cloud-controller-manager 仅作用在特定的云平台上,如果你在自己的环境中运行Kubernetes,或者在本地计算机中运行学习环境, 所部署的环境中不需要云控制器管理器。

Node组件

节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行环境。

kubelet

kebelet是运行在每个节点上的代理,保证容器都运行在pod中。

kubelet 接收一组通过各类机制提供给它的PodSpecs,确保这些 PodSpecs 中描述的容器处于运行状态且是健康的。 kubelet 只管理由 Kubernetes 创建的容器。

kube-proxy

kube-proxy是运行在每个节点上的网络代理,负责维护节点上的网络规则。这些网络规则允许从集群内部或外部发起的网络会话与 Pod 进行网络通信。

如果操作系统提供了数据包过滤层并可用的话,kube-proxy 会通过它来实现网络规则。否则, kube-proxy 仅转发本身的流量。

container runtime

容器运行时负责容器运行的环境。

Kubernetes 支持多个容器运行环境: Docker、 containerd、CRI-O 以及 Kubernetes CRI (容器运行环境接口)的其他任何实现。

插件

插件使用 Kubernetes 资源(DaemonSet、 Deployment等)实现集群功能,插件中命名空间域的资源属于 kube-system 命名空间。下面介绍几种插件。

DNS

事实上k8s中除了DNS之外,其他插件都不是必须插件。集群 DNS 是一个 DNS 服务器,和环境中的其他 DNS 服务器一起工作,它为 Kubernetes 服务提供 DNS 记录。

Kubernetes 启动的容器自动将此 DNS 服务器包含在其 DNS 搜索列表中。

Kubenetes API

在上文中介绍过,k8s控制平面包括诸多组件,其中一个很核心的组件就是API Server。它负责提供HTTP API,以供用户、集群中的不同部分以及集群外的组件相互通信。

通过API Server,你可以查询和操作k8s中的对象,如Pod,Namespace,ConfigMap和Event等。大部分操作都可以通过kubectl命令行接口或者类似kubeadm这类命令行工具来执行,其背后实际调用的就是API。

如果你需要在程序中访问k8s的API,可以考虑使用客户端库

Kubernetes对象

理解Kubernetes对象

k8s对象是指k8s系统中的持久化实体,k8s通过这些实体来描述集群状态。

k8s对象是“目标性记录”–一旦创建对象,k8s系统将持续工作以确保对象存在。通过创建对象来告知k8s系统,所需要的集群工作负载是什么样的,这就是k8s集群的期望状态。

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

对象规约与状态

几乎每个k8s对象都包含两个嵌套的对象字段:spec和status,用于管理对象的配置。对于具有spec的对象,必须在创建对象时设置其内容,描述其期望状态。

status描述了对象的当前状态,它是由k8s系统和组件设置并更新的。k8s控制平面全程负责管理对象的实际状态,以使之与期望状态相匹配。

例如,k8s中的Deployment对象能够表示运行在集群中的应用。当创建Deployment时,可能需要设置Deployment的spec,以指定该应用的副本数量。k8s系统读取Deployment的spec,启动指定数量的实例–更新状态与规约相匹配。如果这些实例中有失败的,k8s会执行修正操作,来尝试达到期望值–这意味着它会启动一个新的实例来替换失败的实例。

描述k8s对象

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

apiVersion: apps/v1
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

在kubectl命令行接口中使用apply命令,将.yaml文件作为参数,调用API接口生成对象:

kubectl apply -f https://k8s.io/examples/application/deployment.yaml --record

输出类似如下这样:

deployment.apps/nginx-deployment created

必需字段

在对象参数对应的.yaml文件中,需要配置如下字段:

  • apiVersion - 创建对象所使用的k8s API版本。
  • kind - 想要创建对象的类别
  • metadata - 唯一标识对象的一些数据,包括nameUIDnamespace等。
  • spec - 对象的期望状态

对象spec的精确格式对每个k8s对象来说都是不同的,包含了该对象特定的字段。Kubenetes API 参考 中说明了不同对象的规约格式。

Kubernetes对象管理

kubectl命令行工具支持多种不同的方式来创建和管理k8s对象。

应该只使用一种技术来管理k8s对象,不同的技术混合在一起作用在同一对象上将导致未定义行为。

不同方式的特性如下:

管理技术作用范围建议的环境支持的写入者数学习难度
指令式命令活跃对象开发项目1+
指令式对象配置单个文件生产项目1中等
声明式对象配置文件目录生产项目1+

指令式命令

使用指令式命令时,用户可以在集群中的活动对象上进行操作。这种方式将用户操作传给kubectl命令作为参数或标志。

指令式命令是在集群中运行一次性任务的推荐方式。因为是直接在活跃的对象上操作,所以它不提供以前配置的历史记录。

下面是一个指令式命令的例子:

kubectl create deployment nginx --image nginx

指令式对象配置

在指令式对象配置中,kubectl命令需要指定操作,可选标志和至少一个文件名。指定的文件必须包含yaml或json格式的对象的完整定义。

下面是一个例子:

kubectl create -f nginx.yaml

删除两个配置文件中定义的对象:

kubectl delete -f nginx.yaml -f redis.yaml

通过覆盖活动配置来更新配置文件中定义的对象:

kubectl replace -f nginx.yaml

声明式对象配置

使用声明式对象配置时,用户对本地存储的对象配置进行操作,但是不定义要对该文件操作的类型。kubectl会自动检测每个文件的创建、更新和删除操作。这使得配置可以在目录上工作,根据目录中配置文件,对不同的对象执行不同的操作。

声明式对象配置保留了其他编写者所做的修改,即使这些更改并未合并到对象配置文件中。可以用patch API操作仅写入差异点,而不是使用replace API操作来替换整个对象。

下面是一个声明式对象的例子。

处理configs目录中的所有对象配置文件,创建并更新活跃对象。可以首先使用diff子命令查看将要进行的修改,然后再进行应用:

kubectl diff -f configs/
kubectl apply -f configs/

递归处理目录:

kubectl diff -R -f configs/
kubectl apply -R -f configs/

三种对象操作方式的主要优缺点如下:

指令式命令指令式对象配置声明式对象配置
优点命令简单易学,仅需一步即可对集群进行更改可以将变更通过文件形式存储在版本控制系统如git中;可以与流程集成,如在推送和审计之前检查更新对活动对象的更改即使未合并到配置文件中,也会被保留下来(增量更新);支持对目录进行操作
缺点无法审核和跟踪,不提供记录源,不提供创建新对象的模板不适合对目录进行操作;对活动对象的更新必须反映在配置文件中,否则会在下一次替换时丢失(全量更新)难于调试,出现异常结果时难以理解;diff产生的部分更新会创建复杂的合并和补丁操作

对象名和IDs

每个对象都有一个名字,用来标识在同类资源中的唯一性。此时同时,每个对象还有一个UID,在整个集群中都是唯一的。

举个例子,在同一个命名空间内,只能有一个叫做myapp-1234的pod,但是,还可以同时存在一个也叫这个名字的deployment对象。这是因为他们的对象类型是不同的。

对于用户提供的非唯一属性,Kubernetes提供了labelsannotation机制。

名称

客户端提供的字符串,用来引用资源中的对象,如/api/v1/pods/some name

以下是四种常见的资源命名约束:

DNS子域名

很多资源类型需要可以用作DNS子域名的名称。DNS子域名的定义见RFC 1123规范。需要满足如下规则:

  • 不能超过253个字符
  • 只能包含小写字母、数字以及‘-’和‘.’
  • 必须以字母或数字开头
  • 必须以字母或数字结尾

标签名

某些资源类型需要其名称遵循DNS标签标准,规则如下:

  • 最多63个字符
  • 只能包含小写字母、数字以及‘-’
  • 必须以字母或数字开头
  • 必须以字母或数字结尾

分段路径名

某些资源类型的名称需要作为分段路径名来使用,不能为“.”或者“…”,也不能包含“/”和“%”。下面是一个示例:

apiVersion: v1
kind: Pod
metadata:
	name: nginx-demo
spec:
  containers:
  - name: nginx
     image: nginx:1.14.2
     ports:
     - containerPort: 80

注意: 某些资源类型有额外的命名限制

UIDs

Kubernetes UIDs 是全局唯一标识符(也叫 UUIDs),可以用来标识一个唯一的对象。 UUIDs 是标准化的,见 ISO/IEC 9834-8 和 ITU-T X.667。在 Kubernetes 集群的整个生命周期中创建的每个对象都有一个不同的 uid,它旨在区分类似的实体。

命名空间

在 Kubernetes 中,“名字空间(Namespace)”提供一种机制,将同一集群中的资源划分为相互隔离的组。 同一名字空间内的资源名称要唯一,但跨名字空间时没有这个要求。 名字空间作用域仅针对带有名字空间的对象,例如 Deployment、Service 等, 这种作用域对集群访问的对象不适用,例如 StorageClass、Node、PersistentVolume 等。

使用命名空间

避免使用前缀 kube- 创建名字空间,因为它是为 Kubernetes 系统名字空间保留的。

查看命名空间

你可以使用以下命令列出集群中现存的名字空间:

kubectl get namespace

Kubernetes 会创建四个初始名字空间:

  • default: 未指定命名空间的对象所默认使用的命名空间
  • kube-system: Kubernetes 系统创建对象所使用的命名空间
  • kube-public:这个命名空间是自动创建的,所有用户(包括未经过身份验证的用户)都可以读取它。 这个命名空间主要用于集群使用,处理某些资源在全部集群中是可见和可读的情况。 这个命名空间的公共属性只是一种约定,而不是要求。
  • kube-node-lease:此命名空间用于与各个节点相关的租约(Lease)对象。 节点租期允许 kubelet 发送心跳,由此控制面能够检测到节点故障。

为请求设置名字空间

要为当前请求设置名字空间,请使用--namespace参数。

例如:

kubectl run nginx --image=nginx --namespace=<名字空间名称>
kubectl get pods --namespace=<名字空间名称>

设置命名空间偏好

你可以永久保存命名空间,以用于对应上下文中所有后续 kubectl 命令。

kubectl config set-context --current --namespace=<名字空间名称>
# 验证
kubectl config view | grep namespace:

参考资料

[1]. https://kubernetes.io/zh/docs/concepts/overview/
[2]. https://blog.csdn.net/weichuangxxb/article/details/103754021

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐