k8s上手

K8s 是什么

Kubernetes 是一个开源的容器编排平台,可以自动完成在部署、管理和扩展容器化应用过程中涉及的许多手动操作。Kubernetes 这个名字源于希腊语,意为“舵手”或“飞行员”。K8s 这个缩写是因为 k 和 s 之间有八个字符的关系。 Google 在 2014 年开源了 Kubernetes 项目。
“编排”(Orchestration)在云计算行业里不算是新词汇,它主要是指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义、配置、创建、删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程
而容器时代,“编排”显然就是Docker 等各类容器的一系列定义、配置和创建动作的管理

k8s 能干什么

  • 自动化容器的部署和复制
  • 随时扩展或收缩容器规模
  • 将容器组织成组,并且提供容器间的负载均衡
  • 很容易地升级应用程序容器的新版本
  • 提供容器弹性,如果容器失效就替换它

容器

虚拟机 VS 容器

虚拟机是在操作系统里面,装一款软件,通过这个软件虚拟出“子电脑”,在“子电脑”里,我们可以运行微信、QQ以及其他程序。同样,我们也可以模拟出更多“子电脑”,这些子电脑就是虚拟机了,虚拟之间相互隔离,互不影响。
容器技术本质上跟虚拟技术有一定的区别,虚拟机使用虚拟机管理程序运行在物理设备上,从系统可用资源分配虚拟机实例。换言之,虚拟机需要虚拟一个物理环境,紧接着构建一个完整的操作系统,供应用程序运行。对于容器技术而言,直接将容器层安装在主机操作系统上,直接利用了宿主机的内核,它不需要虚拟整个操作系统,抽象层比虚拟机更少,启动时间更短、占用空间更小。
那什么是容器呢,举个例子:
我们经常遇到这种情况,程序在自己机器上跑的好好的,结果到了别的机器上就不行了,因为两台机器的环境不一样,别人的机器需要重新配置环境才行。为了解决这个问题,容器就出现了,就是连程序带环境一块搬到目标机器上,环境都准备好了,直接就能跑。这个把程序和环境包在一块的东西,就叫容器。
一个“容器”,实际上是由 Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境。
  • Linux Namespace 和 Linux Cgroups,提供了运行时的隔离和资源的授予。
  • rootfs,也就是镜像,提供了容器的运行内容。

