kubernetes 相关概念

lance 2020-03-23 PM 90℃ 0条

kubernetes 内部组件工作原理:http://dockone.io/article/5108


Master

Master 是整个集群的控制中心,kubernetes 的所有控制指令都是发给 master,它负责具体的执行过程。一般我们会把 master 独立于一台物理机或者一台虚拟机,它的重要性不言而喻。
 
master上有这些关键的进程:
Kubernetes API Server(kube-apiserver),提供了 HTTP Rest 接口关键服务进程,是所有资源增、删、改、查等操作的唯一入口,也是集群控制的入口进程。
 
Kubernetes Controller Manager(kube-controlker-manager),是所有资源对象的自动化控制中心,可以理解为资源对象的大总管。
 
Kubernetes Scheduler(kube-scheduler),负责资源调度(pod 调度)的进程,相当于公交公司的“调度室”。
 
etcd Server,kubernetes 里所有资源对象的数据都是存储在 etcd 中的。


Node

除了 Master,Kubernetes 集群中其他机器被称为 Node,早期版本叫做 Minion。Node 可以是物理机也可以是虚拟机,每个 Node 上会被分配一些工作负载(即,docker 容器),当 Node 宕机后,其上面跑的应用会被转移到其他 Node 上。
 
Node 上有这些关键进程:
kubelet:负责 Pod 对应容器的创建、启停等任务,同时与 Master 节点密切协作,实现集群管理的基本功能。
 
kube-proxy:实现 Kubernetes Service 的通信与负载均衡机制的重要组件。
 
Docker Engine(docker):Docker 引擎,负责本机容器的创建和管理。
 

kubectl get nodes #查看集群中有多少个 node
kubectl describe node <node name> #查看 Node 的详细信息

Pod

查看 pod 命令: kubectl get pods
查看容器命令: docker ps
 
可以看到容器和 pod 是有对应关系的,在我们做过的实验中,每个 pod 对应两个容器,一个是 Pause 容器,一个是 rc 里面定义的容器(实际上,每个 pod 里可以有多个应用容器)。这个 Pause 容器叫做“根容器”,只有当 Pause 容器“死亡”才会认为该 pod “死亡”。Pause 容器的 IP 以及其挂载的 Volume 资源会共享给该 pod 下的其他容器。
 
pod 定义示例:

apiVersion: v1
kind: pod
metadata:
  name: myweb
  labels:
    name: myweb
spec:
  containers:
  - name: myweb
    image: kubeguide/tomcat-app:v1
    ports:
    - containerPort: 8080
    env:
    - name: MYSQL_SERVICE_HOST
      value: 'mysql'
    - name: MYSQL_SERVICE_PORT
      value: '3306'

 
每个 pod 都可以对其能使用的服务器上的硬件资源进行限制(CPU、内存)。
CPU 限定的最小单位是 1/1000 个 cpu,用 m 表示,如 100m,就是 0.1 个 cpu。
内存限定的最小单位是字节,可以用 Mi(兆) 表示,如 128Mi 就是 128M。
 
在 kubernetes 里,一个计算资源进行配额限定需要设定两个参数:
1)requests:该资源的最小申请量
2)Limits:该资源允许的最大使用量。
 
资源限定示例:

spec:
  containers:
  - name: db
    image: mysql
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Label

Label 是一个键值对,其中键和值都由用户自定义,Label 可以附加在各种资源对象上,如 Node、Pod、Service、RC 等。一个资源对象可以定义多个 Label,同一个 Label 也可以被添加到任意数量的资源对象上。Label 可以在定义对象时定义,也可以在对象创建完后动态添加或删除。
 
Label 示例:
"release":"stable", "environment":"dev", "tier":"backend" 等等。


RC

RC 是 kubernetes 中核心概念之一,简单说它定义了一个期望的场景,即声明某种pod的副本数量在任意时刻都符合某个预期值,RC 定义了如下几个部分:
1)pod 期待的副本数
2)用于筛选目标 pod 的 Label Selector
3)创建 pod 副本的模板(template)
 
RC 一旦被提交到 kubernetes 集群后,Master 节点上的 Controller Manager 组件就会接收到该通知,它会定期巡检集群中存活的 pod,并确保 pod 数量符合 RC 的定义值。可以说通过 RC,kubernetes 实现了用户应用集群的高可用性,并且大大减少了管理员在传统 IT 环境中不得不做的诸多手工运维工作,比如编写主机监控脚本、应用监控脚本、故障恢复处理脚本等
 
RC 工作流程(假如,集群中有 3 个 Node):
1)RC 定义 2 个 pod 副本
2)假设系统会在 2 个 Node上(Node1 和 Node2)创建 pod
3)如果 Node2 上的 pod(pod2)意外终止,这很有可能是因为 Node2 宕机
4)则会创建一个新的 pod,假设会在 Node3 上创建 pod3,当然也有可能在 Node1 上创建 pod3
 
