feat(local-secrets): introduce unified local secrets management and documentation
- Add example secret files for `app_key`, `db_user_password`, and `redis_password`. - Introduce `local.vault.yml.example` for Ansible Vault encryption of local secrets. - Create migration and setup scripts for transitioning from `.env.local` to secrets files. - Update `docker-compose.local.yml` to adopt Docker Secrets and `_FILE` pattern for local configurations. - Add deployment playbooks and enhanced logging configurations for local development.
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -63,5 +63,10 @@ test-results/
|
|||||||
# WireGuard client configs (generated locally)
|
# WireGuard client configs (generated locally)
|
||||||
deployment/ansible/wireguard-clients/
|
deployment/ansible/wireguard-clients/
|
||||||
|
|
||||||
|
# Local development secrets (Docker Secrets)
|
||||||
|
secrets/*.txt
|
||||||
|
!secrets/*.example
|
||||||
|
deployment/ansible/secrets/local.vault.yml
|
||||||
|
|
||||||
# SSL/TLS certificates
|
# SSL/TLS certificates
|
||||||
**/acme.json
|
**/acme.json
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -37,6 +37,10 @@ reload: ## Dump Autoload & Restart PHP
|
|||||||
docker compose $(COMPOSE_FILES) exec php composer dump-autoload -o
|
docker compose $(COMPOSE_FILES) exec php composer dump-autoload -o
|
||||||
docker compose $(COMPOSE_FILES) restart php
|
docker compose $(COMPOSE_FILES) restart php
|
||||||
|
|
||||||
|
# Local Development Secrets (via Ansible)
|
||||||
|
local-secrets: ## Setup Local Development Secrets via Ansible
|
||||||
|
ansible-playbook -i deployment/ansible/inventory/local.yml deployment/ansible/playbooks/setup-local-secrets.yml
|
||||||
|
|
||||||
# Staging Environment
|
# Staging Environment
|
||||||
up-staging: ## Startet Staging-Container
|
up-staging: ## Startet Staging-Container
|
||||||
docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_STAGING) up -d
|
docker compose -f $(COMPOSE_BASE) -f $(COMPOSE_STAGING) up -d
|
||||||
|
|||||||
@@ -5,3 +5,7 @@ all:
|
|||||||
localhost:
|
localhost:
|
||||||
ansible_connection: local
|
ansible_connection: local
|
||||||
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
||||||
|
children:
|
||||||
|
local:
|
||||||
|
hosts:
|
||||||
|
localhost:
|
||||||
|
|||||||
80
deployment/ansible/playbooks/setup-local-secrets.yml
Normal file
80
deployment/ansible/playbooks/setup-local-secrets.yml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
- name: Setup Local Development Secrets
|
||||||
|
hosts: local
|
||||||
|
gather_facts: yes
|
||||||
|
become: no
|
||||||
|
connection: local
|
||||||
|
|
||||||
|
vars:
|
||||||
|
vault_file: "{{ playbook_dir }}/../secrets/local.vault.yml"
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Get repository root path
|
||||||
|
shell: |
|
||||||
|
cd "{{ playbook_dir }}/../../.."
|
||||||
|
pwd
|
||||||
|
register: repo_root
|
||||||
|
changed_when: false
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Set repository root as fact
|
||||||
|
set_fact:
|
||||||
|
app_stack_path: "{{ repo_root.stdout }}"
|
||||||
|
|
||||||
|
- name: Verify vault file exists
|
||||||
|
stat:
|
||||||
|
path: "{{ vault_file }}"
|
||||||
|
register: vault_stat
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
|
||||||
|
- name: Fail if vault file missing
|
||||||
|
fail:
|
||||||
|
msg: "Vault file not found at {{ vault_file }}. Please create it from local.vault.yml.example"
|
||||||
|
when: not vault_stat.stat.exists
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Load encrypted secrets
|
||||||
|
include_vars:
|
||||||
|
file: "{{ vault_file }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Ensure secrets directory exists for Docker Compose secrets
|
||||||
|
file:
|
||||||
|
path: "{{ app_stack_path }}/secrets"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ ansible_user_id | default(ansible_env.USER | default('user')) }}"
|
||||||
|
group: "{{ ansible_user_id | default(ansible_env.USER | default('user')) }}"
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
|
- name: Create Docker Compose secret files from vault
|
||||||
|
copy:
|
||||||
|
content: "{{ item.value }}"
|
||||||
|
dest: "{{ app_stack_path }}/secrets/{{ item.name }}.txt"
|
||||||
|
owner: "{{ ansible_user_id | default(ansible_env.USER | default('user')) }}"
|
||||||
|
group: "{{ ansible_user_id | default(ansible_env.USER | default('user')) }}"
|
||||||
|
mode: '0600'
|
||||||
|
loop:
|
||||||
|
- name: db_user_password
|
||||||
|
value: "{{ vault_db_password }}"
|
||||||
|
- name: redis_password
|
||||||
|
value: "{{ vault_redis_password }}"
|
||||||
|
- name: app_key
|
||||||
|
value: "{{ vault_app_key }}"
|
||||||
|
- name: vault_encryption_key
|
||||||
|
value: "{{ vault_encryption_key | default(vault_app_key) }}"
|
||||||
|
no_log: yes
|
||||||
|
|
||||||
|
- name: Set secure permissions on secrets directory
|
||||||
|
file:
|
||||||
|
path: "{{ app_stack_path }}/secrets"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ ansible_user_id | default(ansible_env.USER | default('user')) }}"
|
||||||
|
group: "{{ ansible_user_id | default(ansible_env.USER | default('user')) }}"
|
||||||
|
mode: '0700'
|
||||||
|
recurse: yes
|
||||||
|
|
||||||
|
- name: Display secrets setup summary
|
||||||
|
debug:
|
||||||
|
msg: "? Local secrets created in {{ app_stack_path }}/secrets/"
|
||||||
24
deployment/ansible/secrets/local.vault.yml.example
Normal file
24
deployment/ansible/secrets/local.vault.yml.example
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# Local Development Vault Example
|
||||||
|
# Copy this file to local.vault.yml and encrypt with:
|
||||||
|
# ansible-vault encrypt local.vault.yml
|
||||||
|
#
|
||||||
|
# Or use plain text for local development (not recommended for shared machines):
|
||||||
|
# ansible-vault encrypt local.vault.yml --vault-password-file ~/.ansible/vault_pass_local.txt
|
||||||
|
#
|
||||||
|
# For local development, you can also keep it unencrypted if you prefer:
|
||||||
|
# cp local.vault.yml.example local.vault.yml
|
||||||
|
# # Edit local.vault.yml with your local development secrets
|
||||||
|
|
||||||
|
# Database Credentials (Local Development)
|
||||||
|
vault_db_password: "local-dev-db-password-change-me"
|
||||||
|
|
||||||
|
# Redis Password (Local Development)
|
||||||
|
vault_redis_password: "local-dev-redis-password-change-me"
|
||||||
|
|
||||||
|
# Application Secrets (Local Development)
|
||||||
|
# Generate with: php -r "echo 'base64:' . base64_encode(random_bytes(32));"
|
||||||
|
vault_app_key: "base64:local-dev-app-key-change-me-base64-encoded-32-byte-key"
|
||||||
|
|
||||||
|
# Optional: Encryption Key (defaults to app_key if not set)
|
||||||
|
vault_encryption_key: "base64:local-dev-encryption-key-change-me"
|
||||||
@@ -2,9 +2,11 @@
|
|||||||
# Usage: docker-compose -f docker-compose.base.yml -f docker-compose.local.yml up
|
# Usage: docker-compose -f docker-compose.base.yml -f docker-compose.local.yml up
|
||||||
#
|
#
|
||||||
# This file overrides base configuration with local development settings:
|
# This file overrides base configuration with local development settings:
|
||||||
# - Development ports (8888:80, 8443:443, 5433:5432)
|
# - Development ports (8888:80, 443:443, 5433:5432)
|
||||||
# - Host-mounted volumes for live code editing
|
# - Host-mounted volumes for live code editing
|
||||||
# - Debug flags enabled (APP_DEBUG, Xdebug)
|
# - Debug flags enabled (APP_DEBUG, Xdebug)
|
||||||
|
# - Redis with password (Docker Secrets)
|
||||||
|
# - Docker Secrets via *_FILE pattern (consistent with staging/production)
|
||||||
# - Development-friendly restart policies
|
# - Development-friendly restart policies
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@@ -47,10 +49,18 @@ services:
|
|||||||
- ./storage/uploads:/var/www/html/storage/uploads:rw
|
- ./storage/uploads:/var/www/html/storage/uploads:rw
|
||||||
- ./storage/analytics:/var/www/html/storage/analytics:rw
|
- ./storage/analytics:/var/www/html/storage/analytics:rw
|
||||||
environment:
|
environment:
|
||||||
PHP_IDE_CONFIG: "${PHP_IDE_CONFIG:-serverName=docker}"
|
- PHP_IDE_CONFIG=${PHP_IDE_CONFIG:-serverName=docker}
|
||||||
APP_ENV: ${APP_ENV:-development}
|
- APP_ENV=${APP_ENV:-development}
|
||||||
APP_DEBUG: ${APP_DEBUG:-true}
|
- APP_DEBUG=${APP_DEBUG:-true}
|
||||||
XDEBUG_MODE: ${XDEBUG_MODE:-debug}
|
- XDEBUG_MODE=${XDEBUG_MODE:-debug}
|
||||||
|
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
|
||||||
|
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||||||
|
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||||||
|
- APP_KEY_FILE=/run/secrets/app_key
|
||||||
|
secrets:
|
||||||
|
- db_user_password
|
||||||
|
- redis_password
|
||||||
|
- app_key
|
||||||
restart: ${RESTART_POLICY:-unless-stopped}
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
# NOTE: env_file not needed - Framework automatically loads .env.base → .env.local
|
# NOTE: env_file not needed - Framework automatically loads .env.base → .env.local
|
||||||
# Environment variables are loaded by EncryptedEnvLoader in the PHP application
|
# Environment variables are loaded by EncryptedEnvLoader in the PHP application
|
||||||
@@ -77,6 +87,29 @@ services:
|
|||||||
container_name: db
|
container_name: db
|
||||||
ports:
|
ports:
|
||||||
- "${DB_EXTERNAL_PORT:-5433}:5432"
|
- "${DB_EXTERNAL_PORT:-5433}:5432"
|
||||||
|
# Override environment to remove POSTGRES_PASSWORD (we use Docker Secrets via entrypoint)
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${DB_DATABASE:-michaelschiemer}
|
||||||
|
POSTGRES_USER: ${DB_USERNAME:-postgres}
|
||||||
|
# POSTGRES_PASSWORD is NOT set here - it's read from Docker Secret in entrypoint
|
||||||
|
# Performance & Connection Settings
|
||||||
|
POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C"
|
||||||
|
PGDATA: /var/lib/postgresql/data/pgdata
|
||||||
|
secrets:
|
||||||
|
- db_user_password
|
||||||
|
# Use entrypoint to read password from Docker Secret
|
||||||
|
# This overrides the base.yml POSTGRES_PASSWORD environment variable
|
||||||
|
entrypoint: ["/bin/sh", "-c"]
|
||||||
|
command:
|
||||||
|
- |
|
||||||
|
POSTGRES_PASSWORD=$$(cat /run/secrets/db_user_password 2>/dev/null || echo '')
|
||||||
|
if [ -n "$$POSTGRES_PASSWORD" ]; then
|
||||||
|
export POSTGRES_PASSWORD
|
||||||
|
exec /usr/local/bin/docker-entrypoint.sh postgres -c config_file=/etc/postgresql/postgresql.conf
|
||||||
|
else
|
||||||
|
echo "⚠️ Warning: db_user_password secret not found, PostgreSQL may fail to start"
|
||||||
|
exec /usr/local/bin/docker-entrypoint.sh postgres -c config_file=/etc/postgresql/postgresql.conf
|
||||||
|
fi
|
||||||
restart: ${RESTART_POLICY:-unless-stopped}
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
logging:
|
logging:
|
||||||
driver: "${LOG_DRIVER:-local}"
|
driver: "${LOG_DRIVER:-local}"
|
||||||
@@ -95,12 +128,29 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
container_name: redis
|
container_name: redis
|
||||||
restart: ${RESTART_POLICY:-unless-stopped}
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
|
secrets:
|
||||||
|
- redis_password
|
||||||
|
command: >
|
||||||
|
sh -c "redis-server
|
||||||
|
--requirepass $$(cat /run/secrets/redis_password)
|
||||||
|
--maxmemory 256mb
|
||||||
|
--maxmemory-policy allkeys-lru
|
||||||
|
--save 900 1
|
||||||
|
--save 300 10
|
||||||
|
--save 60 10000
|
||||||
|
--appendonly yes
|
||||||
|
--appendfsync everysec"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "sh", "-c", "redis-cli --no-auth-warning -a $$(cat /run/secrets/redis_password) ping"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
logging:
|
logging:
|
||||||
driver: "${LOG_DRIVER:-local}"
|
driver: "${LOG_DRIVER:-local}"
|
||||||
options:
|
options:
|
||||||
max-size: "${LOG_MAX_SIZE:-5m}"
|
max-size: "${LOG_MAX_SIZE:-5m}"
|
||||||
max-file: "${LOG_MAX_FILE:-2}"
|
max-file: "${LOG_MAX_FILE:-2}"
|
||||||
# NOTE: env_file not needed - Framework automatically loads .env.base → .env.local
|
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
@@ -121,6 +171,12 @@ services:
|
|||||||
- WORKER_DEBUG=${WORKER_DEBUG:-false}
|
- WORKER_DEBUG=${WORKER_DEBUG:-false}
|
||||||
- WORKER_SLEEP_TIME=${WORKER_SLEEP_TIME:-100000}
|
- WORKER_SLEEP_TIME=${WORKER_SLEEP_TIME:-100000}
|
||||||
- WORKER_MAX_JOBS=${WORKER_MAX_JOBS:-1000}
|
- WORKER_MAX_JOBS=${WORKER_MAX_JOBS:-1000}
|
||||||
|
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
|
||||||
|
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||||||
|
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||||||
|
secrets:
|
||||||
|
- db_user_password
|
||||||
|
- redis_password
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# NOTE: env_file not needed - Framework automatically loads .env.base → .env.local
|
# NOTE: env_file not needed - Framework automatically loads .env.base → .env.local
|
||||||
deploy:
|
deploy:
|
||||||
@@ -156,3 +212,8 @@ networks:
|
|||||||
cache:
|
cache:
|
||||||
internal: ${NETWORK_CACHE_INTERNAL:-false}
|
internal: ${NETWORK_CACHE_INTERNAL:-false}
|
||||||
|
|
||||||
|
# Docker Secrets Configuration
|
||||||
|
# Secrets are stored in ./secrets/ directory (relative to this file)
|
||||||
|
# Note: Secrets are already defined in docker-compose.base.yml, but we activate them here
|
||||||
|
# for local development. The base.yml defines the secret sources.
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ COPY docker/php/php.${ENV}.ini /usr/local/etc/php/php.ini
|
|||||||
|
|
||||||
# Kopiere PHP-FPM Pool-Konfiguration
|
# Kopiere PHP-FPM Pool-Konfiguration
|
||||||
COPY docker/php/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf
|
COPY docker/php/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf
|
||||||
|
COPY docker/php/zzzz-override.conf /usr/local/etc/php-fpm.d/zzzz-override.conf
|
||||||
|
|
||||||
# Xdebug-Konfiguration nur wenn dev
|
# Xdebug-Konfiguration nur wenn dev
|
||||||
RUN if [ "$ENV" = "dev" ] && [ -f docker/php/xdebug.ini ]; then \
|
RUN if [ "$ENV" = "dev" ] && [ -f docker/php/xdebug.ini ]; then \
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ user = appuser
|
|||||||
group = appuser
|
group = appuser
|
||||||
|
|
||||||
; The address on which to accept FastCGI requests.
|
; The address on which to accept FastCGI requests.
|
||||||
listen = 9000
|
; Use 0.0.0.0:9000 to listen on all interfaces (required for Docker networking)
|
||||||
|
listen = 0.0.0.0:9000
|
||||||
|
|
||||||
; Clear environment in FPM workers
|
; Clear environment in FPM workers
|
||||||
clear_env = no
|
clear_env = no
|
||||||
|
|||||||
4
docker/php/zzzz-override.conf
Normal file
4
docker/php/zzzz-override.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[www]
|
||||||
|
; Override listen address to listen on all interfaces (required for Docker networking)
|
||||||
|
; This file is loaded last (alphabetically) to override www.conf
|
||||||
|
listen = 0.0.0.0:9000
|
||||||
470
docs/deployment/local-secrets-unification-plan.md
Normal file
470
docs/deployment/local-secrets-unification-plan.md
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
# Plan: Vereinheitlichung der lokalen Entwicklungsumgebung mit Staging/Production
|
||||||
|
|
||||||
|
**Datum**: 2025-11-04
|
||||||
|
**Ziel**: Lokale Entwicklungsumgebung auf Docker Secrets und Redis-Passwort umstellen, um Konsistenz mit Staging/Production zu erreichen
|
||||||
|
|
||||||
|
## Aktuelle Situation
|
||||||
|
|
||||||
|
### Lokal (docker-compose.local.yml)
|
||||||
|
- ? **Redis**: Kein Passwort (nur redis.conf)
|
||||||
|
- ? **Docker Secrets**: Nicht verwendet
|
||||||
|
- ? ***_FILE Pattern**: Nicht verwendet
|
||||||
|
- ? **Secrets**: Direkt in `.env.local` (plain text)
|
||||||
|
|
||||||
|
### Staging/Production
|
||||||
|
- ? **Redis**: Mit Passwort via Docker Secrets
|
||||||
|
- ? **Docker Secrets**: Aktiviert
|
||||||
|
- ? ***_FILE Pattern**: F?r alle Secrets
|
||||||
|
- ? **Framework**: `DockerSecretsResolver` unterst?tzt automatisch `*_FILE` Pattern
|
||||||
|
|
||||||
|
## Vorteile der Vereinheitlichung
|
||||||
|
|
||||||
|
### 1. Konsistenz
|
||||||
|
- ? **Gleiche Konfiguration** in allen Umgebungen
|
||||||
|
- ? **Weniger ?berraschungen** bei Deployment
|
||||||
|
- ? **Einfachere Fehlersuche** (gleiche Konfiguration = gleiche Probleme)
|
||||||
|
|
||||||
|
### 2. Framework-Support
|
||||||
|
- ? **Framework unterst?tzt bereits `DockerSecretsResolver`**
|
||||||
|
- ? **Automatisches Laden** von `*_FILE` Pattern
|
||||||
|
- ? **Kein Code-Change n?tig** - nur Konfiguration
|
||||||
|
|
||||||
|
### 3. Sicherheit
|
||||||
|
- ? **Bessere Praxis** auch in Entwicklung
|
||||||
|
- ? **Secrets nicht in `.env.local`** (kann versehentlich committed werden)
|
||||||
|
- ? **Dateisystem-Permissions** f?r Secrets
|
||||||
|
|
||||||
|
### 4. Entwickler-Erfahrung
|
||||||
|
- ? **Testen mit Production-?hnlicher Konfiguration**
|
||||||
|
- ? **Fr?hes Erkennen** von Secrets-Problemen
|
||||||
|
- ? **Einheitliches Setup** f?r alle Entwickler
|
||||||
|
|
||||||
|
## Nachteile / ?berlegungen
|
||||||
|
|
||||||
|
### 1. Komplexit?t
|
||||||
|
- ?? **Mehr Setup-Schritte** f?r neue Entwickler
|
||||||
|
- ?? **Zus?tzliche Secrets-Dateien** m?ssen erstellt werden
|
||||||
|
- ?? **Lokale Secrets-Verwaltung** n?tig
|
||||||
|
|
||||||
|
### 2. Migration
|
||||||
|
- ?? **Bestehende `.env.local`** muss angepasst werden
|
||||||
|
- ?? **Secrets-Verzeichnis** muss erstellt werden
|
||||||
|
- ?? **Dokumentation** muss aktualisiert werden
|
||||||
|
|
||||||
|
## Implementierungsplan
|
||||||
|
|
||||||
|
### Phase 1: Secrets-Verzeichnis und Struktur
|
||||||
|
|
||||||
|
#### 1.1 Secrets-Verzeichnis erstellen
|
||||||
|
```bash
|
||||||
|
mkdir -p secrets
|
||||||
|
chmod 700 secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 .gitignore aktualisieren
|
||||||
|
```gitignore
|
||||||
|
# Secrets (lokal)
|
||||||
|
secrets/*.txt
|
||||||
|
!secrets/*.example
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.3 Beispiel-Secrets erstellen
|
||||||
|
```bash
|
||||||
|
# secrets/redis_password.txt.example
|
||||||
|
# Beispiel: local-dev-redis-password-2024
|
||||||
|
|
||||||
|
# secrets/db_user_password.txt.example
|
||||||
|
# Beispiel: local-dev-db-password-2024
|
||||||
|
|
||||||
|
# secrets/app_key.txt.example
|
||||||
|
# Beispiel: base64:local-dev-app-key-generated
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Docker Compose Konfiguration
|
||||||
|
|
||||||
|
#### 2.1 docker-compose.local.yml aktualisieren
|
||||||
|
|
||||||
|
**Redis Service:**
|
||||||
|
```yaml
|
||||||
|
redis:
|
||||||
|
secrets:
|
||||||
|
- redis_password
|
||||||
|
command: >
|
||||||
|
sh -c "redis-server
|
||||||
|
--requirepass $$(cat /run/secrets/redis_password)
|
||||||
|
--maxmemory 256mb
|
||||||
|
--maxmemory-policy allkeys-lru
|
||||||
|
--save 900 1
|
||||||
|
--save 300 10
|
||||||
|
--save 60 10000
|
||||||
|
--appendonly yes
|
||||||
|
--appendfsync everysec"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "sh", "-c", "redis-cli --no-auth-warning -a $$(cat /run/secrets/redis_password) ping"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**PHP Service:**
|
||||||
|
```yaml
|
||||||
|
php:
|
||||||
|
environment:
|
||||||
|
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||||||
|
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||||||
|
- APP_KEY_FILE=/run/secrets/app_key
|
||||||
|
secrets:
|
||||||
|
- redis_password
|
||||||
|
- db_user_password
|
||||||
|
- app_key
|
||||||
|
```
|
||||||
|
|
||||||
|
**Queue-Worker Service:**
|
||||||
|
```yaml
|
||||||
|
queue-worker:
|
||||||
|
environment:
|
||||||
|
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||||||
|
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||||||
|
secrets:
|
||||||
|
- redis_password
|
||||||
|
- db_user_password
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 docker-compose.base.yml Secrets erweitern
|
||||||
|
|
||||||
|
**Secrets-Sektion:**
|
||||||
|
```yaml
|
||||||
|
secrets:
|
||||||
|
db_user_password:
|
||||||
|
file: ./secrets/db_user_password.txt
|
||||||
|
external: false
|
||||||
|
redis_password:
|
||||||
|
file: ./secrets/redis_password.txt
|
||||||
|
external: false
|
||||||
|
app_key:
|
||||||
|
file: ./secrets/app_key.txt
|
||||||
|
external: false
|
||||||
|
```
|
||||||
|
|
||||||
|
**Hinweis**: `external: false` bedeutet, dass die Dateien lokal sein m?ssen (nicht external wie in Production).
|
||||||
|
|
||||||
|
### Phase 3: Redis-Konfiguration
|
||||||
|
|
||||||
|
#### 3.1 redis.conf anpassen
|
||||||
|
**Option A**: redis.conf entfernt (nur Command-Line-Args)
|
||||||
|
**Option B**: redis.conf mit requirepass (aus Secret geladen)
|
||||||
|
|
||||||
|
**Empfehlung**: Option A - Command-Line-Args sind flexibler und konsistenter mit Staging/Production.
|
||||||
|
|
||||||
|
#### 3.2 redis.conf entfernen oder anpassen
|
||||||
|
```ini
|
||||||
|
# docker/redis/redis.conf
|
||||||
|
# Hinweis: Passwort wird via Command-Line-Args gesetzt (aus Docker Secret)
|
||||||
|
# requirepass wird nicht hier gesetzt, sondern via --requirepass Argument
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Migration bestehender .env.local
|
||||||
|
|
||||||
|
#### 4.1 Secrets aus .env.local extrahieren
|
||||||
|
```bash
|
||||||
|
# Script: scripts/migrate-env-to-secrets.sh
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SECRETS_DIR="./secrets"
|
||||||
|
mkdir -p "$SECRETS_DIR"
|
||||||
|
|
||||||
|
# Redis Password
|
||||||
|
if grep -q "REDIS_PASSWORD=" .env.local; then
|
||||||
|
grep "REDIS_PASSWORD=" .env.local | cut -d'=' -f2 > "$SECRETS_DIR/redis_password.txt"
|
||||||
|
chmod 600 "$SECRETS_DIR/redis_password.txt"
|
||||||
|
echo "? Created secrets/redis_password.txt"
|
||||||
|
# Entferne aus .env.local (kommentiere aus oder entferne)
|
||||||
|
sed -i '/^REDIS_PASSWORD=/d' .env.local
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DB Password
|
||||||
|
if grep -q "DB_PASSWORD=" .env.local; then
|
||||||
|
grep "DB_PASSWORD=" .env.local | cut -d'=' -f2 > "$SECRETS_DIR/db_user_password.txt"
|
||||||
|
chmod 600 "$SECRETS_DIR/db_user_password.txt"
|
||||||
|
echo "? Created secrets/db_user_password.txt"
|
||||||
|
sed -i '/^DB_PASSWORD=/d' .env.local
|
||||||
|
fi
|
||||||
|
|
||||||
|
# APP_KEY
|
||||||
|
if grep -q "APP_KEY=" .env.local; then
|
||||||
|
grep "APP_KEY=" .env.local | cut -d'=' -f2 > "$SECRETS_DIR/app_key.txt"
|
||||||
|
chmod 600 "$SECRETS_DIR/app_key.txt"
|
||||||
|
echo "? Created secrets/app_key.txt"
|
||||||
|
sed -i '/^APP_KEY=/d' .env.local
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "? Migration completed. Please review .env.local and remove migrated secrets."
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2 .env.local bereinigen
|
||||||
|
- Entferne: `REDIS_PASSWORD=`, `DB_PASSWORD=`, `APP_KEY=`
|
||||||
|
- Behalte: Alle anderen Konfigurationen (DB_HOST, DB_PORT, etc.)
|
||||||
|
|
||||||
|
### Phase 5: Dokumentation
|
||||||
|
|
||||||
|
#### 5.1 ENV_SETUP.md aktualisieren
|
||||||
|
- Lokales Setup mit Secrets dokumentieren
|
||||||
|
- Migration-Anleitung hinzuf?gen
|
||||||
|
- Beispiel-Secrets erw?hnen
|
||||||
|
|
||||||
|
#### 5.2 README.md aktualisieren
|
||||||
|
- Setup-Schritte f?r neue Entwickler
|
||||||
|
- Secrets-Verzeichnis erstellen
|
||||||
|
- Beispiel-Secrets kopieren
|
||||||
|
|
||||||
|
#### 5.3 .env.example aktualisieren
|
||||||
|
- Kommentare zu `*_FILE` Pattern hinzuf?gen
|
||||||
|
- Hinweis auf Secrets-Verzeichnis
|
||||||
|
|
||||||
|
## Detaillierte ?nderungen
|
||||||
|
|
||||||
|
### Datei: docker-compose.local.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
php:
|
||||||
|
environment:
|
||||||
|
# Use Docker Secrets via *_FILE pattern (Framework supports this automatically)
|
||||||
|
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||||||
|
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||||||
|
- APP_KEY_FILE=/run/secrets/app_key
|
||||||
|
secrets:
|
||||||
|
- db_user_password
|
||||||
|
- redis_password
|
||||||
|
- app_key
|
||||||
|
|
||||||
|
redis:
|
||||||
|
secrets:
|
||||||
|
- redis_password
|
||||||
|
command: >
|
||||||
|
sh -c "redis-server
|
||||||
|
--requirepass $$(cat /run/secrets/redis_password)
|
||||||
|
--maxmemory 256mb
|
||||||
|
--maxmemory-policy allkeys-lru
|
||||||
|
--save 900 1
|
||||||
|
--save 300 10
|
||||||
|
--save 60 10000
|
||||||
|
--appendonly yes
|
||||||
|
--appendfsync everysec"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "sh", "-c", "redis-cli --no-auth-warning -a $$(cat /run/secrets/redis_password) ping"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
queue-worker:
|
||||||
|
environment:
|
||||||
|
- DB_PASSWORD_FILE=/run/secrets/db_user_password
|
||||||
|
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
|
||||||
|
secrets:
|
||||||
|
- db_user_password
|
||||||
|
- redis_password
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
db_user_password:
|
||||||
|
file: ./secrets/db_user_password.txt
|
||||||
|
external: false
|
||||||
|
redis_password:
|
||||||
|
file: ./secrets/redis_password.txt
|
||||||
|
external: false
|
||||||
|
app_key:
|
||||||
|
file: ./secrets/app_key.txt
|
||||||
|
external: false
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datei: docker-compose.base.yml
|
||||||
|
|
||||||
|
**Secrets-Sektion bereits vorhanden** (Zeilen 192-224), muss nur genutzt werden.
|
||||||
|
|
||||||
|
### Datei: docker/redis/redis.conf
|
||||||
|
|
||||||
|
**Anpassen oder entfernen:**
|
||||||
|
```ini
|
||||||
|
# docker/redis/redis.conf
|
||||||
|
# Hinweis: Passwort wird via Docker Secrets geladen
|
||||||
|
# requirepass wird nicht hier gesetzt, sondern via Command-Line-Args
|
||||||
|
# In docker-compose.local.yml wird --requirepass verwendet
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration f?r bestehende Entwickler
|
||||||
|
|
||||||
|
### Schritt-f?r-Schritt Anleitung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Secrets-Verzeichnis erstellen
|
||||||
|
mkdir -p secrets
|
||||||
|
chmod 700 secrets
|
||||||
|
|
||||||
|
# 2. Secrets aus .env.local extrahieren
|
||||||
|
# Redis Password
|
||||||
|
REDIS_PASS=$(grep "^REDIS_PASSWORD=" .env.local | cut -d'=' -f2)
|
||||||
|
if [ -n "$REDIS_PASS" ]; then
|
||||||
|
echo "$REDIS_PASS" > secrets/redis_password.txt
|
||||||
|
chmod 600 secrets/redis_password.txt
|
||||||
|
echo "? Created secrets/redis_password.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DB Password
|
||||||
|
DB_PASS=$(grep "^DB_PASSWORD=" .env.local | cut -d'=' -f2)
|
||||||
|
if [ -n "$DB_PASS" ]; then
|
||||||
|
echo "$DB_PASS" > secrets/db_user_password.txt
|
||||||
|
chmod 600 secrets/db_user_password.txt
|
||||||
|
echo "? Created secrets/db_user_password.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# APP_KEY
|
||||||
|
APP_KEY=$(grep "^APP_KEY=" .env.local | cut -d'=' -f2)
|
||||||
|
if [ -n "$APP_KEY" ]; then
|
||||||
|
echo "$APP_KEY" > secrets/app_key.txt
|
||||||
|
chmod 600 secrets/app_key.txt
|
||||||
|
echo "? Created secrets/app_key.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Entferne Secrets aus .env.local (oder kommentiere aus)
|
||||||
|
sed -i '/^REDIS_PASSWORD=/d' .env.local
|
||||||
|
sed -i '/^DB_PASSWORD=/d' .env.local
|
||||||
|
sed -i '/^APP_KEY=/d' .env.local
|
||||||
|
|
||||||
|
# 4. Pr?fe Secrets
|
||||||
|
ls -la secrets/
|
||||||
|
# Sollte zeigen: redis_password.txt, db_user_password.txt, app_key.txt
|
||||||
|
|
||||||
|
# 5. Teste Konfiguration
|
||||||
|
docker compose -f docker-compose.base.yml -f docker-compose.local.yml config
|
||||||
|
|
||||||
|
# 6. Starte Container
|
||||||
|
docker compose -f docker-compose.base.yml -f docker-compose.local.yml up -d
|
||||||
|
|
||||||
|
# 7. Teste Redis-Verbindung
|
||||||
|
docker compose exec redis redis-cli --no-auth-warning -a $(cat secrets/redis_password.txt) ping
|
||||||
|
# Erwartet: PONG
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup f?r neue Entwickler
|
||||||
|
|
||||||
|
### Initial Setup Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# scripts/setup-local-secrets.sh
|
||||||
|
|
||||||
|
echo "?? Setting up local development secrets..."
|
||||||
|
|
||||||
|
SECRETS_DIR="./secrets"
|
||||||
|
mkdir -p "$SECRETS_DIR"
|
||||||
|
chmod 700 "$SECRETS_DIR"
|
||||||
|
|
||||||
|
# Generate Redis Password
|
||||||
|
if [ ! -f "$SECRETS_DIR/redis_password.txt" ]; then
|
||||||
|
REDIS_PASS=$(openssl rand -base64 32)
|
||||||
|
echo "$REDIS_PASS" > "$SECRETS_DIR/redis_password.txt"
|
||||||
|
chmod 600 "$SECRETS_DIR/redis_password.txt"
|
||||||
|
echo "? Generated secrets/redis_password.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate DB Password
|
||||||
|
if [ ! -f "$SECRETS_DIR/db_user_password.txt" ]; then
|
||||||
|
DB_PASS=$(openssl rand -base64 32)
|
||||||
|
echo "$DB_PASS" > "$SECRETS_DIR/db_user_password.txt"
|
||||||
|
chmod 600 "$SECRETS_DIR/db_user_password.txt"
|
||||||
|
echo "? Generated secrets/db_user_password.txt"
|
||||||
|
echo "?? Update DB_PASSWORD in .env.local if needed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate APP_KEY (if not exists)
|
||||||
|
if [ ! -f "$SECRETS_DIR/app_key.txt" ]; then
|
||||||
|
APP_KEY=$(php -r "echo 'base64:' . base64_encode(random_bytes(32));")
|
||||||
|
echo "$APP_KEY" > "$SECRETS_DIR/app_key.txt"
|
||||||
|
chmod 600 "$SECRETS_DIR/app_key.txt"
|
||||||
|
echo "? Generated secrets/app_key.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "? Local secrets setup completed!"
|
||||||
|
echo ""
|
||||||
|
echo "?? Next steps:"
|
||||||
|
echo "1. Review secrets/*.txt files"
|
||||||
|
echo "2. Update .env.local if needed (DB_USERNAME, DB_HOST, etc.)"
|
||||||
|
echo "3. Start containers: docker compose -f docker-compose.base.yml -f docker-compose.local.yml up -d"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vorteile dieser L?sung
|
||||||
|
|
||||||
|
### 1. Konsistenz
|
||||||
|
- ? Gleiche Konfiguration in Local, Staging, Production
|
||||||
|
- ? Framework nutzt `DockerSecretsResolver` ?berall
|
||||||
|
- ? Keine Environment-spezifischen Code-Pfade
|
||||||
|
|
||||||
|
### 2. Sicherheit
|
||||||
|
- ? Secrets nicht in `.env.local` (kann versehentlich committed werden)
|
||||||
|
- ? Dateisystem-Permissions (600) f?r Secrets
|
||||||
|
- ? `.gitignore` verhindert versehentliches Committen
|
||||||
|
|
||||||
|
### 3. Wartbarkeit
|
||||||
|
- ? Einheitliche Konfiguration
|
||||||
|
- ? Framework unterst?tzt `*_FILE` Pattern automatisch
|
||||||
|
- ? Klare Trennung: Secrets vs. Konfiguration
|
||||||
|
|
||||||
|
### 4. Entwickler-Erfahrung
|
||||||
|
- ? Testen mit Production-?hnlicher Konfiguration
|
||||||
|
- ? Fr?hes Erkennen von Secrets-Problemen
|
||||||
|
- ? Setup-Script f?r neue Entwickler
|
||||||
|
|
||||||
|
## Nachteile / ?berlegungen
|
||||||
|
|
||||||
|
### 1. Komplexit?t
|
||||||
|
- ?? **Mehr Setup-Schritte** f?r neue Entwickler
|
||||||
|
- ?? **Zus?tzliche Secrets-Dateien** m?ssen verwaltet werden
|
||||||
|
- ?? **Lokale Secrets-Verwaltung** n?tig
|
||||||
|
|
||||||
|
**L?sung**: Setup-Script automatisiert die Erstellung
|
||||||
|
|
||||||
|
### 2. Migration
|
||||||
|
- ?? **Bestehende `.env.local`** muss angepasst werden
|
||||||
|
- ?? **Secrets-Verzeichnis** muss erstellt werden
|
||||||
|
- ?? **Dokumentation** muss aktualisiert werden
|
||||||
|
|
||||||
|
**L?sung**: Migration-Script unterst?tzt den ?bergang
|
||||||
|
|
||||||
|
### 3. Redis-Passwort lokal
|
||||||
|
- ?? **Mehr Konfiguration** f?r lokale Entwicklung
|
||||||
|
- ?? **Passwort muss bekannt sein** f?r Redis-CLI-Zugriff
|
||||||
|
|
||||||
|
**L?sung**:
|
||||||
|
- Passwort in `secrets/redis_password.txt` (leicht zug?nglich lokal)
|
||||||
|
- Helper-Script: `scripts/redis-cli.sh` f?r einfachen Zugriff
|
||||||
|
|
||||||
|
## Alternative Ans?tze
|
||||||
|
|
||||||
|
### Option A: Secrets optional machen (nicht empfohlen)
|
||||||
|
- Redis-Passwort nur wenn Secret vorhanden
|
||||||
|
- Komplexer, weniger konsistent
|
||||||
|
|
||||||
|
### Option B: Nur Production/Staging mit Secrets (aktuell)
|
||||||
|
- Lokal bleibt ohne Secrets
|
||||||
|
- **Nachteil**: Inkonsistenz zwischen Umgebungen
|
||||||
|
|
||||||
|
### Option C: Vereinheitlichung (empfohlen)
|
||||||
|
- Alle Umgebungen nutzen Secrets
|
||||||
|
- **Vorteil**: Maximale Konsistenz
|
||||||
|
|
||||||
|
## Empfehlung
|
||||||
|
|
||||||
|
**Vereinheitlichung (Option C)** ist die beste L?sung, weil:
|
||||||
|
1. ? **Maximale Konsistenz** zwischen allen Umgebungen
|
||||||
|
2. ? **Framework unterst?tzt bereits** `DockerSecretsResolver`
|
||||||
|
3. ? **Bessere Sicherheit** auch lokal
|
||||||
|
4. ? **Fr?hes Erkennen** von Secrets-Problemen
|
||||||
|
5. ? **Setup-Script** macht Migration einfach
|
||||||
|
|
||||||
|
## N?chste Schritte
|
||||||
|
|
||||||
|
1. ? Plan erstellt
|
||||||
|
2. ? Diskussion: Ist Vereinheitlichung gew?nscht?
|
||||||
|
3. ? Implementierung: docker-compose.local.yml anpassen
|
||||||
|
4. ? Migration: Secrets aus .env.local extrahieren
|
||||||
|
5. ? Dokumentation: ENV_SETUP.md und README.md aktualisieren
|
||||||
|
6. ? Testing: Lokale Entwicklungsumgebung testen
|
||||||
|
7. ? Setup-Script: scripts/setup-local-secrets.sh erstellen
|
||||||
359
docs/deployment/local-stack-restructure-plan.md
Normal file
359
docs/deployment/local-stack-restructure-plan.md
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
# Plan: Umstrukturierung der lokalen Entwicklungsumgebung nach Stack-Pattern
|
||||||
|
|
||||||
|
**Datum**: 2025-11-04
|
||||||
|
**Ziel**: Lokale Entwicklungsumgebung in `deployment/stacks/local/` strukturieren, konsistent mit `application` und `staging` Stacks
|
||||||
|
|
||||||
|
## Aktuelle Struktur
|
||||||
|
|
||||||
|
### Root-Level (aktuell)
|
||||||
|
```
|
||||||
|
Repository Root/
|
||||||
|
??? docker-compose.base.yml # Gemeinsame Basis
|
||||||
|
??? docker-compose.local.yml # Local Override
|
||||||
|
??? docker-compose.staging.yml # Staging Override (im Root)
|
||||||
|
??? docker-compose.production.yml # Production Override (im Root)
|
||||||
|
??? secrets/ # (neu, f?r lokale Secrets)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stacks-Struktur (aktuell)
|
||||||
|
```
|
||||||
|
deployment/stacks/
|
||||||
|
??? application/ # Production Stack
|
||||||
|
? ??? docker-compose.yml # Vollst?ndige Definition
|
||||||
|
? ??? README.md
|
||||||
|
??? staging/ # Staging Stack (nur nginx config)
|
||||||
|
? ??? nginx/conf.d/
|
||||||
|
? ??? README.md
|
||||||
|
??? postgresql/ # PostgreSQL Stack
|
||||||
|
??? docker-compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zielstruktur
|
||||||
|
|
||||||
|
### Root-Level (nach Migration)
|
||||||
|
```
|
||||||
|
Repository Root/
|
||||||
|
??? docker-compose.base.yml # Gemeinsame Basis (bleibt)
|
||||||
|
??? docker-compose.staging.yml # Staging Override (bleibt im Root)
|
||||||
|
??? docker-compose.production.yml # Production Override (bleibt im Root)
|
||||||
|
??? docker-compose.postgres-override.yml # (bleibt)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stacks-Struktur (nach Migration)
|
||||||
|
```
|
||||||
|
deployment/stacks/
|
||||||
|
??? application/ # Production Stack
|
||||||
|
? ??? docker-compose.yml
|
||||||
|
? ??? README.md
|
||||||
|
??? staging/ # Staging Stack
|
||||||
|
? ??? nginx/conf.d/
|
||||||
|
? ??? README.md
|
||||||
|
??? local/ # Local Development Stack (NEU)
|
||||||
|
? ??? docker-compose.yml # Vollst?ndige Local-Konfiguration
|
||||||
|
? ??? secrets/ # Lokale Secrets
|
||||||
|
? ? ??? redis_password.txt.example
|
||||||
|
? ? ??? db_user_password.txt.example
|
||||||
|
? ? ??? app_key.txt.example
|
||||||
|
? ??? scripts/ # Helper-Scripts
|
||||||
|
? ? ??? setup-secrets.sh
|
||||||
|
? ? ??? migrate-env-to-secrets.sh
|
||||||
|
? ??? README.md # Local Development Dokumentation
|
||||||
|
??? postgresql/
|
||||||
|
??? docker-compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vorteile der Umstrukturierung
|
||||||
|
|
||||||
|
### 1. Konsistenz
|
||||||
|
- ? **Gleiche Struktur** wie `application` und andere Stacks
|
||||||
|
- ? **Klare Trennung** der Umgebungen
|
||||||
|
- ? **Einheitliches Pattern** f?r alle Stacks
|
||||||
|
|
||||||
|
### 2. Organisation
|
||||||
|
- ? **Lokale Konfiguration** klar als "Stack" erkennbar
|
||||||
|
- ? **Secrets lokal** verwaltet (nicht im Root)
|
||||||
|
- ? **Helper-Scripts** am richtigen Ort
|
||||||
|
|
||||||
|
### 3. Wartbarkeit
|
||||||
|
- ? **Einheitliche Struktur** erleichtert Wartung
|
||||||
|
- ? **Klare Verantwortlichkeiten** pro Stack
|
||||||
|
- ? **Einfachere Navigation** f?r Entwickler
|
||||||
|
|
||||||
|
### 4. Deployment-Konsistenz
|
||||||
|
- ? **Gleiche Kommandos** f?r alle Stacks
|
||||||
|
- ? **Einheitliche Dokumentation**
|
||||||
|
- ? **Konsistente Pfade**
|
||||||
|
|
||||||
|
## Implementierungsplan
|
||||||
|
|
||||||
|
### Phase 1: Verzeichnisstruktur erstellen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p deployment/stacks/local/secrets
|
||||||
|
mkdir -p deployment/stacks/local/scripts
|
||||||
|
chmod 700 deployment/stacks/local/secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: docker-compose.yml migrieren
|
||||||
|
|
||||||
|
**Von**: `docker-compose.base.yml + docker-compose.local.yml` (Root)
|
||||||
|
**Nach**: `deployment/stacks/local/docker-compose.yml` (vollst?ndige Definition)
|
||||||
|
|
||||||
|
**Struktur**:
|
||||||
|
```yaml
|
||||||
|
# deployment/stacks/local/docker-compose.yml
|
||||||
|
# Local Development Stack
|
||||||
|
# Usage: docker compose -f deployment/stacks/local/docker-compose.yml up
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
# ... (aus base.yml + local.yml kombiniert)
|
||||||
|
|
||||||
|
php:
|
||||||
|
# ... mit Secrets und *_FILE Pattern
|
||||||
|
|
||||||
|
redis:
|
||||||
|
# ... mit Passwort (Docker Secrets)
|
||||||
|
|
||||||
|
# ... weitere Services
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
# ... lokale Secrets
|
||||||
|
|
||||||
|
networks:
|
||||||
|
# ... lokale Netzwerke
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Secrets-Verwaltung
|
||||||
|
|
||||||
|
**Struktur**:
|
||||||
|
```
|
||||||
|
deployment/stacks/local/
|
||||||
|
??? secrets/
|
||||||
|
? ??? redis_password.txt.example # Beispiel
|
||||||
|
? ??? db_user_password.txt.example # Beispiel
|
||||||
|
? ??? app_key.txt.example # Beispiel
|
||||||
|
??? .gitignore # secrets/*.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Secrets-Pfade in docker-compose.yml**:
|
||||||
|
```yaml
|
||||||
|
secrets:
|
||||||
|
redis_password:
|
||||||
|
file: ./secrets/redis_password.txt
|
||||||
|
external: false
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Helper-Scripts
|
||||||
|
|
||||||
|
**scripts/setup-secrets.sh**:
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# Setup local development secrets
|
||||||
|
cd "$(dirname "$0")/.." # Zu deployment/stacks/local/
|
||||||
|
# ... Secrets generieren
|
||||||
|
```
|
||||||
|
|
||||||
|
**scripts/migrate-env-to-secrets.sh**:
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# Migriert Secrets aus .env.local zu secrets/
|
||||||
|
cd "$(dirname "$0")/.." # Zu deployment/stacks/local/
|
||||||
|
# ... Migration durchf?hren
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 5: Dokumentation
|
||||||
|
|
||||||
|
**deployment/stacks/local/README.md**:
|
||||||
|
- Setup-Anleitung
|
||||||
|
- Secrets-Verwaltung
|
||||||
|
- Verwendung
|
||||||
|
- Troubleshooting
|
||||||
|
|
||||||
|
## Vergleich der Ans?tze
|
||||||
|
|
||||||
|
### Ansatz A: Vollst?ndige docker-compose.yml (empfohlen)
|
||||||
|
|
||||||
|
**Struktur**:
|
||||||
|
```yaml
|
||||||
|
# deployment/stacks/local/docker-compose.yml
|
||||||
|
# Vollst?ndige Definition (wie application Stack)
|
||||||
|
services:
|
||||||
|
web: ...
|
||||||
|
php: ...
|
||||||
|
redis: ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Vorteile**:
|
||||||
|
- ? Konsistent mit `application` Stack
|
||||||
|
- ? Vollst?ndige Kontrolle
|
||||||
|
- ? Keine Abh?ngigkeit von Root-Level base.yml
|
||||||
|
|
||||||
|
**Nachteile**:
|
||||||
|
- ?? Etwas mehr Code-Duplikation (aber klar getrennt)
|
||||||
|
|
||||||
|
### Ansatz B: Base + Override Pattern (wie Staging)
|
||||||
|
|
||||||
|
**Struktur**:
|
||||||
|
```yaml
|
||||||
|
# deployment/stacks/local/docker-compose.base.yml (oder Link)
|
||||||
|
# deployment/stacks/local/docker-compose.local.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Vorteile**:
|
||||||
|
- ? Weniger Duplikation
|
||||||
|
- ? Konsistent mit Staging-Pattern
|
||||||
|
|
||||||
|
**Nachteile**:
|
||||||
|
- ?? Pfad-Abh?ngigkeiten (base.yml muss relativ erreichbar sein)
|
||||||
|
- ?? Komplexer bei verschiedenen Pfaden
|
||||||
|
|
||||||
|
## Empfehlung: Ansatz A (Vollst?ndige Definition)
|
||||||
|
|
||||||
|
**Begr?ndung**:
|
||||||
|
1. **Konsistenz**: Gleiche Struktur wie `application` Stack
|
||||||
|
2. **Autonomie**: Local Stack ist vollst?ndig unabh?ngig
|
||||||
|
3. **Klarheit**: Alles in einem Verzeichnis
|
||||||
|
4. **Einfachheit**: Keine Pfad-Abh?ngigkeiten
|
||||||
|
|
||||||
|
## Detaillierte Struktur
|
||||||
|
|
||||||
|
### deployment/stacks/local/docker-compose.yml
|
||||||
|
|
||||||
|
**Enth?lt**:
|
||||||
|
- Alle Services aus `docker-compose.base.yml` + `docker-compose.local.yml`
|
||||||
|
- Redis mit Passwort (Docker Secrets)
|
||||||
|
- `*_FILE` Pattern f?r alle Secrets
|
||||||
|
- Lokale Ports (8888:80, 443:443, 5433:5432)
|
||||||
|
- Host-Mounts f?r Entwicklung
|
||||||
|
- Debug-Flags
|
||||||
|
|
||||||
|
**Services**:
|
||||||
|
- `web` (Nginx)
|
||||||
|
- `php` (PHP-FPM)
|
||||||
|
- `db` (PostgreSQL)
|
||||||
|
- `redis` (mit Passwort)
|
||||||
|
- `queue-worker`
|
||||||
|
- `minio` (optional)
|
||||||
|
|
||||||
|
### deployment/stacks/local/secrets/
|
||||||
|
|
||||||
|
**Dateien**:
|
||||||
|
- `redis_password.txt` (gitignored)
|
||||||
|
- `db_user_password.txt` (gitignored)
|
||||||
|
- `app_key.txt` (gitignored)
|
||||||
|
- `*.example` (versioniert, als Beispiele)
|
||||||
|
|
||||||
|
### deployment/stacks/local/scripts/
|
||||||
|
|
||||||
|
**Scripts**:
|
||||||
|
- `setup-secrets.sh` - Generiert Secrets f?r neue Entwickler
|
||||||
|
- `migrate-env-to-secrets.sh` - Migriert bestehende .env.local
|
||||||
|
- `redis-cli.sh` - Helper f?r Redis-CLI mit Passwort
|
||||||
|
|
||||||
|
## Migration
|
||||||
|
|
||||||
|
### Schritt 1: Neue Struktur erstellen
|
||||||
|
```bash
|
||||||
|
mkdir -p deployment/stacks/local/{secrets,scripts}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schritt 2: docker-compose.yml erstellen
|
||||||
|
- Kombiniere `docker-compose.base.yml` + `docker-compose.local.yml`
|
||||||
|
- F?ge Secrets-Konfiguration hinzu
|
||||||
|
- F?ge Redis-Passwort hinzu
|
||||||
|
|
||||||
|
### Schritt 3: Secrets migrieren
|
||||||
|
- Erstelle `secrets/` Verzeichnis
|
||||||
|
- Generiere oder migriere Secrets
|
||||||
|
- Erstelle Beispiel-Dateien
|
||||||
|
|
||||||
|
### Schritt 4: Scripts erstellen
|
||||||
|
- Setup-Script
|
||||||
|
- Migration-Script
|
||||||
|
- Helper-Scripts
|
||||||
|
|
||||||
|
### Schritt 5: Dokumentation
|
||||||
|
- README.md erstellen
|
||||||
|
- ENV_SETUP.md aktualisieren
|
||||||
|
- Haupt-README aktualisieren
|
||||||
|
|
||||||
|
### Schritt 6: Alte Dateien entfernen
|
||||||
|
- `docker-compose.local.yml` im Root (nach Migration)
|
||||||
|
- Root-Level `secrets/` (falls vorhanden)
|
||||||
|
|
||||||
|
## Verwendung nach Migration
|
||||||
|
|
||||||
|
### Vorher (aktuell)
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.base.yml -f docker-compose.local.yml up
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nachher (neu)
|
||||||
|
```bash
|
||||||
|
cd deployment/stacks/local
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**Oder vom Root**:
|
||||||
|
```bash
|
||||||
|
docker compose -f deployment/stacks/local/docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vorteile dieser Struktur
|
||||||
|
|
||||||
|
1. ? **Konsistenz**: Gleiche Struktur wie `application` Stack
|
||||||
|
2. ? **Autonomie**: Local Stack ist vollst?ndig unabh?ngig
|
||||||
|
3. ? **Organisation**: Alles Local-Development in einem Verzeichnis
|
||||||
|
4. ? **Klarheit**: Klare Trennung der Umgebungen
|
||||||
|
5. ? **Wartbarkeit**: Einfacher zu warten und zu erweitern
|
||||||
|
|
||||||
|
## Nachteile / ?berlegungen
|
||||||
|
|
||||||
|
### 1. Pfad-Abh?ngigkeiten
|
||||||
|
- ?? **Build-Kontexte**: M?ssen relativ zum Repository-Root sein
|
||||||
|
- **L?sung**: Absolute Pfade oder `context: ../..` verwenden
|
||||||
|
|
||||||
|
### 2. Migration
|
||||||
|
- ?? **Bestehende Entwickler** m?ssen umstellen
|
||||||
|
- **L?sung**: Migration-Script und Dokumentation
|
||||||
|
|
||||||
|
### 3. Docker Compose Befehle
|
||||||
|
- ?? **Andere Pfade** als bisher
|
||||||
|
- **L?sung**: Helper-Script oder Makefile-Target
|
||||||
|
|
||||||
|
## Alternative: Makefile-Targets
|
||||||
|
|
||||||
|
**Makefile hinzuf?gen**:
|
||||||
|
```makefile
|
||||||
|
local-up:
|
||||||
|
cd deployment/stacks/local && docker compose up -d
|
||||||
|
|
||||||
|
local-down:
|
||||||
|
cd deployment/stacks/local && docker compose down
|
||||||
|
|
||||||
|
local-logs:
|
||||||
|
cd deployment/stacks/local && docker compose logs -f
|
||||||
|
|
||||||
|
local-ps:
|
||||||
|
cd deployment/stacks/local && docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verwendung**:
|
||||||
|
```bash
|
||||||
|
make local-up
|
||||||
|
make local-logs
|
||||||
|
make local-ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## N?chste Schritte
|
||||||
|
|
||||||
|
1. ? Plan erstellt
|
||||||
|
2. ? Diskussion: Ist Stack-Struktur gew?nscht?
|
||||||
|
3. ? Implementierung: Verzeichnisstruktur erstellen
|
||||||
|
4. ? docker-compose.yml migrieren und anpassen
|
||||||
|
5. ? Secrets-System implementieren
|
||||||
|
6. ? Scripts erstellen
|
||||||
|
7. ? Dokumentation
|
||||||
|
8. ? Testing
|
||||||
|
9. ? Alte Dateien entfernen
|
||||||
8
secrets/app_key.txt.example
Executable file
8
secrets/app_key.txt.example
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
# Application Key Example
|
||||||
|
# Copy this file to app_key.txt and set your local development application key
|
||||||
|
# Example: base64:local-dev-app-key-generated
|
||||||
|
#
|
||||||
|
# Generate application key:
|
||||||
|
# php -r "echo 'base64:' . base64_encode(random_bytes(32));"
|
||||||
|
#
|
||||||
|
# Or use existing APP_KEY from .env.local
|
||||||
8
secrets/db_user_password.txt.example
Executable file
8
secrets/db_user_password.txt.example
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
# Database User Password Example
|
||||||
|
# Copy this file to db_user_password.txt and set your local development password
|
||||||
|
# Example: local-dev-db-password-2024
|
||||||
|
#
|
||||||
|
# Generate secure password:
|
||||||
|
# openssl rand -base64 32
|
||||||
|
#
|
||||||
|
# Note: This password should match DB_PASSWORD in your .env.local (if you still use it during migration)
|
||||||
6
secrets/redis_password.txt.example
Executable file
6
secrets/redis_password.txt.example
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
# Redis Password Example
|
||||||
|
# Copy this file to redis_password.txt and set your local development password
|
||||||
|
# Example: local-dev-redis-password-2024
|
||||||
|
#
|
||||||
|
# Generate secure password:
|
||||||
|
# openssl rand -base64 32
|
||||||
@@ -154,10 +154,7 @@ final readonly class LoggerInitializer
|
|||||||
$handlers[] = $this->createCliHandler($config, $env, $minLevel);
|
$handlers[] = $this->createCliHandler($config, $env, $minLevel);
|
||||||
} else {
|
} else {
|
||||||
// Web-Requests: Console Handler auf stderr
|
// Web-Requests: Console Handler auf stderr
|
||||||
$webFormatter = new LineFormatter(
|
$webFormatter = new LineFormatter();
|
||||||
format: '[{timestamp}] [{level_name}] {request_id}{channel}{message}',
|
|
||||||
timestampFormat: 'Y-m-d H:i:s'
|
|
||||||
);
|
|
||||||
$handlers[] = new ConsoleHandler($webFormatter, $minLevel, debugOnly: false);
|
$handlers[] = new ConsoleHandler($webFormatter, $minLevel, debugOnly: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user