Docker部署Rails7应用时esbuild平台不匹配问题求助
问题描述
在Macbook Pro Apple M1 Max上通过命令rails new app -d postgresql --css=tailwind --javascript=esbuild创建的Rails 7应用,本地运行正常,但部署到Docker容器启动时持续触发esbuild平台不匹配错误:容器需要@esbuild/linux-arm64包,当前存在的却是@esbuild/darwin-arm64包。已将node_modules加入.dockerignore,问题仍未解决。
错误信息
你安装的esbuild与当前运行平台不匹配。
这是因为esbuild由原生代码编写,需要安装对应平台的二进制可执行文件才能正常工作。当前环境存在的是
@esbuild/darwin-arm64包,但本平台需要的是@esbuild/linux-arm64包。通常出现这种情况的原因是在Windows或macOS上安装esbuild后,将node_modules目录复制到了运行Linux的Docker镜像中,或是在Windows和WSL环境之间复制了node_modules。如果你用npm安装,可以尝试复制文件时不拷贝
node_modules目录,在目标平台复制完成后运行npm ci或npm install。或者你可以考虑用yarn替代npm,它支持同时为多个平台安装包。如果你用yarn安装,可以在
.yarnrc.yml文件中通过supportedArchitectures特性同时列出当前平台和目标平台。注意这会导致存在多个esbuild副本。另一种方案是使用
esbuild-wasm包,它在所有平台上工作方式一致,但会带来显著的性能损耗,速度有时比原生esbuild慢10倍,所以可能不是最优选择。
技术栈
- Ruby: 3.2.1
- Rails: 7.0.4
现有配置
.dockerignore
node_modules/
Dockerfile
FROM ruby:3.2.1 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev ## Install Node RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - RUN apt update && apt -y install nodejs ## Install Yarn RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt update && apt install yarn RUN mkdir /app WORKDIR /app COPY Gemfile /app/Gemfile COPY Gemfile.lock /app/Gemfile.lock COPY package.json /app/package.json COPY yarn.lock /app/yarn.lock RUN bundle install RUN yarn EXPOSE 3000 CMD ["./bin/dev"]
问题原因及解决办法
原因分析
- yarn.lock平台锁定:在M1 Mac(darwin-arm64)环境下生成的
yarn.lock会记录对应平台的esbuild包版本,直接复制到Linux容器中执行yarn时,会优先安装lock文件中指定的darwin版本,而非适配Linux的版本。 - Node.js版本兼容问题:Docker中安装的Node.js 14.x对arm64架构的Linux支持不完善,导致yarn无法正确拉取对应平台的原生包。
解决方案
方案1:升级Node.js并重新生成yarn.lock
- 修改Dockerfile的Node.js安装部分,替换为支持arm64的新版本(如18.x):
## Install Node RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - RUN apt update && apt -y install nodejs - 调整Dockerfile的依赖安装步骤:删除
COPY yarn.lock /app/yarn.lock这一行,让容器内执行yarn install --production=false(确保安装开发依赖),自动生成适配Linux平台的lock文件,替代本地的darwin版本。
方案2:配置yarn支持多平台
在项目根目录创建.yarnrc.yml文件,添加以下内容,让yarn同时安装适配darwin-arm64和linux-arm64的包:
supportedArchitectures: cpu: - arm64 os: - darwin - linux
本地执行yarn install更新yarn.lock,再重新构建Docker镜像,此时lock文件会包含两个平台的esbuild包信息,容器内安装时会自动选择适配Linux的版本。
方案3:替换为esbuild-wasm(临时方案)
修改package.json,将esbuild依赖替换为跨平台的esbuild-wasm:
{ "devDependencies": { "esbuild-wasm": "^0.19.0" } }
执行yarn install更新依赖后构建Docker镜像。此方案无需处理平台适配,但会导致构建和打包速度大幅下降,仅适合临时测试使用。
内容的提问来源于stack exchange,提问作者RailsOverflow

