#变更管理

0 关注者 · 8 帖子

变更管理是指管理对项目的变更,例如,代码变更或文档变更。这涉及管理版本控制系统、问题跟踪系统、构建、测试和部署等工作。

文章 Michael Lei · 九月 27, 2024 9m read

在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:

  • Git 101
  • Git 流程(开发流程)
  • GitLab 安装
  • GitLab 工作流
  • 持续交付
  • GitLab 安装和配置
  • GitLab CI/CD
  • 为何使用容器
  • 容器基础架构
  • 使用容器的 CD

第一篇文章中,我们介绍了 Git 基础知识、深度理解 Git 概念对现代软件开发至关重要的原因,以及如何使用 Git 开发软件。

第二篇文章中,我们介绍了 GitLab 工作流 – 一个完整的软件生命周期流程,并介绍了持续交付。

第三篇文章中,我们介绍了 GitLab 安装和配置以及将环境连接到 GitLab

第四篇文章中,我们编写了 CD 配置。

第五篇文章中,我们讨论了容器以及使用容器的方式(和原因)。

第六篇文章中,我们将探讨运行包含容器的持续交付管道所需的主要组件以及这些组件如何协同运行。

在这篇文章中,我们将构建上一篇文章中探讨的持续交付配置。

工作流

在持续交付配置中,我们会:

  • 将代码推送到 GitLab 仓库
  • 构建 docker 镜像
  • 进行测试
  • 将镜像发布到 docker 注册表
  • 将旧容器换为注册表中的新版本

也可以用示意图形式表示此流程:

我们开始吧。

构建

首先,我们需要构建镜像。

我们的代码通常存储在仓库中,CD 配置位于 gitlab-ci.yml 中,但为了提高安全性,我们会在构建服务器上存储几个服务器特定的文件。

GitLab.xml

包含 CD 挂钩代码。 该代码是在上一篇文章中开发的,并在 GitHub 上提供。 这是一个小型库,用于加载代码、运行各种挂钩以及测试代码。 作为更好的替代方案,您可以使用 git 子模块将此项目或类似项目包含到您的仓库中。 最好选择子模块,因为子模块更容易保持最新状态。 另一个替代方案是在 GitLab 上为版本添加标签,并使用 ADD 命令加载这些版本。

iris.key

许可证密钥。 或者,它可以在容器构建过程中下载,而不是存储在服务器上。 将密钥存储在仓库中非常不安全。

pwd.txt

包含默认密码的文件。 将这类文件存储在仓库中也非常不安全。 此外,如果您在单独的服务器上托管生产环境,它可能有不同的默认密码。

load_ci.script

初始脚本,它执行以下任务:

  • 实现操作系统身份验证
  • 加载 GitLab.xml
  • 初始化 GitLab 实用工具设置
  • 加载代码

set sc = ##Class(Security.System).Get("SYSTEM",.Properties) write:('sc) $System.Status.GetErrorText(sc) set AutheEnabled = Properties("AutheEnabled") set AutheEnabled = $zb(+AutheEnabled,16,7) set Properties("AutheEnabled") = AutheEnabled set sc = ##Class(Security.System).Modify("SYSTEM",.Properties) write:('sc) $System.Status.GetErrorText(sc) zn "USER" do ##class(%SYSTEM.OBJ).Load(##class(%File).ManagerDirectory() _ "GitLab.xml","cdk") do ##class(isc.git.Settings).setSetting("hooks", "MyApp/Hooks/") do ##class(isc.git.Settings).setSetting("tests", "MyApp/Tests/") do ##class(isc.git.GitLab).load() halt

请注意,第一行有意留空。

由于某些设置可以是服务器特定的,脚本不会存储在仓库中,而是单独存储。 如果此初始挂钩始终相同,将其存储在仓库中即可。

gitlab-ci.yml

现在,继续持续交付配置:

构建镜像:
  stage: build
  tags:
    - test
  script:
    - cp -r /InterSystems/mount ci
    - cd ci
    - echo 'SuperUser' | cat - pwd.txt load_ci.script > temp.txt
    - mv temp.txt load_ci.script
    - cd ..
    - docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t docker.domain.com/test/docker:$CI_COMMIT_REF_NAME .

这里会执行哪些操作?

首先,由于 docker build 只能访问基础构建目录的子目录(本例中是仓库根目录),我们需要将“秘密”目录(包含 GitLab.xmliris.keypwd.txt 和 load_ci.script 的目录)复制到克隆的仓库中。

接下来,首次终端访问需要用户名/密码,因此我们会将这些信息添加到 load_ci.script 中(这也是 load_ci.script 开头一行留空的原因)。

最后,我们会构建 docker 镜像并适当地为其添加标签:docker.domain.com/test/docker:$CI_COMMIT_REF_NAME

其中,$CI_COMMIT_REF_NAME 是当前分支的名称。 请注意,镜像标签的第一部分应与 GitLab 中的项目名称相同,这样才能在 GitLab 的“注册表”标签页中看到它(“注册表”标签页中提供了关于添加标签的说明)。

Dockerfile

构建 docker 镜像是通过 Dockerfile 完成的,具体如下:

FROM docker.intersystems.com/intersystems/iris:2018.1.1.611.0

ENV SRC_DIR=/tmp/src ENV CI_DIR=$SRC_DIR/ci ENV CI_PROJECT_DIR=$SRC_DIR

COPY ./ $SRC_DIR

RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/
&& cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/
&& $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt
&& iris start $ISC_PACKAGE_INSTANCENAME
&& irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script
&& iris stop $ISC_PACKAGE_INSTANCENAME quietly

我们从基本的 iris 容器开始。

首先,我们将仓库(和“秘密”目录)复制到容器中。

接下来,我们将许可证密钥和 GitLab.xml 复制到 mgr 目录中。

然后,我们将密码更改为 pwd.txt 中的值。 请注意,此操作会删除 pwd.txt。

之后,实例启动并执行 load_ci.script。

最后,iris 实例停止。

以下是作业日志(部分日志,跳过了加载/编译日志):

Running with gitlab-runner 10.6.0 (a3543a27)
  on docker 7b21e0c4
Using Shell executor...
Running on docker...
Fetching changes...
Removing ci/
Removing temp.txt
HEAD is now at 5ef9904 Build load_ci.script
From http://gitlab.eduard.win/test/docker
   5ef9904..9753a8d  master     -> origin/master
Checking out 9753a8db as master...
Skipping Git submodules setup
$ cp -r /InterSystems/mount ci
$ cd ci
$ echo 'SuperUser' | cat - pwd.txt load_ci.script > temp.txt
$ mv temp.txt load_ci.script
$ cd ..
$ docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t docker.eduard.win/test/docker:$CI_COMMIT_REF_NAME .
Sending build context to Docker daemon  401.4kB

