课程介绍

OpenStack 是当下炽手可热的 IaaS 开源云计算项目,使用 OpenStack 可满足企业各种云服务需求,如私有云、混合云或公有云。通过本系列教程的学习,即使是一个初入云计算的行业者也能迅速熟悉和掌握 OpenStack 的相关技术,提高职业竞争力,成为一名复合型人才。

本系列教程,分为四部分,共计15篇文章。读者可以从中汲取到完整的项目经验,从菜鸟到精通,这个达人课帮您实现。

第一部分(1-4篇):主要讲解初学者如何参与 OpenStack 社区,进行有效的沟通交流,以及如何提交 Bug 和 Patch,快速提升个人参与开源社区的能力。

第二部分(5篇):主要讲解当下主流的 OpenStack 生产环境级的部署实施。

第三部分(6-14篇):主要讲解 OpenStack 全方位,不同维度和层次的测试体系。涵盖了性能测试、存储测试、功能测试、单元测试以及Dashboard 自动化测试和开发自动化测试框架等内容。

第四部分(15篇):主要讲解如何使用 Harbor 镜像仓库管理 OpenStack Docker 镜像等。

作者介绍

徐超,某互联网公司任云计算工程师。技术出身,三年多 OpenStack 运维开发经验,熟悉 Kubernetes、Docker、Ceph 存储和 CI/CD。2017年初,出版《OpenStack 最佳实践——测试与 CI/CD》一书。

课程内容

导读:浅谈 CI/CD 和软件测试

知其然,知其所以然。相较于DevOps而言,CI/CD是一个相对具象的概念。在 IT 企业中,CI/CD的应用愈加广泛,成为推动软件研发活动的重要基础设施服务,同时推动 DevOps 模式的实际落地。

什么是 CI/CD

在实践 CI/CD 相关内容之前,我们有必要先认识下什么是 CI/CD。

一般传统或者狭义、普遍的 CI/CD,是指持续集成(Continuous Integration,CI)和持续交付(Continuous Delivery,CD)。而更加广义、全面的理解,是指持续集成(Continuous Integration,CI)、持续测试(Continuous Testing,CT)、持续交付(Continuous Delivery,CD)和持续部署(Continuous Deployment,CD)四个方面。通常,一个软件开发的流水线如下图所示。

  • Design:这一阶段完成软件开发的需求分析和设计。
  • Develop:这一阶段完成软件开发的功能代码,一个最佳实践是采用测试驱动开发(TDD)的方法,测试代码和功能代码的编写同时进行。需要注意的是,在 Develop 阶段也会运行单元测试和其他小型测试。
  • Test:这一阶段完成软件的各项大型或专项测试,比如界面测试、API 测试、性能测试和系统测试等。
  • Release:这一阶段完成软件产品的发布,并交付给用户使用。

持续集成(Continuous Integration)

随着敏捷开发的发展,持续集成在软件项目活动中也日益成为主流。顾名思义,持续集成是指每日频繁地(比如一天多次)将代码集成到主干分支中。强调通过集成和测试的速度,快速给出一个集成的结果(是失败还是成功),在代码集成之前,必须先通过自动化测试验证,只要有一个测试用例失败,就不能集成。

Martin Fowler 说过,“持续集成并不能消除Bug,而是让它们非常容易被发现和改正”。这也正是持续集成的真谛所在。

敏捷开发的核心是指整个软件开发活动被划分成一系列短的迭代过程,每个迭代完成一定数量的功能,迭代周期应该尽量短。在软件开发需求已经确定的情况下,迭代应该由测试驱动开发(TDD)和集成反馈来驱动。只有这样,才能为质量持续改进奠定一个良好的基础。

持续集成是和单元测试结合在一起的,也就意味着,持续集成和单元测试需要并行工作。持续集成一般由代码每次 git push/review 触发。先签入代码就先看到构建结果,后签入,则要排在后面。这就要求构建时间不能太长,否则在构建时容易引起混乱,很难知道是谁的代码破坏了集成,导致很难定位问题。

可以说,持续集成是敏捷开发的重要基础环节,没有持续集成,所谓的敏捷开发便失去了赖以生存的土壤,其实施效果也会大打折扣。持续集成是一种软件开发实践,团队成员频繁集成他们开发的代码,每次集成都会经过自动构建——自动测试的验证,以尽快发现集成错误。使用这种方法可以显著减少集成引起的问题,并加快团队合作开发软件的速度。

(1)持续集成过程

持续集成的工作阶段比较明确,主要有三个大的阶段:持续集成准备阶段、持续集成使用阶段和持续集成测试阶段。

持续集成准备阶段的工作主要包括:

  • 通过代码评审系统(比如 Gerrit),实现代码审查和集成反馈。
  • 通过版本控制系统(比如 Git或 GitLab)建立源码仓库。
  • 通过构建工具运行相关构建和测试(比如 Python 项目的 Tox 和 Pytest)。
  • 通过 CI 系统(比如 Jenkins)建立 Job,将版本控制和构建工具整合,并设置构建触发条件。

持续集成使用阶段的工作主要包括:

  • 开发人员向代码评审系统(比如 Gerrit)提交代码。
  • 通过 CI 系统监听代码的提交,运行单元测试,反馈集成结果。
  • 通过构建工具对代码进行编译、打包和部署。
  • 通过版本控制工具实现版本控制与管理。

持续集成测试阶段的工作主要是,CI 系统根据集成结果进行不同操作,如果成功,则将代码合并到主分支;如果失败,则反馈给开发人员修改重新提交。

从中我们可以看到,持续集成涉及的主要工具类别包括:

  • 版本控制工具——实现源代码管理、版本控制。
  • 构建工具——实现代码的自动化编译、打包等,这是持续集成的核心工具。
  • 测试工具——实现代码的自动化测试,以及大型测试或专项测试。
  • CI 系统——整合版本控制、构建工作和测试工作,实现持续集成。

(2)持续集成的好处

主要有以下几点:

  • 易于定位错误。比如当持续集成失败时,说明新提交的代码引起了错误,这样也很容易知道是谁犯了错误,可以找谁来讨论。
  • 提高团队的开发信心。虽然整个系统还不是那么可用,但至少可以看到功能已经在一点点被集成了。
  • 提高对进度的控制和把握。这点非常明显,如果每天都在集成,当然每天都可以看到哪些功能可以使用,哪些功能还没有实现。如果你是开发人员,则不用为在每日 Scrum 晨会时说自己完成了多少开发而烦恼;而如果你是 Scrum Master,那么也不用再烦恼开发人员说完成了代码的40%到底是个什么概念。
  • 有助于代码开发的质量评估。比如从开发质量的评估图表中,找出经常出错的测试和源码等。
  • 与测试工具结合,做到每次提交都进行测试。
  • 快速发现错误。每完成一点开发,就提交评测、代码审查,可以快速发现错误,及时修复,越尽早解决,成本越低。

持续测试(Continuous Testing)

