kubernetes介绍及在线下环境中的CI/CD实践

625 阅读7分钟

kubernetes介绍

先说说docker

image.png
传统虚拟机方案,属于硬件虚拟化+软件实现。 docker由于没有了虚拟操作系统和虚拟机监视器这两个层次,大幅减少了应用程序运行带来的额外消耗。 docker能够直接运行在宿主机上的原理:

  • namespace:进程隔离
  • cgroups:硬件、网络资源隔离、分配

Union File System(AUFS):减少空间占用 aufs是一种支持联合挂载的文件系统,将不同目录挂载到同一个目录下面,只有最上层是可读可写,下层都是只读层。 Docker 中的一个创新是利用了 AUFS 作为底层文件系统实现,通过这种方式,Docker 实现了一种增量式的镜像结构。

每次对镜像内容的修改,Docker 都会将这些修改铸造成一个镜像层,而一个镜像其实就是由其下层所有的镜像层所组成的。当然,每一个镜像层单独拿出来,与它之下的镜像层都可以组成一个镜像。 另外,由于这种结构,Docker 的镜像实质上是无法被修改的,因为所有对镜像的修改只会产生新的镜像,而不是更新原有的镜像。

kubernetes是什么?

  • Kubernetes 是一个可扩展的,用于容器化应用程序编排,管理的平台。由 Google 于 2014 年基于其大规模生产实践经验而开源出来的。Kubernetes 目前在容器编排领域已经成为事实上的标准,社区也非常活跃。
  • Kubernetes 在国内外都已经得到广泛的应用,无论是Google, Amazon, GitHub 等还是国内的阿里,腾讯,百度,华为,京东或其他中小公司等也都已全力推进 Kubernetes 在生产中的使用。
  • 现在无论是运维,后端,DBA,亦或者是前端,机器学习工程师等都需要在工作中或多或少的用到 Docker, 而在生产中大量使用的话 Kubernetes 也将会成为趋势,所以了解或掌握 Kubernetes 也成为了工程师必不可少的技能之一。

为什么需要 kubernetes?

管理大量的容器带来了新的挑战: 故障迁移?资源调度?环境隔离?权限控制?资源限制?负载均衡? k8s的优势:

  • 简化应用部署
  • 提高硬件资源利用率
  • 健康检查和自修复
  • 自动扩容缩容
  • 服务发现和负载均衡

kubernetes的集群架构

  • 主节点,承载 k8s 的控制和管理整个集群系统的控制
  • 工作节点,运行用户实际的应用
                               +-------------+                              
                               |             |                              
                               |             |               +---------------+
                               |             |       +-----> |     Node 1    |
                               | Kubernetes  |       |       +---------------+
+-----------------+            |   Server    |       |                      
|       CLI       |            |             |       |       +---------------+
|    (Kubectl)    |----------->| ( Master )  |<------+-----> |     Node 2    |
|                 |            |             |       |       +---------------+
+-----------------+            |             |       |       
                               |             |       |       +---------------+
                               |             |       +-----> |     Node 3    |
                               |             |               +---------------+
                               +-------------+               

pod-k8s调度的最小单元

一个pod包含一组容器,一个pod不会跨越多个工作节点。

image.png
了解pod

  • pod 相当与逻辑主机,每个 pod 都有自己的 IP 地址
  • pod 内的容器共享相同的 IP 和端口空间
  • 默认情况下,每个容器的文件系统与其他容器完全隔离

kubernetes在线下环境的CI/CD实践

背景

传统的线下环境,由运维手动创建。方式为在物理机上创建虚拟机,通过Jenkins持续集成。使用过程中总结出问题如下:

  • 部署困难:涉及到的第三方服务多,出问题难以解决。部署过程中存在大量重复性工作及需要手动配置的部分(如分配端口号),增加了出错的风险。
  • 资源占用大:各环境项目无法复用。
  • 伸缩困难:采用虚拟机的方式无法动态调节内存占用。

设计思路

  • 通过预定义脚本的方式,尽量减少构建项目需要的配置项,减少学习成本。
  • 通过容器编排,实现资源的动态申请释放。提供一键复制环境的功能。规避手动操作带来的风险。
  • 通过与公司的DNS打通,实现通过域名前缀访问不同环境。

系统设计