RC 中动态修改 pod 副本数量:

kubectl scale rc <rc name> --replicas=n

 
利用动态修改 pod 的副本数,可以实现应用的动态升级(滚动升级):
1)以新版本的镜像定义新的 RC,但 pod 要和旧版本保持一致(由 Label 决定)
2)新版本每增加 1 个 pod,旧版本就减少一个 pod,始终保持固定的值
3)最终旧版本 pod 数为 0,全部为新版本
 
删除 RC

kubectl delete rc <rc name>

 
删除 RC 后,RC 对应的 pod 也会被删除掉


Deployment

在 1.2 版本引入的概念,目的是为了解决 pod 编排问题,在内部使用了 Replica Set,它和 RC 比较,相似度为 90% 以上,可以认为是 RC 的升级版。 跟 RC 比较,最大的一个特点是可以知道 pod 部署的进度。
 
Deployment 示例:

vim tomcat-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - {key: tier, operator: In, values: [frontend]}
  template:
    metadata:
      labels:
        app: app-demo
        tier: frontend
    spec:
      containers:
      - name: tomcat-demo
        image: tomcat
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

 

kubectl create -f tomcat-deployment.yaml
kubectl get deployment

HPA(Horizontail Pod Autoscaler)

在 1.1 版本,kubernetes 官方发布了 HPA,实现 pod 的动态扩容、缩容,它属于一种 kubernetes 的资源对象。它通过追踪分析 RC 控制的所有目标 pod 的负载变化情况,来决定是否需要针对性地调整目标 Pod 的副本数,这是 HPA 的实现原理。
 
pod 负载度量指标:
1)CpuUtilizationPercentage 目标 pod 所有副本自身的 cpu 利用率平用均值。一个 pod 自身的 cpu 利用率=该 pod 当前 cpu 的使用量/pod Request 值。如果某一个时刻,CPUUtilizationPercentage 的值超过了 80%,则判定当前的 pod 已经不够支撑业务,需要增加 pod。
2)应用程序自定义的度量指标,比如服务每秒内的请求数(TPS 或 QPS)
 
HPA 示例:

apiVerion: autosacling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  maxReplicas: 10
  minReplicas: 1
  scaleTargetRef:
    kind: Deployment
    name: php-apache
  targetCPUUtilizationPercentage: 90

 
说明:HPA 控制的目标对象是一个名叫 php-apache 的 Deployment 里的 pod 副本,当 cpu 平均值超过 90% 时就会扩容,pod 副本数控制范围是 1-10.
 
除了以上的 xml 文件定义 HPA 外,也可以用命令行的方式来定义:

kubectl autoscale deployment php-apache --cpu-percent=90 --min=1 --max=10

Service

Service 是 kubernetes 中最核心的资源对象之一,Service 可以理解成是微服务架构中的一个“微服务”,pod、RC、Deployment 都是为 Service 提供嫁衣的。
 
简单讲一个 service 本质上是一组 pod 组成的一个集群,前面我们说过 service 和 pod 之间是通过 Label 来串起来的,相同 Service 的 pod 的 Label 一样。
同一个 service 下的所有 pod 是通过 kube-proxy 实现负载均衡,而每个 service 都会分配一个全局唯一的虚拟 ip,也叫做 cluster ip。
在该 service 整个生命周期内,cluster ip 是不会改变的,而在 kubernetes 中还有一个 dns 服务,它把 service 的 name 和 cluster ip 映射起来。
 
service 示例:(文件名 tomcat-service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  ports:
    - port: 8080
    selector:
      tier: frontend

 

kubectl create -f tomcat-service.yaml
kubectl get endpoints //查看 pod 的 IP 地址以及端口
kubectl get svc tomcat-service -o yaml //查看 service 分配的 cluster ip

 
多端口的 service

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  ports:
    - port: 8080
      name: service-port
    - port: 8005
      name: shutdown-port
    selector:
      tier: frontend

 
对于 cluster ip 有如下限制:
1)Cluster ip 无法被 ping 通,因为没有实体网络来响应
2)Cluster ip 和 Service port 组成了一个具体的通信端口,单独的 Cluster ip 不具备 TCP/IP 通信基础,它们属于一个封闭的空间。
3)在 kubernetes 集群中,Node ip、pod ip、cluster ip 之间的通信,采用的是 kubernetes 自己设计的一套编程方式的特殊路由规则。
 
要想直接和 service 通信,需要一个 Nodeport,在 service 的 yaml 文件中定义:

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  ports:
    - port: 8080
      nodeport: 31002
    selector:
      tier: frontend

 
它实质上是把 cluster ip 的 port 映射到了 node ip 的 nodeport 上了