持续测试作为软件持续集成中的重要组成部分,为软件项目的成功提供了保证软件质量持续改进的重要手段。在持续集成中,更多的是运行小型的单元测试,因此,关于其他测试将在后续章节中阐述。

持续测试是指开发人员提交代码后自动运行相关单元测试,给出测试结果的反馈;如果失败,则会在测试结果的详情页面中输出错误提示。

有了持续测试,我们才能实现真正的测试驱动开发(TDD)。举一个例子,当开发人员向代码评审系统提交了代码后,Jenkins hooks 监听到有代码提交,自动运行单元测试,然后在页面视图上显示测试的结果;如果测试失败,开发人员需要重新修改并再次提交测试,直至成功。

这也需要开发人员在编写功能代码时,同时编写测试代码,这样几乎能够在问题产生之时就将其发现。不经常运行测试通常就不怎么有效,因为从产生缺陷到发现该缺陷相隔时间很长,但持续地(即每一次代码改变时)运行测试能确保快速地发现症结。

持续测试应当输出测试报告,报告是将持续集成的运行情况以适当的形式展现给相关人员的基本方式。报告是持续集成的晴雨表,所以它必须直观、易懂,比如开发人员从错误日志中找到代码出错的位置和原因;QA 测试人员发现测试的覆盖率和执行情况;管理人员从持续集成通过率的趋势中了解到项目的进度和质量。

持续交付(Continuous Delivery)

持续交付和持续部署是两个非常容易混淆的概念。持续交付指的是频繁地将软件的新版本交付给 QA 测试团队或者运营团队,如果评审通过,代码就进入发布、生产阶段。

为了更加符合国内软件行业的实际情况,我在这里将 QA 和测试统称为“QA 测试”。持续交付可以看作是持续集成、持续测试的延续,它强调的是不管怎么更新,软件是随时随地可以交付的。通过严格的自动化测试,可以确保软件开发的质量和进度。因为通过完全的自动化过程把每个变更自动提交到测试环境中,所以当功能开发完成时,就有信心只需要点击一次按钮就能保证发布和部署应用的质量。

(1)选择持续交付工具集

在没有制定出工作流程时,便考虑选择持续交付工具集,是最不重要的决策。实际上,在设计好工作流程和业务流程之后再选择相匹配的工具集即可。考虑到满足实际业务和工作流程的情况,开发一些诸如 Shell、Python 等脚本程序是非常理性的做法。

更重要的是,无论是 CI 还是 CT、CD 等,都可以使用众多的开源工具,这样做没有被锁定的风险,可以自由切换等。

(2)持续交付的角色和方式

产品持续交付的角色应由 QA 测试人员来担任,开发人员也需要参与到产品的某一轮系统测试中,并随时准备 Bug 审查和 Bug 修复。最后,由 QA 测试人员根据具体的产品缺陷、质量情况等做出产品是否适合面向用户交付、发布的决定。

持续交付的目标不是要消灭缺陷,而是要规范开发和测试的流程,从根源上提高软件质量。总之,持续集成、持续测试、持续交付和持续部署的核心就是让不间断的“密集型、高强度、信息及时反馈的持续性改进”成为提高软件产品质量的驱动力。

目前,持续交付的方式一般有:

  • 源代码交付——需要将源代码下载到所需要的环境中,如 Python 的 py、Java 的 java等程序文件。但这些文件都不是标准的软件包,不利于集中管理和运行。
  • Linux 标准包交付——通过 Linux deb 或者 RPM 对项目的依赖进行管理。这种方式相对更加规范和科学,但仍然需要解决包冲突问题。同时,这种方式会经常因服务器环境差异、构建环境初始化失败等问题导致无法部署 Linux 标准包。
  • 虚拟机镜像交付——在虚拟机中安装测试软件产品成功后,直接将该虚拟机镜像(比如VMware 的 vmdk、VirtualBox 的 ova、OpenStack 的 qcow2 等镜像)进行交付、发布。显然,这种方式部署成功率接近100%,而且隔离性好。但存在着虚拟机镜像对服务器资源的消耗,同时容量较大、不够灵活等问题。
  • Docker 镜像交付——这种方式是对虚拟机镜像交付的重大改进,在保证系统隔离的同时,Docker 镜像对服务器的资源消耗更低、更加轻量。这种交付方式将成为主流趋势。

持续部署(Continuous Deployment)

持续部署是持续交付的后续阶段,也是整个CI/CD环节中的最后一环,指的是软件通过测试后自动部署到生产环境中。持续部署的目标是软件在任何时刻都是可部署的,可进入生产阶段,发布给用户使用。持续部署的前提是能够自动化完成集成、测试和交付等。它与持续交付的区别是,持续交付是将软件部署到线上环境中,使用的是手动方式;而持续部署强调的是自动化。换言之,持续部署是持续交付的更高阶段,所有通过了测试验证的软件都自动部署到生产环境中。如果没有制度的约束或其他条件的影响,团队都应该以持续部署为目标,如下图所示。

CI/CD在软件研发测试中的应用

DevOps是一种工程文化、理论集,是一个抽象的概念;而其范畴下的 CI/CD 则是它的具体实现和方法,是一种化抽象为形象的工具集、流程图。如果说 DevOps 是云计算,那么 CI/CD 就是计算、存储和网络,OpenStack 则是其具体实现平台。

软件项目的研发有两大难题:一是确定软件的需求,即确定目标;二是确定当前离目标还有多远,即确定剩余的工作量。后者是项目缺少可见性的问题。前者是持续性反馈的问题。比如来自用户需求的反馈、市场变化的反馈、项目研发测试过程的反馈等。

自动化是软件研发测试中的重要方式。持续集成最大的优点就是降低风险,提高项目研发过程的效率和质量,迎合互联网时代信息快速更新的规律。持续集成本身并不能帮助开发工程师和 QA 工程师解决Bug,而是通过不断的测试和反馈来尽早地发现 Bug,问题发现得越早,处理问题的成本就越小,也越容易解决。由于无法证明通过了某次测试的代码永远无缺陷,因此,持续集成中的测试也就显得非常重要,好的测试能够更多、更快地发现当前版本中的错误。

根据持续集成的作业流,代码从提交到生产环境,整个过程分为以下几步。

提交(Commit)

开发者向代码仓库提交代码。所有后面的步骤都始于本地代码的一次提交。

测试(第1轮)

整个 CI 系统配置了代码仓库系统、Jenkins 系统和代码评审系统的触发器,只要提交代码就会运行自动化测试。一般这里的测试有如下几种。

  • 单元测试:针对函数或模块的测试。
  • 集成测试:针对整个软件的功能测试。
  • 代码风格测试:针对代码的编写风格进行测试,比如 Python 的 PEP 8 等。
  • 其他测试。

构建(Build)

通过第1轮测试后,代码就可以合并进主干分支,推送到私有代码仓库 GitLab 系统中,进行下一阶段的构建了。

从开发人员提交本地代码,到测试通过,代码合并到分支里,提交就算完成了。此时,就需要进行构建进入第2轮测试。所谓构建,指的是将源码转换为可以运行的 Linux 标准软件包,比如安装依赖、生成配置文件等,当然也可以构建成 Docker 镜像。

