使用阿里云免费云效Devops流水线功能自动构建镜像部署项目到自有主机
为什么选择云效DevOps
之前在本地小主机(4C4G)构建镜像,本地发布一切正常。但是第一次在云服务器(2C2G)上打包构建博客项目时出现内存不足错误。
=> ERROR [builder 7/7] RUN npm run docs:build 55.9s
------
> [builder 7/7] RUN npm run docs:build:
1.861
1.861 > vuepress-theme-hope-template@2.0.0 docs:build
1.861 > vuepress-webpack build src
1.861
5.905 - Initializing and preparing data
21.13 ✔ Initializing and preparing data - done in 15.23s
21.13 - Compiling with webpack
54.63
54.63 <--- Last few GCs --->
54.63
54.63 [18:0x56d68b0] 50525 ms: Scavenge 984.0 (1007.1) -> 983.2 (1011.6) MB, 6.7 / 0.0 ms (average mu = 0.362, current mu = 0.327) allocation failure;
54.63 [18:0x56d68b0] 52704 ms: Mark-sweep (reduce) 986.5 (1011.6) -> 984.6 (1006.6) MB, 1402.4 / 0.0 ms (+ 309.2 ms in 52 steps since start of marking, biggest step 18.9 ms, walltime since start of marking 1750 ms) (average mu = 0.287, current mu = 0.235) a
54.63
54.63 <--- JS stacktrace --->
54.63
54.64 FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
54.70 1: 0xb9c1f0 node::Abort() [node]
54.71 2: 0xaa27ee [node]
54.71 3: 0xd73950 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
54.72 4: 0xd73cf7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
54.72 5: 0xf51075 [node]
54.72 6: 0xf6354d v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
54.72 7: 0xf3dc3e v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
54.73 8: 0xf3f007 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
54.74 9: 0xf2020a v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node]
54.74 10: 0x12e543f v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node]
54.75 11: 0x17120b9 [node]
55.51 Aborted (core dumped)
------
Dockerfile:11
--------------------
9 |
10 | COPY . .
11 | >>> RUN npm run docs:build
12 |
--------------------
ERROR: failed to solve: process "/bin/sh -c npm run docs:build" did not complete successfully: exit code: 134
根据官方文档常见错误提示
FATAL ERROR: XXX - JavaScript heap out of memory这意味着你的 Node.js 的
max_old_space_size设置太小而无法构建此应用程序。 你可以尝试通过设置NODE_OPTIONS环境变量来增加max_old_space_size。
max_old_space_size以 MB 为单位,默认情况下max_old_space_size是机器内存大小的一半。该值可以大于你机器的实际内存大小。
- 对于小型项目,通常不会超过 2 GB (2048 MB)。
- 对于大型项目,通常不会超过 4 GB (4048 MB)
- 如果你在大型网站上同时启用博客功能和大量 Markdown 增强功能,通常不会超过 8 GB (8192 MB)
修改Dockerfile
RUN npm run docs:build
改为:
RUN NODE_OPTIONS=--max-old-space-size=2048 npm run docs:build再次构建,云服务器的SSH连接不响应,CPU和内存占用都很高,影响其他服务正常运行。

于是放弃在云服务器上从源代码构建镜像,考虑其他方法。
- 电脑本地开发环境打包编译成静态页面传输到服务器上构建镜像
- 本地小主机打包编译构建镜像
- 代码仓库工作流自动构建镜像
构建对比
本地Linux小主机
| 构建方式 | 打包方式 | 时间(秒) | 镜像大小(MB) |
|---|---|---|---|
| npm | node:18-alpine | 411 | 190 |
| npm | nginx:alpine | 343 | 102 |
| pnpm | node:18-alpine | 438 | 190 |
| pnpm | nginx:alpine | 363 | 102 |
Windos电脑
| 构建方式 | 时间(秒) |
|---|---|
| npm | 49 |
| pnpm | 27 |
所以如果想操作简单,速度比较快的话可以选择用Windos电脑编译构建静态文件传输到云主机进行最后打包成镜像,这点工作量云主机还是能完成的。
如果不怕各种设置繁琐步骤,想一步到位只需提交代码到仓库就自动更新部署可以选择代码仓库流水线。
工作流
各个代码仓库
| 平台 | 免费政策 |
|---|---|
| Github | GitHub Actions 开源仓库免费 ( 私有仓库 2000 分钟/月) |
| Gitee | Gitee Go,单个代码仓库均可直接获得200 分钟免费构建时长;个人每月 1000 分钟免费构建时长自动到账,所有仓库均可使用 |
| 阿里云 云效DevOps | 最大构建时长 1800 分钟/月;最大并行任务数 3;制品仓库容量不限 |
| 腾讯云 CODING | 2核 4GiB;每月持续集成构建时长 10 核时;最大并行任务数 1;Docker 制品库镜像 1000 个 |
因为网络原因对Github很不友好,所以目前的博客代码托管到Gitee上,Gitee Go 提供的免费时长也挺多,但平时跟阿里云平台接触更多,云效与自家的其他云服务产品在CICD流水线方面联动调用更方便,所以综合下来决定使用 阿里云 云效DevOps 平台自动构建部署博客。
云效DevOps介绍




免费基础版功能

这些已经足够使用了。
使用云效DevOps的过程如下:
开发者提交代码变更到代码库,云效在监听着代码库的变动,一旦代码发生变化,将自动触发云效持续部署流水线一次构建任务的运行,包括代码检查、构建、测试部署、测试验证和生产部署等过程。其中,在构建完之后,生成制品包并自动上传至OSS仓库,在部署阶段(测试环境的部署和生产环境的部署)时,再从制品仓库中取得最新的版本,根据不同的部署策略通过主机部署到不同环境,这里资源可以是阿里云或者自建主机资源。

接下来逐一进行详细操作。
代码管理Codeup
不是一定需要将代码上传到云效Codeup才能使用云效Flow流水线,可以在编辑流水线界面将其他代码仓库授权给云效Flow流水线读取代码和更新。


创建仓库
登录云效Codeup
项目源码可以选择从其他仓库导入,或是新建一个仓库从本地推送上去。

我这里选择新建仓库

添加 SSH 公钥
在个人设置添加电脑的 SSH 公钥

推送代码
查看本地关联的远程仓库
>git remote -v
origin git@gitee.com:icurvestar/vuepress-theme-hope.git (fetch)
origin git@gitee.com:icurvestar/vuepress-theme-hope.git (push)现在需要添加多一个远程仓库
git remote add <远程仓库名称> <远程仓库URL>git remote add codeup https://codeup.aliyun.com/61613145202f/icurvestar/icurvestar-blog.git再次查看关联的远程仓库
>git remote -v
codeup https://codeup.aliyun.com/61613145202f/icurvestar/icurvestar-blog.git (fetch)
codeup https://codeup.aliyun.com/61613145202f/icurvestar/icurvestar-blog.git (push)
origin git@gitee.com:icurvestar/vuepress-theme-hope.git (fetch)
origin git@gitee.com:icurvestar/vuepress-theme-hope.git (push)推送代码
git push codeup master
git push codeup dev>git push codeup master
Enumerating objects: 935, done.
Counting objects: 100% (935/935), done.
Delta compression using up to 16 threads
Compressing objects: 100% (922/922), done.
Writing objects: 100% (935/935), 39.80 MiB | 5.08 MiB/s, done.
Total 935 (delta 303), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (303/303), done.
To https://codeup.aliyun.com/6160515b90f3ca58306f572f/icurvestar/icurvestar-blog.git
* [new branch] master -> master
>git push codeup dev
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://codeup.aliyun.com/6160515b90f3ca58306f572f/icurvestar/icurvestar-blog.git
* [new branch] dev -> dev到云效Codeup代码仓库查看

ACR容器镜像服务
个人镜像仓库我选择阿里云的容器镜像服务(ACR),后面让流水线构建的镜像推送到阿里云的镜像仓库。
在容器镜像服务 ACR 控制台创建个人实例,设置好密码后添加仓库

设置代码源,选择本地仓库

【功能变更通知】受云效切换使用新的访问令牌方案的影响,自2024年08月15日起,容器镜像服务个人版暂不支持新绑定云效的代码源。具体的功能更新时间请关注后续通知。由此给您带来的不便敬请谅解,有任何问题可工单联系我们。
仓库对应项目,版本对应标签(tag)

