Dockerfile updates (packages) not pushed to server

Hello all,

My app has already been deployed. I later discovered I needed additional packages installed on my server, namely poppler-utils and ffmpeg. I updated my dockerfile to reflect this and redeployed but these packages were not installed and I have to install them manually after every deployment.

The strange thing is, that other updates seem to have been pushed, albeit for different commands.

I know there is a way to do this, and my understanding is that the docs have been updated to reflect this, but I cannot seem to find the definitive answer to how this is done.

So, for the record, would someone please help with a list of steps.

Thank you all for your support.

Regards
Bashar

It would help if you posted your Dockerfile. It likely contains a series of FROM statements, each of which defines a separate build step. The step that is deployed is the last one, so either:

  • you need to install these packages in that step
  • that FROM step defines a previous step as its base, and you installed these packages in that step
  • (less frequently used) that step contains a COPY statement that copies that package from elsewhere.

Apologies for not having attached it earlier.
Here is my Dockerfile:


ARG RUBY_VERSION=3.3
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base

WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_DEPLOYMENT="1" \
    BUNDLE_PATH="/usr/local/bundle" \
    BUNDLE_WITHOUT="development"

# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential git libpq-dev node-gyp pkg-config python-is-python3 imagemagick libvips libvips-dev libvips-tools poppler-utils ffmpeg && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install JavaScript dependencies
ARG NODE_VERSION=20.17.0
ARG YARN_VERSION=1.22.22
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-build-master

# Install application gems
COPY Gemfile Gemfile.jumpstart Gemfile.lock ./.ruby-version ./
COPY ./lib/jumpstart/ ./lib/jumpstart/
COPY ./config/jumpstart.yml* ./config/jumpstart.yml
RUN bundle install && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile

# Install node modules
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Copy application code
COPY . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile

# Final stage for app image
FROM base

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

RUN mkdir -p /rails/tmp/signatures

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    chown -R rails:rails db log storage tmp tmp/signatures
USER 1000:1000

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

Hope this makes things easier for anyone to recommend and update.

Regards
Bashar

I just asked ChatGPT and this is the answer it gave me:

In a multistage Dockerfile, anything installed in an intermediate stage (build, in this case) won’t be available in the final image (base). Only files or layers explicitly copied from an intermediate stage make it to the final stage.

In your Dockerfile, poppler-utils and ffmpeg are indeed installed in the build stage but not transferred to the final base stage, where the app actually runs. So, they aren’t available when the container is running. The solution is to ensure they’re installed in the final stage where they’re needed.

To keep everything organized and install these only where necessary, here’s the adjusted version:

# Install runtime dependencies in the base stage
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y poppler-utils ffmpeg && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

Or if you prefer them to be universally available, add them to base:

# Install runtime dependencies in the base stage
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y poppler-utils ffmpeg && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

I’ll test this and get back to you all. Meanwhile, I would really appreciate it if someone with “human” intelligence could add to the conversation. Perhaps we can help others in the meantime.

Regards
Bashar

Last time I checked, I qualified as a human.

Without seeing your Dockerfile, I listed three solutions. With the benefit of seeing your dockerfile, ChatGPT narrowed this down to my first two.

Thank you very much @rubys for your support. I really appreciate it. I hope you understand I mean no disrespect as my “dry” words may sound. You’ve helped me save numerous hours of work.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.