Step 1/6 : FROM docker.intersystems.com/intersystems/iris:2018.1.1.611.0 ---> cd2e53e7f850 Step 2/6 : ENV SRC_DIR=/tmp/src ---> Using cache ---> 68ba1cb00aff Step 3/6 : ENV CI_DIR=$SRC_DIR/ci ---> Using cache ---> 6784c34a9ee6 Step 4/6 : ENV CI_PROJECT_DIR=$SRC_DIR ---> Using cache ---> 3757fa88a28a Step 5/6 : COPY ./ $SRC_DIR ---> 5515e13741b0 Step 6/6 : RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/ && cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/ && $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt && iris start $ISC_PACKAGE_INSTANCENAME && irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script && iris stop $ISC_PACKAGE_INSTANCENAME quietly ---> Running in 86526183cf7c . Waited 1 seconds for InterSystems IRIS to start This copy of InterSystems IRIS has been licensed for use exclusively by: ISC Internal Container Sharding Copyright (c) 1986-2018 by InterSystems Corporation Any other use is a violation of your license agreement

%SYS> 1

%SYS> Using 'iris.cpf' configuration file

This copy of InterSystems IRIS has been licensed for use exclusively by: ISC Internal Container Sharding Copyright (c) 1986-2018 by InterSystems Corporation Any other use is a violation of your license agreement

1 alert(s) during startup. See messages.log for details. Starting IRIS

Node: 39702b122ab6, Instance: IRIS

Username: Password:

Load started on 04/06/2018 17:38:21 Loading file /usr/irissys/mgr/GitLab.xml as xml Load finished successfully.

USER>

USER>

[2018-04-06 17:38:22.017] Running init hooks: before

[2018-04-06 17:38:22.017] Importing hooks dir /tmp/src/MyApp/Hooks/

[2018-04-06 17:38:22.374] Executing hook class: MyApp.Hooks.Global

[2018-04-06 17:38:22.375] Executing hook class: MyApp.Hooks.Local

[2018-04-06 17:38:22.375] Importing dir /tmp/src/

Loading file /tmp/src/MyApp/Tests/TestSuite.cls as udl

Compilation started on 04/06/2018 17:38:22 with qualifiers 'c' Compilation finished successfully in 0.194s.

Load finished successfully.

[2018-04-06 17:38:22.876] Running init hooks: after

[2018-04-06 17:38:22.878] Executing hook class: MyApp.Hooks.Local

[2018-04-06 17:38:22.921] Executing hook class: MyApp.Hooks.Global Removing intermediate container 39702b122ab6 ---> dea6b2123165 [Warning] One or more build-args [CI_PROJECT_DIR] were not consumed Successfully built dea6b2123165 Successfully tagged docker.domain.com/test/docker:master Job succeeded

请注意,我使用的是 GitLab Shell 执行器,而不是 Docker 执行器。 当您需要从镜像内部提取某些内容时,将使用 Docker 执行器,例如在 Java 容器中构建 Android 应用程序并且只需要一个 apk 时。 在我们的示例中,我们需要整个容器,因此需要使用 Shell 执行器。 因此,我们通过 GitLab Shell 执行器运行 Docker 命令。

 

运行

我们构建了镜像,接下来要运行镜像。如果是功能分支,我们销毁旧容器并启动新容器即可。 如果是环境,我们可以运行临时容器,在测试成功的情况下,可以替换环境容器(此内容留给读者作为练习)。

脚本如下。

destroy old:
  stage: destroy
  tags:
    - test
  script:
    - docker stop iris-$CI_COMMIT_REF_NAME || true
    - docker rm -f iris-$CI_COMMIT_REF_NAME || true

此脚本会销毁当前运行的容器,并且始终都会成功(默认情况下,如果 docker 尝试停止/移除不存在的容器,则会失败)。

接下来,我们启动新镜像并将其注册为环境。 Nginx 容器 使用 VIRTUAL_HOST 环境变量和 expose 指令(用于了解要代理的端口)自动代理请求。

run image:
  stage: run
  environment:
    name: $CI_COMMIT_REF_NAME
    url: http://$CI_COMMIT_REF_SLUG. docker.domain.com/index.html
  tags:
    - test
  script:
    - docker run -d
      --expose 52773
      --env VIRTUAL_HOST=$CI_COMMIT_REF_SLUG.docker.eduard.win
      --name iris-$CI_COMMIT_REF_NAME
      docker.domain.com/test/docker:$CI_COMMIT_REF_NAME
      --log $ISC_PACKAGE_INSTALLDIR/mgr/messages.log

 

测试

我们来运行一些测试。

test image:
  stage: test
  tags:
    - test
  script:
    - docker exec iris-$CI_COMMIT_REF_NAME irissession iris -U USER "##class(isc.git.GitLab).test()"

发布

最后,我们将镜像发布到注册表中

publish image:
  stage: publish
  tags:
    - test
  script:
    - docker login docker.domain.com -u dev -p 123
    - docker push docker.domain.com/test/docker:$CI_COMMIT_REF_NAME

可以使用 GitLab 秘密变量传递用户名/密码。

现在,我们可以在 GitLab 中看到该镜像:

其他开发者可以从注册表中拉取该镜像。 “环境”标签页上提供了我们所有的环境,可以轻松进行浏览:

 

结论

在这一系列文章中,我介绍了持续交付的常规方式。 这是一个涉及面非常广的话题,您应将这一系列文章视为方法集合,而不是确定性内容。 如果您想自动构建、测试和交付应用程序,可以选择持续交付(一般情况)和 GitLab(特殊情况)。 利用持续交付和容器,您可以根据需要自定义工作流。

链接

后续内容

就是这些! 希望我已介绍了持续交付和容器的基础知识。

但还有一些主题我没有介绍(可能后面会介绍),特别是关于容器的内容:

  • 数据可以在容器外持久保持,以下是相关文档
  • kubernetes 等编排平台
  • InterSystems Cloud Manager
  • 环境管理 – 创建临时环境以进行测试,在功能分支合并后移除旧环境
  • Docker compose 可以实现多容器部署
  • 缩减 docker 镜像大小并缩短构建时间
  • ...
0
0 110
文章 Michael Lei · 九月 27, 2024 2m read

在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:

  • Git 101
  • 流程(开发流程)
  • GitLab 安装
  • GitLab 工作流
  • 持续交付
  • GitLab 安装和配置
  • GitLab CI/CD
  • 为何使用容器?
  • 容器基础架构
  • 使用容器的 GitLab CI/CD

第一篇文章中,我们介绍了 Git 基础知识,以及为什么对 Git 概念的高层次理解对于现代软件开发如此重要,以及如何使用 Git 开发软件。

