-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.prod.yml
More file actions
140 lines (135 loc) · 6.23 KB
/
Copy pathdocker-compose.prod.yml
File metadata and controls
140 lines (135 loc) · 6.23 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
# Reference production compose stack for the EDR server + MySQL.
# Distinct from docker-compose.yml (dev MySQL only). Full setup +
# secret-file generation documented in docker-compose.prod.README.md.
# Boot shortcut:
#
# docker compose -f docker-compose.prod.yml up -d
#
# The server image is pulled from ghcr.io/getvictor/fleet-edr-server; a local
# build uses the docker-compose.prod.build.yml override for smoke tests and
# air-gapped sites.
services:
mysql:
image: mysql:8.4.9@sha256:c36050afdca850f23cef85703f84c7531a5ae155a11b5ee1c60acb09937c4084
restart: unless-stopped
environment:
# MySQL 8.4 reads these _FILE variants natively. Avoids root password in
# any compose env block or docker inspect output.
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root
MYSQL_DATABASE: edr
volumes:
- edr-mysql-data:/var/lib/mysql
secrets:
- mysql_root
healthcheck:
# --silent and redirecting stderr keeps healthcheck logs out of the main
# service log. The 10s start_period lets InnoDB recover before we gate on
# a successful ping.
test: ["CMD-SHELL", "mysqladmin ping --silent 2>/dev/null || exit 1"]
interval: 5s
timeout: 5s
retries: 20
start_period: 10s
# ClickHouse event archive (ADR-0015): the durable event store the server writes ingested events to and reads them back
# from. Reachable only on the private compose network (no host port), same posture as mysql. The default user is
# passwordless; the DSN rides a docker secret so a password can be added later without editing this file.
clickhouse:
image: clickhouse/clickhouse-server:24.8@sha256:1ffa82edee000a42c09313bd9f1293d94c570aee74babc1b3ca9983a35fa597b
restart: unless-stopped
environment:
CLICKHOUSE_DB: edr
# Required for the default user to authenticate over the network with an empty password; without it the server's
# ClickHouse ping fails with code 516 (AUTHENTICATION_FAILED). Mirrors the dev/demo clickhouse service.
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: "1"
ulimits:
# ClickHouse opens many files; the stock 1024 soft limit trips "too many open files" under load.
nofile:
soft: 262144
hard: 262144
volumes:
- edr-clickhouse-data:/var/lib/clickhouse
healthcheck:
test: ["CMD", "clickhouse-client", "--query", "SELECT 1"]
interval: 5s
timeout: 5s
retries: 20
start_period: 10s
server:
# Set EDR_VERSION in .env to pin a release tag (recommended). `latest` is
# fine for dev but unsafe for production because image digests can drift.
# For a local source build instead of a pull, layer the build override:
# docker compose -f docker-compose.prod.yml -f docker-compose.prod.build.yml up -d --build
image: ghcr.io/getvictor/fleet-edr-server:${EDR_VERSION:-latest}
restart: unless-stopped
depends_on:
mysql:
condition: service_healthy
clickhouse:
condition: service_healthy
environment:
# The MySQL DSN needs the runtime root password that MYSQL reads from
# the same secret file. We consume it via *_FILE (see server/config/
# file_env.go) rather than interpolating so the password never lands in
# `docker inspect` output. The env key is blank here so the *_FILE path
# wins unconditionally; the server's fileBackedGetenv wrapper does the
# rest.
EDR_DSN: ""
EDR_DSN_FILE: /run/secrets/edr_dsn
EDR_ENROLL_SECRET_FILE: /run/secrets/enroll_secret
# Deployment root secret (>=32 bytes). Required unconditionally: the
# host-token HMAC pepper and other long-lived keys derive from it via HKDF
# (server/config/config.go loadSecretKey), so the server refuses to boot
# without it. Read from a docker-secret file so it never lands in
# `docker inspect`. Changing it invalidates every enrolled host.
EDR_SECRET_KEY_FILE: /run/secrets/secret_key
# ClickHouse event archive DSN (ADR-0015), the event store the server refuses to boot without. Passwordless on the
# private network; blank env so the *_FILE path wins and no value lands in `docker inspect`.
EDR_CLICKHOUSE_DSN: ""
EDR_CLICKHOUSE_DSN_FILE: /run/secrets/clickhouse_dsn
# TLS cert paths are unconditionally required (issue #140 removed the
# EDR_ALLOW_INSECURE_HTTP opt-out). Mount fullchain.pem + privkey.pem
# under ./tls/ (or override EDR_TLS_DIR to point at your cert store).
# The server refuses to boot when either path is empty or unreadable.
EDR_TLS_CERT_FILE: ${EDR_TLS_CERT_FILE:-/tls/fullchain.pem}
EDR_TLS_KEY_FILE: ${EDR_TLS_KEY_FILE:-/tls/privkey.pem}
EDR_LOG_LEVEL: ${EDR_LOG_LEVEL:-info}
EDR_LOG_FORMAT: "json"
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-}
OTEL_SERVICE_NAME: fleet-edr-server
volumes:
# Optional: mount a tls dir if fullchain.pem + privkey.pem exist. The
# `:ro` flag + `tls:` default-empty env makes this safe when unused.
- ${EDR_TLS_DIR:-./tls}:/tls:ro
secrets:
- enroll_secret
- edr_dsn
- secret_key
- clickhouse_dsn
ports:
- "${EDR_LISTEN:-8088}:8088"
# No server-side HEALTHCHECK: the distroless/static base has no shell
# and no wget/curl, so `CMD-SHELL` healthchecks always fail. Nothing
# depends_on the server here, so operator-side readiness checks
# (curl http(s)://host:${EDR_LISTEN}/readyz) are the canonical path.
# If we ever need container-level health, compile a tiny static
# healthcheck binary into the image and invoke it via
# `HEALTHCHECK ["CMD", "/usr/local/bin/healthcheck"]` (no shell).
volumes:
edr-mysql-data:
edr-clickhouse-data:
secrets:
mysql_root:
file: ./secrets/mysql_root
enroll_secret:
file: ./secrets/enroll_secret
# edr_dsn is derived from mysql_root at `docker compose up` time via a
# compose-secret hack: the operator writes it once. See README.
edr_dsn:
file: ./secrets/edr_dsn
secret_key:
file: ./secrets/secret_key
# Fixed passwordless DSN pointing at the clickhouse service on the private
# network. In a secret file for parity with edr_dsn (a ClickHouse password,
# if added, would live here). See README.
clickhouse_dsn:
file: ./secrets/clickhouse_dsn