基本概念

  1. docker 包括三个概念:镜像(image),容器(container)、仓库(repository
  2. 容器就是镜像运行时的实体,镜像和容器的关系类比与Java 面向对象程序设计中的类和实例是一样的概念。
  3. 每个容器的文件系统与其他容器是隔离的。
  4. 容器可以被创建、启动、停止、删除以及暂停等。
  5. 容器的实质是进程,运行于属于自己独立的命名空间。
  6. 容器内的存储层是跟随容器变化的,生命周期同容器保持一致。容器删除,则存储层信息丢失。所以存储东西最好使用存储卷(volume)、绑定宿主目录等方式。
  7. 容器是应用程序层的一种抽象,将代码和依赖关系打包在一起,可以多个容器同时运行在同一台机器上,并与其他容器共享操作系统内核。

与 K8s 的关系

简单来说,有互补,也有竞争(Docker有一款名为Docker Swarm的产品,是一个集群和调度工具,类似 K8s)。在一般的认知中,Kubernetes 和 Docker 是互补关系:
  • Dockers 属于下层 —— 容器引擎;
  • Kubernetes 属于上层 —— 编排调度层。
简单来说,K8s 是一个大管家。当你在服务器上装了各种容器,随着时间推移,你完全不知道自己有多少个容器,哪个容器负载小,哪个容器负载大,新来的应用要装在哪个容器等等,K8s 就是帮你管理和维护这些容器的。

OCI

OCI(Open Container Initiative)一个关于容器格式和运行时的标准或规范,是由多家公司共同成立的项目,包含运行时标准(runtime-spec )和容器镜像标准(image-spec)。运行时标准规定了怎么去运行一个容器,如何去表达容器的状态和生命周期、如何设置 namespace、cgroup、文件系统等等,可以理解为运行期的动态描述;而容器镜像标准规定了容器镜像的格式、配置、元数据等,可以理解为对镜像的静态描述。

CRI

在 K8s 1.5 版本之后,K8s 推出了自己的运行时接口 api–CRI(container runtime interface)。CRI 接口的推出,隔离了各个容器引擎之间的差异,通过统一的接口与各个容器引擎之间进行互动。CRI 将 Kubelet 代码与具体的容器运行时的实现代码解耦开,只要实现了这样一套接口,就能接入到 Kubernetes 的体系中。
为了进一步与 OCI 进行兼容,K8s 还孵化了CRI-O,成为了架设在 CRI 和 OCI 之间的一座桥梁。通过这种方式,可以方便更多符合 OCI 标准的容器运行时,接入 K8s 进行集成使用。

K8s 构成组件

完整的 Kubernetes 集群是由 控制节点 master 、工作节点 node 构成,因此这种集群方式也分为 一主多从 和 多主多从,而每个节点上又会安装不同组件以提供服务。

Master

集群的控制平面,负责集群的决策(管理),存在以下组件
  • ApiServer :资源操作的唯一入口,接收用户输入的命令,提供认证、授权、Api 注册和发现等机制
  • Scheduler:负责集群资源调度,按照预定的调度策略将 pod 调度到相应的 node 节点上
  • ControllerManager:负责维护集群的状态,比如程序部署安排,故障检测,自动扩展,滚动更新等
  • Etcd:分布式 key-value 存储,负责存储集群中各种资源对象的信息

Node

集群的数据平面,负责为容器提供运行环境(干活),存在以下组件
  • kubelet:一个在集群中每个node上运行的代理。 它保证容器都运行在 Pod 中。kubelet 定期接收新的或修改过的 pod 规范 PodSpecs(主要通过 kube-apiserver)并确保 pod 及容器健康并以所需状态运行。该组件还向 kube-apiserver 报告运行它的主机的健康状况。
  • kube-proxy:集群中每个节点上运行的网络代理,实现 Kubernetes 服务(Service) 概念的一部分。kube-proxy 维护节点上的网络规则,这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。
  • 容器运行时(Container Runtime):容器运行时负责创建容器运行环境,Kubernetes 支持多个容器运行时: Docker、containerd、CRI-O以及任何实现 Kubernetes CRI (容器运行环境接口)的runtime。

K8s 实例调度

  1. kubectl 客户端首先将 CLI 命令转化为 RESTful 的API调用,然后发送到 kube-apiserver。
  2. kube-apiserver 在验证这些 API 调用后,将任务元信息并存储到etcd,接着调用 kube-scheduler 开始决策一个用于作业的 Node 节点。
  3. 一旦 kube-scheduler 返回一个适合调度的目标节点后,kube-apiserver 就把任务的节点信息存入etcd,并创建任务。
  4. 此时目标节点中的 kubelet 正监听 apiserver,当监听到有新任务需要调度到本节点后,kubelet通过本地 runtime 创建任务容器,执行作业。
  5. 接着 kubelet 将任务状态等信息返回给 apiserver 存储到 etcd。
  6. 这样我们的任务已经在运行了,此时controller-manager 发挥作用保证任务一直是我们期望的状态。

K8s 基础资源

K8s 中⼀切皆为资源,⼀切即可描述,⼀切皆可管理,下面几种资源是经常用到的:

NameSpace

命名空间(namespace)是 K8s 提供的组织机制,用于给集群中的任何对象组进行分类、筛选和管理,主要有两个方面的作用:
  • 资源隔离:可为不同的团队 / 用户(或项目)提供虚拟的集群空间,共享同一个K8s 集群资源,以做到彼此之间相互隔离,互不影响。
  • 权限控制:可以指定某个namespace哪些用户可以访问,哪些用户不能访问

Pod

Pod 是 K8s 中能够创建和部署的最小单元,是 K8s 集群中的一个应用实例。Pod中包含了一个或多个容器,还包括了存储、网络等各个容器共享的资源。Pod 内部封装的是容器,容器内部运行的是应用程序。
  • Pod是 K8s 控制的最小单元,一个 Pod 会有多个进程。
  • 一个 Pod 可以被一个容器化的环境看做应用层的“逻辑宿主机”,可以理解为容器的容器,可以包含多个“Container”;
  • 一个 Pod 的多个容器应用通常是紧密耦合的,Pod在 Node 上创建、启动或销毁;
  • Pod 的内部容器网络是互通的,每个Pod 都有独立的虚拟IP。
  • Pod 都是部署完整的应用或模块,同一个Pod容器之间只需要通过 localhsot 就能互相通信。
  • Pod 的生命周期是通过 ReplicaSet 来管理的,通过模板进行定义,然后分配到一个Node上运行。

Deployment

Deployment 是 K8s 中常用的对象类型,通过对 ReplicaSet 和 Pod 进行组装支持了滚动更新、回滚以及扩容等高级功能,⽤于发布无状态应用使用。Dp 最核⼼的功能就是完成了 pod 的控制,建⽴RS(副本个数控制器,也就是⼏个实例)来控制⼀个服务后⾯的 Pod 数⽬,以及 pod 的生命周期,pod 使⽤的资源,pod 是否健康的检查,重启策略等等。日常使用中对于 K8s 的编排操作基本都是基于 dp 资源实现的。

StatefulSet

StatefulSet本质上是 Deployment的一种变体,它为了解决有状态服务的问题,它所管理的 Pod 拥有固定的 Pod 名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。

Service

在 K8s 平台上,Pod是有生命周期,为了可以给客户端一个固定的访问端点,因此需要在客户端和Pod 之间添加一个中间层,这个中间层称之为Service。
Service 服务是 K8s 里的核心资源对象之一,为 pod 稳定地提供服务发现和负载均衡的能力。Service 向上提供了外部网络的访问和 Pod 网络的访问;向下则通过负载均衡把请求分配到不同的Pod中去。
为什么需要 Servic?Kubernetes 的 Pod 是有生命周期的,如果使用 Deployment 或者 StatefulSet 来运行应用程序,则它们会动态创建和销毁 Pod,这也就意味着 Pod 的 IP 是不固定的。比如我们使用三副本的 Deployment 部署了 nginx 服务,每个 Pod 都会被分配一个 IP,由于 Pod 的生命周期不稳定,Pod 可能会被删除重建,而重建的话 Pod 的 IP 地址就会改变。也有一种场景,我们可能会对 nginx Deployment 进行扩缩容,从 3副本扩容为 5 副本或者缩容为 2 副本。当我们需要访问上述的nginx 服务时,客户端对于 nginx 服务的 IP 地址就很难配置和管理。

Ingress

Ingress 是 Kubernetes 的一种 API 对象,将集群内部的 Service 通过 HTTP/HTTPS 方式暴露到集群外部,并通过规则定义 HTTP/HTTPS 的路由。

PV 和 PVC

在 pod 中,容器销毁,则所有容器内部资源都会被销毁,但有些场景下我们希望容器被重新拉起时能保留原有的部分资源,这便有了持久化存储的概念。
持久卷(PersistentVolume,PV)是集群中由管理员配置的一段网络存储,描述一个具体的Volume属性,比如Volume的类型、挂载目录、远程存储服务器地址等。它是集群中的资源,就像节点是集群资源一样。
持久卷申领(PersistentVolumeClaim,PVC)表达的是用户对存储的请求。Pod 会耗用节点资源,而PVC申领会耗用 PV 资源。PVC 申领可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载)。