测试(第2轮或多轮)

构建完成后,就要进行第2轮或多轮测试。总之,构建部署在测试之前。

此阶段的测试最全面,投入资源最多,包括系统测试、功能/集成测试、性能测试等都会运行。需要强调的是,每一个更新点都必须测试到。如果测试的覆盖率不高,进入后面的部署和生产阶段后,很可能会出现严重的问题。

部署

通过多轮测试后,当前代码就是一个可以直接部署的稳定版本。将这个版本的所有文件打包存档(比如 Fuel 的 iso,或其他自研产品的 iso、vmdk 乃至 Docker 镜像等),发布到成品库服务器上。这方面的自动化部署工具有 Ansible、Chef、Puppet 等。

回滚

一旦当前软件版本发生问题,就要回滚到上一次构建的版本,使用上一次构建并发布的版本。

CI/CD 很好地解决了代码从自动化编译打包、自动化构建部署、自动化测试到快速交付产品4个阶段。为此,需要做到:

  • 软件包尽量轻。为了保证代码在编译、打包、构建等阶段做到快速、轻量,应尽可能实现软件的模块化处理。典型的,如将 OpenStack 的各个服务分别放在不同的 Docker 镜像中。
  • 重视管理教育。在公司中,一个团队/部门里的工程师素质是良莠不齐的,不能让少数人影响到一群人、一个整体,仅靠自觉是完全不够的,需要指导团队养成做事的好习惯。一个常见的问题就是开发人员不写单元测试代码,影响到整个软件研发测试的质量和周期。

构建产出物

构建工作主要产出两个东西:待测的软件包和应用系统(有的只有后者)。这两个产出物有所不同,前者是构建过程与环境无关,而且可重复,因此需要提供如 yum、npm、gem 等软件包服务,让构建号和软件包号建立关联,便于回溯。

通过 IaaS 云或 Docker 容器将 CI/CD 环境以微服务的方式运行,做到开箱即用。CI/CD是软件工程的一个重要实践,可以帮助我们更早地发现问题、解决问题,降低成本,同时大大减少交付、发布过程中的不确定性,提高团队的生产效率。当然,CI/CD 与其他工具和方法也紧密相关。

每日构建和每日测试

每日构建(Daily Build)在反应速度上没有持续集成快,它更强调的是通过每天(通常是晚上)自动部署当天开发所累积的代码,并结合每日测试(Daily Test)方法进行自动化测试,用于评估和衡量项目的进度。

持续集成特性决定了不可能在该阶段加入大量的测试,而每日构建则一般是在夜里执行的,那么这时就可以做更多的事情,比如代码质量检查、单元测试、测试覆盖率、集成测试等。每日构建会把当天所有的提交代码都一起做集成,而不像持续集成那样每提交一次代码就做一次集成。持续集成属于增量式构建,而每日构建则是一次完全构建。

每日构建是项目的心跳线。一般而言,通过每日构建我们可以看到项目的进度。比如今天有10个 Bug 的修复代码都提交了,晚上进行自动部署并通过了自动化测试,第二天上班时通过查看邮件我们就可以发现每日构建成功了,那么项目就又往前迈了一大步,开发工作又有了具体的进展。

具体的,每日构建就是在每天晚上自动化部署一个 OpenStack 环境(可以是all-in-one,也可以是 multi-node),然后运行大型或专项测试,比如 API 性能测试、API 接口测试、功能测试、部署测试等。

第01课:如何贡献 OpenStack 社区

OpenStack社区贡献内容包括但不限于:

  • 代码 Review(审查)。
  • 代码 Commit(提交)。
  • 社区文档翻译、编写和修改。
  • 创建 Blueprints。
  • 其他。

注册账号和提交 Bug

在开始贡献之前,我们先来看看 OpenStack 的代码审查的大体流程,如下图所示。

从 OpenStack 本地代码提交到合并的流程主要如下:

  1. 开发人员配置本地 Git 环境。
  2. 开发人员克隆目标项目的代码并进行更改。
  3. 开发人员提交本地代码到远端 Gerrit。
  4. OpenStack 使用 Gerrit 作为代码评审系统,使用 Jenkins 系统对代码进行自动化部署和测试,并反馈测试结果。
  5. 由核心评审人员给出意见,决定是否合并此次提交的代码。

基本步骤如下:

  1. 创建一个 Launchpad 账号(Gerrit 使用 Launchpad 账号进行认证登录)。
  2. 登录 Gerrit,完成其他配置。
  3. 签署贡献者许可协议。
  4. 安装本地 Git 环境。

说明:一般情况下,只有当修复某个代码/文档 Bug 或发现有 Bug 时,才需要在Launchpad 上提交 Bug 信息。

注册 Launchpad 账号

在 https://launchpad.net/ 上注册账号,如下图所示。

提交 Bug

注册成功后,登录 Launchpad,输入想要提交的 Bug 所属的 OpenStack 项目名称。比如这里的 openstack-manual(OpenStack 文档项目),如下图所示。

在图中,可以看到与该项目相关的 Bug、Blueprints 和项目概述信息等内容。点击“Report a bug”,提交一个 Bug,如下图所示。

紧接着,需要简要描述下该 Bug 的一些关键信息,如下图所示。

填写相应的Bug信息,如下图所示。

如果想要修复这个 Bug,可以将它指定给自己,如下图所示。

注意这个 Bug id 号,届时向 OpenStack 社区提交代码时需要。如此,这就是创建 Launchpad账号和提交 Bug 的流程。如果想要修复这个 Bug,那么继续往下操作。

配置账号和提交代码

配置 Gerrit 系统账号

使用在 Launchpad 上注册的账号,登录 https://review.openstack.org,如下图所示。

配置 Gerrit 公钥认证,将 SSH 的 Public Key 粘贴到此处,如下图所示。

签署 ICLA 协议,如下图所示。

在国内网络的背景下,想要向社区代码评审系统提交代码,需要一点小技巧(VPN 用户可以忽略此步骤)。首先需要登录 review.openstack.org,然后在 Settings -> HTTP Password 中生成一个 HTTP 密码,它应该是一个大小写字母加数字的随机字符串。创建一个 HTTP 协议的用户名和密码,如下图所示。

此时,账号已经创建和配置好,下面即可提交修改后的代码了。

提交代码

//clone该Bug所属的项目#git clone https://git.openstack.org/openstack/openstack-manuals //格式为bug/bug id# git checkout -b bug/1575714Switched to a new branch 'bug/1575714'//修改Bug文件# vim doc/contributor-guide/source/api-guides.rst//配置git邮件地址和用户名# git config --global user.email xxxx@xxxx.com# git config --global user.name "xxxx"//添加本地文件# git add .//填写提交信息,格式和内容如下# git commit             Fix OpenStack/api-site git repo urlCloses-Bug: #1575714//添加远程地址# git remote add gerrit\ssh://xxxx@review.openstack.org:29418/openstack/openstack-manuals.git# git remote set-url gerrit\https://http_username:http_password@review.openstack.org/openstack/openstack-manuals.git//提交代码# git reviewYour change was committed before the commit hook was installed.Amending the commit to add a Gerrit change id.remote: Processing changes: new: 1, refs: 1, done    remote: remote: New Changes:remote:   https://review.openstack.org/310508 Fix openstack/api-site git repo urlremote: To https://xxxx:xxxx @review.openstack.org/openstack/openstack-manuals.git * [new branch]      HEAD -> refs/publish/master/bug/1575714

