Dockerfile 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. # Sets timezone
  64. echo "${TZ}" > /etc/localtime; \
  65. # Creates mastodon user/group and sets home directory
  66. groupadd -g "${GID}" mastodon; \
  67. useradd -l -u "${UID}" -g "${GID}" -m -d /opt/mastodon mastodon; \
  68. # Creates /mastodon symlink to /opt/mastodon
  69. ln -s /opt/mastodon /mastodon;
  70. # Set /opt/mastodon as working directory
  71. WORKDIR /opt/mastodon
  72. # hadolint ignore=DL3008,DL3005
  73. RUN \
  74. # Mount Apt cache and lib directories from Docker buildx caches
  75. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  76. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  77. # Apt update & upgrade to check for security updates to Debian image
  78. apt-get update; \
  79. apt-get dist-upgrade -yq; \
  80. # Install jemalloc, curl and other necessary components
  81. apt-get install -y --no-install-recommends \
  82. ca-certificates \
  83. curl \
  84. ffmpeg \
  85. file \
  86. imagemagick \
  87. libjemalloc2 \
  88. patchelf \
  89. procps \
  90. tini \
  91. tzdata \
  92. ; \
  93. # Patch Ruby to use jemalloc
  94. patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby; \
  95. # Discard patchelf after use
  96. apt-get purge -y \
  97. patchelf \
  98. ;
  99. # Create temporary build layer from base image
  100. FROM ruby as build
  101. # Copy Node package configuration files into working directory
  102. COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
  103. COPY .yarn /opt/mastodon/.yarn
  104. COPY --from=node /usr/local/bin /usr/local/bin
  105. COPY --from=node /usr/local/lib /usr/local/lib
  106. ARG TARGETPLATFORM
  107. # hadolint ignore=DL3008
  108. RUN \
  109. # Mount Apt cache and lib directories from Docker buildx caches
  110. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  111. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  112. # Install build tools and bundler dependencies from APT
  113. apt-get update; \
  114. apt-get install -y --no-install-recommends \
  115. g++ \
  116. gcc \
  117. git \
  118. libgdbm-dev \
  119. libgmp-dev \
  120. libicu-dev \
  121. libidn-dev \
  122. libpq-dev \
  123. libssl-dev \
  124. make \
  125. shared-mime-info \
  126. zlib1g-dev \
  127. ;
  128. RUN \
  129. # Configure Corepack
  130. rm /usr/local/bin/yarn*; \
  131. corepack enable; \
  132. corepack prepare --activate;
  133. # Create temporary bundler specific build layer from build layer
  134. FROM build as bundler
  135. ARG TARGETPLATFORM
  136. # Copy Gemfile config into working directory
  137. COPY Gemfile* /opt/mastodon/
  138. RUN \
  139. # Mount Ruby Gem caches
  140. --mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \
  141. # Configure bundle to prevent changes to Gemfile and Gemfile.lock
  142. bundle config set --global frozen "true"; \
  143. # Configure bundle to not cache downloaded Gems
  144. bundle config set --global cache_all "false"; \
  145. # Configure bundle to only process production Gems
  146. bundle config set --local without "development test"; \
  147. # Configure bundle to not warn about root user
  148. bundle config set silence_root_warning "true"; \
  149. # Download and install required Gems
  150. bundle install -j"$(nproc)";
  151. # Create temporary node specific build layer from build layer
  152. FROM build as yarn
  153. ARG TARGETPLATFORM
  154. # Copy Node package configuration files into working directory
  155. RUN apt-get update && \
  156. apt-get -yq dist-upgrade && \
  157. apt-get install -y --no-install-recommends build-essential \
  158. git \
  159. libicu-dev \
  160. libidn-dev \
  161. libpq-dev \
  162. libjemalloc-dev \
  163. zlib1g-dev \
  164. libgdbm-dev \
  165. libgmp-dev \
  166. libssl-dev \
  167. libyaml-dev \
  168. ca-certificates \
  169. libreadline8 \
  170. python3 \
  171. shared-mime-info && \
  172. bundle config set --local deployment 'true' && \
  173. bundle config set --local without 'development test' && \
  174. bundle config set silence_root_warning true && \
  175. corepack enable
  176. COPY Gemfile* package.json yarn.lock .yarnrc.yml /opt/mastodon/
  177. COPY streaming/package.json /opt/mastodon/streaming/
  178. COPY .yarn /opt/mastodon/.yarn
  179. # hadolint ignore=DL3008
  180. RUN \
  181. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  182. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  183. # Install Node packages
  184. yarn workspaces focus --production @mastodon/mastodon;
  185. # Create temporary assets build layer from build layer
  186. FROM build as precompiler
  187. # Copy Mastodon sources into precompiler layer
  188. COPY . /opt/mastodon/
  189. # Copy bundler and node packages from build layer to container
  190. COPY --from=yarn /opt/mastodon /opt/mastodon/
  191. COPY --from=bundler /opt/mastodon /opt/mastodon/
  192. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  193. ARG TARGETPLATFORM
  194. RUN \
  195. # Use Ruby on Rails to create Mastodon assets
  196. OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
  197. # Cleanup temporary files
  198. rm -fr /opt/mastodon/tmp;
  199. # Prep final Mastodon Ruby layer
  200. FROM ruby as mastodon
  201. ARG TARGETPLATFORM
  202. # hadolint ignore=DL3008
  203. RUN \
  204. # Mount Apt cache and lib directories from Docker buildx caches
  205. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  206. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  207. # Mount Corepack and Yarn caches from Docker buildx caches
  208. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  209. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  210. # Apt update install non-dev versions of necessary components
  211. apt-get update; \
  212. apt-get install -y --no-install-recommends \
  213. libssl3 \
  214. libpq5 \
  215. libicu72 \
  216. libidn12 \
  217. libreadline8 \
  218. libyaml-0-2 \
  219. ;
  220. # Copy Mastodon sources into final layer
  221. COPY . /opt/mastodon/
  222. # Copy compiled assets to layer
  223. COPY --from=precompiler /opt/mastodon/public/packs /opt/mastodon/public/packs
  224. COPY --from=precompiler /opt/mastodon/public/assets /opt/mastodon/public/assets
  225. # Copy bundler components to layer
  226. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  227. RUN \
  228. # Precompile bootsnap code for faster Rails startup
  229. bundle exec bootsnap precompile --gemfile app/ lib/;
  230. RUN \
  231. # Pre-create and chown system volume to Mastodon user
  232. mkdir -p /opt/mastodon/public/system; \
  233. chown mastodon:mastodon /opt/mastodon/public/system;
  234. # Set the running user for resulting container
  235. USER mastodon
  236. # Expose default Puma ports
  237. EXPOSE 3000
  238. # Set container tini as default entry point
  239. ENTRYPOINT ["/usr/bin/tini", "--"]