第二篇文章中,我们介绍了 GitLab 工作流 – 一个完整的软件生命周期流程和持续交付。

第三篇文章中,我们介绍了 GitLab 的安装和配置以及如何将环境连接到 GitLab。

第四篇文章中,我们编写了 CD 配置。

第五篇文章中,我们讨论了容器与如何(以及为什么)使用它们。

在本文中,我们将探讨运行使用容器的持续交付管道所需的主要组件,以及它们如何协同工作。

我们的配置如下所示:

在这里,我们可以看到三个主要阶段的分离:

  • 构建
  • 传送
  • 运行

构建

在之前的部分中,构建通常是增量式 – 我们计算当前环境与当前代码库之间的差异,并修改我们的环境以与代码库相对应。 使用容器时,每次构建都是完整构建。 构建的结果是一个可以通过依赖关系在任何地方运行的镜像。

传送

在我们的镜像构建并通过测试后,它会被上传到注册表 – 用于托管 docker 镜像的专用服务器。 在那里,它可以替换具有相同标签的旧镜像。 例如,由于对 master 分支的新提交,我们构建了新镜像 (project/version:master),如果测试通过,我们可以用相同标签的新镜像替换注册表中的旧镜像,这样,所有拉取 project/version:master 的人都会获得新版本。

运行

最后,我们的镜像部署完成。 CI 解决方案(如 GitLab)可以控制此流程,也可以由专门的编排器控制,但目的都一样 – 执行一些镜像,定期检查健康状态,如果有新镜像版本可用就进行更新。

查看 docker 网络研讨会以了解这些不同阶段的解释。

或者,从提交的角度来看:<

在我们的交付配置中,我们会:

  • 将代码推送到 GitLab 仓库
  • 构建 docker 镜像
  • 测试该镜像
  • 将镜像发布到我们的 docker 注册表
  • 用新版本替换注册表中的旧容器

为此,我们需要:

  • Docker
  • Docker 注册表
  • 注册域(可选但推荐)
  • GUI 工具(可选)

 

Docker

首先,我们需要在某个地方运行 docker。 我建议从一台运行主流 Linux 发行版(如 Ubuntu、RHEL 或 Suse)的服务器开始。 不要使用面向云的发行版(如 CoreOS、RancherOS 等) - 它们并不适合初学者。 别忘了将存储驱动程序切换为 devicemapper。 

如果我们在讨论大规模部署,那么使用像 Kubernetes、Rancher 或 Swarm 这样的容器编排工具可以自动执行大多数任务,但我们不会探讨它们(至少在这一部分中)。

 

Docker 注册表

这是我们需要运行的第一个容器,它是一个无状态、可扩缩的服务器端应用程序,作用是存储和分发 Docker 镜像。
您应当在想要实现以下目的时使用注册表:

  •  严格控制您的镜像存储位置
  •  完全掌控您的镜像分发管道
  •  将镜像存储和分发紧密整合到您的内部开发工作流中

此处提供了注册表的文档

连接注册表和 GitLab

注:GitLab 包含内置注册表。 您可以运行它而不使用外部注册表。 请阅读本段中链接的 GitLab 文档。

要将您的注册表连接到 GitLab,您需要运行支持 HTTPS的注册表 – 我使用 Let's Encrypt 获取证书,并按照此 Gist 获取证书并将其传递到容器中。 在确认注册表可以通过 HTTPS 访问后(您可以从浏览器检查),请按照这些说明将注册表连接到 GitLab。根据您的需要和 GitLab 安装情况,这些说明会有所不同。就我而言,配置是将注册表证书和密钥(正确命名且具有正确的权限)添加到 /etc/gitlab/ssl 并将以下行添加到 /etc/gitlab/gitlab.rb 中:

registry_external_url 'https://docker.domain.com'
gitlab_rails['registry_api_url'] = "https://docker.domain.com"

重新配置 GitLab 后,我可以看到一个新的注册表标签页,其中提供了如何正确为新构建的镜像添加标签以便它们会出现在这里的信息。

 

在我们的持续交付配置中,我们将为每个分支自动构建一个镜像,如果镜像通过测试,那么我们会将其发布到注册表并自动运行,因此我们的应用程序将在所有“状态”下自动可用,例如,我们可以访问:

  • 几个功能分支,网址为 <featureName>.docker.domain.com
  • 测试版本,网址为 master.docker.domain.com
  • 试生产版本,网址为 preprod.docker.domain.com
  • 生产版本,网址为 prod.docker.domain.com

为此,我们需要一个域名并添加一条通配符 DNS 记录,将 *.docker.domain.com 指向 docker.domain.com 的 IP 地址。 另一种选项是使用不同的端口。

Nginx 代理

由于我们有几个功能分支,需要将子域自动重定向到正确的容器。 为此,我们可以使用 Nginx 作为反向代理。 此处提供了一份指南

GUI 工具

要开始使用容器,您可以使用命令行或 GUI 界面之一。 有许多可用工具,例如:

  • Rancher
  • MicroBadger
  • Portainer
  • Simple Docker UI
  • ...

它们允许您从 GUI 而不是 CLI 创建和管理容器。 下面是 Rancher 的外观:

 

GitLab Runner

与之前相同,要在其他服务器上执行脚本,我们需要安装 GitLab 运行程序。 我在第三篇文章中探讨过这一点。

请注意,您需要使用 Shell 执行器而不是 Docker 执行器。 当您需要从镜像内部提取某些内容时,将使用 Docker 执行器,例如在 Java 容器中构建 Android 应用程序并且只需要一个 apk 时。 在我们的示例中,我们需要整个容器,因此需要使用 Shell 执行器。

 

结论

开始运行容器十分容易,并且有许多工具可供选择。

使用容器的持续交付与常规的持续交付配置在以下几个方面有所不同:

  • 依赖关系的需求在构建时得到满足,并且在镜像构建后无需考虑依赖关系。
  • 可重现性 – 您可以通过本地运行相同的容器轻松重现任何现有环境。
  • 速度 – 由于容器仅包含您显式添加的内容,它们的构建速度更快,更重要的是,它们仅需构建一次并在需要时使用。
  • 效率 – 同上,与虚拟机等相比,容器产生的开销更少。
  • 可扩缩性 – 使用编排工具,您可以根据工作负载自动扩缩应用程序,并且仅消耗当前所需的资源。

后续内容

在下一篇文章中,我们将创建一个利用 InterSystems IRIS Docker 容器的 CD 配置。

0
0 148
文章 Michael Lei · 九月 27, 2024 4m read

在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:

  • Git 101
  • Git 流程(开发流程)
  • GitLab 安装
  • GitLab 工作流
  • 持续交付
  • GitLab 安装和配置
  • GitLab CI/CD
  • 为何使用容器
  • 使用容器的 GitLab CI/CD

