K8s 小结


K8S

官方文档:https://kubernetes.io/zh-cn/docs

对 K8S 的理解

Kubernetes(K8S)是一个开源容器编排系统,它可以帮助用户快速部署、管理和扩展应用程序。K8S有助于将多个容器打包成一个应用,它为容器提供自动化运维、故障恢复、负载均衡、存储集成和许多其他功能。

K8S的常见使用场景有:

  • 容器编排:K8S可以自动部署和扩缩容多个容器集群,使用者可以控制容器的部署和管理,非常适用于开发和运行分布式应用。
  • 扩展应用:K8S可以帮助用户快速扩展应用,它可以自动添加新的容器来响应用户的需求,可以快速响应扩展应用的需求。
  • 故障恢复:K8S可以帮助用户快速恢复容器,当某个容器出现故障时,K8S可以自动重启容器使之恢复正常。
  • 网络管理:K8S可以帮助用户快速管理网络,它可以自动配置网络,确保容器之间的网络通信正常。

一些介绍一些开发需要了解的常见 K8S 技术。

容器编排

Deployment

K8S Deployment 可以帮助用户实现自动化的部署,更新和管理应用程序,从而提高部署的效率和可靠性。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Deployment 是常见的工作负载,Deployment 资源文件可以指定容器具体的镜像以及它的启动命令,通过 replicas 字段可以指定运行的 pod 数目,Deployment 会自动调度 pod 运行,我们可以很方便的扩缩容 pod 资源,并且 k8s 会自动重启出错的 pod,实现全自动化的运维。

Statefulset

Statefulset 可以看作特殊的 Deployment,由 Deployment 创建的 pod 是无状态的,其名称、网络都是随机的,而 Statefulset 则带有状态。

K8S StatefulSet 和 Deployment 的区别主要有以下几点:

  1. StatefulSet 是一种特殊的 Deployment,它提供了有状态的 Pod 管理,而 Deployment 只支持无状态的 Pod 管理。
  2. StatefulSet 会为每个 Pod 分配一个唯一的标识符(0~N),而 Deployment 不会。
  3. StatefulSet 会保证多副本的 Pod 的按照标识符的顺序启动和停止,而 Deployment 不会。
  4. StatefulSet 支持持久化存储,相同的 Pod 重新部署后其文件内容(通过 PVC)、网络标识符均不变,而 Deployment 不支持。

Daemonset

K8S 集群可能部署在多个节点上,Daemonset 提供这样一种编排方式,如果一个 Pod 以 Daemonset 模式部署,则其会被部署在每一个节点上。

在我实习的时候就曾用到了 Daemonset,部署一个日志收集服务收集所有节点产生的日志文件,使用 Daemonset 非常合适,使用 subPathExpr 能挂在一个和 pod name 相关联的目录,然后就可以对这个目录进行监听。

Job 与 CronJob

Job 是 K8S 中的一个特殊的资源,Job 是只运行一次的程序,通常可以使用 Job 来完成一些初始化或者收集日志等工作,CronJob 支持定时调度,请注意如果 Job 异常退出,K8S 会持续调度 Job 直到它们正常退出。

持久化

这里只介绍三种常见的卷,在 Pod 中引入卷的方式为:通过 volumes 声明卷,在 volumeMounts 将卷挂载到某个目录下。

emptyDir

emptyDir 是一个临时卷,卷最初是空的,当 Pod 被创建是,卷也被创建,多个 Pod 可以共享卷的内容,这是该卷的主要用途,当 Deployment 或所有 Pod 被移除时,卷会被自动删除。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi

configMap

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。

使用 ConfigMap 的用途是将配置与程序分离开来,以便能随时更新配置数据,例如使用 ConfigMap 保存一段脚本,Job 运行这个脚本,这样我们可以随时更改 ConfigMap 来完成热更新的目的。

例如一个初始化数据库的 Job,初始化 SQL 可能随时更改,这时候就可以使用 ConfigMap,这个例子配置如下:

#configmap:sql-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-initdb-sql-config
  namespace: default
