扫码阅读
手机扫码阅读

DevOps 在 Odoo 开发上的实践

469 2024-03-14

本期作者

漆锐

TiDB 数据库工程师

熟悉 DevOps

Odoo 开发的「困境」

正如很多刚起步的项目,我们团队早期在整个 Odoo 项目的开发过程中,同样陷入了很大的困境,那 可谓是相当的难受

首先,我们团队负责 dboms 模块的开发任务,团队中每位开发人员都会负责自己的业务相关的代码。

由于每天可能有多次修改,测试人员是需要同步测试每个人的代码提交,实时反应 bug,这个时候问题就来了。

每个人每天都会有多次提交,那么在测试环境,就需要一个人去做发布,每有一个提交,群里@一下发布人员,发布一下,然后发布完成后再@一下测试。

这样就会带来 人员上以及时间上的浪费,开发、测试、运维沟通多效率低,团队间工作起来非常不舒服。

为了摆脱这一困境,我们 Odoo 团队 决定引入DevOps 开发模式,来提升团队开发效率,避免人员的浪费,把大量重复的事情交由给机器去完成,赋能团队。


为了摆脱开发浪费的困境,
我们寻求 DevOps 的帮助,
那么 DevOps 又是什么呢?

DevOps 提供「出口」

DevOps(Development和Operations的组合词)是 一种重视开发人员(dev)和运维人员(ops)之间沟通合作的一种开发模式。

通过自动化“软件交付”和“构建变更”的流程,来使得构建、测试、发布软件能够更加快捷、频繁、可靠。

可以将 DevOps 看成是软件开发生命周期(SDLC)由瀑布式到敏捷再到精益的发展之后的产物。

伴随着越来越多的公司开始选用 DevOps 作为一个项目的开发模式,DevOps 也成为了时下最为流行、高效率的方式去交付软件。

那么对于全球最为强大的开源 ERP 系统 Odoo 的模块开发来说,引入 DevOps 也是十分有必要的。


DevOps 如此流行,
如此高效,
那么DevOps
又是如何帮助我们摆脱开发困境的呢?

工具介绍

1. 代码托管——Gitlab

Gitlab 是一个基于 Git 的 代码托管和研发协作的开源平台

在 Gitlab 上集成了大量用于软件开发和部署以及项目管理的必要工具。

Gitlab的部署配置相对容易,简单,可以在Kubernetes 上快速完成其部署和启动。

2. CI工具——Jenkins

CI (continuous integration) ,即持续集成,是一种软件开发实践。

持续集成是 DevOps 过程中 最为重要的一环,因为一个项目团队中的每一个成员,通常每天至少集成一次,也就意味着每天将可能有多次集成的动作。

在每次集成的过程中,需要完成的步骤至少包括编译、发布、测试这三个步骤。

这些 步骤都得是自动化执行的,这样,才能够节省大量人力成本。

通过 Jenkins , 实现持续集成,

我们可以获得以下好处:

持续集成可以解决自动化执行购机、测试、部署等重复性的工作,工具集成的效率明显高于人工操作。

持续集成可以更早的获取代码变更的信息,从而更早的进入测试阶段,更早的发现问题,这样解决问题的成本就会显著下降。

持续集成缩短了从开发、集成、测试、部署各个环节的时间,从而也就缩短了中间出现的等待时间。

3. 容器化——Docker & Kubernetes

「优越的容器化」

容器化,相较于传统的 虚拟机部署有着太多的优势, 效率、轻量、复用性、可移植性、隔离性等等,都是虚拟机部署相较于容器化部署的劣势。

「DevOps 核心之一:容器化」

容器技术,凭借其种种优势,在整个 DevOps体系中,具备在很重要的地位。

对于 DevOps 过程来说,通过容器化技术,可以将应用程序以及环境依赖等等打包在一起。

可以 确保在一个环境中开发出来的应用程序可以到另一个环境中工作,也正符合开发人员和测试人员在应用程序上的协同工作。

同时,容器化技术还非常 契合 DevOps 中的 CI/CD 过程

「容器化工具:Docker」

那提到容器化,必绕不开容器化中的巨头docker。

利用docker,我们可以很好的 部署、管理我们的应用程序容器以及镜像。

同时,docker也提供了容器运行时所需要的 环境

当然,docker也存在一定的 缺陷,如实现容器的编排、调度等,都十分困难。

这时候,kubernetes就应运而生。

