Dockerfile 13 KB

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