Dockerfile 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. # syntax=docker/dockerfile:1
  2. # See https://hub.docker.com/r/docker/dockerfile
  3. #######################################################
  4. # Configuration
  5. #######################################################
  6. # See: https://github.com/mlocati/docker-php-extension-installer
  7. ARG DOCKER_PHP_EXTENSION_INSTALLER_VERSION="2.1.80"
  8. # See: https://github.com/composer/composer
  9. ARG COMPOSER_VERSION="2.6"
  10. # See: https://nginx.org/
  11. ARG NGINX_VERSION="1.25.3"
  12. # See: https://github.com/ddollar/forego
  13. ARG FOREGO_VERSION="0.17.2"
  14. # See: https://github.com/hairyhenderson/gomplate
  15. ARG GOMPLATE_VERSION="v3.11.6"
  16. # See: https://github.com/jippi/dottie
  17. ARG DOTTIE_VERSION="v0.9.5"
  18. ###
  19. # PHP base configuration
  20. ###
  21. # See: https://hub.docker.com/_/php/tags
  22. ARG PHP_VERSION="8.3"
  23. # See: https://github.com/docker-library/docs/blob/master/php/README.md#image-variants
  24. ARG PHP_BASE_TYPE="apache"
  25. ARG PHP_DEBIAN_RELEASE="bookworm"
  26. ARG RUNTIME_UID=33 # often called 'www-data'
  27. ARG RUNTIME_GID=33 # often called 'www-data'
  28. # APT extra packages
  29. ARG APT_PACKAGES_EXTRA=
  30. # Extensions installed via [pecl install]
  31. # ! NOTE: imagick is installed from [master] branch on GitHub due to 8.3 bug on ARM that haven't
  32. # ! been released yet (after +10 months)!
  33. # ! See: https://github.com/Imagick/imagick/pull/641
  34. ARG PHP_PECL_EXTENSIONS="redis https://codeload.github.com/Imagick/imagick/tar.gz/28f27044e435a2b203e32675e942eb8de620ee58"
  35. ARG PHP_PECL_EXTENSIONS_EXTRA=
  36. # Extensions installed via [docker-php-ext-install]
  37. ARG PHP_EXTENSIONS="intl bcmath zip pcntl exif curl gd"
  38. ARG PHP_EXTENSIONS_EXTRA=""
  39. ARG PHP_EXTENSIONS_DATABASE="pdo_pgsql pdo_mysql pdo_sqlite"
  40. # GPG key for nginx apt repository
  41. ARG NGINX_GPGKEY="573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62"
  42. # GPP key path for nginx apt repository
  43. ARG NGINX_GPGKEY_PATH="/usr/share/keyrings/nginx-archive-keyring.gpg"
  44. #######################################################
  45. # Docker "copy from" images
  46. #######################################################
  47. # Composer docker image from Docker Hub
  48. #
  49. # NOTE: Docker will *not* pull this image unless it's referenced (via build target)
  50. FROM composer:${COMPOSER_VERSION} AS composer-image
  51. # php-extension-installer image from Docker Hub
  52. #
  53. # NOTE: Docker will *not* pull this image unless it's referenced (via build target)
  54. FROM mlocati/php-extension-installer:${DOCKER_PHP_EXTENSION_INSTALLER_VERSION} AS php-extension-installer
  55. # nginx webserver from Docker Hub.
  56. # Used to copy some docker-entrypoint files for [nginx-runtime]
  57. #
  58. # NOTE: Docker will *not* pull this image unless it's referenced (via build target)
  59. FROM nginx:${NGINX_VERSION} AS nginx-image
  60. # Forego is a Procfile "runner" that makes it trival to run multiple
  61. # processes under a simple init / PID 1 process.
  62. #
  63. # NOTE: Docker will *not* pull this image unless it's referenced (via build target)
  64. #
  65. # See: https://github.com/nginx-proxy/forego
  66. FROM nginxproxy/forego:${FOREGO_VERSION}-debian AS forego-image
  67. # Dottie makes working with .env files easier and safer
  68. #
  69. # NOTE: Docker will *not* pull this image unless it's referenced (via build target)
  70. #
  71. # See: https://github.com/jippi/dottie
  72. FROM ghcr.io/jippi/dottie:${DOTTIE_VERSION} AS dottie-image
  73. # gomplate-image grabs the gomplate binary from GitHub releases
  74. #
  75. # It's in its own layer so it can be fetched in parallel with other build steps
  76. FROM php:${PHP_VERSION}-${PHP_BASE_TYPE}-${PHP_DEBIAN_RELEASE} AS gomplate-image
  77. ARG TARGETARCH
  78. ARG TARGETOS
  79. ARG GOMPLATE_VERSION
  80. RUN set -ex \
  81. && curl \
  82. --silent \
  83. --show-error \
  84. --location \
  85. --output /usr/local/bin/gomplate \
  86. https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${TARGETOS}-${TARGETARCH} \
  87. && chmod +x /usr/local/bin/gomplate \
  88. && /usr/local/bin/gomplate --version
  89. #######################################################
  90. # Base image
  91. #######################################################
  92. FROM php:${PHP_VERSION}-${PHP_BASE_TYPE}-${PHP_DEBIAN_RELEASE} AS base
  93. ARG BUILDKIT_SBOM_SCAN_STAGE="true"
  94. ARG APT_PACKAGES_EXTRA
  95. ARG PHP_DEBIAN_RELEASE
  96. ARG PHP_VERSION
  97. ARG RUNTIME_GID
  98. ARG RUNTIME_UID
  99. ARG TARGETPLATFORM
  100. ENV DEBIAN_FRONTEND="noninteractive"
  101. # Ensure we run all scripts through 'bash' rather than 'sh'
  102. SHELL ["/bin/bash", "-c"]
  103. # Set www-data to be RUNTIME_UID/RUNTIME_GID
  104. RUN groupmod --gid ${RUNTIME_GID} www-data \
  105. && usermod --uid ${RUNTIME_UID} --gid ${RUNTIME_GID} www-data
  106. RUN set -ex \
  107. && mkdir -pv /var/www/ \
  108. && chown -R ${RUNTIME_UID}:${RUNTIME_GID} /var/www
  109. WORKDIR /var/www/
  110. ENV APT_PACKAGES_EXTRA=${APT_PACKAGES_EXTRA}
  111. # Install and configure base layer
  112. COPY docker/shared/root/docker/install/base.sh /docker/install/base.sh
  113. RUN --mount=type=cache,id=pixelfed-apt-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/lib/apt \
  114. --mount=type=cache,id=pixelfed-apt-cache-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/cache/apt \
  115. /docker/install/base.sh
  116. #######################################################
  117. # PHP: extensions
  118. #######################################################
  119. FROM base AS php-extensions
  120. ARG PHP_DEBIAN_RELEASE
  121. ARG PHP_EXTENSIONS
  122. ARG PHP_EXTENSIONS_DATABASE
  123. ARG PHP_EXTENSIONS_EXTRA
  124. ARG PHP_PECL_EXTENSIONS
  125. ARG PHP_PECL_EXTENSIONS_EXTRA
  126. ARG PHP_VERSION
  127. ARG TARGETPLATFORM
  128. COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
  129. COPY docker/shared/root/docker/install/php-extensions.sh /docker/install/php-extensions.sh
  130. RUN --mount=type=cache,id=pixelfed-pear-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/tmp/pear \
  131. --mount=type=cache,id=pixelfed-apt-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/lib/apt \
  132. --mount=type=cache,id=pixelfed-apt-cache-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/cache/apt \
  133. PHP_EXTENSIONS=${PHP_EXTENSIONS} \
  134. PHP_EXTENSIONS_DATABASE=${PHP_EXTENSIONS_DATABASE} \
  135. PHP_EXTENSIONS_EXTRA=${PHP_EXTENSIONS_EXTRA} \
  136. PHP_PECL_EXTENSIONS=${PHP_PECL_EXTENSIONS} \
  137. PHP_PECL_EXTENSIONS_EXTRA=${PHP_PECL_EXTENSIONS_EXTRA} \
  138. /docker/install/php-extensions.sh
  139. #######################################################
  140. # Node: Build frontend
  141. #######################################################
  142. # NOTE: Since the nodejs build is CPU architecture agnostic,
  143. # we only want to build once and cache it for other architectures.
  144. # We force the (CPU) [--platform] here to be architecture
  145. # of the "builder"/"server" and not the *target* CPU architecture
  146. # (e.g.) building the ARM version of Pixelfed on AMD64.
  147. FROM --platform=${BUILDARCH} node:lts AS frontend-build
  148. ARG BUILDARCH
  149. ARG BUILD_FRONTEND=0
  150. ARG RUNTIME_UID
  151. ARG RUNTIME_GID
  152. ARG NODE_ENV=production
  153. ENV NODE_ENV=$NODE_ENV
  154. WORKDIR /var/www/
  155. SHELL [ "/usr/bin/bash", "-c" ]
  156. # Install NPM dependencies
  157. RUN --mount=type=cache,id=pixelfed-node-${BUILDARCH},sharing=locked,target=/tmp/cache \
  158. --mount=type=bind,source=package.json,target=/var/www/package.json \
  159. --mount=type=bind,source=package-lock.json,target=/var/www/package-lock.json \
  160. <<EOF
  161. if [[ $BUILD_FRONTEND -eq 1 ]];
  162. then
  163. npm install --cache /tmp/cache --no-save --dev
  164. else
  165. echo "Skipping [npm install] as --build-arg [BUILD_FRONTEND] is not set to '1'"
  166. fi
  167. EOF
  168. # Copy the frontend source into the image before building
  169. COPY --chown=${RUNTIME_UID}:${RUNTIME_GID} . /var/www
  170. # Build the frontend with "mix" (See package.json)
  171. RUN \
  172. <<EOF
  173. if [[ $BUILD_FRONTEND -eq 1 ]];
  174. then
  175. npm run production
  176. else
  177. echo "Skipping [npm run production] as --build-arg [BUILD_FRONTEND] is not set to '1'"
  178. fi
  179. EOF
  180. #######################################################
  181. # PHP: composer and source code
  182. #######################################################
  183. FROM php-extensions AS composer-and-src
  184. ARG PHP_VERSION
  185. ARG PHP_DEBIAN_RELEASE
  186. ARG RUNTIME_UID
  187. ARG RUNTIME_GID
  188. ARG TARGETPLATFORM
  189. # Make sure composer cache is targeting our cache mount later
  190. ENV COMPOSER_CACHE_DIR="/cache/composer"
  191. # Don't enforce any memory limits for composer
  192. ENV COMPOSER_MEMORY_LIMIT=-1
  193. # Disable interactvitity from composer
  194. ENV COMPOSER_NO_INTERACTION=1
  195. # Copy composer from https://hub.docker.com/_/composer
  196. COPY --link --from=composer-image /usr/bin/composer /usr/bin/composer
  197. #! Changing user to runtime user
  198. USER ${RUNTIME_UID}:${RUNTIME_GID}
  199. # Install composer dependencies
  200. # NOTE: we skip the autoloader generation here since we don't have all files avaliable (yet)
  201. RUN --mount=type=cache,id=pixelfed-composer-${PHP_VERSION},sharing=locked,uid=${RUNTIME_UID},gid=${RUNTIME_GID},target=/cache/composer \
  202. --mount=type=bind,source=composer.json,target=/var/www/composer.json \
  203. --mount=type=bind,source=composer.lock,target=/var/www/composer.lock \
  204. set -ex \
  205. && composer install --prefer-dist --no-autoloader --ignore-platform-reqs --no-scripts
  206. # Copy all other files over
  207. COPY --chown=${RUNTIME_UID}:${RUNTIME_GID} . /var/www/
  208. # Generate optimized autoloader now that we have all files around
  209. RUN set -ex \
  210. && ENABLE_CONFIG_CACHE=false composer dump-autoload --optimize
  211. # Now we can run the post-install scripts
  212. RUN set -ex \
  213. && composer run-script post-update-cmd
  214. #######################################################
  215. # Runtime: base
  216. #######################################################
  217. FROM php-extensions AS shared-runtime
  218. ARG RUNTIME_GID
  219. ARG RUNTIME_UID
  220. ENV RUNTIME_UID=${RUNTIME_UID}
  221. ENV RUNTIME_GID=${RUNTIME_GID}
  222. COPY --link --from=forego-image /usr/local/bin/forego /usr/local/bin/forego
  223. COPY --link --from=dottie-image /dottie /usr/local/bin/dottie
  224. COPY --link --from=gomplate-image /usr/local/bin/gomplate /usr/local/bin/gomplate
  225. COPY --link --from=composer-image /usr/bin/composer /usr/bin/composer
  226. COPY --link --from=composer-and-src --chown=${RUNTIME_UID}:${RUNTIME_GID} /var/www /var/www
  227. COPY --link --from=frontend-build --chown=${RUNTIME_UID}:${RUNTIME_GID} /var/www/public /var/www/public
  228. USER root
  229. # for detail why storage is copied this way, pls refer to https://github.com/pixelfed/pixelfed/pull/2137#discussion_r434468862
  230. RUN set -ex \
  231. && cp --recursive --link --preserve=all storage storage.skel \
  232. && rm -rf html && ln -s public html
  233. COPY docker/shared/root /
  234. ENTRYPOINT ["/docker/entrypoint.sh"]
  235. #######################################################
  236. # Runtime: apache
  237. #######################################################
  238. FROM shared-runtime AS apache-runtime
  239. COPY docker/apache/root /
  240. RUN set -ex \
  241. && a2enmod rewrite remoteip proxy proxy_http \
  242. && a2enconf remoteip
  243. CMD ["apache2-foreground"]
  244. #######################################################
  245. # Runtime: fpm
  246. #######################################################
  247. FROM shared-runtime AS fpm-runtime
  248. COPY docker/fpm/root /
  249. CMD ["php-fpm"]
  250. #######################################################
  251. # Runtime: nginx
  252. #######################################################
  253. FROM shared-runtime AS nginx-runtime
  254. ARG NGINX_GPGKEY
  255. ARG NGINX_GPGKEY_PATH
  256. ARG NGINX_VERSION
  257. ARG PHP_DEBIAN_RELEASE
  258. ARG PHP_VERSION
  259. ARG TARGETPLATFORM
  260. # Install nginx dependencies
  261. RUN --mount=type=cache,id=pixelfed-apt-lists-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/lib/apt/lists \
  262. --mount=type=cache,id=pixelfed-apt-cache-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/cache/apt \
  263. set -ex \
  264. && gpg1 --keyserver "hkp://keyserver.ubuntu.com:80" --keyserver-options timeout=10 --recv-keys "${NGINX_GPGKEY}" \
  265. && gpg1 --export "$NGINX_GPGKEY" > "$NGINX_GPGKEY_PATH" \
  266. && echo "deb [signed-by=${NGINX_GPGKEY_PATH}] https://nginx.org/packages/mainline/debian/ ${PHP_DEBIAN_RELEASE} nginx" >> /etc/apt/sources.list.d/nginx.list \
  267. && apt-get update \
  268. && apt-get install -y --no-install-recommends nginx=${NGINX_VERSION}*
  269. # copy docker entrypoints from the *real* nginx image directly
  270. COPY --link --from=nginx-image /docker-entrypoint.d /docker/entrypoint.d/
  271. COPY docker/nginx/root /
  272. COPY docker/nginx/Procfile .
  273. STOPSIGNAL SIGQUIT
  274. CMD ["forego", "start", "-r"]