Dockerfile 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. # syntax=docker/dockerfile:1.4
  2. # Please see https://docs.docker.com/engine/reference/builder for information about
  3. # the extended buildx capabilities used in this file.
  4. # Make sure multiarch TARGETPLATFORM is available for interpolation
  5. # See: https://docs.docker.com/build/building/multi-platform/
  6. ARG TARGETPLATFORM=${TARGETPLATFORM}
  7. ARG BUILDPLATFORM=${BUILDPLATFORM}
  8. # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.2"]
  9. ARG RUBY_VERSION="3.2.2"
  10. # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
  11. ARG NODE_MAJOR_VERSION="20"
  12. # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
  13. ARG DEBIAN_VERSION="bookworm"
  14. # Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
  15. FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node
  16. # Ruby image to use for base image based on combined variables (ex: 3.2.2-slim-bookworm)
  17. FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby
  18. # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
  19. # Example: v4.2.0-nightly.2023.11.09+something
  20. # Overwrite existance of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
  21. ARG MASTODON_VERSION_PRERELEASE=""
  22. # Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
  23. ARG MASTODON_VERSION_METADATA=""
  24. # Allow Ruby on Rails to serve static files
  25. # See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
  26. ARG RAILS_SERVE_STATIC_FILES="true"
  27. # Allow to use YJIT compiler
  28. # See: https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md
  29. ARG RUBY_YJIT_ENABLE="1"
  30. # Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
  31. ARG TZ="Etc/UTC"
  32. # Linux UID (user id) for the mastodon user, change with [--build-arg UID=1234]
  33. ARG UID="991"
  34. # Linux GID (group id) for the mastodon user, change with [--build-arg GID=1234]
  35. ARG GID="991"
  36. # Apply Mastodon build options based on options above
  37. ENV \
  38. # Apply Mastodon version information
  39. MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \
  40. MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \
  41. # Apply Mastodon static files and YJIT options
  42. RAILS_SERVE_STATIC_FILES=${RAILS_SERVE_STATIC_FILES} \
  43. RUBY_YJIT_ENABLE=${RUBY_YJIT_ENABLE} \
  44. # Apply timezone
  45. TZ=${TZ}
  46. ENV \
  47. # Configure the IP to bind Mastodon to when serving traffic
  48. BIND="0.0.0.0" \
  49. # Use production settings for Yarn, Node and related nodejs based tools
  50. NODE_ENV="production" \
  51. # Use production settings for Ruby on Rails
  52. RAILS_ENV="production" \
  53. # Add Ruby and Mastodon installation to the PATH
  54. DEBIAN_FRONTEND="noninteractive" \
  55. PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" \
  56. # Optimize jemalloc 5.x performance
  57. MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0"
  58. # Set default shell used for running commands
  59. SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"]
  60. ARG TARGETPLATFORM
  61. RUN echo "Target platform is $TARGETPLATFORM"
  62. RUN \
  63. # Remove automatic apt cache Docker cleanup scripts
  64. rm -f /etc/apt/apt.conf.d/docker-clean; \
  65. # Sets timezone
  66. echo "${TZ}" > /etc/localtime; \
  67. # Creates mastodon user/group and sets home directory
  68. groupadd -g "${GID}" mastodon; \
  69. useradd -l -u "${UID}" -g "${GID}" -m -d /opt/mastodon mastodon; \
  70. # Creates /mastodon symlink to /opt/mastodon
  71. ln -s /opt/mastodon /mastodon;
  72. # Set /opt/mastodon as working directory
  73. WORKDIR /opt/mastodon
  74. # hadolint ignore=DL3008,DL3005
  75. RUN \
  76. # Mount Apt cache and lib directories from Docker buildx caches
  77. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  78. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  79. # Apt update & upgrade to check for security updates to Debian image
  80. apt-get update; \
  81. apt-get dist-upgrade -yq; \
  82. # Install jemalloc, curl and other necessary components
  83. apt-get install -y --no-install-recommends \
  84. ca-certificates \
  85. curl \
  86. ffmpeg \
  87. file \
  88. imagemagick \
  89. libjemalloc2 \
  90. patchelf \
  91. procps \
  92. tini \
  93. tzdata \
  94. ; \
  95. # Patch Ruby to use jemalloc
  96. patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby; \
  97. # Discard patchelf after use
  98. apt-get purge -y \
  99. patchelf \
  100. ;
  101. # Create temporary build layer from base image
  102. FROM ruby as build
  103. # Copy Node package configuration files into working directory
  104. COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
  105. COPY .yarn /opt/mastodon/.yarn
  106. COPY --from=node /usr/local/bin /usr/local/bin
  107. COPY --from=node /usr/local/lib /usr/local/lib
  108. ARG TARGETPLATFORM
  109. # hadolint ignore=DL3008
  110. RUN \
  111. # Mount Apt cache and lib directories from Docker buildx caches
  112. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  113. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  114. # Install build tools and bundler dependencies from APT
  115. apt-get install -y --no-install-recommends \
  116. g++ \
  117. gcc \
  118. git \
  119. libgdbm-dev \
  120. libgmp-dev \
  121. libicu-dev \
  122. libidn-dev \
  123. libpq-dev \
  124. libssl-dev \
  125. make \
  126. shared-mime-info \
  127. zlib1g-dev \
  128. ;
  129. RUN \
  130. # Configure Corepack
  131. rm /usr/local/bin/yarn*; \
  132. corepack enable; \
  133. corepack prepare --activate;
  134. # Create temporary bundler specific build layer from build layer
  135. FROM build as bundler
  136. ARG TARGETPLATFORM
  137. # Copy Gemfile config into working directory
  138. COPY Gemfile* /opt/mastodon/
  139. RUN \
  140. # Mount Ruby Gem caches
  141. --mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \
  142. # Configure bundle to prevent changes to Gemfile and Gemfile.lock
  143. bundle config set --global frozen "true"; \
  144. # Configure bundle to not cache downloaded Gems
  145. bundle config set --global cache_all "false"; \
  146. # Configure bundle to only process production Gems
  147. bundle config set --local without "development test"; \
  148. # Configure bundle to not warn about root user
  149. bundle config set silence_root_warning "true"; \
  150. # Download and install required Gems
  151. bundle install -j"$(nproc)";
  152. # Create temporary node specific build layer from build layer
  153. FROM build as yarn
  154. ARG TARGETPLATFORM
  155. # Copy Node package configuration files into working directory
  156. COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
  157. COPY streaming/package.json /opt/mastodon/streaming/
  158. COPY .yarn /opt/mastodon/.yarn
  159. # hadolint ignore=DL3008
  160. RUN \
  161. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  162. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  163. # Install Node packages
  164. yarn workspaces focus --production @mastodon/mastodon;
  165. # Create temporary assets build layer from build layer
  166. FROM build as precompiler
  167. # Copy Mastodon sources into precompiler layer
  168. COPY . /opt/mastodon/
  169. # Copy bundler and node packages from build layer to container
  170. COPY --from=yarn /opt/mastodon /opt/mastodon/
  171. COPY --from=bundler /opt/mastodon /opt/mastodon/
  172. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  173. ARG TARGETPLATFORM
  174. RUN \
  175. # Use Ruby on Rails to create Mastodon assets
  176. OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
  177. # Cleanup temporary files
  178. rm -fr /opt/mastodon/tmp;
  179. # Prep final Mastodon Ruby layer
  180. FROM ruby as mastodon
  181. ARG TARGETPLATFORM
  182. # hadolint ignore=DL3008
  183. RUN \
  184. # Mount Apt cache and lib directories from Docker buildx caches
  185. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  186. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  187. # Mount Corepack and Yarn caches from Docker buildx caches
  188. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  189. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  190. # Apt update install non-dev versions of necessary components
  191. apt-get install -y --no-install-recommends \
  192. libssl3 \
  193. libpq5 \
  194. libicu72 \
  195. libidn12 \
  196. libreadline8 \
  197. libyaml-0-2 \
  198. ;
  199. # Copy Mastodon sources into final layer
  200. COPY . /opt/mastodon/
  201. # Copy compiled assets to layer
  202. COPY --from=precompiler /opt/mastodon/public/packs /opt/mastodon/public/packs
  203. COPY --from=precompiler /opt/mastodon/public/assets /opt/mastodon/public/assets
  204. # Copy bundler components to layer
  205. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  206. RUN \
  207. # Precompile bootsnap code for faster Rails startup
  208. bundle exec bootsnap precompile --gemfile app/ lib/;
  209. RUN \
  210. # Pre-create and chown system volume to Mastodon user
  211. mkdir -p /opt/mastodon/public/system; \
  212. chown mastodon:mastodon /opt/mastodon/public/system; \
  213. # Set Mastodon user as owner of tmp folder
  214. chown -R mastodon:mastodon /opt/mastodon/tmp;
  215. # Set the running user for resulting container
  216. USER mastodon
  217. # Expose default Puma ports
  218. EXPOSE 3000
  219. # Set container tini as default entry point
  220. ENTRYPOINT ["/usr/bin/tini", "--"]