如果需要对之前提交的内容再次进行修改(针对同一个 change-id),则执行如下命令。

# git add .# git commit --amend# git review

查看评审状态

向社区提交代码/文档,需要通过该项目两个 Core(核心开发者)的+2评分,才会被合并到GitHub 代码仓库中,代表此次提交成功。反之,如果有人给出-1、-2的评分或 Jenkins 测试提示失败等,那么你需要针对具体的问题修改提交的内容,然后再次提交,如下图所示。

查看 OpenStack 社区贡献数据

查看 OpenStack 社区贡献数据,可以访问 http://stackalytics.com,输入相应的个人名称、公司名称和 OpenStack 项目名称等进行搜索,如下图所示。

第02课:如何参与 OpenStack 社区交流

要想参与 OpenStack 社区沟通交流,一般最常用的方式是使用 E-mail 和 IRC(Internet Relay Chat,互联网中继聊天,理解为国内的 QQ 即可)。需要注意的是,由于中国时区和北美、欧洲时区存在10个小时以上的差异,使用 IRC 实时聊天工具可能存在沟通障碍问题。下面阐述如何通过这两种方式进行沟通交流。

通过邮件方式交流

  • openstack@lists.openstack.org,该邮件列表 OpenStack 社区通用,一般寻求帮助或者发布信息都可以通过该邮件列表沟通。
  • openstack-announce@lists.openstack.org,该邮件列表专门用于接收 OpenStack 发布团队和 openstack 安全团队重要通告消息,比如有关 OpenStack 的发布,以及 OpenStack 解决了哪些安全漏洞等信息。
  • openstack-operators@lists.openstack.org,该邮件列表是为 OpenStack 运维人员的讨论话题而建立的一个平台,各公司运维人员可以在该邮件列表中交流关于 OpenStack 安装、部署、运维等方面的内容。
  • openstack-dev@lists.openstack.org,该邮件列表是为 OpenStack 开发者交流技术而设立的,对开发者相当重要。

由于 OpenStack 项目众多,为了防止邮件泛滥,通常在发送邮件时会在标题上加上项目名称作为前缀来进行区别。比如“[nova]”,表示这个邮件内容是与 Nova 相关的,如此一来,开发者便可以更有针对性地阅读邮件。

  • openstack-qa@lists.openstack.org,该邮件列表是专门为 QA 测试人员讨论测试用例设计、测试配置以及测试项目、CI/CD 等技术交流而设立的。
  • openstack-zh@lists.openstack.org,这是一个专门的中文邮件列表。

所有的邮件列表都可以在这里找到:https://wiki.openstack.org/wiki/Mailing_Lists。

至于如何订阅邮件,可以在 OpenStack Mailing List 页面中单击 Subscribe 链接,或者直接单击 OpenStack Dev Subscribe,如下图所示。

在 OpenStack Dev Subscribe 页面中输入接收邮件的邮箱地址和名字(可选),即可订阅成功。

比如,要想在 openstack-dev 邮件中提问题,只需要编辑邮件发送到 openstack-dev@ lists.openstack.org 邮箱即可,接下来需要做的就是等待别人回答你的问题,并给予积极的回应。

通过 IRC 方式交流

IRC 介绍

IRC(Internet Relay Chat)是一种实时聊天工具。由于使用邮件无法做到与社区实时互动,所以邮件更适合抛出一个问题或想法,系统性地阐述观点,并不需要立即得到他人的帮助、建议和回复等场景。

对于社区在线即时交互,OpenStack 社区推荐使用 IRC,所有的 OpenStack IRC 聊天室都可以在这里找到:https://wiki.openstack.org/wiki/IRC。比如 #openstack-dev 频道用于讨论开发过程中遇到的问题,#openstack-keystone 则用于讨论有关 Keystone 的问题。

IRC频道和项目例会固然很好,但它们也有局限性,需要考虑到他人因各种原因而未在线的问题,还有时区问题,所以邮件可以起到一个很好的弥补作用。IRC 工具种类繁多,既有 PC 端也有移动端的工具。下面是一些常用且开源的 IRC 工具。

PC 客户端工具:

  • Hexchat Free (Windows XP/Vista/7/8) (Linux)(推荐)
  • Colloquy Free (Mac OS X 10.7)
  • XChat Aqua/Azure (OS X 10-10.6)
  • XChat Linux Free
  • Irssi Free (Linux, FreeBSD, Microsoft Windows, Mac OS X)
  • KVirc Free (Linux, Unix, Mac OS, Windows)
  • Chatzilla Free (Firefox 3.5-20)

移动客户端工具:

  • IRChon Free (iOS)(兼容iPod touch, iPad。需要iOS 2.2.1及以上版本)
  • AndChat Free (Android)
  • YAAIC Free (Android (beta))
  • AndroIRC Free (Android)

OpenStack IRC

OpenStack 各项目例会的安排都列在 https://wiki.openstack.org/wiki/Meetings 上。对于OpenStack 开发者来说,参加项目例会是很重要的。项目例会一般由该项目的 PTL(项目主管)主持,鼓励该项目的所有开发者参加并讨论会议议题。项目例会是 OpenStack 开发者融入社区相当好的一个机会。

OpenStack 的 IRC 会议都有 Log 记录,可以通过 IRC 来了解项目的进展。如果你没有实时参与其中的讨论,那么可以有空时去查阅相关的记录。

  • https://wiki.openstack.org/wiki/IRC
  • https://wiki.openstack.org/wiki/UsingIRC
  • https://wiki.openstack.org/wiki/Meetings
  • http://eavesdrop.openstack.org/irclogs/
  • https://github.com/openstack-infra/irc-meetings
  • http://eavesdrop.openstack.org/meetings/

OpenStack 社区使用的 IRC 服务器地址是 irc.freenode.net,端口是6665和6666。

这里,推荐使用桌面版的一款开源免费的 IRC 客户端工具,即 HexChat,它同时支持Windows、Linux 和 OS X 系统。下载地址:http://hexchat.github.io/downloads.html。安装配置后,如下图所示。

除了以上提到的,使用 E-mail 和 IRC 方式和 OpenStack 社区交流之外,还可以参加诸如 Meetup 等会议。

第03课:深入理解 OpenStack 社区 CI/CD

在介绍 OpenStack 社区 CI/CD 平台之前,有必要先直观认识下社区日常运营的工作量,这将有助于我们理解为什么社区要建设如此丰富、复杂的基础设施服务。

