mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-09 16:24:51 +00:00
more docs and rework
This commit is contained in:
parent
e05575283a
commit
a08a5e7cde
10 changed files with 226 additions and 87 deletions
|
@ -5,14 +5,29 @@
|
|||
# Configuration
|
||||
#######################################################
|
||||
|
||||
# See: https://github.com/composer/composer/releases
|
||||
ARG COMPOSER_VERSION="2.6"
|
||||
|
||||
# See: https://nginx.org/
|
||||
ARG NGINX_VERSION=1.25.3
|
||||
|
||||
# See: https://github.com/ddollar/forego
|
||||
ARG FOREGO_VERSION=0.17.2
|
||||
|
||||
# See: https://github.com/hairyhenderson/gomplate
|
||||
ARG GOMPLATE_VERSION=v3.11.6
|
||||
|
||||
###
|
||||
# PHP base configuration
|
||||
###
|
||||
|
||||
# See: https://hub.docker.com/_/php/tags
|
||||
ARG PHP_VERSION="8.1"
|
||||
|
||||
# See: https://github.com/docker-library/docs/blob/master/php/README.md#image-variants
|
||||
ARG PHP_BASE_TYPE="apache"
|
||||
ARG PHP_DEBIAN_RELEASE="bullseye"
|
||||
|
||||
ARG RUNTIME_UID=33 # often called 'www-data'
|
||||
ARG RUNTIME_GID=33 # often called 'www-data'
|
||||
|
||||
|
@ -57,17 +72,31 @@ FROM nginx:${NGINX_VERSION} AS nginx-image
|
|||
# See: https://github.com/nginx-proxy/forego
|
||||
FROM nginxproxy/forego:${FOREGO_VERSION}-debian AS forego-image
|
||||
|
||||
# gomplate-image grabs the gomplate binary from GitHub releases
|
||||
#
|
||||
# It's in its own layer so it can be fetched in parallel with other build steps
|
||||
FROM php:${PHP_VERSION}-${PHP_BASE_TYPE}-${PHP_DEBIAN_RELEASE} AS gomplate-image
|
||||
|
||||
ARG BUILDARCH
|
||||
ARG BUILDOS
|
||||
ARG GOMPLATE_VERSION
|
||||
|
||||
RUN set -ex \
|
||||
&& curl --silent --show-error --location --output /usr/local/bin/gomplate https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${BUILDOS}-${BUILDARCH} \
|
||||
&& chmod +x /usr/local/bin/gomplate \
|
||||
&& /usr/local/bin/gomplate --version
|
||||
|
||||
#######################################################
|
||||
# Base image
|
||||
#######################################################
|
||||
|
||||
FROM php:${PHP_VERSION}-${PHP_BASE_TYPE}-${PHP_DEBIAN_RELEASE} AS base
|
||||
|
||||
ARG PHP_VERSION
|
||||
ARG PHP_DEBIAN_RELEASE
|
||||
ARG APT_PACKAGES_EXTRA
|
||||
ARG RUNTIME_UID
|
||||
ARG PHP_DEBIAN_RELEASE
|
||||
ARG PHP_VERSION
|
||||
ARG RUNTIME_GID
|
||||
ARG RUNTIME_UID
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
ARG BUILDKIT_SBOM_SCAN_STAGE=true
|
||||
|
@ -173,8 +202,11 @@ USER root:root
|
|||
|
||||
FROM base AS shared-runtime
|
||||
|
||||
ARG RUNTIME_UID
|
||||
ARG BUILDARCH
|
||||
ARG BUILDOS
|
||||
ARG GOMPLATE_VERSION
|
||||
ARG RUNTIME_GID
|
||||
ARG RUNTIME_UID
|
||||
|
||||
ENV RUNTIME_UID=${RUNTIME_UID}
|
||||
ENV RUNTIME_GID=${RUNTIME_GID}
|
||||
|
@ -183,6 +215,7 @@ COPY --link --from=php-extensions /usr/local/lib/php/extensions /usr/local/lib/p
|
|||
COPY --link --from=php-extensions /usr/local/etc/php /usr/local/etc/php
|
||||
COPY --link --from=composer-and-src --chown=${RUNTIME_UID}:${RUNTIME_GID} /var/www /var/www
|
||||
COPY --link --from=forego-image /usr/local/bin/forego /usr/local/bin/forego
|
||||
COPY --link --from=gomplate-image /usr/local/bin/gomplate /usr/local/bin/gomplate
|
||||
|
||||
# for detail why storage is copied this way, pls refer to https://github.com/pixelfed/pixelfed/pull/2137#discussion_r434468862
|
||||
RUN set -ex \
|
||||
|
|
|
@ -93,6 +93,72 @@ services:
|
|||
PHP_BASE_TYPE: fpm
|
||||
```
|
||||
|
||||
## Customizing your `Dockerfile`
|
||||
|
||||
### Running commands on container start
|
||||
|
||||
#### Description
|
||||
|
||||
When a Pixelfed container starts up, the [`ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) script will
|
||||
|
||||
1. Search the `/docker/entrypoint.d/` directory for files and for each file (in lexical order).
|
||||
1. Check if the file is executable.
|
||||
1. If the file is not executable, print an error and exit the container.
|
||||
1. If the file has the extension `.envsh` the file will be [sourced](https://superuser.com/a/46146).
|
||||
1. If the file has the extension `.sh` the file will be run like a normal script.
|
||||
1. Any other file extension will log a warning and will be ignored.
|
||||
|
||||
#### Included scripts
|
||||
|
||||
* `/docker/entrypoint.d/04-defaults.envsh` calculates Docker container environment variables needed for [templating](#templating) configuration files.
|
||||
* `/docker/entrypoint.d/05-templating.sh` renders [template](#templating) configuration files.
|
||||
* `/docker/entrypoint.d/10-storage.sh` ensures Pixelfed storage related permissions and commands are run.
|
||||
* `/docker/entrypoint.d/20-horizon.sh` ensures [Laravel Horizon](https://laravel.com/docs/master/horizon) used by Pixelfed is configured
|
||||
* `/docker/entrypoint.d/30-cache.sh` ensures all Pixelfed caches (router, view, config) is warmed
|
||||
|
||||
#### Disabling entrypoint or individual scripts
|
||||
|
||||
To disable the entire entrypoint you can set the variable `ENTRYPOINT_SKIP=1`.
|
||||
|
||||
To disable individual entrypoint scripts you can add the filename to the space (`" "`) separated variable `ENTRYPOINT_SKIP_SCRIPTS`. (example: `ENTRYPOINT_SKIP_SCRIPTS="10-storage.sh 30-cache.sh"`)
|
||||
|
||||
### Templating
|
||||
|
||||
The Docker container can do some basic templating (more like variable replacement) as part of the entrypoint scripts via [gomplate](https://docs.gomplate.ca/).
|
||||
|
||||
Any file put in the `/docker/templates/` directory will be templated and written to the right directory.
|
||||
|
||||
#### File path examples
|
||||
|
||||
1. To template `/usr/local/etc/php/php.ini` in the container put the source file in `/docker/templates/usr/local/etc/php/php.ini`.
|
||||
1. To template `/a/fantastic/example.txt` in the container put the source file in `/docker/templates/a/fantastic/example.txt`.
|
||||
1. To template `/some/path/anywhere` in the container put the source file in `/docker/templates/a/fantastic/example.txt`.
|
||||
|
||||
#### Available variables
|
||||
|
||||
Variables available for templating are sourced (in order, so *last* source takes precedence) like this:
|
||||
|
||||
1. `env:` in your `docker-compose.yml` or `-e` in your `docker run` / `docker compose run`
|
||||
1. Any exported variables in `.envsh` files loaded *before* `05-templating.sh` (e.g. any file with `04-`, `03-`, `02-`, `01-` or `00-` prefix)
|
||||
1. All key/value pairs in `/var/www/.env.docker`
|
||||
1. All key/value pairs in `/var/www/.env`
|
||||
|
||||
#### Template guide 101
|
||||
|
||||
Please see the [gomplate documentation](https://docs.gomplate.ca/) for a more comprehensive overview.
|
||||
|
||||
The most frequent use-case you have is likely to print a environment variable (or a default value if it's missing), so this is how to do that:
|
||||
|
||||
* `{{ getenv "VAR_NAME" }}` print an environment variable and **fail** if the variable is not set. ([docs](https://docs.gomplate.ca/functions/env/#envgetenv))
|
||||
* `{{ getenv "VAR_NAME" "default" }}` print an environment variable and print `default` if the variable is not set. ([docs](https://docs.gomplate.ca/functions/env/#envgetenv))
|
||||
|
||||
The script will *fail* if you reference a variable that does not exist (and don't have a default value) in a template.
|
||||
|
||||
Please see the
|
||||
|
||||
* [gomplate syntax documentation](https://docs.gomplate.ca/syntax/)
|
||||
* [gomplate functions documentation](https://docs.gomplate.ca/functions/)
|
||||
|
||||
## Build settings (arguments)
|
||||
|
||||
The Pixelfed Dockerfile utilizes [Docker Multi-stage builds](https://docs.docker.com/build/building/multi-stage/) and [Build arguments](https://docs.docker.com/build/guide/build-args/).
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
server {
|
||||
listen 80 default_server;
|
||||
|
||||
server_name ${APP_DOMAIN};
|
||||
server_name {{ getenv "APP_DOMAIN" }};
|
||||
root /var/www/public;
|
||||
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
|
@ -14,7 +14,7 @@ server {
|
|||
index index.html index.htm index.php;
|
||||
|
||||
charset utf-8;
|
||||
client_max_body_size ${POST_MAX_SIZE};
|
||||
client_max_body_size {{ getenv "POST_MAX_SIZE" }};
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
|
@ -3,38 +3,37 @@ source /docker/helpers.sh
|
|||
|
||||
set_identity "$0"
|
||||
|
||||
auto_envsubst() {
|
||||
local template_dir="${ENVSUBST_TEMPLATE_DIR:-/docker/templates}"
|
||||
local output_dir="${ENVSUBST_OUTPUT_DIR:-}"
|
||||
local filter="${ENVSUBST_FILTER:-}"
|
||||
local template defined_envs relative_path output_path output_dir subdir
|
||||
declare template_dir="${ENVSUBST_TEMPLATE_DIR:-/docker/templates}"
|
||||
declare output_dir="${ENVSUBST_OUTPUT_DIR:-}"
|
||||
declare filter="${ENVSUBST_FILTER:-}"
|
||||
declare template defined_envs relative_path output_path output_dir subdir
|
||||
|
||||
# load all dot-env files
|
||||
load-config-files
|
||||
# load all dot-env files
|
||||
load-config-files
|
||||
|
||||
# export all dot-env variables so they are available in templating
|
||||
export ${seen_dot_env_variables[@]}
|
||||
: ${ENTRYPOINT_SHOW_TEMPLATE_DIFF:=1}
|
||||
|
||||
defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" </dev/null))
|
||||
# export all dot-env variables so they are available in templating
|
||||
export ${seen_dot_env_variables[@]}
|
||||
|
||||
find "$template_dir" -follow -type f -print | while read -r template; do
|
||||
relative_path="${template#"$template_dir/"}"
|
||||
subdir=$(dirname "$relative_path")
|
||||
output_path="$output_dir/${relative_path}"
|
||||
output_dir=$(dirname "$output_path")
|
||||
find "$template_dir" -follow -type f -print | while read -r template; do
|
||||
relative_path="${template#"$template_dir/"}"
|
||||
subdir=$(dirname "$relative_path")
|
||||
output_path="$output_dir/${relative_path}"
|
||||
output_dir=$(dirname "$output_path")
|
||||
|
||||
if [ ! -w "$output_dir" ]; then
|
||||
log_error_and_exit "ERROR: $template_dir exists, but $output_dir is not writable"
|
||||
fi
|
||||
if [ ! -w "$output_dir" ]; then
|
||||
log_error_and_exit "ERROR: $template_dir exists, but $output_dir is not writable"
|
||||
fi
|
||||
|
||||
# create a subdirectory where the template file exists
|
||||
mkdir -p "$output_dir/$subdir"
|
||||
# create a subdirectory where the template file exists
|
||||
mkdir -p "$output_dir/$subdir"
|
||||
|
||||
log "Running envsubst on $template to $output_path"
|
||||
envsubst "$defined_envs" <"$template" >"$output_path"
|
||||
done
|
||||
}
|
||||
log "Running [gomplate] on [$template] --> [$output_path]"
|
||||
cat "$template" | gomplate >"$output_path"
|
||||
|
||||
auto_envsubst
|
||||
|
||||
exit 0
|
||||
# Show the diff from the envsubst command
|
||||
if [[ ${ENTRYPOINT_SHOW_TEMPLATE_DIFF} = 1 ]]; then
|
||||
git --no-pager diff "$template" "${output_path}" || :
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -3,10 +3,7 @@ source /docker/helpers.sh
|
|||
|
||||
set_identity "$0"
|
||||
|
||||
log "Create the storage tree if needed"
|
||||
as_runtime_user cp --recursive storage.skel/* storage/
|
||||
|
||||
log "Ensure storage is linked"
|
||||
as_runtime_user php artisan storage:link
|
||||
|
||||
log "Ensure permissions are correct"
|
||||
|
|
|
@ -3,11 +3,6 @@ source /docker/helpers.sh
|
|||
|
||||
set_identity "$0"
|
||||
|
||||
log "==> route:cache"
|
||||
as_runtime_user php artisan route:cache
|
||||
|
||||
log "==> view:cache"
|
||||
as_runtime_user php artisan view:cache
|
||||
|
||||
log "==> config:cache"
|
||||
as_runtime_user php artisan config:cache
|
||||
|
|
|
@ -1,50 +1,71 @@
|
|||
#!/bin/bash
|
||||
set -e -o errexit -o nounset -o pipefail
|
||||
|
||||
[[ -n ${ENTRYPOINT_DEBUG:-} ]] && set -x
|
||||
: ${ENTRYPOINT_SKIP:=0}
|
||||
: ${ENTRYPOINT_SKIP_SCRIPTS:=""}
|
||||
: ${ENTRYPOINT_DEBUG:=0}
|
||||
: ${ENTRYPOINT_ROOT:="/docker/entrypoint.d/"}
|
||||
|
||||
declare -g ME="$0"
|
||||
declare -gr ENTRYPOINT_ROOT=/docker/entrypoint.d/
|
||||
export ENTRYPOINT_ROOT
|
||||
|
||||
source /docker/helpers.sh
|
||||
if [[ ${ENTRYPOINT_SKIP} == 0 ]]; then
|
||||
[[ ${ENTRYPOINT_DEBUG} == 1 ]] && set -x
|
||||
|
||||
# ensure the entrypoint folder exists
|
||||
mkdir -p "${ENTRYPOINT_ROOT}"
|
||||
source /docker/helpers.sh
|
||||
|
||||
if /usr/bin/find "${ENTRYPOINT_ROOT}" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then
|
||||
log "looking for shell scripts in /docker/entrypoint.d/"
|
||||
find "${ENTRYPOINT_ROOT}" -follow -type f -print | sort -V | while read -r f; do
|
||||
case "$f" in
|
||||
*.envsh)
|
||||
if [ -x "$f" ]; then
|
||||
log "Sourcing $f"
|
||||
source "$f"
|
||||
resetore_identity
|
||||
else
|
||||
# warn on shell scripts without exec bit
|
||||
log_warning "Ignoring $f, not executable"
|
||||
declare -a skip_scripts=()
|
||||
IFS=' ' read -a skip_scripts <<<"$ENTRYPOINT_SKIP_SCRIPTS"
|
||||
|
||||
declare script_name
|
||||
|
||||
# ensure the entrypoint folder exists
|
||||
mkdir -p "${ENTRYPOINT_ROOT}"
|
||||
|
||||
if /usr/bin/find "${ENTRYPOINT_ROOT}" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then
|
||||
log "looking for shell scripts in /docker/entrypoint.d/"
|
||||
|
||||
find "${ENTRYPOINT_ROOT}" -follow -type f -print | sort -V | while read -r f; do
|
||||
script_name="$(get_script_name $f)"
|
||||
if array_value_exists skip_scripts "${script_name}"; then
|
||||
log_warning "Skipping script [${script_name}] since it's in the skip list (\$ENTRYPOINT_SKIP_SCRIPTS)"
|
||||
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
|
||||
*.sh)
|
||||
if [ -x "$f" ]; then
|
||||
log "Launching $f"
|
||||
"$f"
|
||||
else
|
||||
# warn on shell scripts without exec bit
|
||||
log_warning "Ignoring $f, not executable"
|
||||
fi
|
||||
;;
|
||||
case "$f" in
|
||||
*.envsh)
|
||||
if [ -x "$f" ]; then
|
||||
log "Sourcing $f"
|
||||
|
||||
*)
|
||||
log_warning "Ignoring $f"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
source "$f"
|
||||
|
||||
log "Configuration complete; ready for start up"
|
||||
else
|
||||
log_warning "No files found in ${ENTRYPOINT_ROOT}, skipping configuration"
|
||||
resetore_identity
|
||||
else
|
||||
# warn on shell scripts without exec bit
|
||||
log_error_and_exit "File [$f] is not executable (please 'chmod +x' it)"
|
||||
fi
|
||||
;;
|
||||
|
||||
*.sh)
|
||||
if [ -x "$f" ]; then
|
||||
log "Launching $f"
|
||||
"$f"
|
||||
else
|
||||
# warn on shell scripts without exec bit
|
||||
log_error_and_exit "File [$f] is not executable (please 'chmod +x' it)"
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
log_warning "Ignoring $f"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log "Configuration complete; ready for start up"
|
||||
else
|
||||
log_warning "No files found in ${ENTRYPOINT_ROOT}, skipping configuration"
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
|
|
@ -10,11 +10,11 @@ declare -ra dot_env_files=(
|
|||
/var/www/.env.docker
|
||||
/var/www/.env
|
||||
)
|
||||
declare -a seen_dot_env_variables=()
|
||||
declare -ga seen_dot_env_variables=()
|
||||
|
||||
function set_identity() {
|
||||
old_log_prefix="${log_prefix}"
|
||||
log_prefix="ENTRYPOINT - [${1}] - "
|
||||
log_prefix="ENTRYPOINT - [$(get_script_name $1)] - "
|
||||
}
|
||||
|
||||
function resetore_identity() {
|
||||
|
@ -22,7 +22,23 @@ function resetore_identity() {
|
|||
}
|
||||
|
||||
function as_runtime_user() {
|
||||
su --preserve-environment $(id -un ${RUNTIME_UID}) --shell /bin/bash --command "${*}"
|
||||
local -i exit_code
|
||||
local target_user
|
||||
|
||||
target_user=$(id -un ${RUNTIME_UID})
|
||||
|
||||
log "👷 Running [${*}] as [${target_user}]"
|
||||
|
||||
su --preserve-environment "${target_user}" --shell /bin/bash --command "${*}"
|
||||
exit_code=$?
|
||||
|
||||
if [[ $exit_code != 0 ]]; then
|
||||
log_error "❌ Error!"
|
||||
return $exit_code
|
||||
fi
|
||||
|
||||
log "✅ OK!"
|
||||
return $exit_code
|
||||
}
|
||||
|
||||
# @description Display the given error message with its line number on stderr and exit with error.
|
||||
|
@ -53,7 +69,7 @@ function log() {
|
|||
}
|
||||
|
||||
function load-config-files() {
|
||||
# Associative array (aka map/disctrionary) holding the unique keys found in dot-env files
|
||||
# Associative array (aka map/dictionary) holding the unique keys found in dot-env files
|
||||
local -A _tmp_dot_env_keys
|
||||
|
||||
for f in "${dot_env_files[@]}"; do
|
||||
|
@ -73,3 +89,14 @@ function load-config-files() {
|
|||
|
||||
seen_dot_env_variables=(${!_tmp_dot_env_keys[@]})
|
||||
}
|
||||
|
||||
function array_value_exists() {
|
||||
local -nr validOptions=$1
|
||||
local -r providedValue="\<${2}\>"
|
||||
|
||||
[[ ${validOptions[*]} =~ $providedValue ]]
|
||||
}
|
||||
|
||||
function get_script_name() {
|
||||
echo "${1#"$ENTRYPOINT_ROOT"}"
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ echo 'APT::Install-Suggests "false";' >>/etc/apt/apt.conf
|
|||
declare -ra standardPackages=(
|
||||
apt-utils
|
||||
ca-certificates
|
||||
gettext-base
|
||||
curl
|
||||
git
|
||||
gnupg1
|
||||
gosu
|
||||
|
@ -25,9 +25,10 @@ declare -ra standardPackages=(
|
|||
locales-all
|
||||
nano
|
||||
procps
|
||||
unzip
|
||||
zip
|
||||
software-properties-common
|
||||
unzip
|
||||
wget
|
||||
zip
|
||||
)
|
||||
|
||||
# Image Optimization
|
||||
|
|
|
@ -679,7 +679,7 @@ auto_globals_jit = On
|
|||
; Its value may be 0 to disable the limit. It is ignored if POST data reading
|
||||
; is disabled through enable_post_data_reading.
|
||||
; http://php.net/post-max-size
|
||||
post_max_size = ${POST_MAX_SIZE}
|
||||
post_max_size = {{ getenv "POST_MAX_SIZE" }}
|
||||
|
||||
; Automatically add files before PHP document.
|
||||
; http://php.net/auto-prepend-file
|
||||
|
@ -831,10 +831,10 @@ file_uploads = On
|
|||
|
||||
; Maximum allowed size for uploaded files.
|
||||
; http://php.net/upload-max-filesize
|
||||
upload_max_filesize = ${POST_MAX_SIZE}
|
||||
upload_max_filesize = {{ getenv "POST_MAX_SIZE" }}
|
||||
|
||||
; Maximum number of files that can be uploaded via a single request
|
||||
max_file_uploads = ${MAX_ALBUM_LENGTH}
|
||||
max_file_uploads = {{ getenv "MAX_ALBUM_LENGTH" }}
|
||||
|
||||
;;;;;;;;;;;;;;;;;;
|
||||
; Fopen wrappers ;
|
||||
|
|
Loading…
Reference in a new issue