-
Notifications
You must be signed in to change notification settings - Fork 354
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
337 lines (313 loc) · 13 KB
/
Copy pathdocker-compose.yml
File metadata and controls
337 lines (313 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
---
x-shared:
zammad-service: &zammad-service
environment: &zammad-environment
MEMCACHE_SERVERS: ${MEMCACHE_SERVERS:-zammad-memcached:11211}
POSTGRESQL_DB: ${POSTGRES_DB:-zammad_production}
POSTGRESQL_HOST: ${POSTGRES_HOST:-zammad-postgresql}
POSTGRESQL_USER: ${POSTGRES_USER:-zammad}
POSTGRESQL_PASS: ${POSTGRES_PASS:-zammad}
POSTGRESQL_PORT: ${POSTGRES_PORT:-5432}
POSTGRESQL_OPTIONS: ${POSTGRESQL_OPTIONS:-?pool=50}
# The bundled zammad-postgresql service creates the database up front, and its
# application role is deliberately not allowed to create databases. Set this to
# 'true' if you point Zammad at an external server and want it to create the
# database itself - the configured role then needs the CREATEDB attribute.
POSTGRESQL_DB_CREATE: ${POSTGRESQL_DB_CREATE:-false}
# Redis standalone
REDIS_URL: ${REDIS_URL:-redis://zammad-redis:6379}
# Redis sentinel
REDIS_SENTINELS:
REDIS_SENTINEL_NAME:
REDIS_USERNAME:
REDIS_PASSWORD:
REDIS_SENTINEL_USERNAME:
REDIS_SENTINEL_PASSWORD:
S3_URL:
# Backup settings
BACKUP_DIR: "${BACKUP_DIR:-/var/tmp/zammad}"
BACKUP_TIME: "${BACKUP_TIME:-03:00}"
BACKUP_ON_START: "${BACKUP_ON_START:-false}"
HOLD_DAYS: "${HOLD_DAYS:-10}"
TZ: "${TZ:-Europe/Berlin}"
# Allow passing in these variables via .env:
AUTOWIZARD_JSON:
AUTOWIZARD_RELATIVE_PATH:
ELASTICSEARCH_ENABLED:
ELASTICSEARCH_SCHEMA:
ELASTICSEARCH_HOST:
ELASTICSEARCH_PORT:
ELASTICSEARCH_USER:
ELASTICSEARCH_PASS:
ELASTICSEARCH_NAMESPACE:
ELASTICSEARCH_REINDEX:
NGINX_PORT:
NGINX_CLIENT_MAX_BODY_SIZE:
NGINX_SERVER_NAME:
NGINX_SERVER_SCHEME:
RAILS_TRUSTED_PROXIES:
ZAMMAD_HTTP_TYPE:
ZAMMAD_FQDN:
ZAMMAD_WEB_CONCURRENCY:
ZAMMAD_MANAGE_SESSIONS_JOBS_WORKERS:
ZAMMAD_PROCESS_SESSIONS_JOBS_WORKERS:
ZAMMAD_PROCESS_SCHEDULED_JOBS_WORKERS:
ZAMMAD_PROCESS_DELAYED_JOBS_WORKERS:
ZAMMAD_PROCESS_DELAYED_JOBS_WORKER_THREADS:
ZAMMAD_PROCESS_DELAYED_AI_JOBS_WORKERS:
ZAMMAD_PROCESS_DELAYED_AI_JOBS_WORKER_THREADS:
ZAMMAD_PROCESS_DELAYED_COMMUNICATION_INBOUND_JOBS_WORKERS:
ZAMMAD_PROCESS_DELAYED_COMMUNICATION_INBOUND_JOBS_WORKER_THREADS:
ZAMMAD_OTRS_IMPORT_READ_TIMEOUT:
ZAMMAD_OTRS_IMPORT_TOTAL_TIMEOUT:
ZAMMAD_HTTP_OPEN_TIMEOUT:
ZAMMAD_HTTP_READ_TIMEOUT:
ZAMMAD_HTTP_TOTAL_TIMEOUT:
ZAMMAD_HTTP_AI_READ_TIMEOUT:
ZAMMAD_HTTP_AI_TOTAL_TIMEOUT:
ZAMMAD_HTTP_ELASTICSEARCH_READ_TIMEOUT:
ZAMMAD_HTTP_ELASTICSEARCH_TOTAL_TIMEOUT:
ZAMMAD_HTTP_ELASTICSEARCH_REINDEX_READ_TIMEOUT:
ZAMMAD_HTTP_ELASTICSEARCH_REINDEX_TOTAL_TIMEOUT:
ZAMMAD_HTTP_IMPORT_ATTACHMENT_READ_TIMEOUT:
ZAMMAD_HTTP_IMPORT_ATTACHMENT_TOTAL_TIMEOUT:
ZAMMAD_HTTP_WEBHOOK_READ_TIMEOUT:
ZAMMAD_HTTP_WEBHOOK_TOTAL_TIMEOUT:
# Allow disabling individual background services in the scheduler container.
ZAMMAD_PROCESS_SESSIONS_JOBS_DISABLE:
ZAMMAD_MANAGE_SESSIONS_JOBS_DISABLE:
ZAMMAD_PROCESS_SCHEDULED_JOBS_DISABLE:
ZAMMAD_PROCESS_DELAYED_JOBS_DISABLE:
ZAMMAD_PROCESS_DELAYED_AI_JOBS_DISABLE:
ZAMMAD_PROCESS_DELAYED_COMMUNICATION_INBOUND_JOBS_DISABLE:
ZAMMAD_GRAPHQL_INTROSPECTION:
ZAMMAD_AI_API_URL:
ZAMMAD_AI_TOKEN:
ZAMMAD_UI_BULK_BACKGROUND_UPDATE_THRESHOLD:
ZAMMAD_SETTING_TTL:
ZAMMAD_SAFE_MODE:
ZAMMAD_WEBSOCKET_SESSION_STORE_FORCE_FS_BACKEND:
ZAMMAD_RAILSSERVER_PORT:
# ZAMMAD_SESSION_JOBS_CONCURRENT is deprecated, please use ZAMMAD_PROCESS_SESSIONS_JOBS_WORKERS instead.
ZAMMAD_SESSION_JOBS_CONCURRENT:
# Variables used by ngingx-proxy container for reverse proxy creations
# for docs refer to https://github.com/nginx-proxy/nginx-proxy
VIRTUAL_HOST:
VIRTUAL_PORT:
# Variables used by acme-companion for retrieval of LetsEncrypt certificate
# for docs refer to https://github.com/nginx-proxy/acme-companion
LETSENCRYPT_HOST:
LETSENCRYPT_EMAIL:
image: ${IMAGE_REPO:-ghcr.io/zammad/zammad}:${VERSION:-7.2.0-0000}
init: true
restart: ${RESTART:-always}
volumes:
- zammad-backup:/var/tmp/zammad:ro # needed for waiting on restore operations
- zammad-storage:/opt/zammad/storage
depends_on:
zammad-memcached:
condition: service_healthy
zammad-postgresql:
condition: service_healthy
zammad-redis:
condition: service_healthy
services:
zammad-backup:
<<: *zammad-service
command: ["zammad-backup"]
volumes:
- zammad-backup:/var/tmp/zammad
- zammad-storage:/opt/zammad/storage
user: 0:0
zammad-elasticsearch:
image: elasticsearch:${ELASTICSEARCH_VERSION:-9.5.3}
restart: ${RESTART:-always}
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
environment:
discovery.type: single-node
xpack.security.enabled: "false"
ES_JAVA_OPTS: ${ELASTICSEARCH_JAVA_OPTS:--Xms1g -Xmx1g}
zammad-init:
<<: *zammad-service
command: ["zammad-init"]
restart: on-failure
user: 0:0
zammad-memcached:
command: memcached -m 256M
image: memcached:${MEMCACHE_VERSION:-1.6.45-alpine}
restart: ${RESTART:-always}
healthcheck:
test: ["CMD", "nc", "-z", "127.0.0.1", "11211"]
interval: 10s
timeout: 5s
start_period: 10s
retries: 5
zammad-nginx:
<<: *zammad-service
command: ["zammad-nginx"]
init: false
expose:
- "${NGINX_PORT:-8080}"
ports:
- "${NGINX_EXPOSE_PORT:-8080}:${NGINX_PORT:-8080}"
depends_on:
zammad-railsserver:
condition: service_healthy
zammad-postgresql:
# PostgreSQL tuning: dedicated variables for the settings the Zammad documentation
# recommends to tune, plus POSTGRES_EXTRA_OPTS for any other setting as raw
# -c flags - see .env.dist. Only variables that are set are passed to the server,
# unset ones leave it completely untouched (including manual tuning in the data
# volume). Compose word-splits the string into argv like a shell, so the
# free-form POSTGRES_EXTRA_OPTS works without a shell wrapper.
command: >-
postgres
${POSTGRES_MAX_CONNECTIONS:+-c max_connections=${POSTGRES_MAX_CONNECTIONS}}
${POSTGRES_SHARED_BUFFERS:+-c shared_buffers=${POSTGRES_SHARED_BUFFERS}}
${POSTGRES_TEMP_BUFFERS:+-c temp_buffers=${POSTGRES_TEMP_BUFFERS}}
${POSTGRES_WORK_MEM:+-c work_mem=${POSTGRES_WORK_MEM}}
${POSTGRES_MAX_STACK_DEPTH:+-c max_stack_depth=${POSTGRES_MAX_STACK_DEPTH}}
${POSTGRES_EXTRA_OPTS:-}
# Docker caps /dev/shm at 64MB - the one PostgreSQL-adjacent knob a -c flag cannot
# reach. Raise it together with shared_buffers/work_mem, otherwise parallel query
# workers can fail with "could not resize shared memory segment".
shm_size: ${POSTGRES_SHM_SIZE:-64mb}
environment:
# The bootstrap role of the postgres image is always a superuser, so it is kept
# separate from the role Zammad connects with and only used for administration.
# Its password falls back to POSTGRES_PASS, so that hardening that one variable
# does not silently leave a superuser behind on the default password.
POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_SUPERUSER_PASS:-${POSTGRES_PASS:-zammad}}
# Consumed by the initdb hook below, to provision Zammad's unprivileged role
# and the database it owns.
ZAMMAD_DB: ${POSTGRES_DB:-zammad_production}
ZAMMAD_DB_USER: ${POSTGRES_USER:-zammad}
ZAMMAD_DB_PASS: ${POSTGRES_PASS:-zammad}
image: postgres:${POSTGRES_VERSION:-17.11-alpine}
restart: ${RESTART:-always}
volumes:
- postgresql-data:/var/lib/postgresql/data
configs:
- source: postgresql-initdb
target: /docker-entrypoint-initdb.d/10-create-zammad-role.sh
mode: 0555
healthcheck:
# Connect over TCP as Zammad's own role rather than using pg_isready, which
# reports success for an unknown role or database, and would also accept the
# socket-only server that runs while the data directory is still initialising.
# Dependent services wait for this healthcheck, so it has to establish that
# the role and the database the initdb hook provisions exist and accept
# connections.
#
# The password is supplied so that this keeps working where host connections
# require authentication, for example with
# POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256. With the image default the
# loopback address is trusted, so the credentials are not verified there.
test:
- CMD-SHELL
- |-
PGPASSWORD="$${ZAMMAD_DB_PASS}" \
psql --no-password --quiet --output /dev/null --variable ON_ERROR_STOP=1 \
--host 127.0.0.1 --username "$${ZAMMAD_DB_USER}" \
--dbname "$${ZAMMAD_DB}" --command "SELECT 1"
interval: 10s
timeout: 5s
start_period: 60s
retries: 5
zammad-railsserver:
<<: *zammad-service
command: ["zammad-railsserver"]
healthcheck:
test: ["CMD", "curl", "-sf", "http://127.0.0.1:${ZAMMAD_RAILSSERVER_PORT:-3000}"]
interval: 30s
timeout: 5s
start_period: 120s
retries: 3
zammad-redis:
image: redis:${REDIS_VERSION:-8.10.2-alpine}
restart: ${RESTART:-always}
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
start_period: 10s
retries: 5
zammad-scheduler:
<<: *zammad-service
command: ["zammad-scheduler"]
zammad-websocket:
<<: *zammad-service
command: ["zammad-websocket"]
configs:
postgresql-initdb:
# Provisions the database that Zammad uses, owned by a dedicated login role.
#
# The postgres image unconditionally makes its bootstrap role a superuser. Zammad
# does not need any superuser capability - it only owns its own database and
# relies on the built-in plpgsql extension - so the application role is created
# here as a plain login role, rather than reusing the bootstrap role.
#
# This runs only while an empty data directory is initialised. Installations whose
# volume already exists keep the role layout they were created with, see the
# README for how to migrate those.
#
# The content is inlined so that this file stays self-contained and can be
# deployed as-is, for example by pasting it into Portainer. '$$' escapes Compose
# interpolation, so those variables are expanded inside the container instead.
content: |
#!/bin/bash
set -o errexit
set -o pipefail
# initdb has already run by the time this hook does, so a rejected configuration
# cannot be repaired by correcting it and starting again: the data directory is
# populated and the entrypoint never processes this directory a second time.
# Say so, rather than leaving the operator with a role or database that is
# merely reported missing later on.
zammad_abort() {
echo "$1" >&2
echo "Correct this, then remove the postgresql-data volume and start again. The" >&2
echo " database directory is already initialised, so this will not run twice." >&2
exit 1
}
# Zammad must not reuse the bootstrap role, which is always a superuser. This
# cannot be enforced on later starts: the only reliable signal is this
# comparison, and checking the role's actual attributes instead would mark
# every installation predating this change as unhealthy.
if [ "$${ZAMMAD_DB_USER}" = "$${POSTGRES_USER}" ]; then
zammad_abort "POSTGRES_USER and POSTGRES_SUPERUSER must differ, the latter is a superuser."
fi
# The system databases exist already, so they would keep the bootstrap role as
# their owner, and Zammad would run inside a database it does not own.
case "$${ZAMMAD_DB}" in
postgres | template0 | template1)
zammad_abort "POSTGRES_DB must not be one of PostgreSQL's system databases."
;;
esac
echo "Creating the '$${ZAMMAD_DB_USER}' role and the '$${ZAMMAD_DB}' database…"
# The identifiers and the password are passed as psql variables, so that psql
# quotes them and no shell quoting can leak into the statements. The role owns
# the database, which already carries every privilege it needs on it.
psql --variable ON_ERROR_STOP=1 \
--username "$${POSTGRES_USER}" \
--dbname "$${POSTGRES_DB}" \
--variable role="$${ZAMMAD_DB_USER}" \
--variable pass="$${ZAMMAD_DB_PASS}" \
--variable db="$${ZAMMAD_DB}" <<'EOSQL'
CREATE ROLE :"role" LOGIN PASSWORD :'pass';
CREATE DATABASE :"db" OWNER :"role";
EOSQL
volumes:
elasticsearch-data:
driver: local
postgresql-data:
driver: local
redis-data:
driver: local
zammad-backup:
driver: local
zammad-storage:
driver: local