k8s指南-概述

目录:
(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

让我们回顾一下历史,看看部署方式的发展历程:
k8s指南-概述_第1张图片

传统部署时代

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

虚拟化部署时代

为了解决传统部署方式中存在的问题,虚拟化技术出现了。虚拟化部署允许用户在一个物理机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集群的组件图:
k8s指南-概述_第2张图片

控制平面

控制平台组件负责为集群做全局决策,比如任务调度,同时还能检测和响应集群事件,例如当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

你可能感兴趣的:(工具,云原生,kubernetes,docker,容器)