本篇是系列中的第五篇内容,我们继续聊聊如何把一个简化过的私有云环境部署在笔记本里,以满足低成本、低功耗、低延时的实验环境。如果你有闲置的轻量云服务器,也可以动手试试。
作为“持续集成”章节的第一篇内容,我们先来聊聊在单机服务器上的 CI 的使用。
关于基础的搭建,之前的文章中已经多次提到,所以我就不再赘述,本文将着重介绍过程中的一些细节,如果你对 Gitea 和 Drone 或者 GitLab 感兴趣,可以阅读之前的内容:
为了更低的维护成本,以及后续多机扩展使用,本文所有程序的使用均在容器环境下。
在展开实践细节之前,我们得先来聊聊“设计”。
CI 过程中的参与者主要有下面这几类(本篇暂不聊软件仓库部分):用户、Git服务、CI 服务、CI 执行器。
简单针对上面的参与者进行定义:“用户”可以是有血有肉的人,也可以是自动化的脚本或者 BOT,各种数据的创造者;“Git 服务”,用于存储代码数据,提供基础的权限功能和界面管理的程序;“CI 服务”,提供持续集成的任务的调度和管理的程序;“CI 执行器”,用于执行具体的 CI 任务的程序。
考虑到单机服务器上除了 Git 服务和 CI 服务之外,还会运行我们需要更新和部署的程序,为了让资源使用效率更好、维护成本更低、避免我们为每一个 Web 程序配置 HTTPS 证书,我们可以添加一个支持服务发现的应用网关。
即使是单机服务器,我们依旧需要注意 SSH 的使用安全,在多机环境下,我们会使用跳板机和云服务器安全策略来进行集中的安全管理,在单机场景下,我使用 SSH 服务开关来完成简单的安全防护(不用的时候,直接关闭,也为互联网上的嗅探机器人省点电)。
如果将上面的“参与者”用图例来表示,一个最基础的单机 CI 使用模式会类似下面这样:
我将图中不同角色的数据交互进行的数字序号标注,简单解释一下这些序号代表的具体内容:
https://gitea.lab.com
、https://gitlab.lab.com
、https://drone.lab.com
。在单机全容器模式下,我们一般会用两种方式可以完成部署。
一类是基于文件挂载的方式,比如在 CI 过程中将 CI JOB 容器中的文件系统和宿主机打通,然后将构建产物同步到宿主机中、类似的变体还有使用各种网络文件协议进行文件系统挂载;另外一类,则是使用 SSH 或者 SCP 、Rsync 等方式,在容器中访问宿主机完成数据交换或者服务初始化或启停操作。
除此之外,如果我们借助软件仓库、容器仓库,还能够完成纯容器交付,让交互更纯粹和“干净”。这个话题,我们会在后续文章中展开。
接下来,我们以上文中的 “SSH 开关”这个应用,在 Gitea 和 Drone 环境中进行持续集成和部署实践为例,来聊聊如何在单机模式下使用 CI。
因为这个项目类型是一个不支持热加载的、需要持续运行的网络程序,程序的更新需要重启服务。所以我们恰好可以使用“部署模式”中的挂载文件的方式更新文件,以及使用 SSH
的方式来进行服务的停止和重新启动。(如果是静态资源类的项目部署,则只需要完成资源替换更新即可)
首先将需要集成 CI 的项目放置上传到 Gitea 中的某个仓库中,这里以上文中提到的 Git SSH 开关为例。在项目中创建一个名为 .drone.yml
的 CI 配置文件。
一个相对通用的 CI 配置可以用下面的形式来表达:
---
kind: pipeline
name: default
steps:
- name: clone
- name: stop-previous-services
depends_on: [ clone ]
- name: update-services
depends_on: [ stop-previous-services ]
- name: start-new-services
depends_on: [ update-services ]
上面的配置包含了:下载仓库代码、停止原先的服务、更新服务程序代码、重新启动服务四个过程。在实际生产中,根据业务类型,我们的执行顺序可能会有变化,甚至不再是上面的“串行”方式执行。
按照上面的配置将 CI 配置好之后,当我们推送代码到代码仓库触发 CI 任务后。在图形界面中,我们将看到类似上图的结果。
不论是使用哪一种 CI 工具,我都推荐你使用 Git Over SSH 的方式来获取代码,而非使用 Git Token 或者账号密码的方式来进行交互。这样可以让你的程序对于某一种 CI 或者 Git 仓库的依赖更低,更容易在合适的时间点、以低成本切换到更合适的工具。
在 Drone CI 中,如果想使用 SSH 方式来下载代码,可以使用下面的配置:(在 GitLab Runner 中同理)
---
kind: pipeline
name: default
clone:
disable: true
steps:
- name: clone
image: alpine/git
pull: if-not-exists
environment:
KEY:
from_secret: ssh_key
commands:
- GIT_HOST=$(echo $DRONE_GIT_SSH_URL | sed 's/git@/\1/' | sed 's/:.*/\1/') && mkdir "$HOME/.ssh" && echo "$KEY" > "$HOME/.ssh/id_rsa" && chmod 600 $HOME/.ssh/id_rsa && eval `ssh-agent -s` && ssh-add $HOME/.ssh/id_rsa && ssh-keyscan $GIT_HOST > ~/.ssh/known_hosts && chmod 400 "$HOME/.ssh/known_hosts";
- git clone $DRONE_GIT_SSH_URL .
- git -c advice.detachedHead=false checkout $DRONE_COMMIT
上面的代码中,为了使用 SSH 方式下载程序代码,CI 程序会做两件事:
ssh_key
环境变量,然后将变量输出成程序可以直接使用的 rsa_key
,并设置好权限,使用 ssh-agent
加载程序。HTTP
协议替换为 Git
协议,以备程序使用。当然,想要使用 SSH 方式下载代码,我们需要在 Git 软件的账号或者仓库中配置 SSH Key
。
这个应用中,我们在 docker-compose.yml
定义了容器的启动方式,所以服务的启动和关闭可以使用我们熟悉的命令 docker-compose up -d
和 docker-compose down
来完成。
因为 CI 在容器中执行,我们不能直接操作宿主机,所以需要借助 SSH 或者 dind 模式的 docker.sock
来完成服务状态的改变。
本文先聊聊如何使用 SSH 来解决基础的部署操作:
- name: stop-or-start-services
image: deploy-tool
depends_on: [ clone ]
pull: if-not-exists
environment:
KEY:
from_secret: ssh_key
# 环境变量,除了私密的定义在 CI 软件的环境变量中,也可显式声明在 CI 配置中
TARGET_HOST: user@host
TARGET_PORT: 22
commands:
- mkdir "$HOME/.ssh" && echo "$KEY" > "$HOME/.ssh/id_rsa" && chmod 600 $HOME/.ssh/id_rsa && eval `ssh-agent -s` && ssh-add $HOME/.ssh/id_rsa";
# 关闭服务
- ssh -i "$HOME/.ssh/id_rsa" -p $TARGET_PORT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TARGET_HOST "bash -c \"cd /app-path/ && docker-compose down\""
# 启动服务
- ssh -i "$HOME/.ssh/id_rsa" -p $TARGET_PORT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TARGET_HOST "bash -c \"cd /app-path/ && docker-compose up -d\""
和下载代码类似,我们从环境变量中初始化 rsa key
,然后在 ssh-agent
中加载私钥。然后使用 ssh
客户端连接宿主机,切换工作目录,执行命令操作服务的启动和关闭即可。
同样的,想要使用 SSH 操作服务器,我们需要在服务器对应用户的 ~/.ssh/authorized_keys
中配置对应的公钥。
更新代码有两种方式,一种是使用上文中提到的 SSH 的方式,远程执行 scp
、rsync
等命令同步数据,另外一种则是使用文件挂载的方式。因为我们的部署在同一台机器上,所以文件挂载不失为一个高效的方式。
以 Drone CI 配置为例,演示如何挂载宿主机目录到容器内:
- name: update-services
image: deploy-tool
depends_on: [ stop-previous-services ]
pull: if-not-exists
commands:
- rm -rf /deploy/*
- cp -r /drone/src/* /deploy/
- cp -r /drone/src/.env /deploy/
volumes:
- name: host-dir
path: /deploy
volumes:
- name: host-dir
host:
path: /app-path
在接下来的“持续集成”相关文章中,我将展开聊聊 CI 在多机和相对复杂场景下的使用,以及其他场景类型的部署实战细节。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。