data: # key - val
  initdb.sql: |
     you sql here
#Jod:init-sql.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-init
spec:
 template:
  metadata:
    name: myjob
  spec:
   containers:
   - name: init-sql
     image: monasca/mysql-init
     volumeMounts:
      - name: mysql-initdb
        mountPath: app/config	# 挂载
     command: ["sh","-c","mysql -u root -pxxx -P3306 -h host < app/config/init.sql"]
   volumes:
   - name: mysql-initdb
     configMap:
       name: mysql-initdb-sql-config
       items:
       - key: initdb.sql
         path: init.sql 	# 意思是 configMap 中 key 为 initdb.sql 的 val 被写入到 init.sql 文件中
   restartPolicy: OnFailure

除了作为文件外,ConfigMap 还能作为 ENV 被引入。

hostPath

允许将主机目录挂载到容器内,类似于 docker -v,持久化存储。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # 宿主上目录位置
      path: /data
      # 此字段为可选
      type: DirectoryOnCreate

网络管理

Service

Service 将多个 Pod 看作一组服务,服务可以在集群内外暴露,并提供负载均衡服务。Service 是微服务通信的重要组件,一个简单的 Service 资源如下:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80			# 访问虚拟 IP 端口
      targetPort: 9376  # POD 端口
      nodePort: 8080    # 可选的,访问任意一个节点使用的 IP

Service 通过 selector 绑定 Pod,例如所有 key 为 app,val 为 MyApp 的 Pod 都被绑定在 my-service 之上,这些 Pod 的服务名称均为 my-service。

Service 会为这一组服务分配一个内部的 Cluster IP(虚拟的,只能在内部访问),通过这个 IP:PORT 即可负载均衡到某个 Pod 中

img

Service 支持 NodePort 方式访问服务,这样可以将一个 Service 与 Node 的一个端口绑定,访问 NodeIP:PORT 也可以访问服务。

Service 具体是由 kube-proxy 实现的,这是运行在每一个节点上的网络代理进程,它监听 api-server 的信息,对每一个 Service 创建转发表,并进行负载均衡,默认的方式是轮询。

DNS

DNS 是由 K8S 插件实现的,它抽象了一个服务注册与服务发现功能,安装了这个插件之后,每一个 Service 都会被注册,同一个命名空间内的服务可以通过 Service 的 name 直接访问,例如 http://my-service:80,不同命名空间的服务需要加上命名空间后缀访问。

我实习的公司私有化部署就是使用了 DNS,这样不需要改变公有化中服务注册服务发现的代码逻辑,写一个轻量级的注册中心,根据原来的服务名返回一个 DNS 给服务即可。

Ingress

Ingress 可以看作是 Service 的 Service,Ingress 是一种路由规则,用于将外部 HTTP/HTTPS 请求路由到集群内部的服务。它使用一组规则,根据请求的主机名,路径或其他属性,将请求路由到不同的 Service。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80
  - http: ...

上诉例子中定义了一个 Ingress 资源,任何以 /testpath 为前缀的路径都将会被路由到 my-service 服务中去。Ingress 之间也支持互相转发,可以通过 ingressClassName 来互相引用。

Ingress 只是一系列规则,我们需要额外的实现来进行转发,这就是 Ingress Controller。

ingress-controller 并不是k8s自带的组件,实际上ingress-controller只是一个统称,用户可以选择不同的ingress-controller实现,目前,由k8s维护的ingress-controller只有google云的GCE与ingress-nginx两个,具体可以参考官方文档。但是不管哪一种ingress-controller,实现的机制都大同小异,只是在具体配置上有差异。

一般来说,ingress-controller 的形式都是一个pod,里面跑着daemon程序和反向代理程序。daemon负责不断监控集群的变化,根据 ingress 对象生成配置并应用新配置到反向代理,比如 nginx-ingress 就是动态生成 nginx 配置,动态更新 upstream,并在需要的时候reload 程序应用新配置。


文章作者: Happysnaker
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Happysnaker !
  目录