Buildkite环境下Rails Docker Compose资产编译失效问题求助
我正按照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