社区 CI 规模

  • 500 > Git 项目仓库数
  • 5000 > Jenkins Job 项目任务数
  • 10 > Jenkins Master 节点数
  • 1000 > Jenkins Slave 节点数
  • 24000 > 每天执行的任务数
  • 5000 > 社区开发者人数
  • 1000 > 虚拟机运行数量

社区 CI 挑战

  • 项目多、Git 仓库多、分支多(master、stable)。
  • 有各种项目相关的 Job 任务。
  • 任务配置麻烦(多种后端、多种云环境、多个部署节点等)。
  • CI Pipeline(流水线)复杂且繁多(如检查、测试、发布和周期任务等)。

针对所面临的规模和挑战,OpenStack 社区构筑了一套完善的 CI/CD 平台,被统称为OpenStack Infra(OpenStack 基础设施平台)。OpenStack 基础设施平台主要包括:

  • Storyboard——任务跟踪系统,用于管理那些彼此之间紧密联系的系统。在 OpenStack这种内部关系紧密的系统中,一个功能或一个 Bug 都会至少影响两个项目,所以这样的问题需要在项目间统一跟踪。
  • Gerrit——代码评审系统,包括 Git 等子系统。
  • Zuul——运行 Jenkins 任务的组织系统(通过测试系统与代码评审系统结合,反馈提交的代码集成测试状况等),包括触发构建等子系统。
  • Jenkins——持续集成系统,包括 Jenkins 任务执行节点、Gearman 服务等子系统。
  • GitHub——代码仓库管理系统。
  • DevStack——一个从源码库安装 OpenStack 环境的工具。
  • Nodepool——负责管理 OpenStack 云平台上虚拟机的生命周期,构建 VM 资源池以供DevStack 安装使用。
  • ELK(Elasticsearch、Logstash 和 Kibana)——社区日志管理系统。
  • Launchpad——用于跟踪 OpenStack 相关事项的系统,包括 Bugs、Releases、Blueprints等子系统。
  • IRC——社区开发人员在线交流工具。

其中 Zuul、Jenkins-job-builder、Gearman Plugin、DevStack、Nodepool 等都是由 OpenStack 基础设施服务团队开发维护的。社区 CI/CD 系统运行工作流程如下图所示。

这里简要梳理下当社区开发人员向代码评审系统提交代码之后,代码会经过哪些环节,系统会执行哪些任务,才会最终被合并到 GitHub 代码仓库系统中。整体流程如下图所示。

首先是 PEP 8 代码风格测试。因为社区开发者人数众多,所以保证代码风格统一是非常重要的,需要确保大家都使用同样的编码方式和风格等。

然后是单元测试。仅仅测试被变更的子项目,不考虑跟其他子模块交互的情况。社区会针对不同的平台和软件版本进行测试,包括 Python 2.x 和 3.x,在不同操作系统上运行不同的软件版本。

最后是集成测试。社区在由 HP、Rackspace 等提供的 IaaS 云虚拟机上,使用 DevStack安装所有的组件,然后在这个单节点(all-in-one 环境)上运行不同的模板。不同的模板对不同的模块进行不同的配置,比如使用不同的数据库、不同的消息队列、不同的存储类型,不过基本上只测试那些常用的如 MySQL、PostgreSQL、RabbitMQ 等,当然社区也在考虑引入 ZeroMQ 的测试。

集成测试所使用的 VM 一般配置为8GB内存,系统是 Ubuntu ,然后让 DevStack 在该VM 上安装 OpenStack。Nodepool 用来管理 VM,通过缓存来预备这些机器。同时将 DevStack 所需要的依赖软件包等都预先下载到本地,这样测试本身就可以离线运行了。

测试执行完之后,再销毁这些 VM。实际创建的 VM 数量要比运行成功的测试数量多,因为 Zuul 的随机机制,有时候当测试跑到一半时才发现还需要一些其他东西,于是测试执行不下去了,此时会删除该 VM,启动一个新的。大致的比例是,如果一天跑10000个任务,那么启动的 VM 数量差不多在100000量级,即1:10的比例。

无疑,社区在测试方面做出了严格的限制,即只有写好了单元测试的代码变更提交才能够被接受。对于社区而言,未经测试的变更就是有问题的和有风险的。因为现在 OpenStack 项目发展很快,不断催生出新的组件,一个小错误就可能会影响整个系统的运行。

为了解决这些问题,社区使用了 Test Repository 框架,让大多数单元测试在这个框架中可以并行处理,并快速反馈测试结果。社区 QA 团队自行开发的 Zuul 系统,一方面可以并行测试一系列提交的代码,同时又保持它们的测试顺序不变。

OpenStack Infra资料请参考这里。

持续集成系统(Jenkins)

OpenStack 社区使用开源的 Jenkins 系统来负责持续集成。在应用中,Jenkins 使用 Zuul和 Gearman 进行管理。其具体的任务配置管理,使用 Jenkins-job-builder 基于 YAML 文件格式来定义 Job 内容,采用命令行创建和管理 Jenkins Job,Job 文件采用 Git 版本控制工具进行管理。OpenStack 的使用方式为:

  • 使用 YAML 文件编写 Job 内容。
  • 使用 Gerrit 管理 Job 定义的创建和变更。
  • 使用 Jenkins-job-builder 定义创建多个 Job。
  • 使用 Puppet 推送 Jenkins-job-builder 进行部署、更新 Jenkins 的 Job。

Pipeline

Pipeline 的字面意思就是流水线,是很好用的一个 Jenkins 插件,将很多步骤按顺序排列好,结束一个后执行下一个。在真实的工作环境中有很多 Job,比如先编译,然后执行代码静态检查、单元测试,最后部署服务、重启服务、进行 UI 测试等。我们需要对这些 Job 进行一些设置,将它们的上下游关系配置好。Pipeline 提供了图形界面,可以在界面上形象地看到整个构建任务的执行流程和完成度。示例如下。

Job模板:

- job-template:    name: 'gate-{name}-docs'    builders:      - shell: 'git checkout {branch_name}'

Jenkins-job-builder项目定义:

- project:    name: project-name    branch_name: new_branch    jobs:      - gate-{name}-docs

Job分组管理:

- job-group:    name: '{name}-tests'    jobs:      - '{name}-unit-tests'      - '{name}-perf-tests'

Job定义:

- job:    name: foo-test    project-type: freestyle    builders:      - make-test    publishers:      - archive

可以在 Job 文件中增加模块,比如 Builder、Publisher 等,使用宏(即批量处理,就是将一些命令组织在一起,作为一个单独命令完成某个特定任务)来定义 Jenkins 需要执行的任务。

- builder:  name: make-test  builders:    - shell: 'make test'

如何使用 Jenkins-job-builder

Jenkins-job-builder(简称 JJB)是用来创建 Jenkins 任务的工具。为了简化配置大量 Jenkins任务的工作量,OpenStack 采用更容易阅读的基于 YAML 或 JSON 格式的文件来编辑任务,然后使用 JJB 将 YAML 或 JSON 格式的配置转化为可以被 Jenkins 理解的 XML 格式的任务配置文件,并更新到 Jenkins 中。

