您现在的位置是:首页 >技术杂谈 >[k8s]Kubernetes简介网站首页技术杂谈

[k8s]Kubernetes简介

alwaysrun 2024-07-01 11:59:31
简介[k8s]Kubernetes简介

容器管理工具可以完成容器的基础管理,但是容器的应用并不是只能进行简单应用部署的,可以使用容器完成企业中更加复杂的应用部署,当需要对多应用的系统进行部署时,就需要更加复杂的工具来完成对容器运行应用的编排,这就是容器编排部署工具。

Kubernetes介绍

k8s是一个轻便的和可扩展的开源平台,用于管理多个主机上的容器化的应用,让部署容器化的应用简单并且高效,提供了应用部署、规划、更新、维护的一种机制,能进行应用的自动化部署及扩缩容。
在这里插入图片描述

k8s集群是Master和Worker的模式:

  • Master节点上有kube-apiserver、kube-controller-mansger、kube-scheduler以及etcd进程,分别用于接收客户端请求并控制集群、资源对象的控制中心并监控容器健康、资源调度、资源对象数据存储等功能
  • Worker节点上有kubelet、kube-proxy、docker,分别用于管理Pod及Pod容器并定时向Master汇报节点资源信息、实现Service的透明代理及负载均衡、运行容器。

术语

k8s中概念与术语大多围绕资源对象(Resource Object),其一般包括几个通用属性:版本、类别(Kind)、名称、标签和注解。

  • 对象的名称要唯一;
  • 对象的标签很重要(如表明对象的特征、类别);
  • 注解通常用于对象属性的自定义扩展;

Label

Label(标签)是一个key=value的键值对,可以附加到任何资源上。例如Node,Pod,Service,RC等,一个资源对象可以定义多个Label,一个Label可以被添加到多个资源上,通常在资源定义时确定,也可在在对象创建后动态添加或删除。

给资源对象定义个Label,就相当于给他打了一个标签;随后,可通过Label Selector(标签选择器)查询或筛选拥有某些Label的资源对象。标签匹配:

  • {key}={value}:匹配所有拥有{key}={value}标签的资源;
  • {key}!={value}:匹配所有不具有{key}={value}标签的资源;
  • {key} in ({v1}, {v2}:匹配任意指定的标签;
  • {key} not in ({v1}, {v2}:匹配不具有指定的标签;
  • AND操作:通过逗号组合多个选择条件,如name=redis, env!=test

label定义在metadata中:

metadata:
  name: redis
  labels:
    name: redis
    app: red-example

StatefulSet

StatefulSet用于有状态的中间件集群(每个节点有固定身份ID,规模固定,每个节点有状态且持久化数据到永久存储中):

  • StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来 发现集群内的其他成员。假设StatefulSet的名称为kafka,那么第1个Pod 叫kafka-0,第2个叫kafka-1,以此类推。
  • StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod 时,前n-1个Pod已经是运行且准备好的状态。
  • StatefulSet里的Pod采用稳定的持久化存储卷,通过PV或PVC来 实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数 据的安全)。

STS模式下的POD中,可通过{pod-name}.{service}来访问节点。

存储类

存储类对象包括Volume、PersistentVolume、PVC和StorageClass

Volume

Volume是Pod中能够被多个容器访问的共享目录,k8s的Volume定义在Pod上,然后被Pod的多个容器挂载到具体的文件目录下;与Pod的生命周期相同,与容器的生命周期无关,当容器终止或重启时,Volume中的数据也不会丢失。

先在Pod上声明一个Volume,然后在容器中引用该Volume并Mount到容器中的某个目录上

spec:
  volumes:
  - name: datavol
    emptyDir: {}
  containers:
  - name: test-volume
    image: tomcat
    volumeMounts:
    - mountPath: /mydata-data
      name: datavol

k8s提供了丰富的volume类型:

  • emptyDir:在Pod分配到Node时创建的,初始内容为空,无需指定宿主机上对应的目录文件,K8S自动分配,当Pod从Node上移除时,emptyDir中的数据也会被永久删除。可用于:
    • 临时空间
    • 长时间任务的中间过程CheckPoint的临时保存目录
    • 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)
    • 使用的是节点的存储介质,可通过设定emptyDir.medium为Memory以使用内存(会被记入容器的内存消耗,受到资源限制和配额机制的管理)
  • hostPath:在Pod上挂载宿主机上的文件或目录。可用于:
    volumes:
    - name: hostpath
      hostpath:
        path: "/path"
    
    • 容器生成的日志需要永久保存时
    • 需要访问宿主机上的Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主机/var/lib/docker目录,使容器内部应用可以直接访问Docker的文件系统。
  • NFS:使用NFS网络文件系统提供的共享目录存储数据时,需在系统中部署一个NFS Server。
    volumes:
    - name: nfs
    nfs:
        server: {nfs-server address}
        path: "/"
    

