使用 Docker 镜像和 GitLab 的 CI/CD 工具构建管道,并将其部署到 VPS/KVM Linux 服务器
- 对 Linux、Docker 和 CI/CD 有基本了解。
- GitLab 帐户(免费订阅就足够了)。
- 具有 SSH 访问权限的 Linux 服务器(非 root 用户就足够了)。我使用的是带有 LAMP[1] 技术堆栈的 Ubuntu 16.04 LTS 系统。
- 配备 SSH 和 LFTP 的轻量级 Docker 镜像[2]。
- 您已登录 GitLab
- 您是项目/存储库的所有者
- 您可以在本地计算机上通过 Git 访问此存储库以进行拉取和推送操作
我使用GitKraken[3],一个Git GUI工具,可以更全面地执行Git操作。 关于 CI/CD 的 GitLab
GitLab 提供了一种通过 Docker 和 Shared Runners 处理 CI/CD 管道的简单方法。每次运行 Pipeline 时,GitLab 都会创建一个单独的虚拟机并构建一个 Docker 镜像。可以使用 YAML 配置文件来配置管道。一个管道可以有多个任务,但是如果任务太多,管道的运行时间就会更长。我们绝对不希望这样,因为免费订阅每月最多可以有 2000 分钟的构建时间。 “GitLab.com 上的共享运行器以自动缩放模式运行,由 DigitalOcean 提供支持。自动缩放意味着减少启动构建的延迟并为每个项目隔离虚拟机,从而最大限度地提高安全性。”——来自 GitLab 文档的说明为 GitLab 的运行器创建 SSH 密钥
注意:即使您的服务器已经具有 SSH 访问权限,仍然建议您使用 SSH 密钥CI 创建 /CD 创建一组新的密钥,并为部署过程创建一个新的非 root 用户。 我们将从 Docker 容器通过 SSH 连接到我们的服务器,这意味着我们无法输入用户密码(即非交互式登录),因此我们需要使用 无密码 SSH 创建密钥对我们本地的机器。通常我会创建一个 2048 字节 RSA 密钥 ,因为这足够安全。
$ ssh-keygen rsa -b 2048
输入上面的命令,按照步骤创建。如果您对创建步骤有任何疑问,请使用 man ssh-key。不要忘记为密钥对设置密码。创建完成后,我们需要将私钥导入到我们的服务器中: $ ssh-copy-id -i /path/to/key user@host
现在您可以尝试通过以下命令进行连接: $ ssh -i /path/to/key user@host
连接过程不应要求您输入密码。稍后我们将使用这个私钥。 选择Dockerfile
我使用Docker Hub来存储我的自定义Dockerfile,这个Dockerfile构建了一个轻量级镜像(约8Mb)基于安装了OpenSSH和LFTP的Alpine。在GitLab的CI/CD中,我们需要使用这个镜像来运行Pipeline的任务和脚本。图像 更轻的重量意味着下载图像的时间更少。您可以使用您自己的映像或使用我的 Dockerfile[4]。 Pipeline 配置
在正式构建之前,您需要在存储库的根目录中创建一个新镜像。在文件夹中创建一个“.gitlab-ci.yml”文件。接下来我将解释我正在使用的配置文件。如果有兴趣,可以先去GitLab官网[5]阅读配置文件格式以及所有可以使用的配置项。 我的配置文件如下:
image: jimmyadaro/gitlab-ci-cd:latest
Deploy:
stage: deploy
only:
— ‘master’
when: manual
allow_failure: false
before_script:
#Create .ssh directory
— mkdir -p ~/.ssh
#Save the SSH private key
— echo “$SSH_PRIVATE_KEY” > ~/.ssh/id_rsa
— chmod 700 ~/.ssh
— chmod 600 ~/.ssh/id_rsa
— eval $(ssh-agent -s)
— ssh-add ~/.ssh/id_rsa
script:
#Backup everything in /var/www/html/
— ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $USERNAME@$HOST “zip -q -r /var/backups/www/01-Deploy-$(date +%F_%H-%M-%S).zip /var/www/html/”
#Deploy new files to /var/www/html
— lftp -d -u $USERNAME, -e ‘set sftp:auto-confirm true; set sftp:connect-program “ssh -a -x -i ~/.ssh/id_rsa”; mirror -Rnev ./ /var/www/html — ignore-time — exclude-glob .git* — exclude .git/; exit’ sftp://$HOST
— rm -f ~/.ssh/id_rsa
— ‘echo Deploy done: $(date “+%F %H:%M:%S”)’
我们逐行看看配置文件的每一步都做了什么。 image: jimmyadaro/gitlab-ci-cd:latest
此行告诉运行程序从 Docker Hub 获取最新版本的容器并运行它。您可以在此处设置要使用的映像来执行此操作,但是不要忘记为映像安装OpenSSH和LFTP。 Deploy:
该行设置管道任务名称。必须设置此行才能创建作业。stage: deploy
此行设置作业的艺术家姓名。如果您需要运行多个阶段,例如“备份”、“构建”、“部署”等,阶段名称可以帮助您识别管道的当前状态。由于我不需要任何其他阶段,因此我只使用一项任务,并且该任务只有一个阶段。车道和阶段的名称可以任意设置。例如,您的任务可以称为“ASDF”,阶段可以称为“GHJK”。但是,如果您有多个阶段,则肯定需要标识不同的阶段,因此我建议标准化这些名称。 。 only:
— ‘master’
此行指定仅当存储库的主分支收到更新(例如 git merge)时才会激活管道。因此,我建议使用其他分支进行开发(如development、wip等),然后使用master分支作为“生产分支”。 when: manual
这一行表示您必须输入项目的 CI/CD 配置才能手动触发整个部署过程。这一步当然可以跳过,但我更喜欢手动激活管道。如果删除此规则,对所选分支(在本例中为主分支)的任何更改都将触发管道。 allow_failure: false
这条规则意味着,如果你的 pipeline 中还有其他阶段,当某个任务发生错误时,剩余的任务将不允许继续进行。这是一个可选配置。 before_script:
#Create .ssh directory
— mkdir -p ~/.ssh
#Save the SSH private key
— echo “$SSH_PRIVATE_KEY” > ~/.ssh/id_rsa
— chmod 700 ~/.ssh
— chmod 600 ~/.ssh/id_rsa
— eval $(ssh-agent -s)
— ssh-add ~/.ssh/id_rsa
before_script 单元中设置的所有命令都会在主单元(主脚本)执行之前执行。正如您所看到的,每个 shell 命令行都必须用破折号(“-”)指定。上面的命令会将我们刚刚生成的 SSH 私钥存储在容器的默认 SSH 路径中,允许我们无需密码即可连接到我们的服务器。 新生成的私钥作为受保护变量存储在我的项目的 CI/CD 配置中。在 GitLab Web 界面中,单击“设置”>“CI/CD”>“变量”以查看此变量。同样,我使用受保护的变量存储用于部署的服务器地址和用户名(非 root 用户)。 script:
#Backup everything in /var/www/html/
— ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $USERNAME@$HOST “zip -q -r /var/backups/www/01-Deploy-$(date +%F_%H-%M-%S).zip /var/www/html/”
#Deploy new files to /var/www/html
— lftp -d -u $USERNAME, -e ‘set sftp:auto-confirm true; set sftp:connect-program “ssh -a -x -i ~/.ssh/id_rsa”; mirror -Rnev ./ /var/www/html — ignore-time — exclude-glob .git* — exclude .git/; exit’ sftp://$HOST
— rm -f ~/.ssh/id_rsa
— ‘echo Deploy done: $(date “+%F %H:%M:%S”)’
script下的内容是GitLab的runner执行的主要单元。首先,我连接到我的服务器并将所有内容备份到 ZIP 文件。此 ZIP 文件将以当前时间命名(格式为 yyyy-mm-dd_hh-mm-ss):— ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa $USERNAME@$HOST “zip -q -r /var/backups/www/01-Deploy-$(date +%F_%H-%M-%S).zip /var/www/html/” 注意:您需要在服务器上安装 ZIP CLI。 备份/var/www/html后,使用LFTP连接到我的服务器并上传最新的repo文件。这里我使用SFTP,FTP配置有点不同: — lftp -d -u $USERNAME, -e ‘set sftp:auto-confirm true; set sftp:connect-program “ssh -a -x -i ~/.ssh/id_rsa”; mirror -Rnev ./ /var/www/html — ignore-time — exclude-glob .git* — exclude .git/; exit’ sftp://$HOST
使用mirror -Rnev ./ /var/www/html让LFTP将./(我的存储库的根目录)下的所有文件上传到/var在我的服务器 /www/html 路径上。上面一些参数的含义如下: - -你设置我们的sftp://$HOST的SSH用户名。
- -e 用于设置执行命令(使用单引号进行配置)。
- -R 用于调节后视镜。
- -n 表示仅上传新文件。
- -e 用于删除不在我们的源中的文件。
- -v 用于配置扩展日志文件。
- ignore-time 在决定是否下载时忽略时间。
- exclude-glob .git` 将排除任何目录中与 `.git 匹配的所有文件(例如 .gitignore 和 .gitkeep)。您可以在这里设置其他文件匹配方式。
- exclude .git/ 此配置将阻止上传我们存储库中的 git 文件。
- exit 停止 LFTP 和 SSH 的执行。
— rm -f ~/.ssh/id_rsa
— ‘echo Deploy done: $(date “+%F %H:%M:%S”)’
以上部分是我的配置文件的全部内容。下面是 GitLab 中成功的 Pipeline 执行过程:
我尝试了一些其他方法,例如使用 rsync 代替 LFTP,使用多个阶段和具有依赖关系的缓存任务(我能够重用 SSH 密钥),使用 Docker 的 ENTRYPOINT 和 CMD 等,但我发现上述方法对我来说最快、最简单。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网