K8S实战技巧(一)

ronald10个月前职场2250

一. 概述

        K8S是谷歌开源的一个容器编排管理工具,可以帮助业务实现自动化部署、故障发现、容灾、扩缩容、流量管理等,大大提升业务的服务能力;k8s通过yaml描述文件实现容器的部署,本文介绍一些实际应用过程中可能用到一些k8s的特性及配置方法,适用于对k8s有一定了解的读者。

二. 共享进程命名空间

        K8S以POD为基本的调度单位,通常一个POD中运行着互相配合的几个容器;设想这样一个场景:在原先架构中,一个对外服务通常包含以下几个进程:业务进程(主要的业务处理逻辑)、配置代理进程(负责实时和配置中心通信,拉取最新的配置,并通知业务进程读取配置)、网络进程(负责接管业务进程对外通信链接);当部署到K8S之后,就是这样一个业务POD,包含业务进程容器,配置代理进程容器和网络进程容器;这样就有一个问题,即配置代理进程拉取到配置之后,如何通知业务进程读取最新配置呢?一个方案是:发消息通知业务进程;这里介绍另外一个方案,即业务进程注册信号处理函数,代理进程发信号给业务进程,业务进程收到信号之后重载配置。

       那么问题来了,业务进程和配置代理进程运行在不同的容器中,怎么让配置代理进程给业务进程发信号呢?其中一个办法是把两个进程放在一个容器中,这样确实可以解决问题,但是由于二者在一个容器中,以后配置代理进程更新会和业务进程的服务耦合在一起,这也不符合配置代理进程的设计初衷;所幸K8S提供了一种POD中运行的多个容器共享进程中间的机制,配置方式如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      shareProcessNamespace: true
      containers:
      - name: nginx
        image: nginx:1.14.2
       containers:
      - name: config-agent
        image: config-agent:lastest

        由上面yaml配置可知,我们配置了一个nignx-deployment的Pod,里面运行着两个容器,nginx容器,里面运行nginx进程负责对外提供http服务和config-agent容器,里面运行config-agent进程负责和配置中心系统同步最新配置,通过设置.spec.template.spec.shareProcessNamespace为true,使得Pod下多个容器的进程共享进程命名空间。以此可以达到效果:

      1)运行在配置容器中的进程可以看到业务容器的进程,反之亦然,即一个POD中的多个容器内运行的进程在一个进程空间之下

      2)在配置代理容器中,给业务进程容器的业务进程发信号,业务进程容器中的业务进程可以收到

      3)当配置代理容器中的镜像需要更新时,直接原地更新即可,不会对业务进程所在的容器有影响

共享卷

       同样还是上述的场景,由于容器之间文件系统是隔离的,所以默认情况下config-agent容器里面的文件nginx容器里面的进程是看不到的,那么怎么可以让nginx容器里面的进程可以读到config-agent容器里面的文件呢?K8S提供了卷(volume)的机制,解决这种Pod上多个容器共享文件的场景。K8S支持多种共享卷机制,这里介绍HostPath类共享卷的用法:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      shareProcessNamespace: true
      containers:
      - name: nginx
        image: nginx:1.14.2
        volumeMounts:
        - mountPath: /home/walker/nginx/conf
          name: global-config
       containers:
      - name: config-agent
        image: config-agent:lastest
        volumeMounts:
        - mountPath: /home/walker/config
          name: global-config
     volumes:      
     - name: config
       hostPath:  path: /home/walker
       type: DirectoryOrCreate

所谓hostpath是指我们在Pod所在node上创建一个目录,这个目录作为我们多个容器的指定目录的挂载点,在本例中我们有:

1)在.spec.volumnes下创建了一个挂载目录,名字叫config,路径为node的/home/walker目录下,类型为hostpath,表示是主机的路径,type为DirectoryOrCreate,表示若是目录不存在的化,会自动创建一个新的目录;

2)nginx容器的配置.spec.containers.volumeMounts表示nginx容器里面的目录/home/walker/nginx/conf,会挂载到node节点的路径下/home/walker下,此后任何主机上/home/walker目录下的修改都会被nginx容器里面的进程通过/home/walker/nginx/conf读取到,反之任何nginx容器内/home/walker/nginx/conf目录的修改,都会被同样挂载到这个目录的进程所感知到。

3)需要注意的是,一旦设置了挂载点,如本例nginx的/home/walker/nginx/conf挂载到node的/home/walker路径下,在容器启动之初,容器的/home/walker/nginx/conf会被清空,即若是在打镜像的时候,这个路径下有其他文件因为设置共享卷的缘故,原镜像打进去的东西会被清空掉。

Chart部署

       上述主要介绍了生产环境下Pod内多个容器如何共享文件和进程命名空间,但是一般情况下,我们技术人员在发布之前会有一个私有的测试环境进行验证,按照上述方式进行部署私有测试环境的话,会有一个问题就是挂载路径相同,导致不同人的私有测试环境互相覆盖;这种不仅限于挂载点,还有端口、环境变量等一些列的差异化;当然,我们可以每个研发人员将yaml文件拉取下来,各自修改,但是这种方式麻烦且容易出错。因此我们希望有一种机制,即建立一个yaml文件模板将需要定制化的参数变量化,在实际部署的时候,根据我们提供的变量将这个模板渲染成我们需要的yaml文件——Helm和Chart帮助我们实现了这一个目标。

helm是K8S的包管理工具,而Chart,是Helm的应用打包格式,由一系列文件组成,这些文件描述了K8S部署应用所需的资源,chart的目录结构及对应文件作用如下:

nginx/
  Chart.yaml          # 包含当前 chart 信息的 YAML 文件
  LICENSE             # 可选:包含 chart 的 license 的文本文件
  README.md           # 可选:一个可读性高的 README 文件
  values.yaml         # 当前 chart 的默认配置 values
  values.schema.json  # 可选: 一个作用在 values.yaml 文件上的 JSON 模式
  charts/             # 包含该 chart 依赖的所有 chart 的目录
  crds/               # Custom Resource Definitions
  templates/          # 模板目录,与 values 结合使用时,将渲染生成 Kubernetes 资源清单文件
  templates/NOTES.txt # 可选: 包含简短使用使用的文本文件


相关文章

Lua热更新机制(上)

Lua热更新机制一个Lua热更新demo    Lua在游戏开发中能广泛使用不仅由于其轻量易嵌入的特性,还有一个重要的点是易于热更新,设想在产品线上运营过程中,出现bug需要修复,频繁停机对于产品体验影响大,也影响口碑;所以实际运营我们是希望能尽量避免停止服务进行代码更新的操作,下面先从一段比较简单的代码看Lua的热更新机制:require &qu...

Lua的垃圾回收(下)

Lua 5.3版本的垃圾回收Lua垃圾回收源码实现    结合前面描述的垃圾回收的流程,我们参照源码进行逐个的拆解和介绍。    lua的垃圾回收主要都是在接口luaC_step里面完成的,这里面本质上是控制了一个状态机,根据global_State->gcstate进行渐进式的垃圾回收处理。GCSpause&n...

Lua和C

Lua和C

一.背景    在实际游戏业务运营过程中,经常会出现一些紧急的配置修改、bug修复等;这种规划外的变更行为希望能做到用户无感知,否则对于游戏体验和产品口碑有很大影响,在此背景下,热更新能力成为成熟上线游戏的标准配置。    一般情况下,后台逻辑热更新能力的技术方案有两种:    ...

关于LUA(上)

    Lua是一种轻量小巧的脚本语言,C语言编写,并提供了易于使用的扩展接口和机制,易于嵌入到应用中,在游戏开发中经常被用来进行外层业务系统的开发。Lua的table    Lua的基本数据类型有八种,分别是:nil、boolean、number、string、userdata、function、thread 和 t...

Lua的垃圾回收(上)

Lua 5.3版本的垃圾回收垃圾回收算法    垃圾回收算法一般分为两类:引用计数法和标记扫描法。引用计数法    所谓引用计数法,是指在为对象申请内存的时候,在分配的内存块预留一块区域用于存放这块内存被引用的次数,当被引用的时候增一,解引用的时候减一,当这块内存的引用次数降到0的时候,这块内存被认为不可访问,直接被回...

关于LUA(下)

关于LUA(下)

Lua与OOP    Lua是面向过程的语言,不提供面向对象的特性,但是我们可以利用Lua的元表和元方法模拟面向对象的效果。OOP的特性封装    所谓封装,是隐藏对象的属性和细节,仅对外暴露公共的访问方式。本质上分为两层:    1)成员变量和成员方法,提升代码的内聚性,降低模...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。