第一篇文章中,我们介绍了 Git 基础知识、深度理解 Git 概念对现代软件开发至关重要的原因,以及如何使用 Git 开发软件。

第二篇文章中,我们介绍了 GitLab 工作流 – 一个完整的软件生命周期流程,并介绍了持续交付。

第三篇文章中,我们介绍了 GitLab 安装和配置以及将环境连接到 GitLab

第四篇文章中,我们编写了 CD 配置。

在这篇文章中,我们将介绍容器以及使用容器的方法(和原因)。

这篇文章假设读者熟悉 docker 和容器的概念。 如果您想了解容器镜像,请查阅 @Luca Ravazzolo 撰写的文章。

优势

使用容器有诸多优势:

  • 可移植性
  • 效率
  • 隔离
  • 轻量
  • 不可变性

下面我们来具体介绍这些优势。

可移植性

容器将应用程序与运行所需的一切(如配置文件和依赖项)打包在一起。 这样一来,您可以在您本地台式机、物理服务器、虚拟服务器、测试、暂存、生产环境以及公共云或私有云等不同环境中轻松、可靠地运行应用程序。

可移植性的另一个优势是,在您构建 Docker 镜像并确认它可以正常运行后,它便可以在任何运行 docker 的位置(目前是 Windows、Linux 和 MacOS 服务器)运行。

效率

实际上,您只需要运行应用程序进程,而不需要运行所有系统软件等。 容器恰好可以满足这一需求 – 容器仅会运行您明确需要的进程,而不运行其他进程。 由于容器不需要单独的操作系统,占用的资源较少。 虚拟机的大小通常为几千兆字节,而容器的大小通常只有几百兆字节,因此在一台服务器上运行的容器数量要比虚拟机多得多。 由于容器对底层硬件的利用率更高,您需要的硬件更少,从而降低了裸机成本和数据中心成本。

隔离

容器会将应用程序与其他一切隔离开,同时多个容器可以在同一台服务器上运行,它们可以完全彼此独立。 容器之间的任何交互都应明确声明。 如果一个容器发生故障,它不会影响其他容器,并且可以快速重新启动。 得益于这种隔离机制,安全性也得到了保障。 例如,利用裸机上的 Web 服务器漏洞可能会让攻击者访问整个服务器,但如果使用的是容器,攻击者只能访问 Web 服务器容器。

轻量

由于容器不需要单独的操作系统,只需几秒钟即可启动、停止或重新启动,从而可以加快所有相关开发流程并缩短生产时间。 您可以更快地开始工作,并且无需花费任何时间进行配置。

不可变性

不可变基础架构由不可变组件组成,每次部署时都会替换这些组件,而不是就地更新。 这些组件通过每次部署构建一次的通用镜像启动,可以进行测试和验证。不可变性减少了不一致情况,并且可以轻松地在应用程序的不同状态之间进行复制和移动。 详细了解不可变性

新可能

利用上文提到的所有优势,我们可以通过全新的方式管理基础架构和工作流。

编排

裸机或虚拟机环境存在一个问题 – 它们具有个体性,这一问题会在使用过程中带来许多意外,而这些意外通常不尽如人意。 解决这一问题的方法是基础架构即代码 – 利用 DevOps 团队为源代码使用的版本控制方法,采用描述性模型管理基础架构。

通过基础架构即代码,无论环境的起始状态如何,部署命令始终会将目标环境设为相同的配置。 要实现这一点,可自动配置现有目标,也可以丢弃现有目标并重新创建全新的环境。

因此,利用基础架构即代码,团队会更改环境描述并对配置模型进行版本控制,而配置模型通常采用 JSON 等归档完好的代码格式。 发布管道会执行该模型,以配置目标环境。 如果团队需要进行更改,则可以编辑源代码,而不是目标环境。

借助容器,这一切都可以实现,并且实施起来简单得多。 关闭容器并启动一个新容器只需几秒钟,而配置新虚拟机则需要几分钟。 我甚至都没有提到将服务器回滚到空白状态。

扩缩

基于之前的描述,您可能认为基础架构即代码本身是静态的。 并不是这样,因为编排工具也可以根据当前工作负载提供横向扩缩(进行更多相同的配置)。 您仅应运行目前需要的容器,并相应地扩缩应用程序。 这样还可以降低成本。

结论

容器可以简化开发流程。 消除了环境之间的不一致,可以更轻松地进行测试和调试。 可以通过编排构建可扩缩应用程序。可以轻松实现部署或回滚到不可变历史的任意点。

组织希望在更高层级上处理任务,其中所有上述问题均已得到解决,并且我们发现调度程序和编排程序以自动方式为我们处理更多的任务。

后续内容

在下一篇文章中,我们将探讨使用容器进行配置,并创建利用 InterSystems IRIS Docker 容器的 CD 配置。

0
0 100
文章 Michael Lei · 九月 27, 2024 8m read

在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:

  • Git 101
  • Git 流程(开发流程)
  • GitLab 安装
  • GitLab 工作流
  • 持续交付
  • GitLab 安装和配置
  • GitLab CI/CD

第一篇文章中,我们介绍了 Git 基础知识、深度理解 Git 概念对现代软件开发至关重要的原因,以及如何使用 Git 开发软件。

第二篇文章中,我们介绍了 GitLab 工作流 – 一个完整的软件生命周期流程,并介绍了持续交付。

第三篇文章中,我们介绍了 GitLab 安装和配置以及将环境连接到 GitLab

在这篇文章中,我们将介绍编写 CD 配置。

计划

环境

首先,我们需要多个环境以及与之对应的分支:

环境分支交付有权提交的角色有权合并的角色
测试master自动开发者、所有者开发者、所有者
预生产preprod自动所有者
生产prod半自动(按下按钮进行交付)

所有者

开发周期

作为示例,我们将使用 GitLab 流程开发一个新功能,并使用 GitLab CD 进行交付。

  1. 在功能分支中开发功能。
  2. 对功能分支进行审查并将其合并到 master 分支中。
  3. 一段时间(合并了多个功能)后,将 master 分支合并到 preprod 分支中
  4. 一段时间(用户测试等)后,将 preprod 分支合并到 prod 分支中

具体如下图所示(我用草图标出了我们需要为 CD 开发的部分):

  1. 开发和测试
    • 开发者将新功能的代码提交到单独的功能分支中
    • 功能稳定后,开发者将功能分支合并到 master 分支中
    • 来自 master 分支的代码被交付到测试环境,在其中进行加载和测试
  2. 交付到预生产环境
    • 开发者创建从 master 分支到 preprod 分支的合并请求
    • 仓库所有者在一段时间后批准合并请求
    • 来自 preprod 分支的代码被交付到预生产环境
  3. 交付到生产环境
    • 开发者创建从 preprod 分支到 prod 分支的合并请求
    • 仓库所有者在一段时间后批准合并请求
    • 仓库所有者按下“部署”按钮
    • 来自 prod 分支的代码被交付到生产环境

