如何在Ubuntu18.04上使用GitLabCI/CD设置持续部署管道

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。

介绍

GitLab 是一个开源协作平台,除了托管代码存储库之外,它还提供强大的功能。 您可以跟踪问题、托管包和注册表、维护 Wiki、设置持续集成 (CI) 和持续部署 (CD) 管道等等。

在本教程中,您将使用 GitLab 构建持续部署管道。 您将配置管道以构建 Docker 映像,将其推送到 GitLab 容器注册表,并使用 SSH 将其部署到您的服务器。 管道将为推送到存储库的每个提交运行。

您将部署一个小的静态网页,但本教程的重点是配置 CD 管道。 静态网页仅用于演示目的; 您也可以使用其他 Docker 映像应用相同的管道配置进行部署。

完成本教程后,您可以在浏览器中访问http://your_server_IP查看自动部署的结果。

先决条件

要完成本教程,您需要:

第 1 步 - 创建 GitLab 存储库

让我们首先创建一个 GitLab 项目并向其中添加一个 HTML 文件。 您稍后会将 HTML 文件复制到 Nginx Docker 映像中,然后您将部署到服务器。

登录到您的 GitLab 实例,然后单击 新建项目

  1. 给它一个合适的项目名称
  2. 可选择添加 项目描述
  3. 确保根据您的要求将 Visibility Level 设置为 PrivatePublic
  4. 最后点击【X14X】创建项目【X32X】

您将被重定向到项目的概述页面。

让我们创建 HTML 文件。 在项目的概览页面上,单击 新建文件

文件名 设置为 index.html 并将以下 HTML 添加到文件正文中:

索引.html

<html>
<body>
<h1>My Personal Website</h1>
</body>
</html>

点击页面底部的Commit changes创建文件。

当在浏览器中打开时,此 HTML 将生成一个空白页面,其中一个标题显示 我的个人网站

Dockerfiles 是 Docker 用来构建 Docker 镜像的配方。 让我们创建一个 Dockerfile 来将 HTML 文件复制到 Nginx 图像中。

回到项目概览页面,点击【X50X】+【X55X】按钮,选择【X83X】新建文件【X95X】选项。

文件名 设置为 Dockerfile 并将这些指令添加到文件正文中:

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 内容的目录。

点击页面底部的Commit changes创建文件。

在下一步中,您将配置一个 GitLab 运行器以控制谁可以执行部署作业。

第 2 步 — 注册 GitLab Runner

为了跟踪将与 SSH 私钥联系的环境,您需要将您的服务器注册为 GitLab 运行器。

在您的部署管道中,您希望使用 SSH 登录到您的服务器。 为此,您将 SSH 私钥存储在 GitLab CI/CD 变量中(步骤 5)。 SSH 私钥是一段非常敏感的数据,因为它是您服务器的入场券。 通常,私钥永远不会离开生成它的系统。 在通常情况下,您会在主机上生成一个 SSH 密钥,然后在服务器上对其进行授权(即将公钥复制到服务器),以便手动登录并执行部署例程。

这里情况略有变化:您希望授予自治权限 (GitLab CI/CD) 访问您的服务器以自动化部署例程。 因此,私钥需要离开生成它的系统,并信任 GitLab 和其他相关方。 您永远不希望您的私钥进入不受您控制或信任的环境。

除了 GitLab,GitLab 运行器是您的私钥将进入的另一个系统。 对于每个管道,GitLab 使用运行器来执行繁重的工作,即执行您在 CI/CD 配置中指定的作业。 这意味着部署作业最终将在 GitLab 运行器上执行,因此私钥将被复制到运行器,以便它可以使用 SSH 登录到服务器。

如果您使用未知的 GitLab Runners(例如,shared runners)来执行部署作业,那么您将不知道系统正在与私钥联系。 即使 GitLab 运行器在作业执行后清理所有数据,您也可以通过将自己的服务器注册为 GitLab 运行器来避免将私钥发送到未知系统。 然后将私钥复制到您控制的服务器上。

首先登录到您的服务器:

ssh sammy@your_server_IP

为了安装 gitlab-runner 服务,您将添加官方 GitLab 存储库。 下载并检查安装脚本:

curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh > script.deb.sh
less script.deb.sh

一旦您对脚本的安全性感到满意,请运行安装程序:

sudo bash script.deb.sh

这可能不是很明显,但您必须输入您的 非 root 用户的密码才能继续。 执行前面的命令时,输出将如下所示:

Output[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 命令完成后,您将收到以下消息:

OutputThe repository is setup! You can now install packages.

接下来安装 gitlab-runner 服务:

sudo apt install gitlab-runner

通过检查服务状态来验证安装:

systemctl status gitlab-runner

您将在输出中包含 active (running)

Output● 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:

  1. 在您的 GitLab 项目中,导航到 Settings > CI/CD > Runners
  2. 手动设置特定 Runner 部分中,您将找到 注册令牌 和 GitLab URL。 将两者复制到文本编辑器; 您将需要它们来执行下一个命令。 它们将被称为 https://your_gitlab.comproject_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 的关于 executors 的文档)。
  • --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 命令后,您将收到以下输出:

OutputRunner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

通过转到 GitLab 中的 Settings > CI/CD > Runners 来验证注册过程,注册的跑步者将在此处显示。

在下一步中,您将创建一个部署用户。

第 3 步 — 创建部署用户

您将创建一个专用于部署任务的用户。 您稍后将配置 CI/CD 管道以使用该用户登录服务器。

在您的服务器上,创建一个新用户:

sudo adduser deployer

您将被引导完成用户创建过程。 输入强密码以及您想要指定的任何其他用户信息(可选)。 最后用 Y 确认用户创建。

将用户添加到 Docker 组:

sudo usermod -aG docker deployer

这允许 deployer 执行执行部署所需的 docker 命令。

警告: 将用户添加到 Docker 组, 授予等同于 root 用户 的权限。 有关这如何影响系统安全性的更多详细信息,请参阅 Docker Daemon Attack Surface


在下一步中,您将创建一个 SSH 密钥,以便能够以 deployer 身份登录到服务器。

第 4 步 — 设置 SSH 密钥

您将为部署用户创建一个 SSH 密钥。 GitLab CI/CD 稍后将使用该密钥登录服务器并执行部署例程。

让我们首先切换到新创建的 deployer 用户,您将为其生成 SSH 密钥:

su deployer

系统会提示您输入 deployer 密码以完成用户切换。

接下来,生成一个 4096 位的 SSH 密钥。 正确回答ssh-keygen命令的问题很重要:

  1. 第一个问题:用 ENTER 回答它,它将密钥存储在默认位置(本教程的其余部分假设密钥存储在默认位置)。
  2. 第二个问题:配置密码保护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----- 之后添加换行符:

~/.ssh/id_rsa

-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

现在导航到 GitLab 项目中的 Settings > CI / CD > Variables,然后单击 Add Variable。 填写以下表格:

  • 键:ID_RSA
  • 值:粘贴剪贴板中的 SSH 私钥(包括末尾的换行符)。
  • 类型:文件
  • 环境范围:全部(默认)
  • 保护变量:Checked
  • 掩码变量:未选中

注意:该变量不能被屏蔽,因为它不符合正则表达式的要求(参见GitLab关于被屏蔽变量的文档)。 但是,私钥永远不会出现在控制台日志中,这使得屏蔽它已经过时了。


将为每个 CI/CD 作业在运行器上创建一个包含私钥的文件,其路径将存储在 $ID_RSA 环境变量中。

使用您的服务器 IP 创建另一个变量。 点击【X6X】添加变量【X22X】,填写如下表格:

  • 键:SERVER_IP
  • 值:your_server_IP
  • 类型:变量
  • 环境范围:全部(默认)
  • 保护变量:Checked
  • 掩码变量:Checked

最后,使用登录用户创建一个变量。 点击【X6X】添加变量【X22X】,填写如下表格:

  • 键:SERVER_USER
  • 值:deployer
  • 类型:变量
  • 环境范围:全部(默认)
  • 保护变量:Checked
  • 掩码变量:Checked

您现在已将私钥存储在 GitLab CI/CD 变量中,这使得密钥在管道执行期间可用。 在下一步中,您将继续配置 CI/CD 管道。

第 6 步 — 配置 .gitlab-ci.yml 文件

您将配置 GitLab CI/CD 管道。 该管道将构建一个 Docker 映像并将其推送到容器注册表。 GitLab 为每个项目提供一个容器注册表。 您可以通过访问来探索容器注册表包和注册表 > 容器注册表在您的 GitLab 项目中(阅读更多内容 GitLab 的容器注册表文档 .) 管道的最后一步是登录服务器,拉取最新的 Docker 映像,移除旧容器,然后启动新容器。

现在您将创建包含管道配置的 .gitlab-ci.yml 文件。 在GitLab中,进入【X21X】项目概览【X41X】页面,点击【X63X】+【X68X】按钮,选择【X92X】新建文件【X104X】。 然后将文件名设置为.gitlab-ci.yml

(或者,您可以克隆存储库并在本地计算机上对 .gitlab-ci.yml 进行所有以下更改,然后提交并推送到远程存储库。)

要开始添加以下内容:

.gitlab-ci.yml

stages:
  - publish
  - deploy

每个作业都分配到一个 阶段。 分配给同一阶段的作业并行运行(如果有足够的运行器可用)。 阶段将按照指定的顺序执行。 在这里,publish 阶段将首先进行,deploy 阶段将次之。 后续阶段仅在前一阶段成功完成时开始(即所有作业都已通过)。 艺名可以任意选择。

当您想将此 CD 配置与测试和构建应用程序的现有 CI 管道相结合时,您可能需要在现有阶段之后添加 publishdeploy 阶段,以便部署只有在测试通过时才会发生。

在此之后,将其添加到您的 .gitlab-ci.yml 文件中:

.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_LATESTlatest 标签添加到图像中。 这是提供始终代表最新版本的标签的常用策略。 对于每个部署,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 代表 <registry URL>/<namespace>/<project> 部分并且是强制性的,因为它是项目的注册表根。 $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 文件中:

.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_BUILD_TOKEN $CI_REGISTRY
    - docker push $TAG_COMMIT
    - docker push $TAG_LATEST

publish 部分是 CI/CD 配置中的第一个 job。 让我们分解一下:

  • image 是用于此作业的 Docker 映像。 GitLab 运行器将为每个作业创建一个 Docker 容器,并在该容器中执行脚本。 docker:latest 图像确保 docker 命令可用。
  • stage 将作业分配给 publish 阶段。
  • services 指定 Docker-in-Docker — dind 服务。 这就是您在特权模式下注册 GitLab 运行器的原因。

publish 作业的脚本部分 指定要为此作业执行的shell 命令。 执行这些命令时,工作目录将设置为存储库根目录。

  • docker build ...:基于 Dockerfile 构建 Docker 映像,并使用变量部分中定义的最新提交标记对其进行标记。
  • docker login ...:将 Docker 登录到项目的容器注册表。 您使用预定义变量 $CI_BUILD_TOKEN 作为身份验证令牌。 GitLab 将生成令牌并在作业的生命周期内保持有效。
  • docker push ...:将两个镜像标签推送到容器注册表。

在此之后,将 deploy 作业添加到您的 .gitlab-ci.yml

.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_BUILD_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:撤销私钥对groupothers的所有权限,只有所有者才能使用。 这是一个要求,否则 SSH 拒绝使用私钥。
  • apk update && apk add openssh-client:更新 Alpine 的包管理器 (apk) 并安装提供 ssh 命令的 openssh-client

接下来是四个连续的 ssh 命令。 每个模式是:

ssh connect pattern for all deployment commandsssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "command"

在每个 ssh 语句中,您正在远程服务器上执行 command。 为此,您使用您的私钥进行身份验证。

选项如下:

  • -i 代表 身份文件$ID_RSA 是包含私钥文件路径的 GitLab 变量。
  • -o StrictHostKeyChecking=no 确保绕过这个问题,无论您是否信任远程主机。 这个问题无法在管道等非交互式上下文中回答。
  • $SERVER_USER$SERVER_IP 是您在步骤 5 中创建的 GitLab 变量。 它们为 SSH 连接指定远程主机和登录用户。
  • command 将在远程主机上执行。

部署最终通过在您的服务器上执行以下四个命令来进行:

  1. docker login ...:将 Docker 登录到容器注册表。
  2. docker pull ...:从容器注册表中拉取最新的镜像。
  3. docker container rm ...:如果存在,则删除现有容器。 || true 确保退出代码始终成功,即使没有以名称 my-app 运行的容器。 这保证了 delete if exists 例程在容器不存在时不会破坏管道(例如,对于第一次部署)。
  4. docker run ...:使用注册表中的最新映像启动一个新容器。 容器将命名为 my-app。 主机上的端口80将绑定到容器的端口80(顺序为-p host:container)。 -d 以分离模式启动容器,否则管道将卡住等待命令终止。

注意: 考虑到执行命令的 GitLab 运行器是完全相同的服务器,使用 SSH 在您的服务器上运行这些命令可能看起来很奇怪。 然而它是必需的,因为运行程序在 Docker 容器中执行命令,因此如果您在不使用 SSH 的情况下执行命令,您将部署在容器内部而不是服务器中。 有人可能会争辩说,您可以使用 shell 执行程序 在主机本身上运行命令,而不是使用 Docker 作为运行程序执行程序 。 但是,这会对您的管道产生限制,即运行器必须与您要部署到的服务器是同一台服务器。 这不是一个可持续和可扩展的解决方案,因为有一天您可能希望将应用程序迁移到不同的服务器或使用不同的运行器服务器。 在任何情况下,使用 SSH 来执行部署命令都是有意义的,可能是出于技术或迁移相关的原因。


让我们继续将其添加到 .gitlab-ci.yml 中的部署作业中:

.gitlab-ci.yml

. . .
deploy:
. . .
  environment:
    name: production
    url: http://your_server_IP
  only:
    - master

GitLab 环境 允许您控制 GitLab 中的部署。 您可以通过转到 Operations > Environments 来检查 GitLab 项目中的环境。 如果管道尚未完成,则将没有可用的环境,因为到目前为止还没有进行部署。

当管道作业定义 environment 部分时,GitLab 将在每次作业成功完成时为给定环境(此处为 production)创建部署。 这允许您跟踪 GitLab CI/CD 创建的所有部署。 对于每个部署,您都可以看到相关的提交和创建它的分支。

还有一个可用于重新部署的按钮,可让您回滚到旧版本的软件。 单击 查看部署 按钮时,将打开在 environment 部分中指定的 URL。

唯一的部分定义了作业将运行的分支和标签的名称。 默认情况下,GitLab 将为每次推送到存储库启动管道并运行所有作业(前提是 .gitlab-ci.yml 文件存在)。 only 部分是将作业执行限制到某些分支/标签的一种选择。 在这里,您只想为 master 分支执行部署作业。 要定义关于作业是否应该运行的更复杂的规则,请查看 rules 语法。

注意: 2020 年 10 月,GitHub 将默认分支的命名约定master 更改为 main。 其他提供商,例如 GitLab 和开发者社区,一般都开始采用这种方法。 本教程中使用术语 master 分支来表示您可能有不同名称的默认分支。


您完整的 .gitlab-ci.yml 文件将如下所示:

.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_BUILD_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_BUILD_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中点击页面底部的Commit changes,创建.gitlab-ci.yml文件。 或者,当您在本地克隆 Git 存储库时,提交并将文件推送到远程。

您已经创建了一个 GitLab CI/CD 配置,用于构建 Docker 映像并将其部署到您的服务器。 在下一步中,您将验证部署。

第 7 步 — 验证部署

现在,您将在 GitLab 的各个位置以及您的服务器和浏览器中验证部署。

当一个 .gitlab-ci.yml 文件被推送到存储库时,GitLab 将自动检测它并启动 CI/CD 管道。 在您创建 .gitlab-ci.yml 文件时,GitLab 启动了第一个管道。

转到 GitLab 项目中的 CI/CD > Pipelines 以查看管道的状态。 如果作业仍在运行/挂起,请等到它们完成。 您将看到一个带有两个绿色复选标记的 Passed 管道,表示发布和部署作业运行成功。

让我们检查一下管道。 点击Status栏中的passed按钮,打开流水线的概览页面。 您将获得一般信息的概览,例如:

  • 整个管道的执行时间。
  • 针对哪个提交和分支执行了管道。
  • 相关的合并请求。 如果负责的分支机构有一个开放的合并请求,它会显示在这里。
  • 在此管道中执行的所有作业及其状态。

接下来点击 deploy 按钮打开部署作业的结果页面。

在作业结果页面上,您可以看到作业脚本的 shell 输出。 这是调试失败的管道时要寻找的地方。 在右侧边栏中,您将找到您添加到此作业的部署标签,并且它是在您的 Deployment Runner 上执行的。

如果滚动到页面顶部,您会发现 This job is deploy to production 消息。 GitLab 认识到由于作业的环境部分而发生了部署。 单击 production 链接移动到生产环境。

您将对所有生产部署有一个概览。 到目前为止,只有一个部署。 对于每个部署,最右侧都有一个 重新部署 按钮。 重新部署将重复该特定管道的部署工作。

重新部署是否按预期工作取决于管道配置,因为它只会在相同情况下重复部署作业。 由于您已配置为使用提交 SHA 作为标记来部署 Docker 映像,因此重新部署将适用于您的管道。

注意: 您的 GitLab 容器注册表可能有 过期策略 。 过期策略会定期从容器注册表中删除旧镜像和标签。 因此,比过期策略更早的部署将无法重新部署,因为此提交的 Docker 映像将从注册表中删除。 您可以在 设置 > CI/CD > 容器注册表标签过期策略 中管理过期策略。 到期间隔通常设置为较高,例如 90 天。 但是当您遇到尝试部署由于过期策略而从注册表中删除的图像的情况时,您也可以通过重新运行该特定管道的 publish 作业来解决问题,这将为给定的提交重新创建图像并将其推送到注册表。


接下来单击查看部署按钮,它将在浏览器中打开http://your_server_IP,您应该会看到我的个人网站标题。

最后,我们要检查服务器上部署的容器。 转到您的终端并确保再次登录,如果您已经断开连接(它适用于两个用户,sammydeployer):

ssh sammy@your_server_IP

现在列出正在运行的容器:

docker container ls

这将列出 my-app 容器:

OutputCONTAINER 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

阅读 如何在 Ubuntu 18.04 上安装和使用 Docker 指南 以了解有关管理 Docker 容器的更多信息。

您现在已经验证了部署。 在下一步中,您将完成回滚部署的过程。

第 8 步 — 回滚部署

接下来,您将更新网页,这将创建一个新部署,然后使用 GitLab 环境重新部署之前的部署。 这涵盖了在部署有缺陷的情况下部署回滚的用例。

首先在 index.html 文件中进行一些更改:

  1. 在 GitLab 中,转到 项目概述 并打开 index.html 文件。
  2. 单击编辑按钮打开在线编辑器。
  3. 将文件内容更改为以下内容:

索引.html

<html>
<body>
<h1>My Enhanced Personal Website</h1>
</body>
</html>

单击页面底部的 Commit changes 保存更改。

将创建一个新管道来部署更改。 在 GitLab 中,转到 CI/CD > 管道 。 管道完成后,您可以在浏览器中打开 http://your_server_IP 以查看更新后的网页,现在显示 我的增强型个人网站 而不是 我的个人网站

当您移至 Operations > Environments > production 时,您将看到新创建的部署。 现在单击初始旧部署的 重新部署 按钮:

单击 Rollback 按钮确认弹出窗口。

该旧管道的部署作业将重新启动,您将被重定向到作业的概述页面。 等待作业完成,然后在浏览器中打开 http://your_server_IP,您将在其中看到初始标题 我的个人网站 再次出现。

让我们总结一下您在本教程中所取得的成就。

结论

在本教程中,您已经使用 GitLab CI/CD 配置了一个持续部署管道。 您创建了一个由 HTML 文件和 Dockerfile 组成的小型 Web 项目。 然后您将 .gitlab-ci.yml 管道配置配置为:

  1. 构建 Docker 映像。
  2. 将 Docker 映像推送到容器注册表。
  3. 登录服务器,拉取最新的镜像,停止当前容器,重新启动一个。

GitLab 现在将在每次推送到存储库时将网页部署到您的服务器。

此外,您已经在 GitLab 和您的服务器上验证了部署。 您还创建了第二个部署并使用 GitLab 环境回滚到第一个部署,这演示了您如何处理有缺陷的部署。

至此,您已经自动化了整个部署链。 您现在可以更频繁地与世界和/或客户共享代码更改。 因此,开发周期可能会变得更短,因为收集反馈和发布代码更改所需的时间更少。

作为下一步,您可以通过域名访问您的服务并保护与 HTTPS 的通信,如何使用 Traefik 作为 Docker 容器的反向代理 是一个很好的后续。