Search code examples
dockerdockerfilebuilding-github-actions

Copy files to a Docker image using entrypoint instead of dockerfile for GitHub actions


I created a Dockerfile for my website development (Jekyll in this case, but I do not think that matters much).

In case this information is helpful, I code locally using Visual Studio Code and the Remote Containers extension. This extension allows me to manage my code locally while keeping it in sync with the container.

To publish my website, I run a GitHub Action that creates a container from my Dockerfile and then runs all the build code from an entrypoint.sh file. Here is the pertinent code from my Dockerfile:

FROM ruby:alpine as jekyll

ENV env_workspace_directory=$workspace_directory

... more irrelevant code ...

RUN echo "#################################################"
RUN echo "Copy the GitHub repo to the Docker container"
RUN echo "COPY . ${env_workspace_directory}"
COPY . ${env_workspace_directory}

RUN echo "#################################################"
RUN echo "Run the entrypoint "
ENTRYPOINT ["/entrypoint.sh"]

Because I am using the Remote Containers VS Code extension, I do not want the Dockerfile to contain the COPY . ${env_workspace_directory} code. Instead, I only want that code to run when used as a GitHub Action.

So I guess I have two questions, with the first being ideal:

  1. Is it possible to write like-type code that will copy the contents of the currently open GitHub branch (or at least the main branch), including all files and subfolders into the Docker container using the entrypoint.sh file instead? If so, what would that entrypoint.sh code look like?

  2. Is it possible to leave the COPY command in the Dockerfile and make it conditional? For example "Only run the COPY command if running from a GitHub Action"?

For #1 above, I reviewed this Stack Overflow article that says you can use the docker cp command, but I am unsure if that is (a) correct and (b) how to be sure I am using the $workspace_directory.

I am very new to Dockerfiles, writing shell commands, and GitHub Actions, so apologies if this question is an easy one or if more clarifications are required.

Here is the Development repo if that is useful.


Solution

  • A Docker volume mount happens after the image is built but before the main container process is run. So if you do something like

    docker run -v "$PWD/site:/site" your-image
    

    then the entrypoint.sh script will see the host content in the container's /site directory, even if something different had been COPYed in the Dockerfile.

    There are no conditionals or flow control in Dockerfiles, beyond shell syntax within individual RUN instructions. You could in principle access a Git repository in your container process, but managing the repository location, ssh credentials, branches, uncommitted files, etc. can get complex.

    Depending on how you're using the image, I could suggest two approaches here.

    If you have a deploy-time action that uses this image in its entirety to build the site, then just leave your Dockerfile as-is. In development use a bind mount to inject your host content; don't especially worry about skipping the image COPY here.

    Another approach is to build the image containing the Jekyll tool, but to treat the site itself as data. In that case you'd always run the image with a docker run -v or Compose volumes: option to inject the data. In the Dockerfile you might create an empty directory to be safe

    RUN mkdir "${env_workspace_directory}" # consider a fixed path
    

    and in your entrypoint script you can verify the site exists

    if [ ! -f "$env_workspace_directory/_site.yml" ]; then
      cat >&2 <<EOF
    There does not seem to be a Jekyll site in $env_workspace_directory.
    Please re-run this container with the site mounted.
    EOF
      exit 1
    fi