HH-445: deploy production observability and runbooks (#96)

* HH-445: deploy production observability and runbooks

* fix(ops): share production database DSN

* fix(HH-445): enforce database TLS gate

* fix(HH-445): preserve production serve command

* fix(prod): require external database dependencies

* fix(prod): unify database host rejection gates

* test(prod): enforce exact database TLS runbook contract

---------

Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Rogee
2026-08-22 19:39:57 +08:00
committed by GitHub
co-authored by rogee
parent 61376a57fd
commit fb83285617
28 changed files with 1622 additions and 220 deletions
+24 -93
View File
@@ -1,110 +1,41 @@
# GoChat Fluentd Configuration
# Reference: Chatwoot logging infrastructure pattern
# Collects structured JSON logs from GoChat containers and sends to Elasticsearch
#
# Deployment: deploy/fluentd/ — apply as ConfigMap + Deployment in K8s
# Usage: kubectl apply -k deploy/fluentd/
# ---- Source: tail GoChat container logs ----
# Production Docker Compose log collector. Docker's non-blocking Fluentd driver
# sends every service with a gochat.<container> tag to this forward input.
<source>
@type tail
path /var/log/containers/gochat*.log
pos_file /var/log/fluentd-gochat.pos
tag gochat.app
read_from_head true
<parse>
@type json
time_key timestamp
time_format %Y-%m-%dT%H:%M:%S.%NZ
keep_time_key true
</parse>
@type forward
bind 0.0.0.0
port 24224
</source>
# ---- Source: tail GoChat worker logs ----
<source>
@type tail
path /var/log/containers/gochat-worker*.log
pos_file /var/log/fluentd-gochat-worker.pos
tag gochat.worker
read_from_head true
<parse>
@type json
time_key timestamp
time_format %Y-%m-%dT%H:%M:%S.%NZ
keep_time_key true
</parse>
</source>
# ---- Filter: Add Kubernetes metadata (pod name, namespace, labels) ----
<filter gochat.**>
@type kubernetes_metadata
@id filter_kube_metadata
</filter>
# ---- Filter: Parse log level for Elasticsearch routing ----
<filter gochat.**>
@type record_transformer
<record>
# Add searchable fields from GoChat structured logs
log_level ${record["level"]}
component ${record["component"]}
environment ${record["GOCHAT_ENV"]}
# Flatten error details for Kibana searching
error_message ${record["error"]}
service ${tag_parts[1]}
environment production
</record>
</filter>
# ---- Output: Elasticsearch (primary) ----
# Local, disk-buffered JSON is the reliable baseline and remains searchable
# without an external logging vendor. Ship these files onward if required.
<match gochat.**>
@type elasticsearch
@id out_es_gochat
@log_level info
# Elasticsearch connection
host ${ELASTICSEARCH_HOST}
port ${ELASTICSEARCH_PORT}
scheme https
ssl_version TLSv1_2
# Authentication
user ${ELASTICSEARCH_USER}
password ${ELASTICSEARCH_PASSWORD}
# Index naming: gochat-YYYY.MM.dd (daily rotation)
index_name gochat
template_name gochat
template_file /fluentd/etc/gochat-index-template.json
# ILM (Index Lifecycle Management) for automatic rotation
ilm_policy_name gochat-log-policy
ilm_policy_id gochat-log-policy
# Bulk indexing for performance
bulk_request_timeout 10s
flush_interval 5s
retry_max_interval 30s
retry_forever true
# Buffer configuration (disk-backed for reliability)
<buffer>
@type file
path /fluentd/log/gochat
append true
compress gzip
<buffer time>
@type file
path /var/log/fluentd/buffers/gochat
path /fluentd/buffer/gochat
timekey 60
timekey_wait 10s
timekey_use_utc true
flush_mode interval
flush_interval 5s
flush_thread_interval 1s
flush_mode lazy
chunk_limit_size 16m
total_limit_size 8g
retry_type exponential_backoff
retry_forever true
overflow_action block
chunk_limit_size 16M
total_limit_size 8G
</buffer>
# Time-based index naming
time_key timestamp
time_slice_format %Y.%m.%d
time_slice_wait 10m
<format>
@type json
</format>
</match>
# ---- Output: Stdout for debugging ----
<match gochat.debug.**>
@type stdout
</match>