提高GitLab CICD效率:Rust编译速度飙升秘籍

在GitLab CICD的流水线作业中,发现Rust编译速度是个瓶颈,因为耗费CPU,非常缓慢,一次构建居然需要20几分钟,这大大超出我们的心理预期。

sccache

经过调研,发现sccache可以优化二次编译的速度。本质上是将编译结果以某种方式缓存,下次编译时可以复用。

它可以使用cargo install sccache直接安装,也可以使用二进制文件,在这里下载sccache-v0.3.0-x86_64-unknown-linux-musl.tar.gz。也可以用代理加速:archive.fastgit.org/mozilla/scc...

对于我们而言,我们可以将sccache的编译结果存储在NAS中,这样不同的工作空间就可以共享缓存。

优化

修改GitLab Runner运行时镜像,Rust默认的环境变量,其实就是缓存位置:

dockerfile 复制代码
FROM rust:1.62.1

WORKDIR /app

ENV TZ "Asia/Shanghai"
# 更改cargo的默认位置,在物理机上通常是~/.cargo,而容器里是/usr/local/cargo
ENV CARGO_HOME="/rust-cache/cargo"
# 更改rustc的编译文件
ENV RUSTC_WRAPPER="/rust-cache/bin/sccache"
# 更改sccache的默认缓存位置,也就是~/.cache/sccache
ENV SCCACHE_DIR="/rust-cache/sccache"

再在K8S使用helm创建GitLab Runner用到的图------gitlab-runner中需要缓存的地方挂载出来:

toml 复制代码
[[runners.kubernetes.volumes.pvc]]
name = "runner-rust-cache"
mount_path = "/rust-cache/config" 
sub_path = "config"
readOnly = true

[[runners.kubernetes.volumes.pvc]]
name = "runner-rust-cache"
mount_path = "/rust-cache/sccache"   
sub_path = "sccache"
readOnly = true

[[runners.kubernetes.volumes.pvc]]
name = "runner-rust-cache"
mount_path = "/rust-cache/bin/sccache"
sub_path = "bin/sccache"

[[runners.kubernetes.volumes.pvc]]
name = "runner-rust-cache"
mount_path = "/rust-cache/registry/cache" 
sub_path = "registry/cache" 

[[runners.kubernetes.volumes.pvc]]
name = "runner-rust-cache"
mount_path = "/rust-cache/registry/index"   
sub_path = "registry/index" 

这里的runner-rust-cache,是需要挂载的pvc:

yaml 复制代码
---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: runner-rust-cache
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  storageClassName: runner-rust-cache
  mountOptions:
    - vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport
  nfs:
    server: "xx.amazonaws.com.cn"
    path: "/mnt/runner/rust"

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: runner-rust-cache
  namespace: gitlab-runner
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: runner-rust-cache
  resources:
    requests:
      storage: 10Gi

验证

挂载前,24分36秒:

挂载后7分14秒: 这个时间虽然仍不理想,但差强人意。

mold

mold是现有Unix链接器的更快的替代品。它比LLVM lld链接器快几倍,后者是第二快的开源链接器。mold旨在通过最小化构建时间,特别是在快速调试-编辑-重建周期中,提高开发人员的生产力。

所以重点是,它可以加快链接速度,也就是我们使用cargo build看到控制台一系列输出编译中的最后一步(前面都是编译具体某个包,最后一步是将这些内容整合)。在这里下载:github.com/rui314/mold...,或者换用代理加速:archive.fastgit.org/rui314/mold...

需要在cargo目录的config中配置:

toml 复制代码
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/xx/mold-1.4.0-x86_64-linux/bin/mold"]

第一次耗时正常是23分14秒。

加了mold之后是20分30秒,节省了不到3分钟。

有了sccache缓存后,正常是7分54秒:

加了mold以后是6分18秒,节省了一分半。

以下是一个集成了sccache和mold的基础镜像,用来在流水线中构建产物(运行cargo build):

dockerfile 复制代码
FROM rust:alpine3.17

WORKDIR /app

RUN set -eux && sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
  && apk update \
  && apk add --no-cache musl-dev pkgconfig openssl-dev clang wget make git bzip2 ca-certificates python3 bash build-base coreutils gcompat libgcc libc-dev

RUN mkdir download && cd download \
  && wget https://github.com/rui314/mold/releases/download/v1.4.0/mold-1.4.0-x86_64-linux.tar.gz && tar xzvf mold-1.4.0-x86_64-linux.tar.gz && mv mold-1.4.0-x86_64-linux ../mold \
  && wget https://github.com/mozilla/sccache/releases/download/v0.3.0/sccache-v0.3.0-x86_64-unknown-linux-musl.tar.gz && tar xzvf sccache-v0.3.0-x86_64-unknown-linux-musl.tar.gz && mv sccache-v0.3.0-x86_64-unknown-linux-musl/sccache ../ && chmod +x /app/sccache \ 
  && apk del -f wget \
  && rm -rf /var/lib/apt/lists/* && rm -rf ../download 

ENV TZ "Asia/Shanghai"
ENV CARGO_HOME="/rust-cache/cargo"
ENV RUSTC_WRAPPER="/app/sccache"
ENV SCCACHE_DIR="/rust-cache/sccache"
ENV RUSTFLAGS="-C target-feature=-crt-static"

CMD /bin/bash

这里安装了不少依赖,都是我们项目中用到的,读者可以视情况做些删减。

我们线上的cargo配置为:

toml 复制代码
[source.crates-io]
replace-with = 'tuna'

[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"

[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/app/mold/bin/mold"]

调整CPU

我们本机构建Rust产物也没有那么慢,为什么流水线就那么慢呢?

相对于前端项目,Rust的构建可谓是非常消耗CPU了。我们的前端项目构建通常在3分钟左右,最长的有10分钟。

所以针对Rust项目,调大runner的CPU,原来是200m:

yaml 复制代码
builds:
  cpuLimit: 600m
  cpuRequests: 200m

修改为1,相当于从0.2升到1:

yaml 复制代码
builds:
  cpuLimit: 1.5
  cpuRequests: 1

第一次缩减到5分钟,使用sccache后缩减到3分钟左右,这样差不多就可以忍受了。

总结

在GitLab CICD的流水线作业中,Rust编译速度是个瓶颈,我们通过sccache共享缓存和使用mold加速链接,以及最终调整runner分配的CPU,将一个项目首次耗时从23分钟降到5分钟,后续耗时降到3分钟左右,极大地提高了我们的生产效率。

相关推荐
冬奇Lab9 小时前
一天一个开源项目(第41篇):Workout.cool - 现代化开源健身教练平台,训练计划与进度追踪
docker·开源·资讯
天朝八阿哥16 小时前
使用Docker+vscode搭建离线的go开发调试环境
后端·docker·visual studio code
DongLi012 天前
rustlings 学习笔记 -- exercises/06_move_semantics
rust
阿虎儿2 天前
Docker安装(非sudo用户可用)
docker
ssshooter2 天前
Tauri 踩坑 appLink 修改后闪退
前端·ios·rust
布列瑟农的星空2 天前
前端都能看懂的rust入门教程(二)——函数和闭包
前端·后端·rust
蚂蚁背大象3 天前
Rust 所有权系统是为了解决什么问题
后端·rust
布列瑟农的星空3 天前
前端都能看懂的rust入门教程(五)—— 所有权
rust
fetasty3 天前
rustfs加picgo图床搭建
docker
蝎子莱莱爱打怪3 天前
GitLab CI/CD + Docker Registry + K8s 部署完整实战指南
后端·docker·kubernetes