实际上,Jenkins创建的任务是以 XML 文件的格式保存在 $JENKINS_HOME/jobs/ [job-name]/config.xml 中的,JJB 能够将 YAML 转化为 XML 文件(借助 Jenkins 提供的命令接口),并更新到 Jenkins 中。

这里,以测试配置、更新任务以及删除任务为例,阐述Jenkins-job-builder方法的使用。

(1)首先,安装Jenkins-job-builder。

# pip install jenkins-job-builder

(2)测试配置任务。

当任务配置的 YAML 文件编写完成之后,可以通过“jenkins-jobs test”测试配置格式和内容是否正确。

# jenkins-jobs test path/to/myjob.yaml  

若测试通过,将输出 XML 格式的任务配置;如果想将测试的 XML 格式的任务配置输出到文件,则可以添加“-o”参数。

# jenkins-jobs test -o output path/to/myjob.yaml  

JJB 将在与 myjob.yaml 相同的目录下新建一个名为“output”的文件夹,并在其内创建一个用 YAML 中定义的任务名命名的文件,就是 XML 格式的任务配置文件。

(3)更新任务。

测试通过后,可以使用“jenkins-jobs update”命令将 YAML 文件定义的任务更新到 Jenkins中。

# jenkins-jobs [--conf jenkins_jobs.ini] update path/to/job1.yaml  

Update 命令需要指定保存有 Jenkins 服务器信息的配置文件,用“--conf”来显式指定该配置文件,如果不显式指定,则默认读取“/etc/jenkinsjobs/jenkinsjobs.ini”文件。该配置文件保存有 Jenkins 的 URL 和登录信息,内容如下:

[jenkins]  user=jenkins  password=password  url=http://localhost:8081/jenkins  

从而 JJB 可以将任务更新到 ini 配置文件指定的Jenkins系统中。路径也可以是目录,那么就是更新指定目录下所有的YAML、YML和JSON文件,多个路径用冒号隔开。

(4)删除任务。

删除任务使用如下命令:

# jenkins-jobs [--conf jenkins_jobs.ini] delete job1

其中 job1 为任务名称。

OpenStack 如何使用 Jenkins-job-builder

在 OpenStack 环境中,可以在 project-config:jenkins/jobs/ 目录下找到 YAML 脚本文件。在该目录下有4种配置文件。

(1)defaults.yaml 文件

该文件为全局默认配置文件,是所有 Jenkins 任务的全局属性定义,即 name 为“global”的属性,比如默认的描述、任务是并行执行的、任务超时时间为30分钟等。

(2)macros.yaml文件

该文件保存了所有的宏定义,包括一些比较通用的 builders 或 publishers,供各任务调用,如下所示。

- builder:        name: git-prep        builders:        - shell: "/slave_scripts/git-prep.sh"    - publisher:        name: console-log        publishers:          - scp:              site: 'scp-server'              files:                - target: 'logs/$JOB_NAME/$BUILD_NUMBER'                  copy-console: true                  copy-after-failure: true  

(3)<project-name>.yaml 文件

该文件为各个项目的配置脚本,任务和任务模板定义在各个项目的脚本文件中。每个项目都有一个以项目名命名的 <project-name>.yaml 文件,里面的内容基本就是“- job:”和“- job-template:”,还有“- job-groups:”。

(4)projects.yaml 文件

该文件包含了所有项目的 Job 配置,即所有项目均集中配置在 projects.yaml 文件中,各个项目以字母顺序排列,各项目的 job 属性来自于任务和任务模板的定义。

针对 Jenkins-job-builder 的单独介绍,请访问这里。

Jenkins-job-builde 配置实例,请查看这里。

集群任务分发系统(Gearman)

Gearman 是一个分布式队列系统,负责将合适的任务分发到多台机器上,以便快速分解完成大型任务。Gearman 架构示意图如下图所示。

Gearman通常由三部分组成,即 Client、Worker 和 Job Server(任务服务器)。由 Worker执行 Client 发来的 Job,再通过 Job Server 返回给 Client。Gearman 提供了 Client、Worker 的 API,利用这些 API 与 Job Server 通信。

Gearman 接收到来自 Jenkins 的分发任务后,将 Job 发送到具体的工作节点上。Gearman和 Jenkins 系统集成示意图如下图所示。流程如下:

  • 首先,Jenkins Master 节点通过 Gearman Plugin 和 Gearman Server 系统建立交互。
  • 其次,Zuul 系统将构建请求提交到 Gearman Server 系统。
  • 最后,Gearman 系统再将 Job 任务分发到 Jenkins Slave 工作节点上执行。

任务组织系统(Zuul)

简单而言,Zuul 是一个面向多项目配置与自动化检测代码测试是否通过的系统。它同时与Gerrit、Jenkins 进行消息通信,使用 layout.yaml 文件进行灵活配置,适合多种项目的自动化操作,可以并行执行一系列变更的测试。

Zuul 有两个主要组件分别为 scheduler 和 merger。Zuul 保证合并进入源代码库的代码变更都是通过测试的。比如通过监测 Gerrit 的事件以触发相应的 Pipeline 及其对应的 Job,从代码的提交,到社区人员评审的 -1/+1、-2/+2 等事件流触发相应操作。

如下是社区的 OpenStack Nova 计算项目的一个 Zuul 配置文件。

projects:  - name: OpenStack/nova    check:       - gate-nova-pep8      - gate-nova-docs      - gate-nova-Python27      - gate-Tempest-devstack-vm-full    gate:       - gate-nova-pep8      - gate-nova-docs      - gate-nova-Python27      - gate-Tempest-devstack-vm-full    experimental:       - gate-devstack-vm-cells     slient:       - gate-Tempest-devstack-vm-large-ops    post:       - nova-branch-tarball      - nova-coverage      - nova-docs      - nova-upstream-translation-update    pre-release:      - nova-tarball         release:      - nova-tarball        - nova-docs    periodic:      - nova-propose-translation-update      - periodic-nova-Python27-stable-folsom      - periodic-nova-Python27-stable-grizzly

这里有一个特性是预测执行,即预测并提前执行可能需要的任务,以便加速整个处理过程。这个特性在 Pipeline 中得到了广泛使用,以提高整体效率。比如 Nodepool 会预先在 OpenStack 云环境中创建好相应的虚拟机;DevStack 会事先将相应的依赖包和其他项目源码下载下来,以便快速安装单节点的 OpenStack 测试环境。

一个 Check Pipeline 文件内容如下:

pipelines:  - name: check    manager: IndependentPiplelineManager    precedence: low    trigger:        Gerrit:        - event: patchset-created    success:        Gerrit:        verified: 1    failure:        Gerrit:        verified: -1

一个 Gate Pipeline 文件内容如下:

pipelines:  - name: name    manager: DependentPiplelineManager    precedence: high    trigger:      Gerrit:        - event: comment-added          approval:            - approved: 1    start:      Gerrit:        verified: 0             success:      Gerrit:        verified: 2        submit: true    failure:      Gerrit:        verified: -2

一个 Zuul 任务队列的文件内容如下:

projects:  - name: OpenStack/nova    gate:       - gate-nova-Python27      - gate-Tempest-devstack-vm  - name: OpenStack/glance    gate:      - gate-glance-Python27      - gate-Tempest-devstack-vm

什么是 Gate Job

在回答该问题之前,我们需要先认识下 OpenStack 代码的提交与合并过程。

首先,开发人员克隆相关的 OpenStack 项目(如 Keystone、Nova 等),做了代码(也包括 rst 文档)修改后,使用 git 命令提交到代码评审系统中。

然后,Jenkins 做自动化测试。Jenkins 可能会运行一个或多个工作任务来执行不同类型的测试,以验证这些提交的 Patch(补丁)是否安全、正确。这些工作便被称为“Gate Job”。

这里 Gate 可以被形象地理解为“看门人”。社区开发人员提交的 Patch 是否得到批准,是根据 Jenkins Gate Job 执行的测试结果来确定的。然后基于测试结果,将 -1/+1 的投票反馈到代码评审系统(Gerrit)中。

在这里,我们可以找到 OpenStack 每个项目的 Gate Job 配置文件,这些配置文件均采用YAML 文件格式编写。这里是链接地址。

向一个特定项目提交 Patch 后,会执行哪些任务

如果想知道向社区提交代码后,Jenkins 会执行哪些任务,一个直接的办法是在 Gerrit 系统中查看。还有一个办法则是查看项目的配置文件:project-config/zuul/layout.yaml。通过该链接地址,可以找到 OpenStack 项目的模板文件内容。

如何添加一个新的 Job

首先需要选择哪些项目属于这个 Job。在 projects.yaml 文件中可以看到所有项目的 Job。点击这里获得链接地址:。

比如将一个名称为“abregman-new-job”的 Job 添加到“devstack-jobs”项目下。

jobs:

  - gate-Tempest-dsvm-{name}{job-suffix}:      pipeline: gate      name: abregman-new-job      node: devstack-centos7      job-suffix: ''

文件中的“node:devstack-centos7”用于告诉 Jenkins 在哪些节点上运行任务。devstack-centos7只是一个节点的标签。所以,当 Job 运行时,它将寻找标签为“devstack-centos7”的节点。

假设每次提交 Patch 时,都要运行“openstack-dev/devstack”这个 Job,则可以这样编写:

- name: openstack-dev/devstack  gate:    - gate-Tempest-abregman-new-job

现在,我们添加了一个 Job(gate-Tempest-abregman-new-job)到“openstack-dev/devstack”项目中,并在 Gate Pipeline Job 下。这样,当上述代码内容提交并合并后,就可以提交 Patch 到 openstack-dev/devstack 项目中,来观察它们的 Job 是如何运行的。一个全局的社区 Zuul Job 运行状态如下图所示。

代码评审系统(Gerrit)

社区采用了开源的 Gerrit 系统用于代码评审,以及细粒度的开发者权限控制等。而第三方系统与 Gerrit 的集成主要通过 Webhooks、event-stream、REST API 等方式交互。

通常,Gerrit评审系统上的代码有如下几种状态。

  • 代码已提交,正等待审核。
  • 代码处于 Jenkins 的自动化测试验证阶段。
  • 代码处于人工审核阶段。
  • 代码处于接受认可阶段。
  • 代码被合并。

相应地,Gerrit 的触发类型有如下几种。

  • 合并代码同步复制到GitHub仓库。
  • 修改合并。
  • 添加评论(处于评审状态时)。
  • 引用更新(包括分支、标签等)。

Gerrit 与 Jenkins 集成

通常将 Gerrit 评论页面中显示的 Jenkins Job 执行结果和耗时时间,作为代码评审的依据。还有一个 Gerrit 的辅助配置工具 Jeepyb,它是一个帮助简化 Gerrit 管理的工具集,可以很简便地管理项目并和 Launchpad、GitHub 等系统进行集成。在 Jeepyb 中采用 YAML 文件定义项目。

- project: example/Gerrit  description: Fork of Gerrit used by Example- project: OpenStack/project-name  acl-config: /home/gerrit2/acls/project-name.config  upstream: git://github.com/awesumsauce/project-name.git

Jeepyb 基于 Gerrit 进行分组,将 Administrators、Registered Users、Anonymous Users 用户组划分在每个项目中,针对每个项目都有一个 ACL(访问控制列表)的配置文件。Jeepyb 描述项目和分值的权限采用 git refs 的语法格式。

[access "refs/heads/*"]label-Code-Review = -2..+2 group project-name-corelabel-Workflow = -1..+1 group project-name-core[access "refs/heads/proposed/*"]label-Code-Review = -2..+2 group project-name-milestonelabel-Workflow = -1..+1 group project-name-milestone[receive]requireChangeId = truerequireContributorAgreement = tree[submit]mergeContent = true

Gerrit 与 Launchpad 集成

在 Gerrit 系统中,修改 etc/gerrit.config 配置文件,如下所示。

[commentlink "launchpad"]    match = "([Bb]ug\\s+#?)(\\d+)"    link = https://bugs.launchpad.net/mahara/+bug/$2

OpenStack 社区遵循的原则是人人平等,即每个人提交的代码都需要经过相同的验证测试和其他人员的评审,只有通过了,其代码才能被合并到仓库中。在代码评审系统中评分有0、-1/+1、-2/+2这几项,具体含义如下表所示。

分值 含义
0 不计分,即该项分值不会被统计到stackalytics.com中
-1 对于评审人员而言,这个提交是需要修改的
+1 对于评审人员而言,这个提交是不错的,但是还需要其他人批准
-2 严重错误,不能合并到项目中
+2 对于核心评审者而言,这个提交很好,同意合并代码

通常给出评分为-1、-2的评审人员,需要进行评论,阐明其为什么是错误的,或者说明应该怎样修改。这些评论可以帮助提交者或其他评审人员重新更新和评审。核心评审者能够给予分值为 -2/+2 的投票并批准提交,一旦有两个核心评审者给了+2分值,那么代码就会被合并到 GitHub 项目中。

Software Factory 介绍和使用

Software Factory 是一个由 Red Hat 开源的用于在 OpenStack 云平台和其他环境中部署的CI/CD 项目,该项目集成了 Jenkins、Zuul、Gerrit、Nodepool、Redmine 等系统,支持从源代码提交,到编译打包和部署,再到项目管理等任务。

Software Factory可以安装在 OpenStack 云平台上,也可以安装在 LXC 容器中及虚拟机上等。如果需要使用 Nodepool 在 Jenkins Slave 节点上管理 Job、测试等任务,或者将应用 push 到 Swift 对象存储上,那么需要:

  • 创建一个或多个运行虚拟机的 OpenStack 租户。
  • 创建 Swift Endpoint(端点)来存储和发布应用。