Persistent Volume

Persistent Volume(PV)和与之关联的Persistent Volume Claim(PVC)是一块网络存储,挂接到虚机上的‘网盘’。PV是K8s集群中某个网络存储中对应的的一块存储,与Volume相似,但有以下区别:

  • PV只能是网络存储,不属于任何Node,但可以在任何Node上访问。
  • PV并不是定义在Pod上的,而是独立于Pod之外定义的。
  • PV目前只有几种类型:GCE Persistent Disks、NFS、RBD、iSCSCI、AWS ElasticBlockStore、GlusterFS
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvtest
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: {nfs-server address}
    path: /path

PV的accessModes属性,目前有以下几种类型:

  • ReadWriteOnce:读写权限,并且只能被单个Node挂载
  • ReadOnlyMany:只读权限,允许被多个Node挂载
  • ReadWriteMany:读写权限,允许被多个Node挂载

某个Pod想申请某种条件的PV,则首先需要定义一个Persistent Volume Claim(PVC)对象

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

然后,在Pod的Volume定义中引用上述PVC即可

volumes:
- name: pvtest
  persistentVolumeClaim:
    claimName: myclaim

PV有以下几种状态:

  • Available:空闲状态
  • Bound:已经绑定到某个PVC上
  • Released:对应的PVC已经删除,但资源还没有被集群回收
  • Failed:PV自动回收失败。

IP地址

k8s中有三种网络(每种代表不同的寻址空间):

  • Node IP:Node节点IP地址,包含内部(集群节点间访问)和外部IP地址;
  • Pod IP:访问Pod(仅限集群内部访问),Pod挂掉重启后会改变;
  • Cluster IP:是访问Service的IP地址(仅能从内部访问);该服务提供通过标签管理Pod的功能(Pod重启后,IP地址改变,但标签不变);
  • External IP:提供从外部访问Service访问的功能;

Node IP

Node IP是k8s集群中每个节点物理网卡的IP地址(真实存在的),查询Node IP:

kubectl get nodes # 获取节点名称
kubectl describe node {node-name} # 显示node详情,其中Address下的InternalIP字段即为Node IP 

# 或直接查询
kubectl get nodes -o wide

Pod IP

是Docker Engine根据网桥的IP地址段分配的(通常为虚拟的二层网络)

kubectl get pods [-n admin] # 获取所有(admin空间下)的pod
kubectl describe pod [-n admin] {pod-name} # 获取pod的详情,IP字段即为分配的IP地址

# 或直接查询
kubectl get pod [-n admin] -o wide

Service Cluster IP

Service是Kubernetes最核心的概念,通过创建Service,可以为一组具有相同功能的容器用用提供一个统一的入口地址,并且将请求进行负载分发到后端的各个容器应用上。

kubectl get svc [-n admin]  # 查询cluster IP

