feat: add NATS + Dapr infrastructure for event-driven architecture
- infra/compose/nats.yml: NATS server with JetStream, persistence volume, healthcheck - infra/compose/dapr.yml: Dapr placement service for sidecar coordination - infra/dapr/: Dapr global config, pubsub component (NATS), statestore (Redis) - infra/compose/scraper.yml: add Dapr sidecar container + depends_on nats/dapr - docs/add-dapr-service.md: guide for integrating Dapr into new services - docs/add-new-app.md: add Dapr sidecar step - ARCHITECTURE.md: add NATS/Dapr to infra table + service mesh diagram - infra/README.md: update layout and deployment order - deploy-docker.yml: add nats.yml + dapr.yml to ALL_COMPOSE_FILES Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
d546a1acf9
commit
ea168b4b20
+15
-6
@@ -9,16 +9,19 @@ infra/
|
||||
├── compose/ # One compose file per stack/service
|
||||
│ ├── traefik.yml # Public reverse proxy
|
||||
│ ├── shared.yml # Shared Redis
|
||||
│ └── scraper.yml # Scraper API
|
||||
│ ├── nats.yml # NATS message broker + JetStream
|
||||
│ ├── dapr.yml # Dapr placement service
|
||||
│ └── scraper.yml # Scraper API (app + Dapr sidecar)
|
||||
├── docker/ # Dockerfiles and image runtime helpers
|
||||
├── dapr/ # Dapr component configs
|
||||
│ ├── config.yaml # Global Dapr configuration
|
||||
│ └── components/ # Pub/sub (NATS), state store (Redis)
|
||||
├── traefik/ # Static and dynamic Traefik configuration
|
||||
│ ├── dynamic/ # Routers, services, middlewares, TLS certs
|
||||
│ └── TRAEFIK_ENV_CONFIG.md
|
||||
└── config/ # Service bootstrap configuration
|
||||
```
|
||||
|
||||
Archived configs that are not deployed live under `docs/config/`.
|
||||
|
||||
## First-time setup
|
||||
|
||||
Create the shared Docker network before starting any service:
|
||||
@@ -34,12 +37,18 @@ Create `.env` from `.env.example` and fill production values. Do not commit `.en
|
||||
The GitHub deploy workflow combines the active compose files automatically. For manual deployment, use this order:
|
||||
|
||||
```bash
|
||||
# 1. Shared services
|
||||
docker compose -f infra/compose/shared.yml up -d
|
||||
|
||||
# 2. Message bus + Dapr placement
|
||||
docker compose -f infra/compose/nats.yml up -d
|
||||
docker compose -f infra/compose/dapr.yml up -d
|
||||
|
||||
# 3. Reverse proxy
|
||||
docker compose -f infra/compose/traefik.yml up -d
|
||||
|
||||
docker compose \
|
||||
-f infra/compose/scraper.yml \
|
||||
up -d
|
||||
# 4. Application services (with Dapr sidecars)
|
||||
docker compose -f infra/compose/scraper.yml up -d
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
dapr-placement:
|
||||
container_name: dapr-placement
|
||||
image: daprio/dapr:latest
|
||||
restart: always
|
||||
networks:
|
||||
- app-shared-net
|
||||
command: ["./placement", "--port", "50005"]
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'wget --spider http://localhost:50005/healthz || exit 1']
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
external: true
|
||||
@@ -0,0 +1,32 @@
|
||||
services:
|
||||
nats:
|
||||
container_name: nats
|
||||
image: nats:latest
|
||||
restart: always
|
||||
networks:
|
||||
app-shared-net:
|
||||
aliases:
|
||||
- nats
|
||||
ports:
|
||||
- '4222:4222' # client connections
|
||||
- '8222:8222' # HTTP monitor / health
|
||||
command:
|
||||
- '--jetstream'
|
||||
- '--store_dir=/data'
|
||||
- '--max_payload=8MB'
|
||||
volumes:
|
||||
- nats_data:/data
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'wget --spider http://localhost:8222/healthz || exit 1']
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
nats_data:
|
||||
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
external: true
|
||||
@@ -3,6 +3,11 @@ services:
|
||||
container_name: scraper-api
|
||||
image: ghcr.io/asepharyana/asepharyana-hub/scraper-api:sha-c4ecf8f
|
||||
restart: always
|
||||
depends_on:
|
||||
dapr-placement:
|
||||
condition: service_healthy
|
||||
nats:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
app-shared-net:
|
||||
aliases:
|
||||
@@ -20,6 +25,29 @@ services:
|
||||
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- EXTERNAL_BROWSERLESS_WS=ws://100.121.180.82:3001
|
||||
|
||||
scraper-api-dapr:
|
||||
container_name: scraper-api-dapr
|
||||
image: daprio/daprd:latest
|
||||
restart: always
|
||||
depends_on:
|
||||
dapr-placement:
|
||||
condition: service_healthy
|
||||
nats:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- app-shared-net
|
||||
command:
|
||||
- './daprd'
|
||||
- '--app-id=scraper-api'
|
||||
- '--app-port=4091'
|
||||
- '--dapr-http-port=3500'
|
||||
- '--dapr-grpc-port=50001'
|
||||
- '--placement-host-address=dapr-placement:50005'
|
||||
- '--components-path=/components'
|
||||
volumes:
|
||||
- ../../infra/dapr/components:/components
|
||||
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: pubsub
|
||||
spec:
|
||||
type: pubsub.natsstreaming
|
||||
version: v1
|
||||
metadata:
|
||||
- name: natsURL
|
||||
value: nats://nats:4222
|
||||
- name: natsStreamingClusterID
|
||||
value: dapr-cluster
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: statestore
|
||||
spec:
|
||||
type: state.redis
|
||||
version: v1
|
||||
metadata:
|
||||
- name: redisHost
|
||||
value: redis:6379
|
||||
- name: redisPassword
|
||||
value: ""
|
||||
- name: keyPrefix
|
||||
value: "dapr"
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: dapr-config
|
||||
spec:
|
||||
tracing:
|
||||
samplingRate: "1"
|
||||
zipkin:
|
||||
endpointAddress: ""
|
||||
metrics:
|
||||
enabled: true
|
||||
mtls:
|
||||
enabled: false
|
||||
Reference in New Issue
Block a user