Red Hat 官方提供了不同版本的 Software Factory 的 qcow2 镜像,用于作为虚拟机来直接使用。如何在 OpenStack 云平台上部署 Software Factory 项目呢?这里使用命令行方式部署,执行如下步骤。

(1)下载镜像。

# wget http://46.231.133.241:8080/v1/AUTH_sf/sf-images/softwarefactory-C7. 0-2.2.2.img.qcow2

(2)生成镜像。

# glance image-create --progress --disk-format qcow2 --container-format bare --name sf-2.2.2 --file softwarefactory-C7.0-2.2.2.img.qcow2

(3)使用镜像创建虚拟机。

# nova boot --image sf-2.2.2 --flavor 4 --nic net-id=b6c3b5d7-73b3-4b6d-8b3b-2a543ce91bee software_factory

(4)在 Dashboard 界面上,绑定一个外网 IP 地址给虚拟机。

(5)在浏览器中,使用该外网 IP 地址访问 Software Factory 系统,并可以使用 GitHub 账号登录 Software Factory,如下图所示。

可以在系统的导航栏中看见该平台集成了很多子系统,用于负责不同的任务。Software Factory 非常适用于中小型规模的研发测试环境,通过高度集成、简化的自动化部署方式等,在使用方面显得非常简便。无论是 Gerrit、Jenkins 还是 Redmine等,均可以在其上面自行创建项目、分配权限、管理日常开发等。

第04课:企业如何通过 OpenStack 社区互操作性认证
第05课:Docker 容器化部署运维 OpenStack 和 Ceph
第06课:Selenium 前端自动化测试介绍和使用
第07课 开发 OpenStack Dashboard 自动化测试框架
第08课:自动化测试 OpenStack Dashboard 前端
第09课:如何测试 OpenStack 代码平面
第10课:如何测试 OpenStack 网络平面
第11课:自动化测试 OpenStack 平台功能
第12课:自动化测试 OpenStack 平台性能
第13课:如何设计 OpenStack 测试用例
第14课:如何测试 Ceph 分布式存储
第15课:使用 Harbor 管理 OpenStack 镜像

阅读全文: http://gitbook.cn/gitchat/column/5aa795539c3cf94d49162f03

OpenStack 快速进阶教程相关推荐

  1. javaweb不同用户需要几张表_程序员必备2020版:JavaWeb快速进阶全套教程

    Java Web应用由一组Servlet.HTML页.类.以及其它可以被绑定的资源构成.它可以在各种供应商提供的实现Servlet规范的Servlet容器中运行. JavaWeb项目简单来说就是一个应 ...

  2. JSP WEB开发入门基础到高手进阶教程002

    JSP WEB开发入门基础到高手进阶教程 -------开发入门 JSP与微软的Active Server Pages 兼容,但它是使用类似HTML的卷标以及Java程序代码段而不是VBScript. ...

  3. BeagleBone Black快速入门教程

    BeagleBone Black快速入门教程 试读样张下载地址:http://pan.baidu.com/s/1bnjJEnP 本教程是国内唯一BeagleBone Black中文教程.本教程全面讲解 ...

  4. python快速入门答案-总算懂得python脚本快速入门教程

    PyQt5是基于Digia公司强大的图形程式框架Qt5的python接口,由一组python模块构成.PyQt5本身拥有超过620个类和6000函数及方法.在可以运行于多个平台.PyQt5拥有双重协议 ...

  5. 专为设计师而写的GitHub快速入门教程

    在互联网行业工作的想必都多多少少听说过GitHub的大名,除了是最大的开源项目托管平台,许多企业也都是用GitHub来协同开发工作,当然我们彩程也是其中之一.笔者最初决定学习Git也是因为在团队内部设 ...

  6. STM32 进阶教程 16 - ADC1与ADC2同步采样

    前言 STM32中在有2个或以上ADC模块的产品中,可以使用双ADC模式.在双ADC模式里,根据ADC1_CR1寄存器中DUALMOD[2:0]位所选的模式,转换的启动可以是ADC1主和ADC2从的交 ...

  7. STM32 进阶教程 5 - 内联函数

    前言 在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展):也就是说建议编译器将指定的函数体插入并取代每一处调 ...

  8. HTML+CSS小白入门与进阶教程

    HTML+CSS小白入门与进阶教程 本文旨在让你快速了解HTML语法结构,通过实例操作快速从无到有的入门与进阶.Html语言学习的特点有点像刚开始学word软件,word的功能就像html标签,用多了 ...

  9. Django进阶教程

    Django进阶教程 Queryset特性及高级查询技巧 什么是QuerySet QuerySet是Django提供的强大的数据库接口(API).正是因为通过它,我们可以使用filter, exclu ...

  10. python教程自带数据库_Python入门进阶教程-数据库操作

    Python数据库操作Python版本3.8.0,开发工具:Pycharm 建议本节在掌握了数据库相关操作后再进行学习 MySQL 是最流行的关系型数据库管理系统.本小节通过Python对MySQL数 ...

最新文章

  1. RabbitMQ惰性队列
  2. 实现gridview中checkbox的全选和反选,以及固定gridview列字符串的长度,多余的以...表示...
  3. Hive日期格式转换
  4. jw player去掉logo 二次开发
  5. flashfxp怎么传文件,小编教你flashfxp怎么传文件
  6. 企业单方调岗降薪,务工者不服离职索赔
  7. virtualBox安装centos7并实现宿主机、虚拟机、外网三网互通
  8. 吉德林法则 (Kidlin's Law)的真实案例(1)
  9. 根据字符的首字母进行分类
  10. Java实现使用Modbus4j+seroUtils读取Mudbus RTU/ASCII Over TCP/IP连接设备数据
  11. 数列的组合及排列方式java_java数组排列组合
  12. UR机械臂+RG2机械手控制 学习及实际控制 系列第三篇-1
  13. 关于阿里矢量图iconfont的应用
  14. 2020--管理类联考--网课推荐
  15. 【区块链108将】职品汇龚才春:通过区块链建立招聘生态,建立真实的应聘环境...
  16. linux下oracle升级,Linux下升级ORACLE 10
  17. win10环境下适应pip安装autobahn提示认证失败的问题
  18. iOS获取视频图片(视屏截图)
  19. F5运维之 将Windows中的证书导入F5
  20. 2019百度智能云渠道生态年度盛典:携手合作伙伴开启智能生态元年

热门文章

  1. 【C语言】calloc函数
  2. HotDB——布式事务数据库中不同数据库表对象的类型设计准测
  3. 科大讯飞18岁成人礼:这家极客公司未来不设限
  4. ICS bomblab总结
  5. BJ54坐标或者XA80坐标到WGS84坐标的转换(小工具附代码)
  6. python获取文字坐标_python坐标获取
  7. 逍遥书生服务器啥时候维护完毕,2020年8月18日定期维护解读
  8. 学习java之java帝国的诞生
  9. Bit-Vector框架(1) — Reaching Definition Analysis
  10. CF687 D2 C. Bouncing Ball(DP)