Service的Cluster IP(集群IP,是一个虚拟的IP):

  • 仅仅作用于kubernetes Service这个对象,并由Kubernetes管理和分配IP地址;
  • 无法被ping;
  • 只能结合Service Port组成一个具体的通信端口,单独的Cluster IP不具备TCP/IP通信的基础;

External IP

xternal IP是为了解决如何从外部访问service服务的,外部访问Service的方式有两种:

  • 通过设置nodePort映射到物理机,同时设置Service的类型为NodePort;
  • 通过设置LoadBalancer映射到云服务上提供的LoadBalancer地址(仅适用公用云)。

Pod

Kubernetes使用Pod来管理容器。每个Pod都有个一个特殊的Pause容器(称为‘根容器’),其对应的镜像属于Kubernetes平台一部分;除此之外,Pod还包含一个或多个用户业务容器。

  • Pod是调度(以及复制管理)的基本单位,让多个应用进程一起有效地调度和伸缩。
  • Pod中容器,共享PID、IPC、Network 和UTS namespace。

K8S对长时间运行容器的要求是:其主程序要一直在前台运行

Pod定义

定义包含一个容器的Pod:

apiVersion: v1
kind: Pod
metadata: # 定义Pod元数据
  nam: nginx-test
  labels:
    app: nginx-test
spec: # 容器详细定义
  containers:
  - name: nginx-test
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80

containers是Pod中的容器列表:

spec:
  containers:  #容器列表
  - name: string  #容器名称
    image: string  #所用镜像
    imagePullPolicy: [Always|Never|IfNotPresent]  #镜像拉取策略
    command: [string]  #容器的启动命令列表
    args: [string]  #启动命令参数列表
    workingDir: string  #工作目录
    volumeMounts:  #挂载在容器内部的存储卷配置
    - name: string  #共享存储卷名称
      mountPath: string  #存储卷绝对路径
      readOnly: boolean  #是否只读
    ports:  #容器需要暴露的端口号列表
    - name: string  #端口名称
      containerPort: int  #容器监听端口
      hostPort: int  #映射宿主机端口
      protocol: string  #端口协议
    env:  #环境变量
    - name: string
      value: string
    - name: INJECT_POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: INJECT_SERVICE_ACCOUNT
      valueFrom:
        fieldRef:
          fieldPath: spec.serviceAccountName
    resources:  #资源限制
      limits:
        cpu: string  #单位是core
        memory: string  #单位是MiB、GiB
    livenessProbe:  #探针,对Pod各容器健康检查的设置,如几次无回应,则会自动重启
      exec:
        command: [string]
      httpGet:
        path: string
        port: number
        host: string
        scheme: string
        httpHeaders:
        - name: string
          value: string
      tcpSocket:
        port: number
      initialDelaySeconds: 0  #启动后多久进行检测
      timeoutSeconds: 0  #超时时间
      periodSeconds: 0  #间隔时间
      successThreshold: 0  #
      failureThreshold: 0
    securityContext: #权限设置
      privileged: false  #是否允许创建特权模式的Pod
  volumes:
  - name: podinfo
    downwardAPI:
      items:
      - path: "labels"
        fieldRef:
          fieldPath: metadata.labels
      - path: "annotations"
        fieldRef:
          fieldPath: metadata.annotations

环境变量注入

  • 通过valueFrom,可把Pod或container信息注入到容器运行环境,方便获取;
  • 通过downwardAPI,可把Pod或container信息挂载为文件(如上,会挂载后会在目录下生成labels和annotations两个文件);

Pod生命周期与重启策略

系统为Pod定义了各种生命周期状态:

状态值说明
PendingPod已创建,但Pod内的容器(一个或多个)镜像还没创建(包括在下载过程中)
RunningPod内的所有容器以创建,且至少一个容器处于运行状态、启动状态或正在重启
SucceededPod内所有容器均成功执行后退出(且不会再重启)
FailedPod内所有容器均已退出(且至少一个退出状态为失败)
Unknown由于某些原因无法获取该Pod的状态(如网络通讯问题等)

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,包括:

  • 重启间隔为sync-frequency*2n(n为1、2、4、8…,最长为5分钟);成功重启10分钟后重置改间隔。
