Dockerfile 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. # syntax=docker/dockerfile:1.10
  2. # This file is designed for production server deployment, not local development work
  3. # For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/README.md#docker
  4. # Please see https://docs.docker.com/engine/reference/builder for information about
  5. # the extended buildx capabilities used in this file.
  6. # Make sure multiarch TARGETPLATFORM is available for interpolation
  7. # See: https://docs.docker.com/build/building/multi-platform/
  8. ARG TARGETPLATFORM=${TARGETPLATFORM}
  9. ARG BUILDPLATFORM=${BUILDPLATFORM}
  10. # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"]
  11. # renovate: datasource=docker depName=docker.io/ruby
  12. ARG RUBY_VERSION="3.3.6"
  13. # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
  14. # renovate: datasource=node-version depName=node
  15. ARG NODE_MAJOR_VERSION="22"
  16. # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
  17. ARG DEBIAN_VERSION="bookworm"
  18. # Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
  19. FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node
  20. # Ruby image to use for base image based on combined variables (ex: 3.3.x-slim-bookworm)
  21. FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
  22. # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
  23. # Example: v4.3.0-nightly.2023.11.09+pr-123456
  24. # Overwrite existence of 'alpha.X' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
  25. ARG MASTODON_VERSION_PRERELEASE=""
  26. # Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="pr-123456"]
  27. ARG MASTODON_VERSION_METADATA=""
  28. # Will be available as Mastodon::Version.source_commit
  29. ARG SOURCE_COMMIT=""
  30. # Allow Ruby on Rails to serve static files
  31. # See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
  32. ARG RAILS_SERVE_STATIC_FILES="true"
  33. # Allow to use YJIT compiler
  34. # See: https://github.com/ruby/ruby/blob/v3_2_4/doc/yjit/yjit.md
  35. ARG RUBY_YJIT_ENABLE="1"
  36. # Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
  37. ARG TZ="Etc/UTC"
  38. # Linux UID (user id) for the mastodon user, change with [--build-arg UID=1234]
  39. ARG UID="991"
  40. # Linux GID (group id) for the mastodon user, change with [--build-arg GID=1234]
  41. ARG GID="991"
  42. # Apply Mastodon build options based on options above
  43. ENV \
  44. # Apply Mastodon version information
  45. MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \
  46. MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \
  47. SOURCE_COMMIT="${SOURCE_COMMIT}" \
  48. # Apply Mastodon static files and YJIT options
  49. RAILS_SERVE_STATIC_FILES=${RAILS_SERVE_STATIC_FILES} \
  50. RUBY_YJIT_ENABLE=${RUBY_YJIT_ENABLE} \
  51. # Apply timezone
  52. TZ=${TZ}
  53. ENV \
  54. # Configure the IP to bind Mastodon to when serving traffic
  55. BIND="0.0.0.0" \
  56. # Use production settings for Yarn, Node and related nodejs based tools
  57. NODE_ENV="production" \
  58. # Use production settings for Ruby on Rails
  59. RAILS_ENV="production" \
  60. # Add Ruby and Mastodon installation to the PATH
  61. DEBIAN_FRONTEND="noninteractive" \
  62. PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" \
  63. # Optimize jemalloc 5.x performance
  64. MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0" \
  65. # Enable libvips, should not be changed
  66. MASTODON_USE_LIBVIPS=true \
  67. # Sidekiq will touch tmp/sidekiq_process_has_started_and_will_begin_processing_jobs to indicate it is ready. This can be used for a readiness check in Kubernetes
  68. MASTODON_SIDEKIQ_READY_FILENAME=sidekiq_process_has_started_and_will_begin_processing_jobs
  69. # Set default shell used for running commands
  70. SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"]
  71. ARG TARGETPLATFORM
  72. RUN echo "Target platform is $TARGETPLATFORM"
  73. RUN \
  74. # Remove automatic apt cache Docker cleanup scripts
  75. rm -f /etc/apt/apt.conf.d/docker-clean; \
  76. # Sets timezone
  77. echo "${TZ}" > /etc/localtime; \
  78. # Creates mastodon user/group and sets home directory
  79. groupadd -g "${GID}" mastodon; \
  80. useradd -l -u "${UID}" -g "${GID}" -m -d /opt/mastodon mastodon; \
  81. # Creates /mastodon symlink to /opt/mastodon
  82. ln -s /opt/mastodon /mastodon;
  83. # Set /opt/mastodon as working directory
  84. WORKDIR /opt/mastodon
  85. # hadolint ignore=DL3008,DL3005
  86. RUN \
  87. # Mount Apt cache and lib directories from Docker buildx caches
  88. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  89. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  90. # Apt update & upgrade to check for security updates to Debian image
  91. apt-get update; \
  92. apt-get dist-upgrade -yq; \
  93. # Install jemalloc, curl and other necessary components
  94. apt-get install -y --no-install-recommends \
  95. curl \
  96. file \
  97. libjemalloc2 \
  98. patchelf \
  99. procps \
  100. tini \
  101. tzdata \
  102. wget \
  103. ; \
  104. # Patch Ruby to use jemalloc
  105. patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby; \
  106. # Discard patchelf after use
  107. apt-get purge -y \
  108. patchelf \
  109. ;
  110. # Create temporary build layer from base image
  111. FROM ruby AS build
  112. # Copy Node package configuration files into working directory
  113. COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
  114. COPY .yarn /opt/mastodon/.yarn
  115. COPY --from=node /usr/local/bin /usr/local/bin
  116. COPY --from=node /usr/local/lib /usr/local/lib
  117. ARG TARGETPLATFORM
  118. # hadolint ignore=DL3008
  119. RUN \
  120. # Mount Apt cache and lib directories from Docker buildx caches
  121. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  122. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  123. # Install build tools and bundler dependencies from APT
  124. apt-get install -y --no-install-recommends \
  125. autoconf \
  126. automake \
  127. build-essential \
  128. cmake \
  129. git \
  130. libgdbm-dev \
  131. libglib2.0-dev \
  132. libgmp-dev \
  133. libicu-dev \
  134. libidn-dev \
  135. libpq-dev \
  136. libssl-dev \
  137. libtool \
  138. meson \
  139. nasm \
  140. pkg-config \
  141. shared-mime-info \
  142. xz-utils \
  143. # libvips components
  144. libcgif-dev \
  145. libexif-dev \
  146. libexpat1-dev \
  147. libgirepository1.0-dev \
  148. libheif-dev \
  149. libimagequant-dev \
  150. libjpeg62-turbo-dev \
  151. liblcms2-dev \
  152. liborc-dev \
  153. libspng-dev \
  154. libtiff-dev \
  155. libwebp-dev \
  156. # ffmpeg components
  157. libdav1d-dev \
  158. liblzma-dev \
  159. libmp3lame-dev \
  160. libopus-dev \
  161. libsnappy-dev \
  162. libvorbis-dev \
  163. libvpx-dev \
  164. libx264-dev \
  165. libx265-dev \
  166. ;
  167. RUN \
  168. # Configure Corepack
  169. rm /usr/local/bin/yarn*; \
  170. corepack enable; \
  171. corepack prepare --activate;
  172. # Create temporary libvips specific build layer from build layer
  173. FROM build AS libvips
  174. # libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
  175. # renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
  176. ARG VIPS_VERSION=8.16.0
  177. # libvips download URL, change with [--build-arg VIPS_URL="https://github.com/libvips/libvips/releases/download"]
  178. ARG VIPS_URL=https://github.com/libvips/libvips/releases/download
  179. WORKDIR /usr/local/libvips/src
  180. # Download and extract libvips source code
  181. ADD ${VIPS_URL}/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.xz /usr/local/libvips/src/
  182. RUN tar xf vips-${VIPS_VERSION}.tar.xz;
  183. WORKDIR /usr/local/libvips/src/vips-${VIPS_VERSION}
  184. # Configure and compile libvips
  185. RUN \
  186. meson setup build --prefix /usr/local/libvips --libdir=lib -Ddeprecated=false -Dintrospection=disabled -Dmodules=disabled -Dexamples=false; \
  187. cd build; \
  188. ninja; \
  189. ninja install;
  190. # Create temporary ffmpeg specific build layer from build layer
  191. FROM build AS ffmpeg
  192. # ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
  193. # renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
  194. ARG FFMPEG_VERSION=7.1
  195. # ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"]
  196. ARG FFMPEG_URL=https://ffmpeg.org/releases
  197. WORKDIR /usr/local/ffmpeg/src
  198. # Download and extract ffmpeg source code
  199. ADD ${FFMPEG_URL}/ffmpeg-${FFMPEG_VERSION}.tar.xz /usr/local/ffmpeg/src/
  200. RUN tar xf ffmpeg-${FFMPEG_VERSION}.tar.xz;
  201. WORKDIR /usr/local/ffmpeg/src/ffmpeg-${FFMPEG_VERSION}
  202. # Configure and compile ffmpeg
  203. RUN \
  204. ./configure \
  205. --prefix=/usr/local/ffmpeg \
  206. --toolchain=hardened \
  207. --disable-debug \
  208. --disable-devices \
  209. --disable-doc \
  210. --disable-ffplay \
  211. --disable-network \
  212. --disable-static \
  213. --enable-ffmpeg \
  214. --enable-ffprobe \
  215. --enable-gpl \
  216. --enable-libdav1d \
  217. --enable-libmp3lame \
  218. --enable-libopus \
  219. --enable-libsnappy \
  220. --enable-libvorbis \
  221. --enable-libvpx \
  222. --enable-libwebp \
  223. --enable-libx264 \
  224. --enable-libx265 \
  225. --enable-shared \
  226. --enable-version3 \
  227. ; \
  228. make -j$(nproc); \
  229. make install;
  230. # Create temporary bundler specific build layer from build layer
  231. FROM build AS bundler
  232. ARG TARGETPLATFORM
  233. # Copy Gemfile config into working directory
  234. COPY Gemfile* /opt/mastodon/
  235. RUN \
  236. # Mount Ruby Gem caches
  237. --mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \
  238. # Configure bundle to prevent changes to Gemfile and Gemfile.lock
  239. bundle config set --global frozen "true"; \
  240. # Configure bundle to not cache downloaded Gems
  241. bundle config set --global cache_all "false"; \
  242. # Configure bundle to only process production Gems
  243. bundle config set --local without "development test"; \
  244. # Configure bundle to not warn about root user
  245. bundle config set silence_root_warning "true"; \
  246. # Download and install required Gems
  247. bundle install -j"$(nproc)";
  248. # Create temporary node specific build layer from build layer
  249. FROM build AS yarn
  250. ARG TARGETPLATFORM
  251. # Copy Node package configuration files into working directory
  252. COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
  253. COPY streaming/package.json /opt/mastodon/streaming/
  254. COPY .yarn /opt/mastodon/.yarn
  255. # hadolint ignore=DL3008
  256. RUN \
  257. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  258. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  259. # Install Node packages
  260. yarn workspaces focus --production @mastodon/mastodon;
  261. # Create temporary assets build layer from build layer
  262. FROM build AS precompiler
  263. # Copy Mastodon sources into precompiler layer
  264. COPY . /opt/mastodon/
  265. # Copy bundler and node packages from build layer to container
  266. COPY --from=yarn /opt/mastodon /opt/mastodon/
  267. COPY --from=bundler /opt/mastodon /opt/mastodon/
  268. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  269. # Copy libvips components to layer for precompiler
  270. COPY --from=libvips /usr/local/libvips/bin /usr/local/bin
  271. COPY --from=libvips /usr/local/libvips/lib /usr/local/lib
  272. ARG TARGETPLATFORM
  273. RUN \
  274. ldconfig; \
  275. # Use Ruby on Rails to create Mastodon assets
  276. SECRET_KEY_BASE_DUMMY=1 \
  277. bundle exec rails assets:precompile; \
  278. # Cleanup temporary files
  279. rm -fr /opt/mastodon/tmp;
  280. # Prep final Mastodon Ruby layer
  281. FROM ruby AS mastodon
  282. ARG TARGETPLATFORM
  283. # hadolint ignore=DL3008
  284. RUN \
  285. # Mount Apt cache and lib directories from Docker buildx caches
  286. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  287. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  288. # Mount Corepack and Yarn caches from Docker buildx caches
  289. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  290. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  291. # Apt update install non-dev versions of necessary components
  292. apt-get install -y --no-install-recommends \
  293. libexpat1 \
  294. libglib2.0-0 \
  295. libicu72 \
  296. libidn12 \
  297. libpq5 \
  298. libreadline8 \
  299. libssl3 \
  300. libyaml-0-2 \
  301. # libvips components
  302. libcgif0 \
  303. libexif12 \
  304. libheif1 \
  305. libimagequant0 \
  306. libjpeg62-turbo \
  307. liblcms2-2 \
  308. liborc-0.4-0 \
  309. libspng0 \
  310. libtiff6 \
  311. libwebp7 \
  312. libwebpdemux2 \
  313. libwebpmux3 \
  314. # ffmpeg components
  315. libdav1d6 \
  316. libmp3lame0 \
  317. libopencore-amrnb0 \
  318. libopencore-amrwb0 \
  319. libopus0 \
  320. libsnappy1v5 \
  321. libtheora0 \
  322. libvorbis0a \
  323. libvorbisenc2 \
  324. libvorbisfile3 \
  325. libvpx7 \
  326. libx264-164 \
  327. libx265-199 \
  328. ;
  329. # Copy Mastodon sources into final layer
  330. COPY . /opt/mastodon/
  331. # Copy compiled assets to layer
  332. COPY --from=precompiler /opt/mastodon/public/packs /opt/mastodon/public/packs
  333. COPY --from=precompiler /opt/mastodon/public/assets /opt/mastodon/public/assets
  334. # Copy bundler components to layer
  335. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  336. # Copy libvips components to layer
  337. COPY --from=libvips /usr/local/libvips/bin /usr/local/bin
  338. COPY --from=libvips /usr/local/libvips/lib /usr/local/lib
  339. # Copy ffpmeg components to layer
  340. COPY --from=ffmpeg /usr/local/ffmpeg/bin /usr/local/bin
  341. COPY --from=ffmpeg /usr/local/ffmpeg/lib /usr/local/lib
  342. RUN \
  343. ldconfig; \
  344. # Smoketest media processors
  345. vips -v; \
  346. ffmpeg -version; \
  347. ffprobe -version;
  348. RUN \
  349. # Precompile bootsnap code for faster Rails startup
  350. bundle exec bootsnap precompile --gemfile app/ lib/;
  351. RUN \
  352. # Pre-create and chown system volume to Mastodon user
  353. mkdir -p /opt/mastodon/public/system; \
  354. chown mastodon:mastodon /opt/mastodon/public/system; \
  355. # Set Mastodon user as owner of tmp folder
  356. chown -R mastodon:mastodon /opt/mastodon/tmp;
  357. # Set the running user for resulting container
  358. USER mastodon
  359. # Expose default Puma ports
  360. EXPOSE 3000
  361. # Set container tini as default entry point
  362. ENTRYPOINT ["/usr/bin/tini", "--"]