背景
接手了一台基于海思 Hi3519 的算法开发容器,想在里面装上 Claude Code 来辅助写代码。结果一上来就卡死:npm install 装不上、装上了又跑不起来,我一度以为是"容器内核版本太低"。
折腾了大半天才发现,问题压根不在内核,而是这台 Ubuntu 18.04 容器的 glibc 太旧。而且中途还被一堆吓人的报错带偏过两次。这篇就把整条路完整记录下来------在不重建容器的前提下,把 Claude Code 装上并跑起来。
我的环境如下:
| 配置项 | 详情 |
|---|---|
| 系统 | Ubuntu 18.04(容器,不可重建镜像) |
| 主机/平台 | Hi3519 嵌入式交叉编译环境 |
| 架构 | x86_64(交叉编译容器,板子才是 ARM) |
| glibc | 2.27 |
| 用户 | root |
| 目标 | 装上并跑通 claude(Claude Code CLI) |
⚠️ 先把结论摆这:Claude Code 官方要求 Node.js 18+ ,而 Node 18+ 的官方预编译二进制依赖 glibc 2.28+ ,Ubuntu 18.04 自带的是 glibc 2.27。所以真正卡你的几乎都是 glibc,不是内核。容器是和宿主机共享内核的,你在容器里本来也改不了内核。
准备工作
先花十秒确认一下你是不是和我同一种情况。
查 glibc 版本:
bash
ldd --version

如果第一行是 2.27(或更低),那 Node 18+ 的官方包在你这儿是跑不起来的,典型报错长这样:
node: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by node)

确认架构(后面下载要用):
bash
uname -m
我这里是 x86_64。如果你这儿显示 aarch64,后文所有下载链接和目录名里的 x64 都要换成 arm64。
思路很简单:Node.js 官方维护了一套非官方构建(unofficial-builds) ,其中 glibc-217 版本是专门用 glibc 2.17 编译的,反而能在我们这套 glibc 2.27 上正常运行。我们就用它装一个真正的 Node 22。
本文用到的版本清单:
- Node.js v22.11.0 (
linux-x64-glibc-217) - Claude Code:
@anthropic-ai/claude-code(npm 全局安装)
安装
一、下载并解压 glibc-217 版本的 Node 22
这一步是整篇的地基。下面这条命令把专为老系统编译的 Node 22 拉下来,它不需要 glibc 2.28:
bash
cd ~
curl -O https://unofficial-builds.nodejs.org/download/release/v22.11.0/node-v22.11.0-linux-x64-glibc-217.tar.gz
tar -xzf node-v22.11.0-linux-x64-glibc-217.tar.gz
解压后会得到 ~/node-v22.11.0-linux-x64-glibc-217/ 这个目录,真正的 node 就在它的 bin/ 下。
二、让新 node 全局生效(关键,别用 .bashrc)
很多教程让你把 export PATH=... 写进 ~/.bashrc,但在容器里这招经常失灵------后面有专门的避坑小节讲原因。我推荐一个完全不依赖 shell 配置、一次性永久生效 的办法:把新 node 软链进 /usr/local/bin,直接盖掉系统里的老 node。
bash
ln -sf ~/node-v22.11.0-linux-x64-glibc-217/bin/node /usr/local/bin/node
ln -sf ~/node-v22.11.0-linux-x64-glibc-217/bin/npm /usr/local/bin/npm
ln -sf ~/node-v22.11.0-linux-x64-glibc-217/bin/npx /usr/local/bin/npx
新开一个终端(不要手动 export 任何东西),验证 node 已经换成新版:
bash
which node # 应指向 /usr/local/bin/node
node -v # 应显示 v22.11.0

只要 node -v 稳定显示 v22.11.0,这一步就成了------以后无论用 bash 还是 sh、登录还是非登录 shell 进容器,node 都是新版。
⚠️ 避坑提示 :如果
which node还是指向老的(说明你这套环境里/usr/bin在 PATH 中排在/usr/local/bin前面),软链会被老的盖住。这种情况见下面"坑三"的兜底 wrapper 方案。
三、用新 node 的 npm 安装 Claude Code
为了让全局包装到一个统一、可控的位置(也方便后面升级),先把 npm 的全局目录固定到 /usr/local,再安装:
bash
npm config set prefix /usr/local
npm install -g @anthropic-ai/claude-code@latest
npm config set prefix 是持久的(写进 ~/.npmrc),装完后 cli.js 会落在 /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js,claude 命令则生成在 /usr/local/bin/claude。
测试 Claude Code 是否跑通
直接敲:
bash
claude --version

能正常打印出版本号、或者进入 claude 的交互界面而不是一屏报错,就说明装好了。

避坑提示(本文精华)
整条路我实际踩了三个坑,每一个都差点把我带沟里,单独拎出来讲。
⚠️ 坑一:别被"内核版本太低"带偏
我最开始的判断就是错的------以为容器内核太旧装不了。实际上:
- 容器和宿主机共享内核,你在容器里既改不了内核,Claude Code 也基本不依赖内核版本;
- 真凶是 glibc 2.27,而 Node 18+ 的官方二进制要 glibc 2.28+。
判断方法就是上面那条 ldd --version。看到 GLIBC_2.28 not found 就别再往内核方向想了,直接上 glibc-217 版本的 Node。
⚠️ 坑二:满屏报错别慌,真正的错误只有最后三行
我用一个老版本的 node 把 claude 装上后,一跑直接刷出几百行 密密麻麻的代码,看着像几百个错误。其实那一大坨 99% 是 cli.js 这个被极度压缩的文件的源代码 ------Node 抛语法错误时会把出错文件的内容一股脑打印出来。

真正有用的只有最后三行:
SyntaxError: Unexpected token '??='
at Loader.moduleStrategy (internal/modules/esm/translators.js:149:18)
at async link (internal/modules/esm/module_job.js:67:21)
??=(空值合并赋值)是 ES2021 的语法,需要 Node 15 以上 才认识。报这个错,就说明你实际运行 cli.js 的 node 是 14 或更老 (报错路径里 module_job.js 这种不带 node: 前缀的旧式内部模块名也能佐证)。
解决办法就是本文正文------换成真正的 Node 22。
顺带说一句,这一坨报错里还混着
proxyConnect、Replaying proxy buffer之类的字样,一度让我以为是代理出了问题。我还专门跑了curl -x "$https_proxy" -I https://api.anthropic.com,结果返回HTTP/2 403------这个 403 是正常的 (对根路径发没带 key 的请求,服务端就该拒),能看到server: cloudflare就证明代理和网络都没毛病。env | grep -i proxy也是空的,根本没代理。那段proxyConnect只是恰好是文件开头附近的代码被当作"出错上下文"打印了,纯属误导。认准最后那行SyntaxError就行。
总结
回头看,这次卡住的根因其实就一句话:老系统(Ubuntu 18.04 / glibc 2.27)装新工具(要 Node 18+),被 glibc 版本卡住了 。绕过的关键就是用 glibc-217 的非官方 Node 构建。
整条路最值钱的不是命令,而是那两次"误判→反转":别被"内核太低"带偏(真凶是 glibc),也别被满屏报错吓住(真正的错误只在最后三行,认准 ??= 就知道是 node 太老)。希望你能少走我这大半天的弯路。