V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
bologer
V2EX  ›  DevOps

CI/CD 每次 Build 前都要 npm install 一次吗? 每次安装依赖太浪费时间了

  •  1
     
  •   bologer · 2019-12-29 19:03:07 +08:00 · 11961 次点击
    这是一个创建于 1784 天前的主题,其中的信息可能已经有所发展或是发生改变。
    36 条回复    2020-07-05 14:59:24 +08:00
    springz
        1
    springz  
       2019-12-29 19:05:29 +08:00
    是的,所以大部分 CI/CD 工具都可以设置 cache 策略。
    我这里是直接通过 nfs 挂载。
    springz
        2
    springz  
       2019-12-29 19:06:17 +08:00
    编译 Android 将近 1G 的 .gradle
    ayase252
        3
    ayase252  
       2019-12-29 19:09:42 +08:00 via iPhone
    一般而言会有某种依赖的 cache 机制
    cz5424
        4
    cz5424  
       2019-12-29 19:10:31 +08:00 via iPhone
    提前 npm install 打包成镜像,然后用这个镜像来 ci/cd
    locoz
        5
    locoz  
       2019-12-29 19:13:57 +08:00
    加缓存啊
    lihongjie0209
        6
    lihongjie0209  
       2019-12-29 19:19:17 +08:00   ❤️ 3
    之前研究过, 最简单的办法就是在 npm install 之前判断一下 package.json 是否被修改过了, 如果没有就不需要 install 了。

    当然这么做的前提是你每次 npm install 的文件夹是可以在下一个 build 周期可见的, 类似每次用 docker 镜像的话你需要创建一个共享磁盘挂载上去。

    但我觉得 ci 最好不要有状态, 每次都重新构建可以避免一起奇怪的问题, 同时也保证了构建的可复现。

    所以最后的解决方案是在局域网内部搭建了一个缓存服务器 nexus, 用于缓存 npm/maven 的包, 这样可以极大的缩短构建时 install 的时间。

    但是这任然需要大量的磁盘 IO,npm install 一次几万个包都是正常现象, 所以还要优化的话就需要
    1. 换固态磁盘
    2. 使用内存文件系统

    我目前用的是 2, 构建速度已经很快了
    ccbikai
        7
    ccbikai  
       2019-12-29 19:20:39 +08:00 via iPhone
    npm ci
    jybox
        8
    jybox  
       2019-12-29 19:39:15 +08:00   ❤️ 8
    利用 Docker 的缓存:

    ADD package.json .
    RUN npm install
    ADD . .

    package.json 不变 Docker 就不会重新运行 npm install
    Rwing
        9
    Rwing  
       2019-12-29 19:39:18 +08:00
    这就是为什么很多 dockfile 都先 copy package.json 的原因,docker 自己有缓存,如果 package.json 没有变化的话。
    KnightYoung
        10
    KnightYoung  
       2019-12-29 19:44:32 +08:00
    @lihongjie0209 #6 应该是判断 lock 文件吧?
    Chingim
        11
    Chingim  
       2019-12-29 20:53:47 +08:00 via Android
    缓存 node_modules,然后在缓存的基础上 npm install,一般在 10 秒以内。
    rockyou12
        12
    rockyou12  
       2019-12-29 20:56:31 +08:00
    用 yarn 就是了,npm 本来就是设计傻逼了
    optional
        13
    optional  
       2019-12-29 21:04:48 +08:00 via iPhone
    @rockyou12 0202 年了
    rockyou12
        14
    rockyou12  
       2019-12-29 22:02:06 +08:00
    @optional 怎么,难道 npm 还能大改?要是 npm 还是有下一半断掉只能清空 node_modules 这种弱智问题,它就还是 sb
    indev
        15
    indev  
       2019-12-29 22:22:56 +08:00
    CI 设置好 cache,npm i 秒秒钟
    connection
        16
    connection  
       2019-12-29 22:45:35 +08:00
    优先 cache 呗
    springz
        17
    springz  
       2019-12-29 22:49:47 +08:00
    nfs 做一台缓存机,容器直接挂载也很方便的。
    Opportunity
        18
    Opportunity  
       2019-12-29 23:09:03 +08:00
    不是应该运行 npm ci 的吗?怎么都在用 npm install
    wangyzj
        19
    wangyzj  
       2019-12-29 23:51:50 +08:00
    yarn
    orvice
        20
    orvice  
       2019-12-30 00:00:55 +08:00
    如果用 docker 的话 有 cache
    seki
        21
    seki  
       2019-12-30 00:37:42 +08:00
    @Opportunity npm ci 的原理是删掉 node_modules 然后重新安装一遍,对 node_modules 文件夹做的缓存就没意义了
    seki
        22
    seki  
       2019-12-30 00:42:47 +08:00
    可以自己内部搭一个 npm 源, nuxus 或者 verdaccio ——不过 postinstall 就没办法了
    ci 能设置缓存的话也可以缓存一下 node_modules
    dcalsky
        23
    dcalsky  
       2019-12-30 01:04:47 +08:00 via Android
    想知道 go 和 python 都是怎么搞的
    PainAndLove
        24
    PainAndLove  
       2019-12-30 01:16:05 +08:00
    可以根据 yarn.lock 生成一个对应 node_modules 的缓存包。
    blless
        25
    blless  
       2019-12-30 01:17:29 +08:00 via Android
    @dcalsky go 设计之初就考虑了快速编译,本机编译还有缓存优化。但是走 ci 也是重头编译。另外就是 go 的依赖很轻,直接 vendor 跟项目集成就可以。所以也不用下载。
    python 也要下载,但是应该没有依赖地狱,具体也不太清楚了。要加速也得用 docker 那样做缓存。
    gkiwi
        26
    gkiwi  
       2019-12-30 01:34:46 +08:00
    残暴的方法,就是把 node_module 打成 tar 包,然后。。
    ===
    最初设计的方式也是基于 package.json md5 之类搞,但是越想越复杂,比如多人共享时候怎么办,最终偷懒了、、
    conn4575
        27
    conn4575  
       2019-12-30 02:29:24 +08:00 via Android
    go 和 python 也有类似的问题,不过依赖不像 node 这么恐怖,所以不明显,最佳方案还是使用 docker 这样的方式
    Trim21
        28
    Trim21  
       2019-12-30 07:23:19 +08:00 via Android
    @dcalsky
    python
    安装使用 pip install --user,然后把整个.local 文件夹缓存下来

    或者用虚拟环境,把 venv 缓存下来(这个遇到过缓存里面的 python 突然没法用的情况)。

    或者单纯的把 pip 的 http 缓存存下来,但这样每次还是要重新安装一遍,太慢了。
    pmispig
        29
    pmispig  
       2019-12-30 09:25:28 +08:00
    我的方案
    1: 把主要几个项目的 package.json add,npm install 在用户目录生成缓存,把这个做成基础镜像
    2: 项目在基础镜像的基础上,构建时,将外部目录 node_modules 挂载进来
    3:校验 package.json 的 md5 值,如果不变,就直接 build.变了就 install
    vevlins
        30
    vevlins  
       2019-12-30 09:47:38 +08:00 via iPhone
    我提一个问题,按照上面说的各种 package.json 不变就不重新构建,无法依靠 semantic 版本号进行小版本的自动更新了。
    winiex
        31
    winiex  
       2019-12-30 09:53:59 +08:00   ❤️ 1
    总算知道 npmjs.com 上庞大的下载数是怎么来的了= =
    KuroNekoFan
        32
    KuroNekoFan  
       2019-12-30 09:54:14 +08:00
    npm 本身就有 cache 啊...
    dcalsky
        33
    dcalsky  
       2019-12-30 11:55:15 +08:00 via Android
    @Trim21 缓存.local 之后打包到 docker 里怎么办? add .local 吗?
    Trim21
        34
    Trim21  
       2019-12-30 17:46:25 +08:00
    @dcalsky #33 你都用 docker 了,pip install 之后打个镜像不就行了吗
    lewinlan
        35
    lewinlan  
       2019-12-31 09:00:02 +08:00 via Android
    本地 runner 可以用 docker-volume 做缓存
    leohxj
        36
    leohxj  
       2020-07-05 14:59:24 +08:00
    利用 Docker Layer 缓存特性, 把 install 相关的文件单独 COPY

    ```
    COPY package.json yarn.lock
    RUN yarn install --frozen-lockfile
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1946 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:35 · PVG 08:35 · LAX 16:35 · JFK 19:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.