How to `bundle install` in Codespaces Dockerfile

In Codespaces, I can’t figure out how to run bundle install at the end of a Dockerfile.

Some variations I’ve tried are:

RUN bundle install

RUN bundle install --gemfile=/workspaces/marketing-website/Gemfile

WORKDIR workspaces/marketing-website
RUN bundle install

No dice; each time I get “Could not locate Gemfile,” despite the fact that I have a Gemfile in the root directory of my project, where you’d expect it to be.

I’m using the default Dockerfile for Ruby provided by Codespaces, with just the bundle install stuff added at the bottom. The full Dockerfile is pasted below.

I suspect the problem is that my project files haven’t actually been moved into a directory within the container yet. (I.e., I don’t see any COPY command or other magic that’s making this happen.)

Instead, it seems like my project files get into the container via the docker run command that GitHub/VS Code is executing for me. From the container’s creation log:

[2021-09-05T14:18:12.674Z] Start: Run: docker run --sig-proxy=false -a STDOUT -a STDERR --mount type=bind,src=/var/lib/docker/codespacemount/workspace/marketing-website/..,dst=/workspaces --mount source=/root/.codespaces/shared,target=/workspaces/.codespaces/shared,type=bind --mount source=/var/lib/docker/codespacemount/.persistedshare,target=/workspaces/.codespaces/.persistedshare,type=bind --mount source=/.codespaces/agent/mount,target=/.codespaces/bin,type=bind --mount source=/mnt/containerTmp,target=/tmp,type=bind --mount type=bind,src=/.codespaces/agent/mount/cache,dst=/vscode -l Type=codespaces -l vsch.remote.devPort=0 -e CODESPACES=true -e RepositoryName=marketing-website -e ContainerVersion=11 --label ContainerVersion=11 --hostname codespaces_896c3c --add-host codespaces_896c3c:127.0.0.1 --network host --entrypoint /bin/sh vsc-marketing-website-119993718dc2d88084025e55af5ac69f -c echo Container started

Do I understand correctly that, based on this setup, my project’s files haven’t been moved into the container while the Dockerfile commands are running?

I’ve tried to remedy this by adding the following to the Dockerfile:

COPY /var/lib/docker/codespacemount/workspace/marketing-website/Gemfile /workspaces/marketing-website/testing/

But this gives an error: [2021-09-05T15:02:58.680Z] COPY failed: file not found in build context or excluded by .dockerignore: stat var/lib/docker/codespacemount/workspace/marketing-website/Gemfile: file does not exist

Am I making a dumb mistake with COPY, or is the problem that I don’t have permissions to grab that (or any) file from the host’s filesystem?

If in fact I don’t have access to the host filesystem so I can’t COPY the Gemfile before running bundle install in the Dockerfile, what’s the “right way” to get my gems installed automatically upon container creation?

I know I can use “postCreateCommand” or the ENTRYPOINT technique described at https://code.visualstudio.com/docs/remote/containers-advanced, but I was hoping to do this within the Docker setup, so I can get the benefits of caching and a fast container startup if my Gemfile.lock hasn’t changed.

Dockerfile contents

# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/ruby/.devcontainer/base.Dockerfile

# [Choice] Ruby version: 3, 3.0, 2, 2.7, 2.6

ARG VARIANT="3.0"

FROM mcr.microsoft.com/vscode/devcontainers/ruby:0-${VARIANT}

# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10

ARG NODE_VERSION="none"

RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

# [Optional] Uncomment this section to install additional OS packages.

# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \

# && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment this line to install additional gems.

# RUN gem install <your-gem-names-here>

# [Optional] Uncomment this line to install global node packages.

# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

# Can't get any of these variations to work:

# WORKDIR "/var/lib/docker/codespacemount/workspaces/marketing-website"

# WORKDIR /workspaces/marketing-website

# RUN bundle install

# RUN bundle install --gemfile=/var/lib/docker/codespacemount/workspace/marketing-website/Gemfile

# RUN bundle install --gemfile=/workspaces/marketing-website/Gemfile

# Can't get this to work. Do I have permissions to access files on the host filesystem like this?
# COPY /var/lib/docker/codespacemount/workspace/marketing-website/Gemfile /workspaces/marketing-website/jho/

Update: problem solved!

My assumptions were correct about the project’s files not getting injected into the container until docker run.

Am I making a dumb mistake with COPY , or is the problem that I don’t have permissions to grab that (or any) file from the host’s filesystem?

The answer: yes, COPY does work fine; it was a dumb/simple fix:

Instead of COPY /var/lib/docker/codespacemount/workspace/marketing-website/Gemfile <destination_inside_container>, it’s just COPY Gemfile <destination_inside_container>,

with just one other gotcha:

because my project has a .devcontainer folder and then devcontainer.json within that folder, I needed to add “context”: “…” to the “build” config in that file. I found this clue in the Python example project for Codespaces here.

Here’s what the final Dockerfile looks like:

# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/ruby/.devcontainer/base.Dockerfile

# [Choice] Ruby version: 3, 3.0, 2, 2.7, 2.6
ARG VARIANT="3.0"
FROM mcr.microsoft.com/vscode/devcontainers/ruby:0-${VARIANT}

# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
#     && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment this line to install additional gems.
# RUN gem install <your-gem-names-here>

# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

COPY Gemfile /tmp/gemfile-tmp/
COPY Gemfile.lock /tmp/gemfile-tmp/
RUN bundle install --gemfile=/tmp/gemfile-tmp/Gemfile \
    && rm -rf /tmp/gemfile-tmp