VPSPulse Mirrors

High-Performance Open-Source Archive

Docker and CI workflows

Docker and CI workflows

This vignette shows how to use sysreqr to generate system-requirement snippets for Docker images and CI pipelines. It assumes basic familiarity with both. See vignette("linux-fundamentals") for a primer.

The simple case: one project, one Dockerfile

If you have a project directory and want a Dockerfile snippet that installs its system requirements, pipe check_project() into dockerfile().

plan <- check_project(".", platform = "ubuntu-22.04")
cat(dockerfile(plan))

The output looks like this:

RUN apt-get update && apt-get install -y --no-install-recommends \
    libxml2-dev \
    libcurl4-openssl-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

Paste it into a Dockerfile immediately after the base image, or write it to a side file with write_dockerfile_snippet() and INCLUDE it from your build pipeline.

Always pass platform for Docker builds

When you build a Docker image, the container’s operating system is what matters, not your laptop. If you build a rocker/r-ver image from a Mac, the container is Debian-based. So always supply platform explicitly when generating Dockerfile snippets.

plan <- check_packages("xml2", platform = "ubuntu-22.04")
cat(dockerfile(plan))
#> RUN apt-get update && apt-get install -y --no-install-recommends \
#>     libxml2-dev \
#>     && rm -rf /var/lib/apt/lists/*

A two-stage Docker pattern

A common practice is to separate the build image (which has compilers and -dev headers) from the runtime image (which only has runtime libraries). This keeps the deployed image small.

# ---- Stage 1: build ----
FROM rocker/r-ver:4.4 AS build

# System build deps (compilers and headers)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libxml2-dev libcurl4-openssl-dev libssl-dev \
    && rm -rf /var/lib/apt/lists/*

COPY . /src
WORKDIR /src
RUN Rscript install-r-dependencies.R

# ---- Stage 2: runtime ----
FROM rocker/r-ver:4.4

# Runtime libraries only (note: no -dev suffix)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libxml2 libcurl4 libssl3 \
    && rm -rf /var/lib/apt/lists/*

COPY --from=build /usr/local/lib/R/site-library /usr/local/lib/R/site-library
COPY --from=build /src /app
WORKDIR /app
CMD ["R", "--no-save"]

sysreqr::dockerfile() produces the build-stage block. The runtime block, which uses the non--dev variants, is a manual mirror.

Pinning Posit Package Manager snapshots

For reproducible Docker images, point R at a dated PPM snapshot rather than latest.

url <- ppm_repo(platform = "ubuntu-22.04", snapshot = "2026-04-01")
url
#> [1] "https://packagemanager.posit.co/cran/__linux__/jammy/2026-04-01"

Drop those lines into your Dockerfile by way of Rscript -e or an .Rprofile written into the image:

RUN echo 'options(repos = c(CRAN = "https://packagemanager.posit.co/cran/__linux__/jammy/2026-04-01"))' \
    >> /usr/local/lib/R/etc/Rprofile.site

Combined with the system-package install above, this gives bit-for-bit reproducible installs.

GitHub Actions

github_actions() (alias gha()) generates a YAML step that runs the same install commands inside a GitHub-hosted Ubuntu runner.

plan <- check_packages(c("xml2", "curl"), platform = "ubuntu-22.04")
cat(github_actions(plan))
#> - name: Install Linux system dependencies
#>   run: |
#>     sudo apt-get update
#>     sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev

Paste it into .github/workflows/<your-workflow>.yaml after the actions/setup-r step:

jobs:
  R-CMD-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true

      - name: Install Linux system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libxml2-dev libcurl4-openssl-dev libssl-dev

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          needs: check

If you prefer to let the r-lib/actions ecosystem handle system requirements for you, use the extra-packages and needs inputs of setup-r-dependencies. sysreqr is then most useful for two things:

  1. Pre-CI auditing: run check_project(".") locally before pushing.
  2. CI for non-R-package projects (Shiny apps, scripts, reports), where the standard r-lib actions are less of a fit.

Beyond GitHub Actions

The install_command() output is portable across CI systems. For GitLab CI:

test:
  image: rocker/r-ver:4.4
  before_script:
    - apt-get update
    - apt-get install -y libxml2-dev libcurl4-openssl-dev libssl-dev
  script:
    - Rscript -e 'devtools::check()'

For Jenkins, Drone, or shell-driven CI, write the install script once:

write_install_script(plan, file.path(tempdir(), "install-sysreqs.sh"))

Then call sh ci/install-sysreqs.sh from any CI runner.

Posit Workbench and Posit Connect

Both Posit Workbench and Posit Connect benefit from Posit Package Manager binary R packages, which avoid source compilation entirely for the distributions they support. use_ppm("user") writes the .Rprofile fragment that points R at the right binary repository.

For Connect specifically, server administrators usually configure the repository at the server level, so end users only need the application code, not .Rprofile edits.

See also

Need mirroring services?
Contact our team at info@vpspulse.com.

Mirror powered by VPSpulse

Infrastructure sponsored by VPSPulse & Secure Payments by ArionPay.