也可以用示意图形式表示此流程:

应用程序

应用程序由两部分组成:

  • 在 InterSystems 平台上开发的 REST API
  • 客户端 JavaScript web 应用程序

阶段

通过上面的计划,我们可以确定需要在持续交付配置中定义的阶段:

  • 加载 – 将服务器端代码导入 InterSystems IRIS
  • 测试 – 测试客户端和服务器代码
  • 封装 – 构建客户端代码
  • 部署 – 使用 Web 服务器“发布”客户端代码

以下是它在 gitlab-ci.yml 配置文件中的样式:

stages:
  - load
  - test
  - package
  - deploy

脚本

加载

下面我们来定义脚本。 脚本文档。 我们先来定义用于加载服务器端代码的脚本 load server

load server:
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test
  stage: load
  script: csession IRIS "##class(isc.git.GitLab).load()"

脚本会执行哪些操作?

  • load server 是脚本名称
  • 接下来,我们来描述此脚本运行的环境
  • only: master – 告知 GitLab 此脚本仅应在向 master 分支进行提交时运行
  • tags: test 指定此脚本仅应在具有 test 标签的运行程序上运行
  • stage 指定脚本的阶段
  • script 定义要执行的代码 在本例中,我们从 isc.git.GitLab 类调用类方法 load

重要说明

对于 InterSystems IRIS,请将 csession 替换为 iris session

对于 Windows,请使用:irisdb -s ../mgr -U TEST "##class(isc.git.GitLab).load()

现在,我们来编写相应的 isc.git.GitLab 类。 此类中的所有入口点如下所示:

ClassMethod method()
{
    try {
        // code
        halt
    } catch ex {
        write !,$System.Status.GetErrorText(ex.AsStatus()),!
        do $system.Process.Terminate(, 1)
    }
}

请注意,可以通过两种方式结束此方法:

  • 停止当前进程 – 在 GitLab 中注册为成功完成
  • 调用  $system.Process.Terminate – 异常终止进程,GitLab 将此情况注册为错误

因此,加载代码如下:

/// Do a full load
/// do ##class(isc.git.GitLab).load()
ClassMethod load()
{
    try {
        set dir = ..getDir()
        do ..log("Importing dir " _ dir)
        do $system.OBJ.ImportDir(dir, ..getExtWildcard(), "c", .errors, 1)
        throw:$get(errors,0)'=0 ##class(%Exception.General).%New("Load error")
    halt
} catch ex {
    write !,$System.Status.GetErrorText(ex.AsStatus()),!
    do $system.Process.Terminate(, 1)
}

}

调用了两个实用方法:

  • getExtWildcard – 获取相关文件扩展名列表
  • getDir – 获取仓库目录

如何获取目录?

执行脚本时,GitLab 会先指定很多环境变量。 其中一个环境变量是 CI_PROJECT_DIR – 克隆仓库以及运行作业位置的完整路径。 我们可以通过 getDir 方法轻松获取:

ClassMethod getDir() [ CodeMode = expression ]
{
##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR"))
}


测试

以下是测试脚本:

load test:
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test
  stage: test
  script: csession IRIS "##class(isc.git.GitLab).test()"
  artifacts:
    paths:
      - tests.html

有哪些更改? 当然是名称和脚本代码,但还添加了工件。 工件是作业成功完成后附加到作业的文件和目录列表。 本例中,测试完成后,我们可以生成重定向到测试结果的 HTML 页面,并使其可以通过 GitLab 访问。

请注意,加载阶段有很多复制粘贴的内容 – 环境是相同的,脚本部分(例如环境)可以单独标记并附加到脚本。 我们来定义测试环境:

.env_test: &env_test
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test

现在,我们的脚本如下:

load test:
  <<: *env_test
  script: csession IRIS "##class(isc.git.GitLab).test()"
  artifacts:
    paths:
      - tests.html

接下来,我们使用 UnitTest 框架执行测试。

