《拿下奇怪的前端报错》:nvm不可用报错`GLIBC_2.27‘‘GLIBCXX_3.4.20‘not Found?+ 使用docker构建多个前端项目实践

news/2024/9/19 8:31:42/ 标签: 前端, docker, node.js

有些前端的小伙伴可能会好奇,nvm是什么?这里接简单介绍下,它是一个Nodejs版本管理工具。为什么需要它呢?当然是需要多个Nodejs版本的时候,那什么时候需要多个Nodejs版本?那肯定是在有点年头的公司了,例如vue2的很多依赖都是在Nodejs14年代的,如果你升级到Node20,那很可能会报错。如果你用vite创建新项目,那也肯定是没法在Node14下运行。(如果你问为啥要Nodejs,欢迎留言,或者看一部它的纪录片哈)

迭代过快虽然能够享受到各种新科技,但对于很多公司来说,去适配nodejs版本也是不太值得投入的成本。ε=(´ο`*)))唉,想想前端就累呀

报错信息具体内容

# node -v
node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node)
node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by node)

nodejs都不可用,更别说构建了,如果构建不出东西,在这个依赖框架的年代,就相当于白干啊!突然怀念jquery的时代了,(#^.^#)

触发场景

  1.  有老的vue项目,需要nodejs14 (这个必须的,18+就构建不了!)
  2. 有新的vue3项目,需要nodejs20+ (vite需要的,ε=(´ο`*)))唉,自己开发是挺爽,但没想到CI这里出问题了哈)
  3. 必须要jenkins上部署和构建(jenkins跑在linux上,之前我被windows server版docker搞的头发掉了一大撮)
  4. 构建物必须是一个docker镜像,这几个项目放在一个镜像(就是要一次构建多个项目)

好像上面是这个时代比较通用的了,于是便很自然的安装了nvm,构建不同项目之前,用nvm切换下。

问题分析

但是,当我构建vue3项目是,就遇到上面的报错了。呃,搜索一通,么得什么头绪,我发现切回去node16就可以了,啊,竟然是版本问题,后面发现是宿主机的centos版本太低了,我的天!我没想到一个前端竟然遇到这个问题,也算是长姿势了!

于是这时候就有个解决办法了,那就是让运维的部署点高版本的centos吧!提了个需求,但不知道何时才能实现,等等等

解决办法

看到这里,问题大概就是找到了,也可以解决了:那就是升级centos版本

解决问题思路扩展

docker容器内构建项目

但是我从第一性原理开始想,为啥我需要安装这个Nodejs呢?既然产出物是前端代码,部署又不需要这个nodejs(只需要一个nginx镜像+那些构建物),构建的时候能不能使用Docker构建,只要用不同的镜像去构建,不就可以了?说干就干。

下面是Dockerfile构建脚本: 阶段1构建,注意不同的项目修改自己node:版本 (这里用到了docker的多阶段构建,想了解的可以自己去研究,或许后期我会抽空介绍它的好处)

# 构建阶段
FROM node:20.16-alpine as builder# 设置工作目录
WORKDIR /app# 复制package.json和package-lock.json(如果存在)
COPY package*.json ./# 安装项目依赖
RUN npm install# 复制项目文件到工作目录
COPY . .# 构建应用
RUN npm run build

这个构建的产出物在镜像内的/app/dist,如果是直接docker部署,可以使用第二个stage直接复制到新的镜像中,但此时为考虑到某些场景需要提取出这个目录,就需要一个辅助的nodejs方法:

1. 构建

2. 启动容器

3. 复制到目标目录

启动临时容器复制到宿主机目录

一个全功能辅助的nodejs脚本

下面这个方法是一个build.cjs脚本内容,构建的时候,定义好需要构建的模块,然后node build.cjs就可以了,这里不展开。

function buildRunCopy(imageName, dockerfileDir, containerDist, outputDir) {// 生成容器名称const containerName = `container-${imageName}`;// 构建 Dockerfile 路径和输出目录的绝对路径const dockerfilePath = path.resolve(dockerfileDir, "Dockerfile");const hostDir = path.resolve(outputDir);try {// 创建宿主机目录(如果不存在的话)if (!fs.existsSync(hostDir)) {fs.mkdirSync(hostDir, { recursive: true });}// 构建 Docker 镜像console.log("Building Docker image...");execSync(`docker build -t ${imageName} -f ${dockerfilePath} ${dockerfileDir}`,{stdio: "inherit",cwd: dockerfileDir,});console.log("Docker image built successfully.");// 运行 Docker 容器console.log("Running Docker container...");execSync(`docker run --name ${containerName} -d ${imageName}`);console.log("Docker container started successfully.");// 复制容器内的目录到宿主机目录execSync(`docker cp ${containerName}:/${containerDist} ${hostDir}`);console.log("Files copied successfully.");} catch (error) {console.error(`Error: ${error.message}`);throw error;} finally {// 停止并移除 Docker 容器try {console.log("Removing Docker container...");execSync(`docker rm -f ${containerName}`);console.log("Docker container removed successfully.");} catch (removeError) {console.error(`Error removing Docker container: ${removeError.message}`);}}
}

脚本函数用法举例

下面就是一个例子:将项目某个test-app下面的项目进行构建,并将其构建物从/app/dist复制到原项目下面的dist目录

// 构建 build.cjs const basePath = path.join(projectsBasePath, "test-app");const tmpDistFolder = path.join(basePath, "dist");console.info(`清理构建临时目录`);fs.rmSync(tmpDistFolder, { recursive: true, force: true });buildRunCopy("test-app", basePath, "/app/dist", basePath);

然后就可以实现使用docker构建项目了,宿主机的nodejs只需要跑这个脚本,构建过程用到的nodejs是来自于容器内的,想用啥版本直接修改Dockerfile文件就可了

看完记得活动下脖子,这算是我今天的前3.5个小时的总结了...


http://www.ppmy.cn/news/1527594.html

相关文章

使用git命令

git add . git commit -m "commit message" 拉取 git pull origin <branch-name> 推送 git push origin <branch-name> 创建新分支 git branch <new-branch-name> # 切换到新分支 git checkout <new-branch-name> 合并分支 git mer…

区块链先驱孙宇晨:引领价值传播,激发行业创新活力

​孙宇晨&#xff0c;这位被誉为“区块链布道师”的年轻企业家&#xff0c;以其独特的愿景和行动力在区块链行业中脱颖而出。作为波场TRON的创始人&#xff0c;他不仅是区块链技术的倡导者&#xff0c;更是一位不懈推动行业发展的领导者。他通过自身的努力和影响力&#xff0c;…

C++ | Leetcode C++题解之第415题字符串相加

题目&#xff1a; 题解&#xff1a; class Solution { public:string addStrings(string num1, string num2) {int i num1.length() - 1, j num2.length() - 1, add 0;string ans "";while (i > 0 || j > 0 || add ! 0) {int x i > 0 ? num1[i] - 0 …

进程监控与管理详解

一、进程的定义: 进程process是正在运行的程序,包括: 分配的内存地址空间 安全属性、包括所有权和特权 一个或多个线程 进程状态 进程的环境包括: 本地和全局变量 当前调度上下文…

算法入门-贪心1

第八部分&#xff1a;贪心 409.最长回文串&#xff08;简单&#xff09; 给定一个包含大写字母和小写字母的字符串 s &#xff0c;返回通过这些字母构造成的最长的回文串 的长度。 在构造过程中&#xff0c;请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串…

清理C盘缓存的垃圾,专业清理C盘缓存垃圾的步骤与策略

在维护计算机系统的过程中&#xff0c;定期清理C盘&#xff08;通常是系统盘&#xff09;中的缓存和垃圾文件是一项至关重要的任务。这不仅能有效释放磁盘空间&#xff0c;提升系统性能&#xff0c;还能减少因磁盘空间不足导致的程序运行缓慢或错误。以下是一系列专业且安全的步…

在 Stable Diffusion 1.5 中 Lora, Dreambooth, Textual Inversion的详解指北

Lora, Dreambooth and Textual Inversion 说明 您是否想象过您可爱的宠物与埃菲尔铁塔合影的画面&#xff0c;或者想象过如何生成一张带有您朋友面孔的人工智能图像&#xff1f; 是的&#xff0c;通过稳定扩散技术的微调&#xff0c;这完全是可能的&#xff01; 创建这些场景…

LCR 023

题目&#xff1a;LCR 023 解法一&#xff1a;哈希表 将链表A所有元素放入Set中&#xff0c;遍历链表B元素&#xff0c;若某一元素在Set中存在&#xff0c;则该元素便是重复元素 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {Set<Object> set …

万兆时代 TCP/IP如何赋能以太网飞跃

科技飞速发展&#xff0c;数据传输的需求日益增长&#xff0c;尤其是在物理、科研等领域&#xff0c;对数据传输的速度、稳定性和效率提出了更高的要求。在这样的背景下&#xff0c;万兆以太网&#xff08;10Gbit Ethernet&#xff09;以其高带宽、低延迟和强大的传输能力成为众…

Pybind11的使用

目录 1. 引言1.1 Pybind11 简介1.2 为什么需要 Pybind11 2. 使用 Pybind11 进行 C 与 Python 交互2.1 基本用法2.2 编译与生成共享库2.2.1 在 Linux 下编译2.2.2 在 macOS 下编译2.2.3 编译选项详解 2.3 在 Python 中使用编译后的模块 3. 高级用法与注意事项3.1 绑定类和复杂数…

Open3D 特征点匹配(Python)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 假设有两个点云,即源点云与目标点云,这里基于目标点云每个点的FPFH特征向量为基础构建kdtree,以此我们可以以源点云中的FPFH特征向量为查询点,获取每个查询点对应的最近特征点(即目标点云中的FPFH特征向量)。…

算法打卡:第九章 动态规划part11

今日收获&#xff1a;最长公共子序列&#xff0c;不相交的线&#xff0c;最大子序和&#xff0c;判断子序列 1. 最长公共子序列 题目链接&#xff1a;1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; &#xff08;1&#xff09;dp[i][j]表示…

十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)

十&#xff0c;Spring Boot 的内容协商的详细剖析(附Debug调试说明) 文章目录 十&#xff0c;Spring Boot 的内容协商的详细剖析(附Debug调试说明)1. 基本介绍2. 准备工作3. 内容协商的本质4. 内容协商&#xff1a;注意事项和使用细节5. 总结&#xff1a;6. 最后&#xff1a; 1…

微信小程序中的模块化、组件化开发:完整指南

文章目录 前言一、模块化与组件化开发的优势1.1模块化开发的优势1.2 组件化开发的优势 二、组件的抽离标准及规范2.1 抽离组件的标准2.2 组件化开发规范 三、模块化规范的种类及优劣比较3.1 CommonJS3.2 ES6 Modules3.3 优劣对比 四、组件封装&#xff1a;全局组件、分包组件、…

PCIe扫盲(六)

系列文章目录 PCIe扫盲&#xff08;一&#xff09; PCIe扫盲&#xff08;二&#xff09; PCIe扫盲&#xff08;三&#xff09; PCIe扫盲&#xff08;四&#xff09; PCIe扫盲&#xff08;五&#xff09; PCIe扫盲&#xff08;六&#xff09; 文章目录 系列文章目录Flow Control…

【PHP】使用thinkphp5查询最大值时,把varchar类型字段转换成数字

有时候我们需要把carchar类型的字段进行聚合函数运运行&#xff08;max、min、avg&#xff09;&#xff0c;但是如果直接用聚合函数&#xff0c;得到的结果是错误的&#xff0c;因为varchar字段是字符串&#xff0c;无法直接使用聚合函数&#xff0c;所以需要把varchar字段转换…

apach httpd多后缀解析漏洞

漏洞详情&#xff1a; httpd支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。 那么&#xff0c;在有多个后缀的情况下&#xff0c;只要一个文件含有.php后缀的文件即将被识别成PHP文件&#xff0c;没必要是最后一个后缀。 利用这个特性&#xff0c;可以绕过…

[Linux]从零开始的泰山派系统安装与远程教程

一、前言 泰山派买回来也有一阵子了&#xff0c;最近慢慢开始研究。当然&#xff0c;学习这种Linux的开发板的第一步就是安装系统&#xff0c;对于RK系列的芯片系统安装有专门的软件&#xff0c;所有在系统安装方面比较简单。更多的还是我们应该怎么去编译系统&#xff0c;这一…

激光粉尘传感器:筑牢粮仓安全防线,有效应对粮食粉尘爆炸高危风险

随着我国农业的持续发展和粮食产量的稳步提升&#xff0c;2023年全国粮食总产量达到了13908.2亿斤&#xff0c;这一丰硕成果不仅保障了国家的粮食安全&#xff0c;也对粮食的储备、加工、运输等环节提出了更高的要求。然而&#xff0c;在粮食产业链的各个环节中&#xff0c;粮食…

[模板]树的最长路径

[模板]树的最长路径 题目描述 给定一棵树&#xff0c;树中包含 n 个结点&#xff08;编号1~n&#xff09;和 n-1 条无向边&#xff0c;每条边都有一个权值。 现在请你找到树中的一条最长路径。 换句话说&#xff0c;要找到一条路径&#xff0c;使得使得路径两端的点的距离最远…