系统简要说明

  • 系统内部包含有多套互相隔离的环境,每套环境需要配置环境id(如:beike-test),同时支持配置中文别名(中文别名显示在Jenkins系统环境目录的“名称”字段处),便于用户了解环境用途。
  • 每个环境拥有自己独立的域名前缀(如:test1.contract.alibaba-inc.com)。在公司内部网络访问该域名时可以解析到对应的环境中,切换环境无需配置hosts文件,只需要更改域名即可。
  • 使用Jenkins做为环境及项目的后台系统。用户登录到Jenkins后,可以查看到一些类似于文件夹一样的目录,每个目录对应一个环境,如下图所示:

系统架构基本介绍

系统主要分为以下几部分:

  • Kubernetes集群系统:通过容器编排,将所有物理机整合,动态调节资源。同时使用覆盖网络将网络打通。
  • Jenkins:使用自己实现的Shell覆盖Jenkins构建项目时执行的Bash Shell,完成更为智能的自动化构建。
  • 访问路由系统:通过外部DNS服务以及集群内部的Nginx,实现通过域名前缀访问不同环境。

系统架构图及说明

  • 通过Kubernetes将所有机器整合,各个机器的CPU、内存等资源整合成一个共享的资源池,均衡负载。
  • 部署Weave容器构建虚拟网桥,使不同节点的容器可以互相访问。
  • 部署Kube-DNS服务代替宿主机公网DNS,实现内部动态DNS解析,避免项目重启导致的IP漂移。
  • 部署Nginx容器通过解析测试域名中的环境id,转发到对应环境中。
  • 除静态文件之外的每个项目均通过Docker容器启动,暴露所需的端口。通过Kubernetes中的网桥访问内部及外部网络,同时向Kube-DNS注册带有环境id的域名,使得Nginx可以转发到该项目。
  • 部署Jenkins Master容器,并在每台宿主机上通过SSH配置Slave节点,使Jenkins可以负载均衡到任意一台主机上执行构建任务。
  • 将Jenkins执行Shell使用的Bash Shell替换为自定义的Shell。
    • 构建项目:脚本通过提取项目配置,构建项目并使用容器部署,动态分配内部网段的IP,并通过环境id拼接域名注册到Kube-DNS。同时构建前检查集群剩余资源是否充足。
    • 删除项目:通过环境id,查找到对应环境的对应项目,停止项目并释放资源,删除静态文件等。
  • 搭建NFS网络文件系统,将Nginx Conf、Jenkins Shell、Jenkins Slave等目录及文件统一挂载。
  • 配置Kubernetes定时任务脚本,定时清理异常项目。
  • 在外部DNS服务上配置规则,将带有环境id的域名解析到Kubernetes集群。
  • 将项目日志输出统一映射到Jenkins对应项目的工作空间下,使用者可以直接在Jenkins中查看日志。提供一台机器用于命令行查看日志。

系统流程

添加项目

流程图如下:

k8s yaml文件:

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: PROJECT_NAME
  labels:
    usercreate: "true"
    app: PROJECT_NAME
    project: PROJECT
    group: GROUP_ID
spec:
  selector:
    matchLabels:
      usercreate: "true"
      app: PROJECT_NAME
      project: PROJECT
      group: GROUP_ID
  replicas: 1
  template:
    metadata:
      labels:
        usercreate: "true"
        app: PROJECT_NAME
        project: PROJECT
        group: GROUP_ID
    spec:
      containers:
      - name: java
        image: openjdk:8-jre
        resources:
          requests:
            memory: 1024Mi
        env:
        - name: transformers_local_id
          value: GROUP_ID
        workingDir: /usr/target
        command: ["/bin/bash"]
        args: ["-c","./bin/start.sh"]
        ports:
        - containerPort: 80
        - containerPort: 20880
        volumeMounts:
        - name: target
          mountPath: /usr/target
        - name: logback
          mountPath: /data/var/log/application
        - name: apollo
          mountPath: /opt/settings
      volumes:
      - name: target
        hostPath:
          path: TARGET_PATH
      - name: logback
        hostPath:
          path: LOGBACK_PATH
      - name: apollo
        hostPath:
          path: APOLLO_PATH
---

访问环境

环境转发还可以使用cookie与header的方式,例如:
image.png
用户在访问对应环境时,通过在测试域名中添加环境id名作为前缀,外部DNS将开发域名解析到Kubernetes集群。集群内部的Nginx容器解析环境id,通过内部DNS转发到对应环境的项目中。

查看日志

  • 在Jenkins中查看
  • 通过SSH到宿主机查看

由于使用了NFS或分布式文件系统,并且将日志挂载到宿主机,因此可以到宿主机查看日志

  • 进入容器查看

参考链接