拉取镜像命令则为:
$ docker pull registry.cn-hangzhou.aliyuncs.com/icurvestar/icurvestar-blog:[镜像版本号]添加自有主机
由于云服务器不在阿里云,不能直接选择服务器实例,需要给服务器安装一个云助手Agent代理程序。
云助手是专为云服务器ECS打造的原生自动化运维工具,免密码、免登录、无需使用跳板机,即可批量执行命令(Shell、PowerShell、Bat等),实现自动化运维脚本、轮询进程、安装卸载软件、启动或停止服务、安装补丁或安装安全更新等任务。
云效流水线通过云助手在服务器执行命令来部署服务,达到自动部署目的。
在云效Devops的流水线flow主机组设置新建主机组

复制命令到服务区上运行,导入后勾选确定

# bash <(curl -L -k http://agent-install-default.oss-cn-hangzhou.aliyuncs.com/production-install.sh) '*********' http://agent-install-default.oss-cn-hangzhou.aliyuncs.com/production-agent.tgz https://devops.aliyuncs.com/api/verifySnAndRegionId?sign=***** ****** 1724554923017 default
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4586 100 4586 0 0 65884 0 --:--:-- --:--:-- --:--:-- 66463
检查目录
/dev/fd/63: line 3: [: missing `]'
python
检查wget
检查zlib-dev openssl-devel bzip2-devel包是否缺失
获取SN。
SN:'*********'
安装SN。
下载并安装Agent
--2024-08-25 10:47:53-- http://agent-install-default.oss-cn-hangzhou.aliyuncs.com/production-agent.tgz
Resolving agent-install-default.oss-cn-hangzhou.aliyuncs.com (agent-install-default.oss-cn-hangzhou.aliyuncs.com)... 118.31.232.197
Connecting to agent-install-default.oss-cn-hangzhou.aliyuncs.com (agent-install-default.oss-cn-hangzhou.aliyuncs.com)|118.31.232.197|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 61063692 (58M) [application/gzip]
Saving to: ‘/tmp/agent.tgz’
/tmp/agent.tgz 100%[=================================================================================================================>] 58.23M 1.73MB/s in 34s
2024-08-25 10:48:27 (1.71 MB/s) - ‘/tmp/agent.tgz’ saved [61063692/61063692]
unzip agent...
finished unzip agent
启动Agent。
/home/staragent/bin/agent.sh
Stopping staragentd: Agent not running.
Agent not running.
stop staragent finish
Starting staragentd: 安装成功命名一下

添加完成

# cat /usr/sbin/staragent_sn
63b870b9-7f52-4ddd-8c94-2703ab73c187Alibaba Cloud Linux
CentOS 6/7/8及更高版本
CoreOS
Debian 8/9/10及更高版本
OpenSUSE
Rocky Linux
RedHat 5/6/7及更高版本
RedHat中需要您自行下载rpm包安装云助手Agent,具体操作,请参见安装云助手Agent。
SUSE Linux Enterprise Server 11/12/15及更高版本
Ubuntu 12/14/16/18及更高版本
Window Server 2012/2016/2019及更高版本
运行云助手Agent不可避免的占用一些服务区资源
官方文档标注云助手Agent所在主机的各项资源占用情况如下:
| 主机资源 | Linux操作系统 | Windows操作系统 |
|---|---|---|
| CPU | 平均CPU使用率不到1% | 平均CPU使用率不到1% |
| 物理内存 | 约17 MB | 约10 MB |
| 磁盘I/O | 平稳运行时几乎没有I/O,仅在下载升级安装包和保存命令脚本等场景下产生磁盘I/O | 平稳运行时几乎没有I/O,仅在下载升级安装包和保存命令脚本等场景下产生磁盘I/O |
| 网络I/O | 平稳运行时仅有心跳上报等数据产生的少量I/O | 平稳运行时仅有心跳上报等数据产生的少量I/O |
ECS实例中需要安装云助手Agent后才能使用云助手,2017年12月01日之后使用公共镜像创建的ECS实例,默认预装云助手Agent。因此,部分ECS实例需要自行安装云助手Agent。
启动:/home/staragent/bin/staragentctl restart;
重启:/home/staragent/bin/staragentctl restart;
查看状态:/home/staragent/bin/staragentctl status;
卸载:
1. /home/staragent/bin/staragentctl stop;
2. rm -rf /home/staragent;
3. rm /usr/sbin/staragent_sn执行命令cat /home/staragent/conf/channels.conf查看该文件,内容会是一个ip+port的列表,尝试运行telnet <ip> <port>,只要任意一个连通,则服务正常;如果全部不通,请检查您的网络。# /home/staragent/bin/staragentctl status
------agent running ok------
StartTime : 2024-08-25 10:48:33 CST
RegisterTime : 2024-08-25 10:48:36 CST
ServiceTag : *********
ServerConnected : 1
LastHeartBeatTime : 2024-08-25 11:02:34 CST
ServerAddr : *********:8000
LocalAddr : *********
Max Core count : 0
Total CPU Count : 2
Total CPU Rate : 4.04%
Total MEM Rate : 20.59%
Process CPU Rate : 1.52%
Load Avg (1,5,15) : 39,30,21
Virtual Memory : 1233MB
Physical Memory : 14MB创建流水线
回到项目代码处点击侧边栏的流水线创建

没有很合适的模板,需要的是:镜像构建并推送到阿里云镜像仓库-->主机部署,所以选择自定义一个模板,方便其他项目复用。

模板编辑
阿里云镜像构建
添加任务
选择阿里云镜像构建个人版
Node.js 镜像构建是用执行流水线的Node.js环境编译构建的,而我是在Dockerfile中用镜像的Node.js环境来编译。

编辑任务
连接前面创建好的容器镜像服务(ACR)和选择创建好的镜像仓库,添加多一个latest标签方便部署,其他按照个人情况设置。

**解决方案:**按照以下步骤,修改您的 Dockerfile:
将境外镜像在 pull 到本地。
docker pull openjdk:8-jdk-alpine将基础镜像 push 到阿里云镜像仓库(cr.console.aliyun.com)的国内 region(比如北京、上海等)。
docker tag openjdk:8-jdk-alpine registry.cn-beijing.aliyuncs.com/yournamespace/openjdk:8-jdk-alpinedocker push registry.cn-beijing.aliyuncs.com/yournamespace/openjdk:8-jdk-alpine修改你的 dockerfile 中 FROM,从你自己的镜像仓库下载镜像 。
From registry.cn-beijing.aliyuncs.com/yournamespace/openjdk:8-jdk-alpine
也可以选择使用其他的镜像地址,在Dockerfile中更改
比如
FROM node:18
改为
FROM docker.1panel.live/library/node:18
或
FROM hub.atomgit.co/library/node:18由开放原子开源基金会牵头,联合多家行业伙伴(华为、浪潮、DaoCloud 、谐云、青云、飓风引擎以及 OpenSDV 开源联盟、openEuler 社区、OpenCloudOS 社区等成员单位)发起,遵循OCI(Open Container Initiative,以下简称“OCI”)容器镜像标准,旨在为开发者提供开放中立、安全可信、高效便捷的新一代开源容器镜像中心
构建加速
在持续集成的代码构建中的耗时通常集中在2个部分,首先是从外部获取构建所需的依赖以及代码本身的编译行为。通过使用Flow的自定义缓存能够我们有效降低获取依赖时的耗时。本文将介绍如何加速常见的编译工具的构建效率。
Yarn构建加速
使用中国内地registry和mirror
使用中国内地registry仓库避免由于海外网络访问导致的依赖下载慢的问题
yarn config set registry https://npmmirror.com
对于构建中由于Building fresh packages导致构建慢的情况需要指定特定外部依赖的中国内地镜像源:
yarn config set sass_binary_site "https://npmmirror.com/mirrors/node-sass/"
除了通过yarn config set指定依赖下载路径以外,还可以通过.yarnrc进行配置。在项目根路径中创建.yarnrc并配置以下内容:
registry "https://registry.npmmirror.com"
sass_binary_site "https://npmmirror.com/mirrors/node-sass/"
phantomjs_cdnurl "https://cdn.npmmirror.com/binaries/phantomjs"
electron_mirror "https://cdn.npmmirror.com/binaries/electron/"
sqlite3_binary_host_mirror "https://foxgis.oss-cn-shanghai.aliyuncs.com/"
chromedriver_cdnurl "https://cdn.npmmirror.com/binaries/chromedriver"
配置yarn全局缓存
设置缓存目录,并在流水线自定义缓存中添加缓存目录/root/.yarn配置
# 设置全局缓存
yarn config set cache-folder ~/.yarn
# 构建中优先使用缓存中
yarn install --prefer-offline
通过以上命令设置缓存目录,并确保下载依赖过程中优先使用本地缓存,可以最大限度减少由于外部网络导致的依赖下载慢的问题。
Npm构建加速
使用中国内地registry和mirror
说明
或者直接使用cnpm
对于使用npm的用户可以创建.npmrc并设置以下内容:
registry="https://registry.npmmirror.com"
sass_binary_site="https://npmmirror.com/mirrors/node-sass/"
phantomjs_cdnurl="https://cdn.npmmirror.com/binaries/phantomjs"
electron_mirror="https://cdn.npmmirror.com/binaries/electron/"
sqlite3_binary_host_mirror="https://foxgis.oss-cn-shanghai.aliyuncs.com/"
chromedriver_cdnurl="https://cdn.npmmirror.com/binaries/chromedriver"
构建中使用全局缓存
构建时,使用以下命令设置npm的全局缓存路径,并在流水线自定义缓存配置中添加/root/.npm缓存路径,并使用以下命令安装依赖包,优先从本地缓存获取依赖包:
npm config set cache ~/.npm
npm install --prefer-offline --no-audit
Golang构建加速
使用go proxy
使用Goproxy从中国内地下载外部依赖:
export GOPROXY=https://goproxy.cn
添加go mod缓存
持久化Go Mod缓存,Flow中Go构建环境的默认缓存目录是/go/pkg/mod。用户需要在流水线自定义缓存中添加该缓存路径即可。 在构建过程中将会优先使用/go/pkg/mod中的本地缓存,从而减少由于外部网络请求导致的构建慢的问题。
Python构建加速
使用pypi镜像
使用阿里云pypi镜像
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
添加pip依赖缓存
缓存pip本地依赖,流水线自定义缓存配置中添加缓存目录/root/.cache/pip,确保pip install时优先从版本缓存中获取依赖包
镜像构建加速
如果你的Dockerfile中FROM了dockerhub的镜像或者其他海外镜像,比如:
FROM nginx:1.19.1
.....
由于跨境网络问题,这种Dockerfile的构建会不稳定或者比较慢,可以使用以下方式解决:将境外镜像pull到本地,然后push到阿里云镜像仓库(cr.console.aliyun.com)的中国内地region(比如北京、上海等),然后修改你的Dockerfile中的FROM。比如:
docker pull nginx:1.19.1
docker tag nginx:1.19.1 registry.cn-beijing.aliyuncs.com/yournamespace/nginx:1.19.1
docker push registry.cn-beijing.aliyuncs.com/yournamespace/nginx:1.19.1主机Docker部署
添加Docker部署任务

编辑任务
选择前面添加好的主机组
部署脚本根据自己具体情况设置

我是在本地创建docker-compose.yml使用docker compose up -d命令部署,部署前要重新拉取下最新镜像
# cat docker-compose.yml
services:
icurvestar-blog:
image: registry.cn-hangzhou.aliyuncs.com/icurvestar/icurvestar-blog:latest
container_name: icurvestar-blog
ports:
- "127.0.0.1:18080:8080"
networks:
- icurvestar_net
networks:
icurvestar_net:
name: icurvestar_net
driver: bridge点击右上角更新并关闭保存模板
使用模板创建流水线
创建

添加流水线源

完整的流水线

运行流水线
手动运行或者提交代码测试一下

成功构建镜像并上传阿里云镜像仓库

可以到控制台查看

部署阶段

执行部署命令日志

服务器面板查看容器情况

流水线总耗时3分13秒
