Dockerfile 13 KB

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