「容器管理工具:Kubernetes」

kubernetes 就是一个基于容器的集群管理平台。

可以实现对 docker 包括容器,的更高级更灵活的管理,如负载均衡、服务发现、滚动升级等等。

结合 docker 和 kubernetes 可以很方便的实现 DevOps。

4. Kubernetes 容器管理——Rancher

Rancher是一个管理 Kubernetes的平台。

通过 Rancher,可以部署以及管理任何位置的Kubernetes 集群。

同时,Rancher 提供了一个简单直接的用户界面给 DevOps 团队来管理自己的应用程序。

团队成员不需要深入去了解Kubernetes,利用Rancher即可玩转Kubernetes。

同时,Rancher还 提供一套 cli 以及 api,来帮助我们去管理运行在其上的 Kubernetes 集群。

5. 镜像存储——Harbor

Harbor 是一个由VMware公司开源的企业级DockerRegistry项目。

能够帮助公司在内网环境搭建起一个 docker 镜像存储服务。

Harbor 在 DevOps 体系当中, 扮演着类似于数据库的角色。

这里面存储的都是 Jenkins CI 流程之后的产物——应用程序的 docker 镜像。

6. 代码质量检测——SonarQube

SonarQube 是一款静态代码质量分析工具。

支持 JS、Golang、Java、Python 等 25 种以上的语言,能够集成在 IDE、Jenkins 等服务当中。

可以随时 查看代码质量的分析报告,更具报告去修改代码

SonarQube 通过配置的代码分析规则,从可靠性、安全性、可维护性、覆盖率、重复率等方面分析项目,风险等级从 A~E 划分为5个等级。

同时,SonarQube 可以集成pmd、findbugs、checkstyle 等插件来扩展使用其他规则来检验代码质量。

SonarQube 还设置了质量门,通过设置的质量门评定此次提交分析的项目代码是否达到了规定的要求。

7. 代码规范检测——Pylint-odoo

Pylint是一个 Python 的静态代码检测器。

它会分析 Python 代码中的错误,查找不符合代码风格标准和有潜在问题的代码。

除了平常代码分析工具的作用之外,它提供了更多的功能:

如检查一行代码的长度,变量名是否符合命名标准,一个声明过的接口是否被真正实现等等。

还有一个针对Odoo 的项目叫作 Pylint-odoo,是OCA开源的一款odoo代码检测工具

具体地址: GitHub - OCA/pylint-odoo: Odoo plugin for Pylint

在了解完基本的工具后,

接下来就是重要的四步,

包括 Build、Unit test、QA test、Deploy

Step1: Build

首先得做一个 odoo 基础镜像

这个基础镜像里面 包含必要的 postgreSQL 客户端

众所周知,odoo 的数据库管理都是通过执行 psql、pg_dump 等去实现的,所以运行 odoo 的环境,得包含一个 PostgreSQL 的客户端。

再就是这个环境当中需要 包含 Python3,以及一些基础包等等。

基础镜像 Dockerfi le 参考

FROM ubuntu:18.04 SHELL ["/bin/bash", "-xo", "pipefail", "-c"] # Generate locale C.UTF-8 for postgres and general locale dataENV LANG C.utf8 ADD . /app WORKDIR /app COPY ./requirements-base.txt /app RUN sed -i 's#http://deb.debian.org#http://mirrors.aliyun.com#g' /etc/apt/sources.list # Install some deps, lessc and less-plugin-clean-css, and wkhtmltopdfRUN apt-get update && \ apt-get install -y --no-install-recommends \ curl \ dirmngr \ fonts-noto-cjk \ gnupg \ libssl-dev \ node-less \ npm \ libxml2-dev libxslt1-dev libevent-dev \ build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libreadline-dev libffi-dev gcc make wget \ libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \ libtiff5-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev \ liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev libxcb1-dev \ python3 \ python3-dev \ python3-num2words \ python3-pdfminer \ python3-pip \ python3-phonenumbers \ python3-pyldap \ python3-qrcode \ python3-renderpm \ python3-setuptools \ python3-slugify \ python3-vobject \ python3-watchdog \ python3-xlrd \ python3-xlwt \ xz-utils \ # 更新pip && pip3 install --upgrade pip \ # 安装wheel && pip3 install wheel \ && pip3 install -r requirements-base.txt -i https://mirrors.aliyun.com/pypi/simple \ && pip3 install psycopg2-binary \ # 删除安装包 && cd .. \ && rm -rf /Python* \ && find / -name "*.py[co]" -exec rm '{}' ';' \ # 设置系统时区 && rm -rf /etc/localtime \ && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && npm install -g rtlcss \ && curl -o wkhtmltox.deb -sSL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.buster_amd64.deb \ && echo 'ea8277df4297afc507c61122f3c349af142f31e5 wkhtmltox.deb' | sha1sum -c - \ && apt-get install -y --no-install-recommends ./wkhtmltox.deb \ && rm -rf /var/lib/apt/lists/* wkhtmltox.deb # install latest postgresql-clientRUN echo 'deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main' > /etc/apt/sources.list.d/pgdg.list \ && GNUPGHOME="$(mktemp -d)" \ && export GNUPGHOME \ && repokey='B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8' \ && gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "${repokey}" \ && gpg --batch --armor --export "${repokey}" > /etc/apt/trusted.gpg.d/pgdg.gpg.asc \ && gpgconf --kill all \ && rm -rf "$GNUPGHOME" \ && apt-get update  \ && apt-get install --no-install-recommends -y postgresql-client \ && rm -f /etc/apt/sources.list.d/pgdg.list \ && rm -rf /var/lib/apt/lists/*

