You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Buildkite环境下Rails Docker Compose资产编译失效问题求助

Rails + Docker + Buildkite:预编译资产在容器运行时消失的问题

我正按照Buildkite官方示例,为Rails应用在Buildkite上搭建基于Docker和docker-compose的测试环境。在Dockerfile中,我们执行了资产编译操作,预期产物会生成到public/packs-test/目录,而且通过Dockerfile中的RUN ls /app/public命令也能确认该目录存在。但当Buildkite通过命令docker-compose -f docker-compose.yml run -e RAILS_ENV=test --rm app /bin/sh -e -c 'ls public'运行容器时,却看不到packs-test目录,导致每次运行测试时容器都会重新编译资产。本地测试时该目录正常存在,怀疑是Buildkite弹性栈的配置导致此问题,想请教是否遗漏了资产预编译的步骤,或有其他可行的解决思路?

Dockerfile

FROM ruby:2.5.1
# Lets us use "source"
SHELL ["/bin/bash", "-c"]
EXPOSE 5000
ENV RAILS_ENV=test
# Node/Yarn stuff
ENV NODE_VERSION 10.15.3
ENV YARN_VERSION 1.16.0
# Node, needed for asset pipeline
RUN curl -sSL "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" | tar --strip-components=2 -xJ -C /usr/local/bin/ node-v$NODE_VERSION-linux-x64/bin/node
RUN curl https://www.npmjs.com/install.sh | bash
# Install Yarn
RUN npm install -g "yarn@$YARN_VERSION"
WORKDIR /app
# Install Rubygems first
ADD Gemfile Gemfile.lock /app/
RUN gem install bundler \
    && bundle install -j 4
# Install npm libraries next
ADD package.json yarn.lock /app/
RUN yarn install --frozen-lockfile
# Now add the rest of your code
ADD . /app/
RUN RAILS_ENV="test" bundle exec rails assets:precompile
RUN ls /app/public
CMD ["rails", "server", "-p", "5000"]

docker-compose.yml

version: '3'
services:
  app:
    build: .
    depends_on:
      - db
      - redis
    volumes:
      - "./:/app"
    environment:
      REDIS_URL: redis://redis
    ports:
      - "5000:5000"
  db:
    image: postgres:10
  redis:
    image: redis

解决思路

我一眼就发现了核心问题——你的docker-compose.yml里把本地的./目录挂载到了容器的/app目录!这会直接覆盖掉Docker构建阶段生成的public/packs-test/目录:容器启动时,挂载的本地目录会替换掉容器内原本的/app路径内容。本地测试正常是因为你本地环境已经生成了预编译资产,但Buildkite弹性栈是全新的临时环境,工作目录里并没有这个预编译目录,所以容器启动后自然看不到。

这里有几个可行的解决办法:

  • 移除本地目录挂载(推荐):既然你已经在Dockerfile里把代码ADD到容器中,并且完成了资产预编译,测试环境完全不需要再挂载本地目录。修改docker-compose.yml的app服务,删掉volumes: - "./:/app"这一行即可,Buildkite运行时直接使用容器内已构建好的代码和资产。

  • 挂载时排除public目录:如果确实需要保留本地目录挂载(比如特殊调试场景),可以用Docker的绑定挂载排除规则,避免覆盖容器内的public目录。修改volumes配置为:

    volumes:
      - "./:/app"
      - "/app/public"
    

    这样Docker会保留容器内预编译好的/app/public目录,不会被本地的public目录覆盖。

  • 在Buildkite步骤中重新预编译(不推荐):如果上面的方法都不适用,也可以在Buildkite的运行命令里追加预编译步骤,但这会额外增加测试时间,失去提前预编译的意义。比如把命令改成:

    docker-compose -f docker-compose.yml run -e RAILS_ENV=test --rm app /bin/sh -e -c 'bundle exec rails assets:precompile && ls public && 你的测试命令'
    

另外提个小优化:你的Dockerfile已经设置了ENV RAILS_ENV=test,后面执行rails assets:precompile时没必要重复指定RAILS_ENV="test",直接写成RUN bundle exec rails assets:precompile就可以了。


内容的提问来源于stack exchange,提问作者Kyle Byrne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:37:46