策略说明
Always容器失效时,kubelet自动重启改容器
OnFailure容器终止且退出码不为0时,重启
Never不会重启

NodeSelector(定向调度)

K8S的Scheduler服务负责Pod的调度(通常无法知道Pod最终会被调度到哪个节点上,但实际可通过标签来指定调度到的Node):

  • 给Node打标签:kubectl label nodes {node-name} {lbl-key}={lal-value}
  • 在Pod定义中添加nodeSelector设置:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-deploy
  labels:
    app: redis-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis-app
  template:
    metadata:
      labels:
        app: redis-app
    spec:
      containers:
      - name: redis-pod
        image: kubeguide/redis-master
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: 6379
      # 选择有SSD硬盘的Node
      nodeSelector:
        disk-type: ssd

指定选择标签后,若未找到指定标签的Node,即使有其他空余Node,也无法正常调度。K8S还给Node预定义了一些标签:

  • kubernetes.io/hostname
  • kubernetes.io/os
  • kubernetes.io/arch

NodeAffinity(亲和性调度)

NodeAffinity为亲和性调度策略(用于替换NodeSelector):

  • RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定规则(与NodeSelector类似,为硬限制);
  • PreferredDuringSchedulingIgnoreDuringExecution:优先满足,尝试调度指定Node(为软限制);
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
  containers:
  - name: with-node-affinity
    image: google/pause

NodeAffinity语法支持操作符有:In, NotIn, Exists, DoesNotExit, Gt, Lt;有多个matchExpressions时,需满足所有才匹配。

PodAffinity(Pod亲和性)

Affinity标识多个Pod在同一拓扑域中共存;而Anti Affinity标识多个Pod在同一拓扑域中互斥。K8S内置了一下常用拓扑域:

  • topology.kubernetes.io/region
  • topology.kubernetes.io/zone

要求新Pod与security=s1的Pod在同一Zone;但不与app=nginx的Pod在同一个Node;

apiVersion: v1
kind: Pod
metadata:
  name: anti-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - s1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname

  containers:
  - name: anti-affinity
    image: k8s.gcr.io/pause:3.1

ConfigMap

ConfigMap是k8s的一个配置管理组件,可以将配置以key-value的形式传递(通常用来保存不需要加密的配置信息,加密信息则需用到Secret)主要用来应对以下场景:

  • 将配置信息和docker镜像解耦;
  • 多个服务共用配置的情况;

有三种常见创建方式:

  • 通过yaml/json文件创建(推荐): kubectl create -f configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata: 
      name: test-conf
      namespace: test
    data: # 两个键key1、conf
      key1:value1
      conf: |+
        SESSION_LIFETIME: 3600
        URL: "http://test-server:8080"
    
  • 通过–from-file创建:kubectl create configmap {cm-name} --from-file=app.properties (文件名作为key,整个内容作为键)
    key.1 = value-1
    key.2 = value-2
    
  • 通过key-value字符串创建:kubectl create configmap {cm-name} --from-literal=key1=value1 --from-literal=key2=value2

通过create方式创建若已存在,则报错;可通过以下方式更新(不存在时自动创建):

kubectl create configmap nginx-config --from-file first.yaml --from-file second.yaml -o yaml --dry-run=client | kubectl apply -f -

用户配置文件:

  • 将配置文件内容保存到ConfigMap中:key为文件名,value为文件内容;
  • 在Pod配置文件中,将ConfigMap定义为特殊的Volume进行挂载。当Pod创建时,ConfigMap中配置文件会自动还原到Node本地目录,并映射到Pod里;
  • 当ConfigMap内容修改后,K8s会自动重新获取,并更新节点上对应的文件。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。