有了基础镜像之后,就可以在基础镜像的基础上去构建项目镜像了,最简单粗暴的方法就是将代码一股脑的全部拷贝进镜像,将端口暴露,最后直接执行 odoo-bin 就OK了。

项目镜像 Dockerfile 参考

# set the base imageFROM harbor.dev.com/odoo/base:latest ADD . /app WORKDIR /app RUN pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple # Expose Odoo servicesEXPOSE 8069 8071 8072 # Set the default config fileENV ODOO_RC /app/odoo.conf CMD ["python3","/app/odoo-bin","--config=/app/odoo.conf"]

Jenkins build 过程展示

Step2: Unit Test

Odoo 的单元测试方式有很多种,这里我们先单只考虑 Python 的单元测试,使用 Python 去编写。

关于怎么去编写 Odoo 模块的单元测试这里不做过多介绍,具体的内容可以参考官方文档:

https://www.odoo.com/documentation/14.0/developer/howtos/rdtraining/E_unittest.html

Jenkins中的运行方式

stage 'Unit Test'gitlabCommitStatus('UnitTest'){ echo 'UnitTest' container('odoo-base'){ sh './odoo-bin -c ./odoo.conf --test-enable --log-level=info --stop-after-init -u test-model -d odoo-dev' } }

--test-enable 选项通知 Odoo 运行测试

--stop-after-init 标记在测试运行后停止实例

-u 更新指定模块

-d 指定数据库

Odoo 返回的状态为测试错误的次数,所以只有不是0,就表明测试失败,服务器日志中可以获取更多信息。

这种测试的方式最大的缺点是 即使我们知道大部分代码都正常,但还是要测试整个模块,而且还要去更新整个模块。

有一种简洁些的方式是 可指定测试的内容(如 test_library.py)

这样公会运行指定文件中所定义的测试,它不会更新模块,所以如果修改了字段或数据文件而没更新的话就不会生效。

Jenkins 运行单元测试结果

Step3: QA Test

对于代码的质量检查,无论在何种情况下,这都是非常有必要的。

这里选择的工具是 SonarQube 以及 Pylint-odoo

对于 SonarQube 来说,其 本身是没有适合于Odoo 语法的语法分析模板

但好在其模板可以配置,所以这一部分需要耗费一定的精力根据自己的需求去修改其语法模板,以达到自己的要求。

pylint-odoo 是一个由 OCA 组织维护的一款开源的基于 pylint 的 odoo 静态代码分析工具。

这一步的流程同样是在 Jenkinsfile 中写好的,具体参考:

stage 'QA Test'gitlabCommitStatus('QA Test'){ echo 'pylint test' sh 'pylint --load-plugins=pylint_odoo -d all -e odoolint ./addons' echo 'QA Tets' def scannerHome = tool 'sonar.dev.com'  withSonarQubeEnv(installationName:'sonar.dev.com',credentialsId:'sonar_admin'){ sh scannerHome + '/bin/sonar-scanner -Dsonar.projectKey=odoo -Dsonar.sources=./dboms-addons' } }

Sonar 测试结果展示

Step4: Deploy

经过Unit Test 和 QA Test之后,就进入到Deploy 阶段。

在这一阶段,会 Build 一个应用程序镜像,并上传至 Harbor,然后利用 Rancher 以及Deploy.yaml 文件去部署应用程序。

Jenkinsfile 参考

stage 'Push Image'gitlabCommitStatus('PushImage'){def IMAGE_NAME = 'harbor.dev.com/odoo/odoo:build-$BUILD_NUMBER'def IMAGE = docker.build(IMAGE_NAME,'.')withDockerRegistry(credentialsId:'token',url:'https://harbor.dev.com/'){ IMAGE.push() sh 'docker rmi ' + IMAGE_NAME }}  stage 'Deploy'gitlabCommitStatus('Deploy'){ withCredentials([string(credentialsId: 'token-rancher', variable: 'token')]) { sh 'rancher login https://rancher.dev.com/ --token $token --skip-verify --context c-wsxm5:p-n8rwf' //根据代码库中的deploy.yaml文件部署镜像 sh 'envsubst < Deploy.yaml | rancher kubectl apply -f -' }}

Deploy.yaml文件参考

# 创建命名空间apiVersion: v1kind: Namespacemetadata: name: odoo  # 项目空间名称 labels: name: odoo  # 标签---# 部署工作负载apiVersion: apps/v1kind: Deploymentmetadata: name: deployment-odoo # 负载名称 namespace: odoo  # 所在namespacespec:  selector:  matchLabels: workloadselector: deployment-odoo  # 选择器 选择标签 replicas: 1  # pod 数量 template: metadata: labels: workloadselector: deployment-odoo  # 标签 spec: containers: - name: odoo  # 容器名称 image: harbor.dev.com/odoo/odoo:build-$BUILD_NUMBER  # 镜像 imagePullPolicy: IfNotPresent ports: - containerPort: 8069  # 端口号 name: app  # 名称 protocol: TCP  # 协议 imagePullSecrets: - name: harbor-sscxx1 dnsPolicy: ClusterFirst  # dRancherNamespace规则---# 创建ServiceapiVersion: v1kind: Servicemetadata: labels: cattle.io/creator: norman name: service-odoo  # service名称 namespace: odoospec: ports: - port: 8069  protocol: TCP targetPort: 8069 selector: workloadselector: deployment-odoo type: ClusterIP---# 创建ingressapiVersion: extensions/v1beta1kind: Ingressmetadata: name: ingress-odoo  # ingress名称 namespace: odoo  # 命名空间spec: rules: - host: odoo.dev.com  #设置访问地址 http: paths: - backend: serviceName: service-odoo  # 服务名称 servicePort: 8069  # 访问端口 pathType: ImplementationSpecific tls: - hosts: - odoo.dev.com secretName: cert

Rancher 界面部署结果

本文主要 给出一种 Odoo 模块开发的 DevOps 解决 方案。

通过这个方案,可以极大的节省 Odoo 开发过程中繁琐的部署、升级步骤所带来的人员以及时间上的消耗。

「我们的实践」

就我们 Odoo 开发团队而言,在引入 DevOps这一套开发模式之后,每一个开发人员在自己的业务开发分支提交代码,都会触发 Jenkins构建流程,完成自动化测试、QA 检测、构建、发布的整个流程,并且将对应的应用程序部署在 Rancher 当中。

测试人员、包括开发人员自己就可以去测试自己分支上的代码,能够更快的定位问题,并且具体到人。

在晚上,还会定时的启动 Jenkins 流程,去自动构建、发布测试分支以及开发分支的代码,到对应的环境。

第二天早上就有各自的测试人员去测试最新的代码,提交 bug,交由对应的开发人员处理。

「优缺点总结」

可以看到,在引入这一套 DevOps 流程之后,团队之间的协作变得更加的高效、快速以及敏捷。

诚然,这个方案还是存在一定的缺陷,存在着改进的地方,时代在进步,技术也在发展,相信未来也会有更好的更适合于 Odoo 开发的DevOps 解决方案。

原文链接: http://mp.weixin.qq.com/s?__biz=Mzg5MzUyOTgwMQ==&mid=2247489237&idx=1&sn=e348dd4f8cd5b25ce95fa9f4136b838b&chksm=c02c2d73f75ba465c74ae36db3a70cb732c87a9f2a085b45924039e7433bef2f5a38c884e2e2#rd