/// do ##class(isc.git.GitLab).test()
ClassMethod test()
{
    try {
        set tests = ##class(isc.git.Settings).getSetting("tests")
        if (tests'="") {
            set dir = ..getDir()
            set ^UnitTestRoot = dir
        $$$TOE(sc, ##class(%UnitTest.Manager).RunTest(tests, "/nodelete"))
        $$$TOE(sc, ..writeTestHTML())
        throw:'..isLastTestOk() ##class(%Exception.General).%New("Tests error")
    }
    halt
} catch ex {
    do ..logException(ex)
    do $system.Process.Terminate(, 1)
}

}

本例中,测试设置是相对于存储单元测试的仓库根目录的路径。 如果此处为空,则跳过测试。 writeTestHTML 方法用于输出重定向到测试结果的 html:

ClassMethod writeTestHTML()
{
    set text = ##class(%Dictionary.XDataDefinition).IDKEYOpen($classname(), "html").Data.Read()
    set text = $replace(text, "!!!", ..getURL())
set file = ##class(%Stream.FileCharacter).%New()
set name = ..getDir() _  "tests.html"
do file.LinkToFile(name)
do file.Write(text)
quit file.%Save()

}

ClassMethod getURL() { set url = ##class(isc.git.Settings).getSetting("url") set url = url _ $system.CSP.GetDefaultApp("%SYS") set url = url_"/%25UnitTest.Portal.Indices.cls?Index="_ $g(^UnitTest.Result, 1) _ "&$NAMESPACE=" _ $zconvert($namespace,"O","URL") quit url }

ClassMethod isLastTestOk() As %Boolean { set in = ##class(%UnitTest.Result.TestInstance).%OpenId(^UnitTest.Result) for i=1:1:in.TestSuites.Count() { #dim suite As %UnitTest.Result.TestSuite set suite = in.TestSuites.GetAt(i) return:suite.Status=0 $$$NO } quit $$$YES }

XData html { <html lang="en-US"> <head> <meta charset="UTF-8"/> <meta http-equiv="refresh" content="0; url=!!!"/> <script type="text/javascript"> window.location.href = "!!!" </script> </head> <body> If you are not redirected automatically, follow this <a href='!!!'>link to tests</a>. </body> </html> }

封装

我们的客户端是一个简单的 HTML 页面:

<html>
<head>
<script type="text/javascript">
function initializePage() {
  var xhr = new XMLHttpRequest();
  var url = "${CI_ENVIRONMENT_URL}:57772/MyApp/version";
  xhr.open("GET", url, true);
  xhr.send();
  xhr.onloadend = function (data) {
    document.getElementById("version").innerHTML = "Version: " + this.response;
  };

var xhr = new XMLHttpRequest(); var url = "${CI_ENVIRONMENT_URL}:57772/MyApp/author"; xhr.open("GET", url, true); xhr.send(); xhr.onloadend = function (data) { document.getElementById("author").innerHTML = "Author: " + this.response; }; } </script> </head> <body onload="initializePage()"> <div id = "version"></div> <div id = "author"></div> </body> </html>

要进行构建,需要将 ${CI_ENVIRONMENT_URL} 替换为其值。 当然,实际应用程序可能需要 npm,但此处仅为了举例说明。 脚本如下:

package client:
  <<: *env_test
  stage: package
  script: envsubst < client/index.html > index.html
  artifacts:
    paths:
      - index.html

部署

最后,我们将 index.html 部署到 Web 服务器根目录,以部署客户端。

deploy client:
  <<: *env_test
  stage: deploy
  script: cp -f index.html /var/www/html/index.html

就是这些!

多个环境

如果您需要在多个环境中执行相同(相似)的脚本,应该如何操作? 脚本部分也可以是标签,因此下面给出了在测试和预生产环境中加载代码的示例配置:

stages:
  - load
  - test

.env_test: &env_test environment: name: test url: http://test.hostname.com only: - master tags: - test

.env_preprod: &env_preprod environment: name: preprod url: http://preprod.hostname.com only: - preprod tags: - preprod

.script_load: &script_load stage: load script: csession IRIS "##class(isc.git.GitLab).loadDiff()"

load test: <<: *env_test <<: *script_load

load preprod: <<: *env_preprod <<: *script_load

通过这种方式,我们便无需复制粘贴代码。

有关完整的 CD 配置,请参阅此处。 该配置遵循在测试、预生产和生产环境之间移动代码的原始计划。

结论

可以将持续交付配置为自动执行任何所需的开发工作流。

链接

后续内容

在下一篇文章中,我们将创建利用 InterSystems IRIS Docker 容器的 CD 配置。

0
0 104
文章 Michael Lei · 九月 26, 2024 7m read

在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:

  • Git 101
  • Git 流程(开发流程)
  • GitLab 安装
  • GitLab 工作流
  • 持续交付
  • GitLab 安装和配置
  • GitLab CI/CD

上一篇文章中,我们介绍了 Git 基础知识、深度理解 Git 概念对现代软件开发至关重要的原因,以及如何使用 Git 开发软件。 我们的侧重点仍是软件开发的实现部分,但本部分会介绍:

  • GitLab 工作流 - 从想法到用户反馈的完整软件生命周期流程
  • 持续交付 – 软件工程方式,团队通过这种方式在短周期内制作软件,从而确保软件可以随时实现可靠发布。 它的目的是更快速、更频繁地构建、测试和发布软件。

GitLab 工作流


GitLab 工作流是软件开发流程整个生命周期中可能采取的操作的逻辑序列。

GitLab 工作流会考虑我们在上一篇文章中探讨的 GitLab 流程。 具体如下:

  1. 想法:每个新提议都始于一个想法。
  2. 问题:探讨想法最有效的方法是为它创建问题。 您的团队和协作者可以在问题跟踪器中帮助您完善和改进问题。
  3. 计划:在讨论达成一致意见后,就可以开始编码了。 但首先,我们需要将问题指定至里程碑和问题看板,以此确定工作流的优先级并进行组织。
  4. 编码:现在,一切安排就绪后,我们就可以编写代码了。
  5. 提交:对草稿满意后,我们便可将代码提交到具有版本控制的功能分支。 上一篇文章详细介绍了 GitLab 流程。
  6. 测试:使用 GitLab CI 运行我们的脚本,以构建并测试应用程序。
  7. 审查:在脚本能够正常运行且测试和构建成功后,我们便可以让代码接受审查并获得批准。
  8. 暂存:现在应该将代码部署到暂存环境,以检查一切是否按预期进行,或者我们是否仍需要进行调整。
  9. 生产:如果一切顺利,便可将代码部署到生产环境!
  10. 反馈:现在可以回顾之前的流程,并检查有哪些阶段的工作需要改进。

再次说明,流程本身不是新的(或者 GitLab 独有的),并且可以通过其他工具来实现。

我们来讨论一下其中的几个阶段以及这些阶段涉及的内容。 还提供文档

问题和计划

GitLab 工作流的开始阶段以问题为中心,问题是指一个功能、一个错误或其他在语义上独立的工作。

问题有多个目的,例如:

  • 管理:问题具有截止日期、指定人员、用时和估计等, 可以帮助跟踪问题解决情况。
  • 行政管理:问题是里程碑的一部分,我们可以通过看板跟踪软件从一个版本过渡到另一个版本的进展。
  • 开发:问题具有与之相关的讨论和提交。

在计划阶段,我们可以按问题的优先级、里程碑、看板将问题分组,并获得问题的概览。

开发在前一部分进行了讨论,只需按照您希望使用的任何 git 流程执行操作即可。 我们开发了新功能并将其合并到 master 分支后,接下来应怎样操作?

持续交付

持续交付是一种软件工程方式,团队通过这种方式在短周期内制作软件,从而确保软件可以随时实现可靠发布。 它的目的是更快速、更频繁地构建、测试和发布软件。 这种方式允许对生产中的应用程序进行更多增量更新,从而帮助缩减交付更改的成本、缩短时间,以及降低风险。 简单且可重复的部署过程对于持续交付非常重要。

GitLab 中的持续交付

在 GitLab 中,持续交付配置按仓库以 YAML 配置文件形式定义。

  • 持续交付配置是一系列连续的阶段
  • 每个阶段都有一个或多个并行执行的脚本

脚本定义了一个操作以及执行该操作需要满足的条件:

  • 要执行的操作(运行 OS 命令、运行容器)?
  • 何时运行脚本:
    • 触发脚本的条件(特定分支)?
    • 之前的阶段失败时是否运行?
  • 手动运行还是自动运行?
  • 脚本在什么环境中运行?
  • 执行脚本后保存哪些工件(这些工件会从环境上传到 GitLab,以便轻松访问)?

环境是配置好的服务器或容器,可用于运行脚本。

运行程序用于在特定环境中执行脚本。 运行程序连接到 GitLab,并根据需要执行脚本。

运行程序可以部署在服务器上、容器上,甚至部署在本地机器上。

持续交付是如何实现的?

  1. 新提交推送到仓库中。
  2. GitLab 检查持续交付配置。
  3. 持续交付配置包含适用于所有情况的全部脚本,因此要过滤出应针对这一特定提交运行的一组脚本(例如提交到 master 分支仅会触发与 master 分支相关的操作)。 这组脚本称为管道
  4. 管道是在目标环境中执行的,执行结果会保存并显示在 GitLab 中。

例如,下面是提交到 master 分支后执行的一个管道:

管道包含四个阶段,各阶段连续执行

  1. 加载阶段会将代码加载到服务器中
  2. 测试阶段会运行单元测试
  3. 封装阶段包含两个并行运行的脚本:
    • 构建客户端
    • 导出服务器代码(主要用于提供信息)
  4. 部署阶段会将构建的客户端移动到 Web 服务器目录中。

我们可以看到,每个脚本都成功运行,如果其中一个脚本运行失败,则默认不会运行后面的脚本(但我们可以更改此行为):

如果我们打开脚本,可以查看日志并确定脚本运行失败的原因:

Running with gitlab-runner 10.4.0 (857480b6)
 on test runner (ab34a8c5)
Using Shell executor...
Running on gitlab-test...
Fetching changes...
Removing diff.xml
Removing full.xml
Removing index.html
Removing tests.html
HEAD is now at a5bf3e8 Merge branch '4-versiya-1-0' into 'master'
From http://gitlab.eduard.win/test/testProject
 * [new branch] 5-versiya-1-1 -> origin/5-versiya-1-1
 a5bf3e8..442a4db master -> origin/master
 d28295a..42a10aa preprod -> origin/preprod
 3ac4b21..7edf7f4 prod -> origin/prod
Checking out 442a4db1 as master...Skipping Git submodules setup$ csession ensemble "##class(isc.git.GitLab).loadDiff()"

[2018-03-06 13:58:19.188] Importing dir /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/

[2018-03-06 13:58:19.188] Loading diff between a5bf3e8596d842c5cc3da7819409ed81e62c31e3 and 442a4db170aa58f2129e5889a4bb79261aa0cad0

[2018-03-06 13:58:19.192] Variable modified var=$lb("MyApp/Info.cls")

Load started on 03/06/2018 13:58:19 Loading file /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/MyApp/Info.cls as udl Load finished successfully.

[2018-03-06 13:58:19.241] Variable items var="MyApp.Info.cls" var("MyApp.Info.cls")=""

Compilation started on 03/06/2018 13:58:19 with qualifiers 'cuk /checkuptodate=expandedonly' Compiling class MyApp.Info Compiling routine MyApp.Info.1 ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1] TEXT: quit, "1.0" } Detected 1 errors during compilation in 0.010s.

[2018-03-06 13:58:19.252] ERROR #5475: Error compiling routine: MyApp.Info.1. Errors: ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1] > ERROR #5030: An error occurred while compiling class 'MyApp.Info' ERROR: Job failed: exit status 1

编译错误导致脚本失败。

结论

  • GitLab 支持软件开发的所有主要阶段。
  • 持续交付可以帮助您自动执行软件构建、测试和部署任务。

后续内容

在下一篇文章中,我们将:

  • 安装 GitLab。
  • 将它连接到多个安装了 InterSystems 产品的环境。
  • 编写持续交付配置。

我们来探讨一下持续交付的运作方式。

首先,我们需要多个环境以及与之对应的分支。 代码进入此分支,并交付到目标环境:

环境分支交付有权提交的角色有权合并的角色
测试master自动开发者、所有者开发者、所有者
preprod预生产自动所有者
prod生产半自动(按下按钮进行交付)

所有者

作为示例,我们将使用 GitLab 流程开发一个新功能,并使用 GitLab CD 进行交付。

  1. 在功能分支中开发功能。
  2. 对功能分支进行审查并将其合并到 master 分支中。
  3. 一段时间(合并了多个功能)后,将 master 分支合并到 preprod 分支中
  4. 一段时间(用户测试等)后,将 preprod 分支合并到 prod 分支中

具体如下图所示:

  1. 开发和测试
    • 开发者将新功能的代码提交到单独的功能分支中
    • 功能稳定后,开发者将功能分支合并到 master 分支中
    • 来自 master 分支的代码被交付到测试环境,在其中进行加载和测试
  2. 交付到预生产环境
    • 开发者创建从 master 分支到 preprod 分支的合并请求
    • 仓库所有者在一段时间后批准合并请求
    • 来自 preprod 分支的代码被交付到预生产环境
  3. 交付到生产环境
    • 开发者创建从 preprod 分支到 prod 分支的合并请求
    • 仓库所有者在一段时间后批准合并请求
    • 仓库所有者按下“部署”按钮
    • 来自 prod 分支的代码被交付到生产环境

也可以用示意图形式表示此流程:

 

0
0 98
文章 Michael Lei · 九月 26, 2024 6m read

大家都搭建了测试环境。

有些人很幸运,可以在完全独立的环境中运行生产。

-- 佚名

.

在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:

  • Git 101
  • Git 流程(开发流程)
  • GitLab 安装
  • GitLab 工作流
  • GitLab CI/CD
  • 包含容器的 CI/CD

第一部分将介绍现代软件开发的基础 – Git 版本控制系统和各种 Git 流程。

Git 101

虽然我们将主要探讨软件开发的概况以及 GitLab 如何帮助我们实现这一目标,但 Git,或者说 Git 设计中的几个基础的高级概念对于更好地理解后面的概念非常重要。

也就是说,Git 是基于这些概念的版本控制系统(还有更多概念,但这几个概念最为重要):

  • 非线性开发意味着,虽然我们的软件是从版本 1 到版本 2、再到版本 3 相继发布的,但实际上从版本 1 到版本 2 的升级是并行完成的 – 多名开发者会同时开发许多功能/错误修复。
  • 分布式开发意味着开发者独立于一个中央服务器或其他开发者,可以轻松地在自己的环境中进行开发。
  • 合并 – 基于前面提到的两个概念,我们会发现很多不同的版本同时存在,我们需要将它们统一成一个完整的状态。

我的意思不是说 Git 发明了这些概念。 Git 并没有发明这些概念, 而是使这些概念变得简单、流行,并加入了多个相关创新概念,也就是说,架构即代码/容器化改变了软件开发。

核心 git 术语

仓库是存储数据以及关于数据的元信息的项目。

  • “从物理层面来讲”,仓库是磁盘上的目录。
  • 仓库用于存储文件和目录。
  • 仓库还会存储每个文件的完整变更历史。

仓库可以:

  • 存储在您自己的计算机本地
  • 远程存储在远程服务器上

但从 git 的角度来看,本地仓库与远程仓库之间没有特殊的区别。

提交是仓库的固定状态。 很显然,如果每次提交都存储仓库的完整状态,我们的仓库很快就会变得非常大。 因此,提交会存储差异,也就是当前提交与其父提交之间的差异。

不同的提交可以具有不同数量的父提交:

  • 0 个 – 仓库中的第一个提交没有父提交。
  • 1 个 – 一切如常 - 我们的提交改变了仓库中的某些内容,就像在父提交期间一样
  • 2 个 – 当我们有两个不同的仓库状态时,我们可以将它们合并成一个新状态。 该状态和该提交就会有 2 个父提交。
  • >2 个 – 当我们将 2 个以上的不同仓库状态合并为一个新状态时,就会有 2 个以上的父提交。 这一概念与我们的讨论并没有特别大的关系,但它确实存在。

现在,对于父提交,每个与之不同的提交都被称为子提交。 每个父提交可以有任意数量的子提交。

分支是对提交的引用(或指针),如下图所示:

该图像显示的仓库具有两个提交(灰色圆圈),第二个圆圈是 master 分支的头部。 在我们添加更多提交后,仓库开始变成下图所示的状态:

这是最简单的情况。 我们的开发者一次负责处理一个更改。 但通常会有很多开发者同时负责处理不同的功能,我们需要使用提交树显示仓库中的变化。

提交树

我们从相同的起始状态开始。 仓库具有两个提交:

但现在,两名开发者在同时工作,为了避免相互干扰,他们在单独的分支中工作:

一段时间后,他们需要合并所做的更改,为此,他们创建了合并请求(也叫拉取请求), 顾名思义,该请求可将两个不同的仓库状态(本例中,我们要将 develop 分支合并到 master 分支中)合并为一个新状态。 接受相应审查并获得批准后,仓库状态如下图所示:

开发继续进行:

Git 101 - 总结

主要概念:

  • Git 是一个非线性的分布式版本控制系统。
  • 仓库用于存储数据以及关于数据的元信息。
  • 提交是仓库的固定状态。
  • 分支是对提交的引用。
  • 合并请求(也叫拉取请求)是将两个不同的仓库状态合并为一个新状态的请求。

如果您想了解更多关于 Git 的信息,可以阅读相关书籍

Git 流程

现在,读者已熟悉基本的 Git 术语和概念,我们来探讨一下如何使用 Git 管理软件生命周期的开发部分。很多实践(称为流程)介绍了使用 Git 的开发流程,但我们只会探讨其中两个:

  • GitHub 流程
  • GitLab 流程

GitHub 流程

GitHub 流程非常简单。 具体如下:

  1. 从仓库创建一个分支。
  2. 将更改提交到新分支
  3. 从您的分支发送一个拉取请求,其中包含您提议的更改,以发起讨论。
  4. 根据需要在您的分支上提交更多更改。 您的拉取请求将自动更新。
  5. 在分支准备好合并后,立即合并拉取请求。

我们需要遵守几条规则:

  • master 分支始终可部署(并且可正常运行!)
  • 不直接在 master 分支中进行开发
  • 在功能分支中进行开发
  • master 分支 == 生产* 环境**
  • 需要尽可能频繁地部署到生产环境

* 不要与“Ensemble 生产”混淆,这里的“生产”是指正式。

** 环境是配置好的代码运行位置,可以是服务器、虚拟机,甚至可以是容器。

如下图所示:

有关 GitHub 流程的更多信息,请参阅此处。 我们还提供了图解指南

GitHub 流程非常适合小型项目,如果您刚开始使用 Git 流程,可以尝试一下。 不过,GitHub 也会使用 GitHub 流程,因此也可以在大型项目中使用 GitHub 流程。

GitLab 流程

如果您还没有准备好立即部署到生产环境,GitLab 流程提供 GitHub 流程 + 环境。 具体做法是:在功能分支中进行开发(与上例相同),合并到 master 分支中(与上例相同),但这里有一个不同之处: master 分支仅等同于测试环境。 除此之外,还有链接到可能存在的各种其他环境的“环境分支”。

通常存在三个环境(可以根据需要创建更多环境):

  • 测试环境 == master 分支
  • 预生产环境 == preprod 分支
  • 生产环境 == prod 分支

进入其中一个环境分支的代码应立即移至相应的环境中,此流程可通过以下方式完成:

  • 自动(我们将在第 2 部分和第 3 部分探讨)
  • 半自动(与自动方式相同,唯一的区别是应按下按钮授权部署)
  • 手动

完整的流程是:

  1. 在功能分支中开发功能。
  2. 对功能分支进行审查并将其合并到 master 分支中。
  3. 一段时间(合并了多个功能)后,将 master 分支合并到 preprod 分支中
  4. 一段时间(用户测试等)后,将 preprod 分支合并到 prod 分支中
  5. 在我们进行合并和测试时,多个新功能已开发完毕并合并到 master 分支中,因此转到  3。

具体如下图所示:

有关 GitLab 流程的更多信息,请参阅此处

结论

  • Git是一个非线性的分布式版本控制系统。
  • Git 流程可用作软件开发周期的准则,有多种 Git 流程可供选择。

链接

讨论问题

  • 您使用 Git 流程吗? 使用哪一种?
  • 您为普通项目使用多少个环境?

后续内容

在接下来的部分中,我们将:

  • 安装 GitLab。
  • 探讨一些建议的调整。
  • 讨论 GitLab 工作流(不要与 GitLab 流程混淆)。

敬请关注。

0
0 129
文章 Jingwei Wang · 三月 28, 2023 5m read

IRIS 配置和用户帐户包含需要跟踪的各种数据元素,许多人难以在 IRIS 实例之间复制或同步这些系统配置和用户帐户。那么如何简化这个过程呢?

在软件工程中,CI/CD 或 CICD 是持续集成 (CI) 和(更常见的)持续交付或(较少见的)持续部署 (CD) 的组合实践集。 CI/CD 能消除我们所有的挣扎吗?

我在一个开发和部署 IRIS 集群的团队工作。我们在 Red Hat OpenShift 容器平台上的容器中运行 IRIS。

如果您当前没有使用 Kubernetes,请不要停止阅读。即使您没有使用 Kubernetes 或在容器中运行 IRIS,您也可能会遇到与我和我的团队面临的挑战类似的挑战。

我们决定将代码与配置分开,并将它们放在不同的 GitHub 存储库中。每次在代码库中进行提交时,都会触发管道运行。结果,从代码库中的文件构建了一个新image。

我们通过将 YAML 文件和其他配置工件添加到部署 GitHub 存储库,将配置定义为以 GitOps 方式使用的代码。 GitOps 是一个软件开发框架,它使组织能够持续交付软件应用程序,同时使用 Git 作为单一事实来源有效地管理 IT 基础设施(以及更多)。 GitOps 的好处之一是能够轻松回滚。您所需要做的就是恢复到 Git 中的先前状态。

0
0 315