Notes on R Container Creation and Usage
Overview
These notes go over the creation and use of a container for statistical analysis, using R and R packages. This container is also available at my GitHub for reproducing some research that I have conducted.
The container address in Docker is: ghcr.io/hellerepi/jgh_container:latest
You can also find the files for making the container at one of my GitHub repositories (here).
How to Use the Container
- Pull the image via Docker or Singularity
- Use image as needed
The details for these steps change in context, which I will note next.
Pulling the Container Image
Assuming you have a container image, you can pull the image to your local computer using Docker Desktop, or if you are in a virtual machine you can use another service like Singularity.
Each of these relies on command line tools. Example commands for pulling the container image are:
# Docker Desktop:
docker pull ghcr.io/hellerepi/jgh_container:latest
# Singularity
singularity pull docker://ghcr.io/hellerepi/jgh_container:latestUsing the Container Image
Once the container is pulled into your environment, you can just use it directly after starting docker or staging your .sif for singularity, and feed it scripts that you’ve previously made via the command line tools for Docker or Singularity. It is actually that convenient. Here are examples of how to use it via command line:
# Start Docker:
"C:\Program Files\Docker\Docker Desktop.exe"
# Docker run:
docker run --rm -v /path/to/project:/project ghcr.io/hellerepi/jgh_container:latest Rscript /project/myscript.R
# Singularity Run:
singularity exec jgh_container_latest.sif Rscript myscript.RFor this example, I assume you do not have admin privileges (and also you are on a windows system). If you did, you would be able to start the docker daemon direclty without using the deskotp. If you were wondering why I’m starting the .exe, that’s why. You could also use the point and click GUI for Docker Desktop as well here, no problem.
As long as you initialized Docker Desktop, you don’t have to do anything else. It’s daemon will spin up in the background and work until you explicitly force Docker to shut down (if you accidentally close the window, it will not shut your container down, so feel free).
Singularity does not have a daemon running, which is why it is considered more secure, but also this side-steps the need for this step.
Singularity’s command is a bit more compact because it provides a .sif file that identifies your container and has it ready to go, and this also provides a bit of extra security that some admin require for secure environments.
Also, you might recognize that --rm will remove something - and it does; this removes the image after you use it so that it’s only hogging disk space in use.
If you’re unfamiliar with the command line, most tools here have explanations of everything built in. For example, if I wanted to know what the command run needed as arguements in my docker run call, I can usually find all the information I need by using a --help call. E.g. docker --help. This also is good to just run and make sure your tool is ready to go in a virtual machine, or perhaps which.
Practical Usage
The image of the container is isolated and you will always route your file through the container, so it isn’t really the case that you can sort of run RStudio through your image - you are never going to “see” the container work, and always feed the work you do to the container via commands.
So, if you want to work “interactively,” this looks like working in RStudio, or the IDE of choice/obligation, then using the terminal in that environment to execute the R file.
For example, I edit my R files in Neovim or RStudio depending, and then if I want to use the container while I’m working in one of those editors I just open the terminal in Neovim or RStudio and execute my container commands there. This gives you the interactive editing, rather than only using a command line.
Container Creation
Here is a simple, but very practical example of a container. You can find it pre-made here at my GitHub account. I wanted something very stable, and I only really need a handful of packages outside of my own functions and base R, so it’s fairly straightforward. I also only use R in this container.
I used GitHub to help me make the container, which makes it really simple if you use their workflow tool. This means we’ll have a Dockerfile, an R Script and the .github/workflows/ component:
jgh_container/
├── Dockerfile
├── install_packages.R
└── .github/
└── workflows/
└── build-push.yml
This can be wherever you like, and can path to easily.
- Dockerfile: This is always named exactly
Dockerfile. The D is capitalized and there is no extension or hard stop. - R Script - This R script,
install_packages.Ris the R script that the dockerfile will run to install the packages I want in my container image. It will run this to create the image, then the image is captured and built with those packages in it. - A GitHub workflow - This is a YAML file that builds the container. GitHub will do everything we need, assuming we give it a proper workflow.
At this point I assume you can access the full files and code there at GitHub, and I will just explain a few parts that might be informative.
The workflow is submitted to a free, limited, and temporary virtual machine (VM) courtesy of GitHub. It’s very nice, and honestly I still am boggled by just being given a free VM because I asked, even if it only has 2 CPUs and 7 GB RAM. This VM understands YAML as-is, and can is ready for small tasks that github calls workflows. And, would you believe these VMs have Docker pre-installed? I will say, it does take a while for the jobs to be completed - the job to build this container seems to take just over 35 minutes, so if you are building a similar container, plan for a little downtime while this runs.
This workflow file finds my Dockerfile, and then the VM can build my container with Docker. Essentially, the Dockerfile starts a Linux machine with R from rocker, runs apt-get install [...] which is the command to install system libraries, copyies install_packages.R into the newly created Linux machine, installs the packages, and then captures the machine in an image.
This workflow will execute whenever it is pushed to GitHub, as well. Ideally this means you can push your container directory to GitHub after you’ve set everything up, and it will just make it happen without anything beyond a commit and push to the repository.
I do want to point out just a couple of things you can see in the Dockerfile. First, you can see that with COPY we are copying (who would have guessed) an R file into the Linux machine we are creating, which gives an example of how to just copy any file into your container. If you have an .Rprofile file that you want to include, some of your own functions, you can use the same manner of copying shown here with the install_packages.R file, and they will be incorporated into your container image for use wherever you need them.
You might also notice that the RUN chunks in the Dockerfile are just BASH commands passed to the terminal, so you can pretty much do anything from here!
Conlcusion
I thought that this would be a much longer set of notes when I started, but making a simple container is actually very simple. There are only a few steps, and the hardest thing is making the container in the first place, but now you have a few notes and an example to start you out.