从代码的视角深入浅出理解DevOps

对于DevOps的理解大家众说纷纭,就连维基百科(Wikipedia)都没有给出一个统一的定义。一般的解释都是从字面上来理解,就是把开发(Development)和运维(Operations)整合到一起,来加速产品从启动到上线的过程,并使之自动化。这个是对DevOps的广义解释,而且大多数人都是认可的。但这个解释太宽泛了,几乎包括了IT的所有内容,使之没有太大意义。 而DevOps是近几年才兴起的(2014年才开始流行),它是对某种项目模式的描述,是有着其特定内涵的。任何项目都可以分成开发和运维两个部分,而开发的一整套流程和工具在DevOps之前早就有了,并没有改变。

DevOps真正改变的是运维。因此从运维的角度去理解DevOps,才能抓住它的本质。你可以把它理解为用开发的方式做运维(Operation as Development),这就是对它的狭义的理解。 开发的方式就是写代码,换句话说DevOps就是通过写代码来做运维。运维里一个非常流行的概念叫“Iac(InfrastructureAsCode)” 基础设施即代码,也就是把运行环境的创建用代码的形式来描述出来,通过运行代码来创建环境。它是运维领域的一场革命,开创了现代运维技术,它也是DevOps的基石。但基础设施创建只是运维的一部分,如果我们把这场革命继续延伸到运维的各个领域,让代码覆盖整个运维,那时就是代码即运维(Operation as Code),这才是DevOps的精髓。

那么从一个应用程序项目的角度看,什么是DevOps呢?它就是把应用程序的代码和运维的代码都放到一个源程序库中,并对它进行版本管理,这样你就拥有了关于这个项目的所有信息,随时可以部署这个程序(包括程序本身和它的运行环境),而且可以保证每次创建出来的程序的运行结果是一样的(因为它的运行环境也是一样的)。

运维即代码(Operation as Code):

下面我们就把运维所做的事情一件一件拆分开,看看他们是怎么用代码来实现的。

运维的工作通常包括下面几个方面:

  • 基础设施:即程序运行环境的创建和维护。
  • 持续部署:部署应用程序,并使整个过程自动化。
  • 服务的健壮性:是指当服务的的运行环境出现了问题,例如网络故障或服务过载或某些微服务宕机的情况下,程序仍能够提供部分或大部分服务。
  • 运行监测:它既包含对程序的监测也包含对运行环境的监测。

基础设施即代码 (Infrastructure as code)

我们通过一个Go(别的语言也大同小异)微服务程序做例子来展示如何用代码来创建基础设施。程序本身的功能非常简单,只是用SQL语句访问数据库中的数据,并写入日志。你可以简单地把它分成两层,后端数据访问层和数据库层。程序的部署环境是基于k8s的容器环境。在k8s中它被分成两个服务。一个是后端程序服务,另一个是数据库(用MySQL)服务。后端程序要调用数据库服务,然后会把一些数据写入日志。

在这种新的模式下,运行环境的代码和应用程序的代码是存在一个源码库中的,这样当你下载了源码库之后,你不但拥有了程序的所有源码,而且也拥有了运行环境的源码。这样当要创建新的运行环境时,只要运行一遍代码就能创建出整套的运行环境,而且每次创建出来的环境都是一致的。

上面就是这个Go程序的目录结构,它里面有一个目录“script”是专门存放与运行环境相关的文件的,里面的“kuburnetes”子目录就是整个运行环境的代码。除了“script”之外的其它目录存有应用程序的代码。这样,与这个应用程序有关的信息都以代码的方式保存在了一个源代码库。有了它之后,你可以随时部署出一个相同的程序的运行环境,而且保证是一模一样的。

“kubernetes”目录下有两个子目录“backend”和“database”分别存放后端程序和数据库的配置文件。它们内部的结构是类似的,都有三个“yaml”文件:

  • backend-deployment.yaml:部署配置文件,
  • backend-service.yaml:服务配置文件
  • backend-volume.yaml:持久卷配置文件.

另外还有一个“.sh”文件是它的运行命令,当你运行这个shell文件时,它就调用上面三个k8s配置文件来创建运行环境。

kubernetes目录的外层有两个“yaml”文件“k8sdemo-config.yaml”和"k8sdemo-secret.yaml",它们是用来创建k8s运行环境参数的,因为它们是被不同服务共享的,因此放在外层。另外还有一个"k8sdemo.sh"文件是k8s命令文件,用来创建k8s对象。

这种源程序结构的一个好处就是使应用程序和它的运行环境能够更好地集成。举个例子,当你要修改服务的端口时,以前,你需要在运行环境和源码里分别修改,但它是分别由开发和运维完成的,这很容易造成修改的不同步。当你把它们放在同一个源码库中,只需要修改一个地方,这样就保证了应用程序和运行环境的一致性。

下面就是后端服务的k8s配置代码:

apiVersion: v1
kind: Service
metadata:
  name: k8sdemo-backend-service
  labels:
    app: k8sdemo-backend
spec:
  type: NodePort
  selector:
    app: k8sdemo-backend
  ports:
    - protocol : TCP
      nodePort: 32080
      port: 80
      targetPort: 8080

相关文章