-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile.multistage
More file actions
108 lines (92 loc) · 3.88 KB
/
Dockerfile.multistage
File metadata and controls
108 lines (92 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# ============================================================================
# MULTISTAGE DOCKERFILE (AFTER OPTIMIZATION)
# ============================================================================
# Key improvements:
# 1. Separate builder stage - build artifacts don't bloat final image
# 2. Strategic layer ordering - dependencies cached independently of code
# 3. Minimal runtime image - only what's needed to run the app
# 4. Faster builds through better caching - renv.lock changes rarely
# 5. Reduced final image size (~40-50% smaller)
# ============================================================================
# ============================================================================
# STAGE 1: Builder - Install dependencies
# ============================================================================
FROM rocker/r2u:24.04 AS builder
# Configure renv cache to use the same path as runtime
# This ensures symlinks remain valid when copied to runtime stage
ENV RENV_PATHS_CACHE="/app/renv/.cache"
# Install system dependencies needed for package compilation
RUN apt-get update && apt-get install -y \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
libfontconfig1-dev \
libharfbuzz-dev \
libfribidi-dev \
libfreetype6-dev \
libpng-dev \
libtiff5-dev \
libjpeg-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# OPTIMIZATION 1: Copy only dependency files first
# This creates a cache-friendly layer that only rebuilds when dependencies change
COPY renv.lock renv.lock
COPY .Rprofile .Rprofile
COPY renv/activate.R renv/activate.R
COPY renv/settings.json renv/settings.json
# OPTIMIZATION 2: Install renv and restore packages
# This layer is cached unless renv.lock changes
RUN R -e "install.packages('renv', repos = 'https://cloud.r-project.org')"
RUN R -e "renv::restore()"
# OPTIMIZATION 3: Copy application code AFTER dependencies are installed
# Code changes won't invalidate the expensive package installation layer
COPY app.R app.R
# ============================================================================
# STAGE 2: Runtime - Minimal production image
# ============================================================================
FROM rocker/r2u:24.04
# Configure renv cache location to match where packages were installed
ENV RENV_PATHS_CACHE="/app/renv/.cache"
# Install ONLY runtime system dependencies (no build tools)
# Note: Using minimal runtime libraries without -dev packages
RUN apt-get update && apt-get install -y --no-install-recommends \
libcurl4 \
libssl3 \
libxml2 \
libfontconfig1 \
libharfbuzz0b \
libfribidi0 \
libfreetype6 \
libpng16-16t64 \
libtiff6 \
libjpeg-turbo8 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy the entire renv library from builder stage (includes cache at /app/renv/.cache)
COPY --from=builder /app/renv /app/renv
COPY --from=builder /app/.Rprofile /app/.Rprofile
COPY --from=builder /app/renv.lock /app/renv.lock
# Copy application code
COPY --from=builder /app/app.R /app/app.R
# Expose Shiny port
EXPOSE 3838
# Run the application
# Note: Use --vanilla to skip .Rprofile and avoid renv activation at runtime
# The renv library path is already in R's search path
CMD ["R", "--vanilla", "-e", ".libPaths('/app/renv/library/linux-ubuntu-noble/R-4.5/x86_64-pc-linux-gnu'); shiny::runApp('/app', host = '0.0.0.0', port = 3838)"]
# ============================================================================
# Build and Run Commands:
# ============================================================================
# Build (single-stage):
# docker build -f Dockerfile.single-stage -t shiny-app:single .
#
# Build (multistage):
# docker build -f Dockerfile.multistage -t shiny-app:optimized .
#
# Run:
# docker run -p 3838:3838 shiny-app:optimized
#
# Compare sizes:
# docker images | grep shiny-app
# ============================================================================