Labels 和 Selectors

标签和选择器。作⽤其实就是给每个容器贴个标签,然后呢,各个控制器通过 Selector 进⾏ pod 的控制管理,⽐如 Deployment,Service 都是这样控制的。

K8s Service 服务类型

  • ClusterIP: 默认类型,自动分配一个集群内部虚拟IP地址,只能被集群内部访问。
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  • NodePort: 通过每个节点上的 IP 和静态端口(NodePort)暴露服务,提供对外访问。也就是说我们可以通过集群中任意一个节点 IP 地址和端口来访问后的 Pod 应用。(常用)
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:    - port: 80
      targetPort: 80      nodePort: 30001
  • LoadBalancer: 使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
      云提供商的 LoadBalancer 插件主流的实现方式:
    • 让 Service 以 NodePort 形式启动
    • 向云提供商的负载均衡配置接口报告 Pod 所在 Node 的 IP 和 NodePort 端口
    • 负载均衡器按照上报的 IP 和 NodePort 自动将流量导到 Node 上,进而导到 Pod 中
  • ExternalName: 把集群外部的服务引入到集群内部来,在集群内部直接使用。
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: ExternalName
  externalName: mysql.database.bytedance.net

K8s 部署一个应用 - 以 Nginx 为例

https://10.227.90.95/ 使用开发机搭建的 K8s 测试集群。
  1. 创建一个 Nginx 的 dp
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
  1. 创建 Service
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30007
posted @ 2023-12-20 11:07  royalrover  阅读(43)  评论(0编辑  收藏  举报