Dockerfile 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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.5"
  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.3
  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. # Download and extract libvips source code
  178. ADD ${VIPS_URL}/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.xz /usr/local/libvips/src/
  179. RUN tar xf vips-${VIPS_VERSION}.tar.xz;
  180. WORKDIR /usr/local/libvips/src/vips-${VIPS_VERSION}
  181. # Configure and compile libvips
  182. RUN \
  183. meson setup build --prefix /usr/local/libvips --libdir=lib -Ddeprecated=false -Dintrospection=disabled -Dmodules=disabled -Dexamples=false; \
  184. cd build; \
  185. ninja; \
  186. ninja install;
  187. # Create temporary ffmpeg specific build layer from build layer
  188. FROM build AS ffmpeg
  189. # ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
  190. # renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
  191. ARG FFMPEG_VERSION=7.1
  192. # ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"]
  193. ARG FFMPEG_URL=https://ffmpeg.org/releases
  194. WORKDIR /usr/local/ffmpeg/src
  195. # Download and extract ffmpeg source code
  196. ADD ${FFMPEG_URL}/ffmpeg-${FFMPEG_VERSION}.tar.xz /usr/local/ffmpeg/src/
  197. RUN tar xf ffmpeg-${FFMPEG_VERSION}.tar.xz;
  198. WORKDIR /usr/local/ffmpeg/src/ffmpeg-${FFMPEG_VERSION}
  199. # Configure and compile ffmpeg
  200. RUN \
  201. ./configure \
  202. --prefix=/usr/local/ffmpeg \
  203. --toolchain=hardened \
  204. --disable-debug \
  205. --disable-devices \
  206. --disable-doc \
  207. --disable-ffplay \
  208. --disable-network \
  209. --disable-static \
  210. --enable-ffmpeg \
  211. --enable-ffprobe \
  212. --enable-gpl \
  213. --enable-libdav1d \
  214. --enable-libmp3lame \
  215. --enable-libopus \
  216. --enable-libsnappy \
  217. --enable-libvorbis \
  218. --enable-libvpx \
  219. --enable-libwebp \
  220. --enable-libx264 \
  221. --enable-libx265 \
  222. --enable-shared \
  223. --enable-version3 \
  224. ; \
  225. make -j$(nproc); \
  226. make install;
  227. # Create temporary bundler specific build layer from build layer
  228. FROM build AS bundler
  229. ARG TARGETPLATFORM
  230. # Copy Gemfile config into working directory
  231. COPY Gemfile* /opt/mastodon/
  232. RUN \
  233. # Mount Ruby Gem caches
  234. --mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \
  235. # Configure bundle to prevent changes to Gemfile and Gemfile.lock
  236. bundle config set --global frozen "true"; \
  237. # Configure bundle to not cache downloaded Gems
  238. bundle config set --global cache_all "false"; \
  239. # Configure bundle to only process production Gems
  240. bundle config set --local without "development test"; \
  241. # Configure bundle to not warn about root user
  242. bundle config set silence_root_warning "true"; \
  243. # Download and install required Gems
  244. bundle install -j"$(nproc)";
  245. # Create temporary node specific build layer from build layer
  246. FROM build AS yarn
  247. ARG TARGETPLATFORM
  248. # Copy Node package configuration files into working directory
  249. COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
  250. COPY streaming/package.json /opt/mastodon/streaming/
  251. COPY .yarn /opt/mastodon/.yarn
  252. # hadolint ignore=DL3008
  253. RUN \
  254. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  255. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  256. # Install Node packages
  257. yarn workspaces focus --production @mastodon/mastodon;
  258. # Create temporary assets build layer from build layer
  259. FROM build AS precompiler
  260. # Copy Mastodon sources into precompiler layer
  261. COPY . /opt/mastodon/
  262. # Copy bundler and node packages from build layer to container
  263. COPY --from=yarn /opt/mastodon /opt/mastodon/
  264. COPY --from=bundler /opt/mastodon /opt/mastodon/
  265. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  266. # Copy libvips components to layer for precompiler
  267. COPY --from=libvips /usr/local/libvips/bin /usr/local/bin
  268. COPY --from=libvips /usr/local/libvips/lib /usr/local/lib
  269. ARG TARGETPLATFORM
  270. RUN \
  271. ldconfig; \
  272. # Use Ruby on Rails to create Mastodon assets
  273. SECRET_KEY_BASE_DUMMY=1 \
  274. bundle exec rails assets:precompile; \
  275. # Cleanup temporary files
  276. rm -fr /opt/mastodon/tmp;
  277. # Prep final Mastodon Ruby layer
  278. FROM ruby AS mastodon
  279. ARG TARGETPLATFORM
  280. # hadolint ignore=DL3008
  281. RUN \
  282. # Mount Apt cache and lib directories from Docker buildx caches
  283. --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \
  284. --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \
  285. # Mount Corepack and Yarn caches from Docker buildx caches
  286. --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
  287. --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
  288. # Apt update install non-dev versions of necessary components
  289. apt-get install -y --no-install-recommends \
  290. libexpat1 \
  291. libglib2.0-0 \
  292. libicu72 \
  293. libidn12 \
  294. libpq5 \
  295. libreadline8 \
  296. libssl3 \
  297. libyaml-0-2 \
  298. # libvips components
  299. libcgif0 \
  300. libexif12 \
  301. libheif1 \
  302. libimagequant0 \
  303. libjpeg62-turbo \
  304. liblcms2-2 \
  305. liborc-0.4-0 \
  306. libspng0 \
  307. libtiff6 \
  308. libwebp7 \
  309. libwebpdemux2 \
  310. libwebpmux3 \
  311. # ffmpeg components
  312. libdav1d6 \
  313. libmp3lame0 \
  314. libopencore-amrnb0 \
  315. libopencore-amrwb0 \
  316. libopus0 \
  317. libsnappy1v5 \
  318. libtheora0 \
  319. libvorbis0a \
  320. libvorbisenc2 \
  321. libvorbisfile3 \
  322. libvpx7 \
  323. libx264-164 \
  324. libx265-199 \
  325. ;
  326. # Copy Mastodon sources into final layer
  327. COPY . /opt/mastodon/
  328. # Copy compiled assets to layer
  329. COPY --from=precompiler /opt/mastodon/public/packs /opt/mastodon/public/packs
  330. COPY --from=precompiler /opt/mastodon/public/assets /opt/mastodon/public/assets
  331. # Copy bundler components to layer
  332. COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
  333. # Copy libvips components to layer
  334. COPY --from=libvips /usr/local/libvips/bin /usr/local/bin
  335. COPY --from=libvips /usr/local/libvips/lib /usr/local/lib
  336. # Copy ffpmeg components to layer
  337. COPY --from=ffmpeg /usr/local/ffmpeg/bin /usr/local/bin
  338. COPY --from=ffmpeg /usr/local/ffmpeg/lib /usr/local/lib
  339. RUN \
  340. ldconfig; \
  341. # Smoketest media processors
  342. vips -v; \
  343. ffmpeg -version; \
  344. ffprobe -version;
  345. RUN \
  346. # Precompile bootsnap code for faster Rails startup
  347. bundle exec bootsnap precompile --gemfile app/ lib/;
  348. RUN \
  349. # Pre-create and chown system volume to Mastodon user
  350. mkdir -p /opt/mastodon/public/system; \
  351. chown mastodon:mastodon /opt/mastodon/public/system; \
  352. # Set Mastodon user as owner of tmp folder
  353. chown -R mastodon:mastodon /opt/mastodon/tmp;
  354. # Set the running user for resulting container
  355. USER mastodon
  356. # Expose default Puma ports
  357. EXPOSE 3000
  358. # Set container tini as default entry point
  359. ENTRYPOINT ["/usr/bin/tini", "--"]