Volume(存储卷)

Volume 是 pod 中能够被多个容器访问的共享目录,kubernetes 中的 volume 和 docker 中的 volume 不一样,主要有以下几个方面:
1)kubernetes 的 volume 定义在 pod 上,然后被一个 pod 里的多个容器挂载到具体的目录下
2)kubernetes 的 volume 与 pod 生命周期相同,但与容器的生命周期没关系,当容器终止或者重启时,volume 中的数据并不会丢失
3)kubernetes 支持多种类型的 volume,如 glusterfs,ceph 等先进的分布式文件系统
 
如何定义并使用 volume 呢?
只需要在定义 pod 的 yaml 配置文件中指定 volume 相关配置即可:

template:
  metadata:
    labels:
      app: app-demo
      tier: frontend
    spec:
      volumes:
        - name: datavol
          emptyDir: {}
      containers:
        - name: tomcat-demo
          image: tomcat
          volumeMounts:
            - mountPath: /mydata-data
              name: datavol
          imagePullPolicy: IfNotPresent

 
说明: volume 名字是 datavol,类型是 emptyDir,将 volume 挂载到容器的 /mydata-data 目录下
 
volume 的类型:
1)emptyDir 是在 pod 分配到 node 时创建的,初始内容为空,不需要关心它将会在宿主机(node)上的哪个目录下,因为这是 kubernetes 自动分配的一个目录,当 pod 从 node 上移除,emptyDir 上的数据也会消失。所以,这种类型的 volume 不适合存储永久数据,适合存放临时文件。
2)hostPath 指定宿主机(node)上的目录路径,然后 pod 里的容器挂载该共享目录。这样有一个问题,如果是多个 node,虽然目录一样,但是数据不能做到一致,所以这个类型适合一个 node 的情况。
配置示例:

volumes:
  - name: "persistent-storage"
    hostPath:
      path: "/data"

 
3)gcePersistentDisk 使用 Google 公有云 GCE 提供的永久磁盘(PD)存储 volume 数据。毫无疑问,使用 gcePersistentDisk 的前提是 kubernetes 的 node 是基于 GCE 的。
配置示例:

volumes:
  - name: test-volume
    gcePersistentDisk:
      pdName: my-data-disk
      fsType: ext4

 
4)awsElasticBlockStore 与 GCE 类似,该类型使用亚马逊公有云提供的 EBS Volume 存储数据,使用它的前提是 Node 必须是 aws EC2。
5)NFS 使用 NFS 作为 volume 载体。
示例:

volumes:
  - name: "NFS"
    NFS:
      server: ip地址
      path: "/"

 
6)其他类型

iscsi
flocker
glusterfs
rbd
gitRepo: 从 git 仓库 clone 一个 git 项目,以供 pod 使用
secret: 用于为 pod 提供加密的信息

persistent volume(PV)

PV 可以理解成 kubernetes 集群中某个网络存储中对应的一块存储,它与 volume 类似,但有如下区别:
1)PV 只能是网络存储,不属于任何 Node,但可以在每个 Node 上访问到
2)PV 并不是定义在 pod 上,而是独立于 pod 之外定义
3)PV 目前只有几种类型:GCE Persistent Disk、NFS、RBD、iSCSCI、AWS ElasticBlockStore、GlusterFS
 
如下是 NFS 类型的 PV 定义:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /somepath
    server: ip

 
其中 accessModes 是一个重要的属性,目前有以下类型:
ReadWriteOnce: 读写权限,并且只能被单个 Node 挂载
ReadOnlyMany: 只读权限,允许被多个 Node 挂载
ReadWriteMany:读写权限,允许被多个 Node 挂载
 
如果某个 pod 想申请某种条件的 PV,首先需要定义一个 PersistentVolumeClaim(PVC) 对象:

kind: persistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi

 
然后在 pod 的 vomume 定义中引用上面的 PVC:

volumes:
  - name: mypd
    persistentVolumeClaim:
      ClaimName: myclaim

Namespace(命名空间)

当 kubernetes 集群中存在多租户的情况下,就需要有一种机制实现每个租户的资源隔离。而 namespace 的目的就是为了实现资源隔离。
 

kubectl get namespace //查看集群所有的 namespace

 
定义 namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: dev

 

kubectl create -f dev-namespace.yaml //创dev namespace

 
然后再定义 pod,指定 namespace

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: dev
spec:
  containers:
  - image: busybox
    command:
      - sleep
      - "500"
    name: busybox

 
查看某个 namespace 下的 pod:

kubectl get pod --namespace=dev

标签: linux, kubernetes, k8s

非特殊说明,本博所有文章均为博主原创。

觉得文章不错,打赏一点吧,1分也是爱😀

WeChat Pay

微信打赏

Alipay

支付宝打赏

评论啦~