如何在 Ubuntu 上使用 GitLab CI/CD 设置持续部署管道
介绍
GitLab 是一个开源协作平台,除了托管代码存储库之外,它还提供强大的功能。您可以跟踪问题、托管包和注册表、维护 Wiki、设置持续集成 (CI) 和持续部署 (CD) 管道等等。
在本教程中,您将使用 GitLab 构建持续部署管道。您将配置管道来构建 Docker 映像,将其推送到 GitLab 容器注册表,并使用 SSH 将其部署到您的服务器。管道将为推送到存储库的每个提交运行。
您将部署一个小型静态网页,但本教程的重点是配置 CD 管道。静态网页仅用于演示目的;您也可以使用其他 Docker 映像来应用相同的管道配置进行部署。
完成本教程后,您可以在浏览器中访问 http://your_server_IP
查看自动部署的结果。
使用 DigitalOcean 应用程序平台从 GitHub 部署前端应用程序。让 DigitalOcean 专注于扩展您的应用程序。
先决条件
如果您使用的是 Ubuntu 16.04 或更低版本,我们建议您升级到更新版本,因为 Ubuntu 不再提供对这些版本的支持。这本指南集将帮助您升级 Ubuntu 版本。
要完成本教程,您将需要:
- 运行 Ubuntu 的服务器,以及具有 sudo 权限的非 root 用户和活动防火墙。有关如何设置这些的指南,请从此列表中选择您的发行版并遵循我们的初始服务器设置指南。您至少需要 1 GB RAM 和 1 个 CPU。
- 按照“如何在 Ubuntu 上安装和使用 Docker”22.04/20.04/18.04 中的指南在服务器上安装 Docker。
- 已启用容器注册表的 GitLab 实例上的用户帐户。 GitLab官方实例的免费方案满足要求。您还可以按照“如何在 Ubuntu 上安装和配置 GitLab”20.04/18.04 指南托管自己的 GitLab 实例。
Gitlab 上的持续开发管道设置
- 创建Gitlab存储库
- 注册 Gitlab Runner
- 创建部署用户
- 设置 SSH 密钥
- 在 Gitlab 中存储 SSH 密钥
- 配置 Gitlab CI/CD 管道
- 验证部署
- 如何回滚部署
第 1 步 — 创建 GitLab 存储库
让我们首先创建一个 GitLab 项目并向其中添加一个 HTML 文件。稍后您会将 HTML 文件复制到 Nginx Docker 映像中,然后将其部署到服务器。
登录到您的 GitLab 实例并单击新建项目。
- 从创建新项目屏幕中,选择创建空白项目。
- 为其指定一个正确的项目名称。
- (可选)添加项目部署目标。
- 确保根据您的要求将可见性级别设置为私有或公开。
- 最后点击创建项目。
您将被重定向到项目的概述页面。
让我们创建 HTML 文件。在项目的概述页面上,点击 + > 新文件。
将文件名设置为index.html
,并将以下 HTML 添加到文件正文:
<html>
<body>
<h1>My Personal Website</h1>
</body>
</html>
单击页面底部的提交更改以创建文件。
当在浏览器中打开时,此 HTML 将生成一个带有一个标题的空白页面,其中显示我的个人网站。
Dockerfile 是 Docker 用于构建 Docker 映像的配方。让我们创建一个 Dockerfile
将 HTML 文件复制到 Nginx 映像中。
返回项目的概述页面,单击+按钮并选择新建文件选项。
将文件名设置为Dockerfile
并将以下指令添加到文件正文中:
FROM nginx:1.18
COPY index.html /usr/share/nginx/html
FROM
指令指定要继承的映像,在本例中为 nginx:1.18
映像。 1.18
是代表 Nginx 版本的镜像标签。 nginx:latest
标签引用最新的 Nginx 版本,但这可能会在将来破坏您的应用程序,这就是为什么建议使用固定版本。
COPY
指令将 index.html
文件复制到 Docker 镜像中的 /usr/share/nginx/html
中。这是 Nginx 存储静态 HTML 内容的目录。
单击页面底部的提交更改以创建文件。
在下一步中,您将配置 GitLab 运行程序来控制谁可以执行部署作业。
第 2 步 — 注册 GitLab Runner
为了跟踪将与 SSH 私钥联系的环境,您将您的服务器注册为 GitLab 运行程序。
在部署管道中,您希望使用 SSH 登录到服务器。为此,您将 SSH 私钥存储在 GitLab CI/CD 变量中(步骤 5)。 SSH 私钥是一个非常敏感的数据,因为它是您服务器的进入门票。通常,私钥永远不会离开生成它的系统。通常情况下,您会在主机上生成 SSH 密钥,然后在服务器上对其进行授权(即将公钥复制到服务器),以便手动登录并执行部署例程。
这里情况略有变化:您希望授予自治机构 (GitLab CI/CD) 访问您的服务器的权限,以自动执行部署例程。因此,私钥需要离开生成它的系统,并委托给 GitLab 和其他相关方。您永远不希望您的私钥进入不受您控制或信任的环境。
除了 GitLab 之外,GitLab runner 是您的私钥将进入的另一个系统。对于每个管道,GitLab 使用运行程序来执行繁重的工作,即执行您在 CI/CD 配置中指定的作业。这意味着部署作业最终将在 GitLab 运行器上执行,因此私钥将被复制到运行器,以便它可以使用 SSH 登录服务器。
如果您使用未知的 GitLab 运行程序(例如共享运行程序)来执行部署作业,那么您将不会意识到系统与私钥的联系。尽管 GitLab 运行程序会在作业执行后清理所有数据,但您可以通过将自己的服务器注册为 GitLab 运行程序来避免将私钥发送到未知系统。然后私钥将被复制到您控制的服务器上。
首先登录您的服务器:
ssh sammy@your_server_IP
为了安装 gitlab-runner 服务,您需要添加官方 GitLab 存储库。下载并检查安装脚本:
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
成功执行后,将返回以下消息:
The repository is setup! You can now install packages.
要安装 gitlab-runner 包,请在终端中运行以下命令:
sudo apt-get install gitlab-runner
当您执行前面的命令时,输出将类似于:
[sudo] password for sammy: % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5945 100 5945 0 0 8742 0 --:--:-- --:--:-- --:--:-- 8729
在curl命令执行完成后,通过检查服务状态来验证安装:
systemctl status gitlab-runner
输出中将显示 active (running)
:
● gitlab-runner.service - GitLab Runner
Loaded: loaded (/etc/systemd/system/gitlab-runner.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-06-01 09:01:49 UTC; 4s ago
Main PID: 16653 (gitlab-runner)
Tasks: 6 (limit: 1152)
CGroup: /system.slice/gitlab-runner.service
└─16653 /usr/lib/gitlab-runner/gitlab-runner run --working-directory /home/gitlab-runner --config /etc/gitla
要注册运行器,您需要获取项目令牌和 GitLab URL:
- 在您的 GitLab 项目中,导航至设置 > CI/CD > 运行器 > 展开。
- 在项目运行程序部分中,单击新建项目运行程序并按照表单为您的项目创建新的运行程序。
- 跑步者就位后,您将找到注册令牌和GitLab URL。将两者复制到文本编辑器;您将需要它们来执行下一个命令。它们将被称为
https://your_gitlab.com
和project_token
。
返回您的终端,为您的项目注册运行器:
sudo gitlab-runner register -n --url https://your_gitlab.com --registration-token project_token --executor docker --description "Deployment Runner" --docker-image "docker:stable" --tag-list deployment --docker-privileged
命令选项可以解释如下:
-n
以非交互方式执行register
命令(我们将所有参数指定为命令选项)。--url
是您从 GitLab 中的运行者页面复制的 GitLab URL。--registration-token
是您从 GitLab 中的运行者页面复制的令牌。--executor
是执行器类型。docker
在 Docker 容器中执行每个 CI/CD 作业(请参阅 GitLab 有关执行器的文档)。--description
是运行程序的描述,它将显示在 GitLab 中。- 如果未明确指定,
--docker-image
是 CI/CD 作业中使用的默认 Docker 映像。 --tag-list
是分配给跑步者的标签列表。标签可用于管道配置中,为 CI/CD 作业选择特定的运行程序。deployment
标签将允许您引用此特定的运行器来执行部署作业。--docker-privileged
在特权模式下执行为每个 CI/CD 作业创建的 Docker 容器。特权容器可以访问主机上的所有设备,并且与容器外部运行的进程具有几乎相同的主机访问权限(请参阅 Docker 的有关运行时权限和 Linux 功能的文档)。在特权模式下运行的原因是您可以使用 Docker-in-Docker (dind) 在 CI/CD 管道中构建 Docker 映像。为容器提供所需的最低要求是一种很好的做法。对于您来说,需要在特权模式下运行才能使用 Docker-in-Docker。请注意,您仅为该特定项目注册了运行程序,您可以控制在特权容器中执行的命令。
执行 gitlab-runner register 命令后,您将收到以下输出:
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
转到 GitLab 中的设置 > CI/CD > 运行器来验证注册过程,其中将显示已注册的运行器。
在下一步中,您将创建一个部署用户。
第 3 步 — 创建部署用户
您将创建一个专用于部署任务的用户。您稍后将配置 CI/CD 管道以使用该用户登录服务器。
在您的服务器上创建一个新用户:
sudo adduser deployer
您将被引导完成用户创建过程。输入强密码以及您想要指定的任何其他用户信息(可选)。最后按Y
确认用户创建。
将用户添加到 Docker 组:
sudo usermod -aG docker deployer
这允许部署者执行执行部署所需的docker
命令。
警告:将用户添加到 Docker 组,将授予与 root 用户同等的权限。有关这对系统安全性有何影响的更多详细信息,请参阅 Docker Daemon Attack Surface。
在下一步中,您将创建一个 SSH 密钥,以便能够以部署者身份登录服务器。
第 4 步 — 设置 SSH 密钥
您将为部署用户创建 SSH 密钥。 GitLab CI/CD 稍后将使用该密钥登录服务器并执行部署例程。
首先切换到新创建的 deployer 用户,您将为其生成 SSH 密钥:
su deployer
系统将提示您输入部署者密码以完成用户切换。
接下来,生成 4096 位 SSH 密钥。正确回答 ssh-keygen 命令的问题非常重要:
- 第一个问题:用
ENTER
回答,它将密钥存储在默认位置(本教程的其余部分假设密钥存储在默认位置)。 - 第二个问题:配置密码来保护SSH私钥(用于身份验证的密钥)。如果您指定密码,则每次使用私钥时都必须输入该密码。一般来说,密码短语为 SSH 密钥添加了另一个安全层,这是一个很好的做法。拥有私钥的人也需要密码才能使用密钥。出于本教程的目的,拥有一个空密码非常重要,因为 CI/CD 管道将以非交互方式执行,因此不允许输入密码。
总而言之,运行以下命令并使用 ENTER
确认这两个问题,以创建 4096 位 SSH 密钥并将其使用空密码存储在默认位置:
ssh-keygen -b 4096
要为 deployer 用户授权 SSH 密钥,您需要将公钥附加到 authorized_keys
文件中:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
~
是 Linux 中用户主目录的缩写。 cat
程序将打印文件的内容;在这里,您使用 >>
运算符重定向 cat
的输出并将其附加到 authorized_keys
文件中。
在此步骤中,您已为 CI/CD 管道创建了 SSH 密钥对,用于登录和部署应用程序。接下来,您将把私钥存储在 GitLab 中,以便在管道过程中可以访问它。
步骤 5 — 将私钥存储在 GitLab CI/CD 变量中
您将把 SSH 私钥存储在 GitLab CI/CD 文件变量中,以便管道可以使用该密钥登录服务器。
当 GitLab 创建 CI/CD 管道时,它会将所有变量发送到相应的运行器,并且这些变量将在作业期间设置为环境变量。特别是,file变量的值存储在文件中,环境变量将包含该文件的路径。
当您在变量部分时,您还将为服务器 IP 和服务器用户添加一个变量,这将通知管道有关目标服务器和要登录的用户。
首先显示 SSH 私钥:
cat ~/.ssh/id_rsa
将输出复制到剪贴板。确保在 -----END RSA PRIVATE KEY-----
之后添加换行符:
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
现在导航到 GitLab 项目中的设置 > CI/CD > 变量,然后单击添加变量。填写表格如下:
- 密钥:
ID_RSA
- 值:从剪贴板粘贴 SSH 私钥(包括末尾的换行符)。
- 类型:文件
- 环境范围:全部(默认)
- 保护变量:选中
- 掩码变量:未选中
注意: 该变量无法被屏蔽,因为它不满足正则表达式要求(请参阅 GitLab 关于屏蔽变量的文档)。但是,私钥永远不会出现在控制台日志中,这使得屏蔽它变得过时。
将在运行器上为每个 CI/CD 作业创建一个包含私钥的文件,其路径将存储在 $ID_RSA
环境变量中。
使用您的服务器 IP 创建另一个变量。单击添加变量并填写表格,如下所示:
- 键:
SERVER_IP
- 值:
your_server_IP
- 类型:变量
- 环境范围:全部(默认)
- 保护变量:选中
- 掩码变量:选中
最后,使用登录用户创建一个变量。单击添加变量并填写表格,如下所示:
- 键:
SERVER_USER
- 值:
部署者
- 类型:变量
- 环境范围:全部(默认)
- 保护变量:选中
- 掩码变量:选中
您现在已将私钥存储在 GitLab CI/CD 变量中,这使得密钥在管道执行期间可用。在下一步中,您将继续配置 CI/CD 管道。
第 6 步 — 配置 .gitlab-ci.yml
文件
您将配置 GitLab CI/CD 管道。该管道将构建一个 Docker 映像并将其推送到容器注册表。 GitLab 为每个项目提供一个容器注册表。您可以通过转到 GitLab 项目中的 Packages & Registries > Container Registry 来探索容器注册表(请参阅 GitLab 的容器注册表文档了解更多信息。)管道中的最后一步是要登录到您的服务器,请拉取最新的 Docker 映像,删除旧容器,然后启动新容器。
现在您将创建包含管道配置的 .gitlab-ci.yml
文件。在 GitLab 中,转到项目概述页面,单击+按钮并选择新建文件。然后将文件名设置为.gitlab-ci.yml
。
(或者,您可以克隆存储库并对本地计算机上的 .gitlab-ci.yml
进行以下所有更改,然后提交并推送到远程存储库。)
首先添加以下内容:
stages:
- publish
- deploy
每个作业都分配给一个_stage_
。分配到同一阶段的作业并行运行(如果有足够的运行程序可用)。阶段将按照指定的顺序执行。在这里,publish
阶段将首先进行,deploy
阶段随后进行。仅当前一阶段成功完成(即所有作业均已通过)时,后续阶段才会开始。艺名可以任意选择。
当您想要将此 CD 配置与测试和构建应用程序的现有 CI 管道相结合时,您可能需要在现有阶段之后添加 publish
和 deploy
阶段,这样只有在测试通过时才会进行部署。
接下来,将其添加到您的 .gitlab-ci.yml 文件中:
. . .
variables:
TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA
变量部分定义了在作业的 script
部分上下文中可用的环境变量。这些变量将像平常的 Linux 环境变量一样可用;也就是说,您可以通过在脚本中添加美元符号(例如 $TAG_LATEST
)来引用它们。 GitLab 为每个作业创建一些预定义变量,提供上下文特定信息,例如作业正在处理的分支名称或提交哈希(了解有关预定义变量的更多信息)。在这里,您从预定义变量中组合了两个环境变量。他们代表:
CI_REGISTRY_IMAGE
:表示与特定项目关联的容器注册表的 URL。此 URL 取决于 GitLab 实例。例如,gitlab.com 项目的注册表 URL 遵循以下模式:registry.gitlab.com/your_user/your_project
。但由于 GitLab 将提供此变量,因此您不需要知道确切的 URL。CI_COMMIT_REF_NAME
:为其构建项目的分支或标记名称。CI_COMMIT_SHORT_SHA
:为其构建项目的提交修订版的前八个字符。
这两个变量均由预定义变量组成,将用于标记 Docker 镜像。
TAG_LATEST
会将 latest
标签添加到图像中。这是提供始终代表最新版本的标签的常见策略。对于每个部署,容器注册表中的最新
映像将被新构建的 Docker 映像覆盖。
另一方面,TAG_COMMIT
使用部署的提交 SHA 的前八个字符作为映像标签,从而为每个提交创建唯一的 Docker 映像。您将能够追踪 Docker 镜像的历史记录,直至 Git 提交的粒度。这是进行持续部署时的常用技术,因为它允许您在部署有缺陷的情况下快速部署旧版本的代码。
正如您将在接下来的步骤中探索的那样,将部署回滚到旧版 Git 版本的过程可以直接在 GitLab 中完成。
$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME
指定 Docker 映像基本名称。根据 GitLab 的文档,Docker 镜像名称必须遵循以下方案:
image name scheme<registry URL>/<namespace>/<project>/<image>
$CI_REGISTRY_IMAGE
表示
部分,并且是必需的,因为它是项目的注册表根。 $CI_COMMIT_REF_NAME
是可选的,但对于托管不同分支的 Docker 映像很有用。在本教程中,您将仅使用一个分支,但构建一个可扩展的结构是件好事。一般来说,GitLab 支持的镜像仓库名称分为三个级别:
repository name levelsregistry.example.com/group/project:some-tag
registry.example.com/group/project/image:latest
registry.example.com/group/project/my/image:rc1
对于您的 TAG_COMMIT
变量,您使用了第二个选项,其中 image
将替换为分支名称。
接下来,将以下内容添加到您的 .gitlab-ci.yml 文件中:
. . .
publish:
image: docker:latest
stage: publish
services:
- docker:dind
script:
- docker build -t $TAG_COMMIT -t $TAG_LATEST .
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker push $TAG_COMMIT
- docker push $TAG_LATEST
publish
部分是 CI/CD 配置中的第一项作业。让我们来分解一下:
image
是用于此作业的 Docker 映像。 GitLab 运行器将为每个作业创建一个 Docker 容器,并在该容器中执行脚本。docker:latest
映像确保docker
命令可用。stage
将作业分配给publish
阶段。services
指定 Docker-in-Docker —dind
服务。这就是您在特权模式下注册 GitLab 运行程序的原因。
publish
作业的 script
部分指定为此作业执行的 shell 命令。执行这些命令时,工作目录将设置为存储库根目录。
docker build ...
:基于Dockerfile
构建Docker镜像,并使用变量部分中定义的最新提交标签对其进行标记。docker login ...
:将 Docker 登录到项目的容器注册表中。您使用预定义变量$CI_JOB_TOKEN
作为身份验证令牌。 GitLab 将生成令牌并在作业的生命周期内保持有效。docker Push ...
:将两个镜像标签推送到容器注册表。
接下来,将 deploy
作业添加到 .gitlab-ci.yml
中:
. . .
deploy:
image: alpine:latest
stage: deploy
tags:
- deployment
script:
- chmod og= $ID_RSA
- apk update && apk add openssh-client
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY"
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT"
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f my-app || true"
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -p 80:80 --name my-app $TAG_COMMIT"
Alpine 是一个轻量级的 Linux 发行版,在这里作为 Docker 镜像就足够了。您将作业分配到deploy
阶段。部署标签确保作业将在标记为 deployment
的运行器上执行,例如您在步骤 2 中配置的运行器。
deploy
作业的 script
部分以两个配置命令开始:
chmod og= $ID_RSA
:撤销私钥中组和其他的所有权限,这样只有所有者才能使用它。这是一个要求,否则 SSH 将拒绝使用私钥。apk update && apk add openssh-client
:更新 Alpine 的包管理器 (apk) 并安装openssh-client
,它提供ssh
命令。
接下来是四个连续的 ssh 命令。每个的模式是:
ssh connect pattern for all deployment commandsssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "command"
在每个 ssh 语句中,您都在远程服务器上执行命令。为此,您需要使用您的私钥进行身份验证。
选项如下:
-i
代表身份文件,$ID_RSA
是包含私钥文件路径的 GitLab 变量。-o StrictHostKeyChecking=no
确保绕过该问题,无论您是否信任远程主机。这个问题无法在非交互式上下文(例如管道)中得到回答。$SERVER_USER
和$SERVER_IP
是您在步骤 5 中创建的 GitLab 变量。它们指定 SSH 连接的远程主机和登录用户。command
将在远程主机上执行。
最终通过在服务器上执行以下四个命令来进行部署:
docker login ...
:将 Docker 登录到容器注册表。docker pull ...
:从容器注册表中提取最新的镜像。docker container rm ...
:删除现有容器(如果存在)。 <代码>|| true 确保退出代码始终成功,即使没有名为my-app
的容器运行。这保证了当容器不存在时(例如,对于第一次部署),如果存在则删除例程不会破坏管道。- docker run ...:使用注册表中的最新映像启动新容器。该容器将被命名为
my-app
。主机上的端口80
将绑定到容器的端口80
(顺序为-p host:container
)。-d
以分离模式启动容器,否则管道将卡住等待命令终止。
注意: 使用 SSH 在服务器上运行这些命令可能看起来很奇怪,因为执行命令的 GitLab 运行程序是完全相同的服务器。但这是必需的,因为运行程序在 Docker 容器中执行命令,因此如果您不使用 SSH 执行命令,您将在容器而不是服务器内部署。有人可能会说,您可以使用 shell 执行器在主机本身上运行命令,而不是使用 Docker 作为运行器执行器。但是,这会对您的管道造成限制,即运行程序必须与您要部署到的服务器是同一台服务器。这不是一个可持续且可扩展的解决方案,因为有一天您可能希望将应用程序迁移到另一台服务器或使用另一台运行器服务器。无论如何,使用 SSH 执行部署命令都是有意义的,可能是出于技术或迁移相关的原因。
让我们继续将其添加到 .gitlab-ci.yml
中的部署作业中:
. . .
deploy:
. . .
environment:
name: production
url: http://your_server_IP
only:
- master
GitLab 环境允许您控制 GitLab 内的部署。您可以通过转到操作 > 环境来检查 GitLab 项目中的环境。如果管道尚未完成,则将没有可用的环境,因为到目前为止尚未进行任何部署。
当管道作业定义 environment
部分时,每次作业成功完成时,GitLab 都会为给定环境(此处为 生产
)创建部署。这允许您跟踪 GitLab CI/CD 创建的所有部署。对于每个部署,您都可以看到相关的提交以及为其创建的分支。
还有一个可用于重新部署的按钮,允许您回滚到旧版本的软件。单击查看部署按钮时,将打开在环境
部分中指定的URL。
only
部分定义了作业将运行的分支和标签的名称。默认情况下,GitLab 将为每次推送到存储库启动一个管道并运行所有作业(前提是 .gitlab-ci.yml 文件存在)。 only
部分是将作业执行限制到某些分支/标签的一种选项。这里您只想执行 master
分支的部署作业。要定义关于作业是否应该运行的更复杂的规则,请查看规则语法。
注意:2020 年 10 月,GitHub 已将默认分支的命名约定从 master
更改为 main
。其他提供商(例如 GitLab)和整个开发者社区也开始遵循这种方法。本教程中使用术语 master
分支来表示您可能具有不同名称的默认分支。
完整的 .gitlab-ci.yml 文件如下所示:
stages:
- publish
- deploy
variables:
TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA
publish:
image: docker:latest
stage: publish
services:
- docker:dind
script:
- docker build -t $TAG_COMMIT -t $TAG_LATEST .
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker push $TAG_COMMIT
- docker push $TAG_LATEST
deploy:
image: alpine:latest
stage: deploy
tags:
- deployment
script:
- chmod og= $ID_RSA
- apk update && apk add openssh-client
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY"
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT"
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f my-app || true"
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -p 80:80 --name my-app $TAG_COMMIT"
environment:
name: production
url: http://your_server_IP
only:
- master
最后点击 GitLab 页面底部的提交更改来创建 .gitlab-ci.yml
文件。或者,当您在本地克隆 Git 存储库后,提交文件并将其推送到远程。
您已经创建了一个 GitLab CI/CD 配置来构建 Docker 映像并将其部署到您的服务器。在下一步中,您将验证部署。
第 7 步 — 验证部署
现在,您将在 GitLab 的各个位置以及服务器和浏览器中验证部署。
当 .gitlab-ci.yml 文件被推送到存储库时,GitLab 将自动检测它并启动 CI/CD 管道。在您创建 .gitlab-ci.yml 文件时,GitLab 启动了第一个管道。
转到 GitLab 项目中的 Build > Pipelines 以查看管道的状态。如果作业仍在运行/待处理,请等待它们完成。您将看到带有两个绿色复选标记的通过管道,表示发布和部署作业已成功运行。
让我们检查一下管道。单击状态列中的通过按钮打开管道的概述页面。您将获得一般信息的概述,例如:
- 整个管道的执行持续时间。
- 对于哪个提交和分支执行了管道。
- 相关合并请求。如果负责的分支有开放的合并请求,它将显示在此处。
- 在此管道中执行的所有作业及其状态。
接下来单击发布按钮打开部署作业的结果页面。
在作业结果页面上,您可以看到作业脚本的 shell 输出。这是调试失败的管道时要查找的位置。在右侧边栏中,您将找到添加到此作业的部署标签,并且它是在您的部署运行器上执行的。
转到构建 > 作业。您将概览所有作业部署。到目前为止只有一个部署。对于每个部署,最右侧都有一个再次运行按钮。重新部署将重复该特定管道的部署作业。
重新部署是否按预期工作取决于管道配置,因为它只会在相同情况下重复部署作业。由于您已配置为使用提交 SHA 作为标记来部署 Docker 映像,因此重新部署将适用于您的管道。
注意:您的 GitLab 容器注册表可能有过期策略。过期策略会定期从容器注册表中删除较旧的映像和标签。因此,早于过期策略的部署将无法重新部署,因为此提交的 Docker 映像已从注册表中删除。您可以在设置 > CI/CD > 容器注册表标签过期策略中管理过期策略。过期间隔通常设置为较高的值,例如 90 天。但是,当您遇到尝试部署因过期策略而从注册表中删除的映像时,您可以通过重新运行该特定管道的 publish 作业来解决问题:好吧,这将重新创建并将给定提交的映像推送到注册表。
接下来单击查看部署按钮,这将在浏览器中打开http://your_server_IP
,您应该会看到我的个人网站 标题。
最后我们要检查服务器上部署的容器。前往您的终端,如果您已经断开连接,请确保再次登录(它适用于 sammy 和 deployer 这两个用户):
ssh sammy@your_server_IP
现在列出正在运行的容器:
docker container ls
这将列出 my-app
容器:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5b64df4b37f8 registry.your_gitlab.com/your_gitlab_user/your_project/master:your_commit_sha "nginx -g 'daemon of…" 4 hours ago Up 4 hours 0.0.0.0:80->80/tcp my-app
您现在已经验证了部署。在下一步中,您将完成回滚部署的过程。
第 8 步 — 回滚部署
接下来,您将更新网页,这将创建一个新的部署,然后使用 GitLab 环境重新部署以前的部署。这涵盖了部署有缺陷时部署回滚的用例。
首先在 index.html
文件中进行一些更改:
- 在 GitLab 中,转到项目概述并打开
index.html
文件。 - 单击编辑按钮打开在线编辑器。
- 将文件内容更改为以下内容:
<html>
<body>
<h1>My Enhanced Personal Website</h1>
</body>
</html>
单击页面底部的提交更改保存更改。
将创建一个新管道来部署更改。在 GitLab 中,转到 CI/CD > 管道。管道完成后,您可以在浏览器中打开 http://your_server_IP
来查看更新后的网页,该网页现在显示我的增强型个人网站 我的个人网站。
当您移至构建>作业时,您将看到新创建的部署。现在,单击初始旧部署的再次运行按钮:
单击回滚按钮确认弹出窗口。
该旧管道的部署作业将重新启动,并且您将被重定向到作业的概述页面。等待作业完成,然后在浏览器中打开 http://your_server_IP
,您将在其中看到初始标题我的个人网站再次出现。
让我们总结一下您在本教程中所取得的成果。
结论
在本教程中,您使用 GitLab CI/CD 配置了持续部署管道。您创建了一个由 HTML 文件和 Dockerfile 组成的小型 Web 项目。然后,您将 .gitlab-ci.yml 管道配置配置为:
- 构建 Docker 镜像。
- 将 Docker 镜像推送到容器注册表。
- 登录服务器,拉取最新的镜像,停止当前容器,然后启动一个新的容器。
现在,每次推送到存储库时,GitLab 都会将网页部署到您的服务器。
此外,您已经验证了 GitLab 和服务器上的部署。您还使用 GitLab 环境创建了第二个部署并回滚到第一个部署,这演示了如何处理有缺陷的部署。
至此,您已经自动化了整个部署链。您现在可以更频繁地与世界和/或客户共享代码更改。因此,开发周期可能会变得更短,因为收集反馈和发布代码更改所需的时间更少。
下一步,您可以通过域名访问您的服务,并确保与 HTTPS 的通信安全,其中“如何在 Ubuntu 20.04/18.04 上使用 Traefik 作为 Docker 容器的反向代理”是一个很好的后续内容。
作者选择免费开源基金来接收捐赠,作为 Write for DOnations 计划的一部分。