提高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分钟左右,极大地提高了我们的生产效率。

相关推荐
南猿北者3 小时前
docker容器
docker·容器
二十雨辰3 小时前
[linux]docker基础
linux·运维·docker
time never ceases3 小时前
使用docker方式进行Oracle数据库的物理迁移(helowin/oracle_11g)
数据库·docker·oracle
老猿讲编程4 小时前
用示例来看C2Rust工具的使用和功能介绍
rust
金庆4 小时前
How to set_default() using config-rs crate
rust·config·set_default·valuekind
MonkeyKing_sunyuhua5 小时前
ubuntu22.04 docker-compose安装postgresql数据库
数据库·docker·postgresql
追风林6 小时前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
许野平7 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
€☞扫地僧☜€7 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
茶馆大橘7 小时前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud