Complete infrastructure: CitrineOS+OpenADR+FM integration, asset sync, scheduling, IaC scripts, K8s manifests, documentation
This commit is contained in:
@@ -3,228 +3,178 @@
|
|||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ CARIFLEX EMS │
|
│ CARIFLEX EMS │
|
||||||
│ Energy Management System for Martinique │
|
│ Energy Management System for Martinique │
|
||||||
├─────────────────────────────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
│ │ OpenADR │ │ FlexMeasures│ │ Grafana │ │
|
│ │ OpenADR │ │ FlexMeasures│ │ Grafana │ │
|
||||||
│ │ VTN/VEN │───▶│ Server │───▶│ Dashboard │ │
|
│ │ VTN/VEN │───▶│ Server │───▶│ Dashboard │ │
|
||||||
│ │ (S2+OpenADR)│ │ (EMS Core) │ │ (14 panels)│ │
|
│ │ (S2+OpenADR)│ │ (EMS Core) │ │ (17 panels)│ │
|
||||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
│ └──────────────┘ └──────┬───────┘ └──────────────┘ │
|
||||||
│ │ │ │ │
|
│ │ │ │
|
||||||
│ ▼ ▼ ▼ │
|
│ │ ▼ │
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
│ │ ┌──────────────┐ │
|
||||||
│ │ PostgreSQL │ │ Redis │ │ Traefik │ │
|
│ │ │ CitrineOS │ │
|
||||||
│ │ (time-series)│ │ (job queue) │ │ (reverse │ │
|
│ │ │ (OCPP 2.0.1)│ │
|
||||||
│ │ │ │ │ │ proxy) │ │
|
│ │ └──────┬───────┘ │
|
||||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
│ │ │ │
|
||||||
│ │
|
│ ▼ ▼ │
|
||||||
└─────────────────────────────────────────────────────────────────────────────┘
|
│ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ PostgreSQL │ │ RabbitMQ │ │
|
||||||
|
│ │ (time-series)│ │ (AMQP/OCPP) │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Integration Flow
|
||||||
|
|
||||||
|
### OpenADR → FlexMeasures → CitrineOS
|
||||||
|
```
|
||||||
|
1. OpenADR VTN creates events (price, load control)
|
||||||
|
2. OpenADR VEN receives events via poll
|
||||||
|
3. VEN posts data to FlexMeasures API (sensors 84, 86, 87)
|
||||||
|
4. FlexMeasures creates charging schedules based on prices
|
||||||
|
5. Schedules sent to CitrineOS via RabbitMQ (OCPP)
|
||||||
|
6. CitrineOS sends OCPP profiles to EV charge points
|
||||||
|
7. Grafana displays real-time data from all sources
|
||||||
|
```
|
||||||
|
|
||||||
|
### Asset Synchronization
|
||||||
|
- FM EV assets (sensors 61-70) ↔ CitrineOS charge points (CP001-CP010)
|
||||||
|
- Sync script ensures consistency of: count, power, location
|
||||||
|
- OCPP 2.0.1 protocol for charge point communication
|
||||||
|
|
||||||
## Network Architecture
|
## Network Architecture
|
||||||
|
|
||||||
### Networks
|
### Networks
|
||||||
| Network | Subnet | Purpose | External |
|
| Network | Subnet | Purpose | External |
|
||||||
|---------|--------|---------|----------|
|
|---------|--------|---------|----------|
|
||||||
| `traefik-public` | 172.29.0.0/16 | Public services (FM, Grafana) | Yes |
|
| `traefik-public` | 172.29.0.0/16 | Public services | Yes |
|
||||||
| `openadr-internal` | 192.168.240.0/24 | OpenADR VTN/VEN communication | No |
|
| `config_cariflex-internal` | 172.23.0.0/16 | Internal services | No |
|
||||||
|
| `openadr-internal` | 192.168.240.0/24 | OpenADR VTN/VEN | No |
|
||||||
|
|
||||||
### DNS/Hosts
|
### DNS/Hosts
|
||||||
| Service | Domain | Container | Port |
|
| Service | Domain | Container | Port |
|
||||||
|---------|--------|-----------|------|
|
|---------|--------|-----------|------|
|
||||||
| FlexMeasures | cariflex.digitribe.fr | flexmeasures-server | 5000 |
|
| FlexMeasures | cariflex.digitribe.fr | flexmeasures-server | 5000 |
|
||||||
| Grafana | grafana.digitribe.fr | smart-city-grafana | 3000 |
|
| Grafana | grafana.digitribe.fr | smart-city-grafana | 3000 |
|
||||||
|
| CitrineOS | citrineos.digitribe.fr | cariflex-citrineos-server | 8080 |
|
||||||
|
| RabbitMQ Mgmt | amqp.digitribe.fr | cariflex-amqp | 15672 |
|
||||||
| OpenADR VTN | - | openadr-vtn | 8080 |
|
| OpenADR VTN | - | openadr-vtn | 8080 |
|
||||||
| OpenADR VEN | - | openadr-ven | - |
|
| OpenADR VEN | - | openadr-ven | - |
|
||||||
|
|
||||||
### Firewall (UFW)
|
|
||||||
- Public ports: 80 (HTTP), 443 (HTTPS), 51820 (WireGuard)
|
|
||||||
- Internal networks: 172.16.0.0/12, 10.0.0.0/8, 192.168.0.0/16, 192.168.240.0/24
|
|
||||||
|
|
||||||
## Docker Containers
|
## Docker Containers
|
||||||
|
|
||||||
### Cariflex EMS Stack
|
### Cariflex EMS Stack
|
||||||
| Container | Image | Network | IP | Port | Status |
|
| Container | Image | Network | IP | Status |
|
||||||
|-----------|-------|---------|----|---- |--------|
|
|-----------|-------|---------|----|--------|
|
||||||
| flexmeasures-server | lfenergy/flexmeasures:latest | traefik-public | 172.29.0.x | 5000 | ✅ UP |
|
| flexmeasures-server | lfenergy/flexmeasures:latest | traefik-public | 172.29.0.x | ✅ UP |
|
||||||
| flexmeasures-worker | lfenergy/flexmeasures:latest | traefik-public | 172.29.0.x | - | ✅ UP |
|
| flexmeasures-worker | lfenergy/flexmeasures:latest | traefik-public | 172.29.0.x | ✅ UP |
|
||||||
| flexmeasures-db | postgres:17 | traefik-public | 172.29.0.x | 5432 | ✅ UP |
|
| flexmeasures-db | postgres:17 | traefik-public | 172.29.0.x | ✅ UP |
|
||||||
| flexmeasures-redis | redis:7-alpine | traefik-public | 172.29.0.x | 6379 | ✅ UP |
|
| flexmeasures-redis | redis:7-alpine | traefik-public | 172.29.0.x | ✅ UP |
|
||||||
| openadr-vtn | flexmeasures-openadr-vtn | openadr-internal | 192.168.240.10 | 8080 | ✅ UP |
|
| openadr-vtn | flexmeasures-openadr-vtn | openadr-internal | 192.168.240.10 | ✅ UP |
|
||||||
| openadr-ven | flexmeasures-openadr-ven | openadr-internal | 192.168.240.11 | - | ✅ UP |
|
| openadr-ven | flexmeasures-openadr-ven | openadr-internal | 192.168.240.11 | ✅ UP |
|
||||||
| smart-city-grafana | grafana/grafana | traefik-public | - | 3000 | ✅ UP |
|
| cariflex-citrineos-server | ghcr.io/citrineos/citrineos-server:latest | config_cariflex-internal | 172.23.0.4 | ✅ UP |
|
||||||
|
| cariflex-citrineos-db | postgis/postgis:16-3.5 | config_cariflex-internal | 172.23.0.x | ✅ UP |
|
||||||
## IP Address Allocation (phpIPAM)
|
| cariflex-amqp | rabbitmq:3-management | config_cariflex-internal | 172.23.0.3 | ✅ UP |
|
||||||
|
| smart-city-grafana | grafana/grafana | traefik-public | - | ✅ UP |
|
||||||
### Cariflex Subnet: 192.168.240.0/24
|
|
||||||
| IP | Service | Container | MAC |
|
|
||||||
|----|---------|-----------|-----|
|
|
||||||
| 192.168.240.1 | Gateway | - | - |
|
|
||||||
| 192.168.240.10 | OpenADR VTN | openadr-vtn | - |
|
|
||||||
| 192.168.240.11 | OpenADR VEN | openadr-ven | - |
|
|
||||||
| 192.168.240.128-254 | Reserved | - | - |
|
|
||||||
|
|
||||||
### Public Subnet (traefik-public): 172.29.0.0/16
|
|
||||||
| IP | Service | Domain |
|
|
||||||
|----|---------|--------|
|
|
||||||
| 172.29.0.x | FlexMeasures | cariflex.digitribe.fr |
|
|
||||||
| 172.29.0.x | Grafana | grafana.digitribe.fr |
|
|
||||||
|
|
||||||
## Sensor Mapping
|
## Sensor Mapping
|
||||||
|
|
||||||
### FlexMeasures Sensors
|
### OpenADR Sensors (from VTN)
|
||||||
| ID | Name | Unit | Type | Source |
|
| ID | Name | Unit | Source |
|
||||||
|----|------|------|------|--------|
|
|----|------|------|--------|
|
||||||
| 41-50 | pv_01..10_power | kW | PV Production | Simulator |
|
| 84 | consumption_price | EUR/MWh | OpenADR VTN |
|
||||||
| 51-60 | bat_01..10_power | kWh | Battery SOC | Simulator |
|
| 86 | load_control_signal | % | OpenADR VTN |
|
||||||
| 61-70 | ev_01..10_power | kWh | EV Charge | Simulator |
|
| 87 | demand_response_signal | dimensionless | OpenADR VTN |
|
||||||
| 81 | irradiance | W/m² | Weather | Open-Meteo |
|
|
||||||
| 82 | temperature | °C | Weather | Open-Meteo |
|
|
||||||
| 83 | wind_speed | m/s | Weather | Open-Meteo |
|
|
||||||
| 84 | consumption_price | EUR/MWh | Price | OpenADR VTN |
|
|
||||||
| 85 | production_price | EUR/MWh | Price | Simulated |
|
|
||||||
| 86 | load_control_signal | % | DSR | OpenADR VTN |
|
|
||||||
| 87 | demand_response_signal | dimensionless | DSR | OpenADR VTN |
|
|
||||||
|
|
||||||
### S2 Resource Mapping
|
### EV Charging Sensors (CitrineOS ↔ FM)
|
||||||
| S2 Resource | FM Sensor | Asset | Min Power | Max Power |
|
| FM Sensor | CitrineOS CP | Connector | Max Power |
|
||||||
|-------------|-----------|-------|-----------|-----------|
|
|-----------|--------------|-----------|-----------|
|
||||||
| battery_01-05 | 51-55 | Bat_01-05 | -50 kW | +50 kW |
|
| 61 | CP001 | 1 | 22 kW |
|
||||||
| ev_01-05 | 61-65 | EV_01-05 | -22 kW | +22 kW |
|
| 62 | CP002 | 1 | 22 kW |
|
||||||
|
| 63 | CP003 | 1 | 22 kW |
|
||||||
|
| 64 | CP004 | 1 | 22 kW |
|
||||||
|
| 65 | CP005 | 1 | 22 kW |
|
||||||
|
| 66 | CP006 | 1 | 11 kW |
|
||||||
|
| 67 | CP007 | 1 | 11 kW |
|
||||||
|
| 68 | CP008 | 1 | 11 kW |
|
||||||
|
| 69 | CP009 | 1 | 11 kW |
|
||||||
|
| 70 | CP010 | 1 | 11 kW |
|
||||||
|
|
||||||
## OpenADR Protocol
|
## Grafana Dashboard (17 panels)
|
||||||
|
|
||||||
### VTN (Virtual Top Node)
|
| # | Panel | Data Source |
|
||||||
- **Container**: openadr-vtn
|
|---|-------|-------------|
|
||||||
- **Port**: 8080 (internal)
|
| 1 | Production PV (kW) | FM sensors 41-50 |
|
||||||
- **Profile**: OpenADR 2.0b
|
| 2 | Consommation VE (kW) | FM sensors 61-70 |
|
||||||
- **Events**: ENERGY_PRICE (24h), LOAD_CONTROL (4h)
|
| 3 | SOC Batteries (kWh) | FM sensors 51-60 |
|
||||||
- **Schedule**: Every 10 seconds poll
|
| 4 | SOC V2G (kWh) | FM sensors 71-80 |
|
||||||
|
| 5 | Flexibilite Totale (kWh) | Calculated |
|
||||||
### VEN (Virtual End Node)
|
| 6 | Impact Reseau (kW) | Calculated |
|
||||||
- **Container**: openadr-ven
|
| 7 | Irradiance & Temperature | FM sensors 81-82 |
|
||||||
- **VTN URL**: http://192.168.240.10:8080/OpenADR2/Simple/2.0b
|
| 8 | Prix DSO (EUR/MWh) | FM sensor 85 |
|
||||||
- **Registration ID**: reg-Cariflex-VEN-001
|
| 9 | DSR Price Signal (EUR/MWh) | FM sensor 84 (OpenADR) |
|
||||||
- **Event Handler**: on_event -> FM API (sensors 84, 86)
|
| 10 | Load Control Signal (%) | FM sensor 86 (OpenADR) |
|
||||||
|
| 11 | Impact Flexibilite Reseau (kW) | Calculated |
|
||||||
### Event Flow
|
| 12 | Battery Power (kW) | FM sensors 51-60 (S2) |
|
||||||
1. VTN creates events (price, load control)
|
| 13 | EV Power (kW) | FM sensors 61-70 (S2) |
|
||||||
2. VEN polls VTN every 10s
|
| 14 | Flexibility Impact (kW) | Calculated (S2) |
|
||||||
3. VEN receives oadrDistributeEvent
|
| 15 | EV Charging Power (kW) | FM sensors 61-70 (CitrineOS) |
|
||||||
4. VEN sends event responses (optIn)
|
| 16 | Active Charging Sessions | Calculated |
|
||||||
5. VEN posts data to FM API
|
| 17 | EV Flexibility Potential (kWh) | Calculated |
|
||||||
6. Grafana displays real-time data
|
|
||||||
|
|
||||||
## S2 Protocol Integration
|
|
||||||
|
|
||||||
### S2 Service
|
|
||||||
- **Location**: openadr-ven container (background process)
|
|
||||||
- **Protocol**: S2 (FRBC - Flexibility Resource Bank Control)
|
|
||||||
- **Mapping**: S2 resources -> FM sensors (51-65)
|
|
||||||
- **Functions**:
|
|
||||||
- process_load_control(): Converts OpenADR load control to S2 FRBC instructions
|
|
||||||
- process_demand_response(): Converts OpenADR demand response to S2 FRBC instructions
|
|
||||||
|
|
||||||
### S2 Message Types
|
|
||||||
- FRBCInstruction: Power setpoint commands
|
|
||||||
- FRBCSystemDescription: Resource capabilities
|
|
||||||
- FRBCActuatorStatus: Resource status feedback
|
|
||||||
- FRBCStorageStatus: Battery/EV storage status
|
|
||||||
|
|
||||||
## Backup Strategy
|
## Backup Strategy
|
||||||
|
|
||||||
### Automated Backups
|
### Automated Backups
|
||||||
- **Script**: `/home/eric/cariflex/scripts/full_backup.sh`
|
- **Script**: `/home/eric/cariflex/scripts/full_backup.sh`
|
||||||
- **Location**: `/home/eric/backups/cariflex/YYYYMMDD_HHMMSS.tar.gz`
|
- **Location**: `/home/eric/backups/cariflex/YYYYMMDD_HHMMSS.tar.gz`
|
||||||
- **Contents**:
|
- **Contents**: PostgreSQL, Redis, FM config, OpenADR scripts, Grafana dashboards, container states, network config
|
||||||
- PostgreSQL dump (flexmeasures DB)
|
|
||||||
- Redis dump (RDB file)
|
|
||||||
- FM config and templates
|
|
||||||
- OpenADR scripts and Dockerfiles
|
|
||||||
- Grafana dashboards (JSON)
|
|
||||||
- Docker container states
|
|
||||||
- Network configuration
|
|
||||||
|
|
||||||
### Backup Retention
|
## Deployment
|
||||||
- Daily backups kept for 30 days
|
|
||||||
- Weekly backups kept for 12 weeks
|
|
||||||
- Monthly backups kept indefinitely
|
|
||||||
|
|
||||||
## Deployment Environments
|
### Docker Compose Files
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `/home/eric/flexmeasures/docker-compose.yml` | FM core stack |
|
||||||
|
| `/home/eric/flexmeasures/docker-compose.openadr.yml` | OpenADR VTN/VEN |
|
||||||
|
| `/home/eric/cariflex/config/docker-compose-citrineos.yml` | CitrineOS stack |
|
||||||
|
|
||||||
### Development
|
### Deployment Commands
|
||||||
- **Host**: Local VM or developer machine
|
```bash
|
||||||
- **Docker Compose**: Single node
|
# FM stack
|
||||||
- **Data**: Simulated
|
cd /home/eric/flexmeasures && docker compose up -d
|
||||||
- **URL**: localhost
|
|
||||||
|
|
||||||
### Test
|
# OpenADR stack
|
||||||
- **Host**: Test server
|
cd /home/eric/flexmeasures && docker compose -f docker-compose.openadr.yml up -d
|
||||||
- **Docker Compose**: Single node
|
|
||||||
- **Data**: Anonymized production data
|
|
||||||
- **URL**: test.cariflex.digitribe.fr
|
|
||||||
|
|
||||||
### Production
|
# CitrineOS stack
|
||||||
- **Host**: Production server (this deployment)
|
cd /home/eric/cariflex/config && docker compose -f docker-compose-citrineos.yml up -d
|
||||||
- **Docker Compose**: Single node (scalable to Swarm/K8s)
|
|
||||||
- **Data**: Real-time production data
|
|
||||||
- **URL**: cariflex.digitribe.fr
|
|
||||||
|
|
||||||
## Security
|
# Verify all
|
||||||
|
docker ps --format "table {{.Names}}\t{{.Status}}" | grep -E "flexmeasures|openadr|citrine|grafana"
|
||||||
### Credentials
|
```
|
||||||
| Service | Username | Password | Location |
|
|
||||||
|---------|----------|----------|----------|
|
|
||||||
| FlexMeasures | admin@digitribe.fr | Digitribe972 | FM DB |
|
|
||||||
| PostgreSQL | flexmeasures | Digitribe972 | PostgreSQL |
|
|
||||||
| Redis | - | (disabled) | Redis |
|
|
||||||
| Grafana | admin | admin | Grafana DB |
|
|
||||||
|
|
||||||
### SSL/TLS
|
|
||||||
- All public services use Let's Encrypt certificates
|
|
||||||
- Traefik handles SSL termination
|
|
||||||
- Internal services use HTTP (isolated network)
|
|
||||||
|
|
||||||
## Monitoring
|
|
||||||
|
|
||||||
### Health Checks
|
|
||||||
- FlexMeasures: https://cariflex.digitribe.fr/health
|
|
||||||
- Grafana: https://grafana.digitrobe.fr/api/health
|
|
||||||
- OpenADR VTN: http://192.168.240.10:8080/OpenADR2/Simple/2.0b
|
|
||||||
|
|
||||||
### Logs
|
|
||||||
- Docker: `docker logs <container>`
|
|
||||||
- FM: `/app/flexmeasures/logs/`
|
|
||||||
- Grafana: `/var/log/grafana/`
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Common Issues
|
### OpenADR Issues
|
||||||
1. **Redis ACL error**: `docker exec flexmeasures-redis redis-cli CONFIG SET requirepass ""`
|
- **VEN not connecting**: Check UFW rules for 192.168.240.0/24
|
||||||
2. **OpenADR connection refused**: Check UFW rules for 192.168.240.0/24
|
- **No price data**: Check VTN logs: `docker logs openadr-vtn`
|
||||||
3. **Grafana no data**: Check datasource UID matches PostgreSQL DS
|
|
||||||
4. **FM worker not running**: `docker restart flexmeasures-worker`
|
|
||||||
|
|
||||||
### Useful Commands
|
### CitrineOS Issues
|
||||||
```bash
|
- **RabbitMQ connection**: Check network aliases on config_cariflex-internal
|
||||||
# View all containers
|
- **OCPP communication**: Verify charge point network connectivity
|
||||||
docker ps -a | grep -E "flexmeasures|openadr|grafana"
|
|
||||||
|
|
||||||
# Check OpenADR communication
|
### FM Scheduling Issues
|
||||||
docker logs openadr-ven | grep -i "price\|load\|event"
|
- **No schedules created**: Check price sensor data (84)
|
||||||
|
- **Worker not running**: `docker restart flexmeasures-worker`
|
||||||
# Check FM API
|
|
||||||
curl -s https://cariflex.digitribe.fr/api/v3_0/sensors
|
|
||||||
|
|
||||||
# Database query
|
|
||||||
docker exec flexmeasures-db psql -U flexmeasures -d flexmeasures -c "SELECT * FROM sensor WHERE id BETWEEN 80 AND 90;"
|
|
||||||
```
|
|
||||||
|
|
||||||
## References
|
## References
|
||||||
- FlexMeasures: https://flexmeasures.readthedocs.io/
|
- FlexMeasures: https://flexmeasures.readthedocs.io/
|
||||||
- OpenLEADR: https://openleadr.org/
|
- OpenLEADR: https://openleadr.org/
|
||||||
|
- CitrineOS: https://citrineos.github.io/
|
||||||
- S2 Protocol: https://s2-standard.github.io/
|
- S2 Protocol: https://s2-standard.github.io/
|
||||||
- Grafana: https://grafana.com/docs/
|
- OCPP 2.0.1: https://www.openchargealliance.org/protocols/ocpp-201/
|
||||||
|
|||||||
339
iac/k8s/README.md
Normal file
339
iac/k8s/README.md
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
# Cariflex EMS - Kubernetes Manifests
|
||||||
|
|
||||||
|
## Namespace
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: cariflex
|
||||||
|
labels:
|
||||||
|
app: cariflex-ems
|
||||||
|
environment: production
|
||||||
|
```
|
||||||
|
|
||||||
|
## ConfigMap
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cariflex-config
|
||||||
|
namespace: cariflex
|
||||||
|
data:
|
||||||
|
# FlexMeasures
|
||||||
|
FM_ENV: "production"
|
||||||
|
FM_LOG_LEVEL: "WARNING"
|
||||||
|
FM_DB_HOST: "postgres-service"
|
||||||
|
FM_REDIS_HOST: "redis-service"
|
||||||
|
|
||||||
|
# OpenADR
|
||||||
|
VTN_ID: "Cariflex-VTN"
|
||||||
|
VEN_ID: "Cariflex-VEN"
|
||||||
|
VTN_PORT: "8080"
|
||||||
|
|
||||||
|
# CitrineOS
|
||||||
|
CITRINEOS_ENV: "production"
|
||||||
|
AMQP_HOST: "rabbitmq-service"
|
||||||
|
AMQP_PORT: "5672"
|
||||||
|
DB_HOST: "citrineos-postgres-service"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: cariflex-secrets
|
||||||
|
namespace: cariflex
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
FM_SECRET_KEY: "${FM_SECRET_KEY}"
|
||||||
|
FM_DB_PASSWORD: "${FM_DB_PASSWORD}"
|
||||||
|
REDIS_PASSWORD: "${REDIS_PASSWORD}"
|
||||||
|
CITRINEOS_DB_PASSWORD: "${CITRINEOS_DB_PASSWORD}"
|
||||||
|
RABBITMQ_PASSWORD: "${RABBITMQ_PASSWORD}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## FlexMeasures Deployment
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: flexmeasures-server
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: flexmeasures-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: flexmeasures-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: flexmeasures
|
||||||
|
image: lfenergy/flexmeasures:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 5000
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: cariflex-config
|
||||||
|
- secretRef:
|
||||||
|
name: cariflex-secrets
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "2"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/v3_0/sensors
|
||||||
|
port: 5000
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/v3_0/sensors
|
||||||
|
port: 5000
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: flexmeasures-service
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: flexmeasures-server
|
||||||
|
ports:
|
||||||
|
- port: 5000
|
||||||
|
targetPort: 5000
|
||||||
|
type: ClusterIP
|
||||||
|
```
|
||||||
|
|
||||||
|
## OpenADR VTN Deployment
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: openadr-vtn
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: openadr-vtn
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: openadr-vtn
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: vtn
|
||||||
|
image: flexmeasures-openadr-vtn:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: cariflex-config
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: openadr-vtn-service
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: openadr-vtn
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
type: ClusterIP
|
||||||
|
```
|
||||||
|
|
||||||
|
## OpenADR VEN Deployment
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: openadr-ven
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: openadr-ven
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: openadr-ven
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: ven
|
||||||
|
image: flexmeasures-openadr-ven:latest
|
||||||
|
env:
|
||||||
|
- name: VTN_URL
|
||||||
|
value: "http://openadr-vtn-service:8080/OpenADR2/Simple/2.0b"
|
||||||
|
- name: FM_HOST
|
||||||
|
value: "https://cariflex.digitribe.fr"
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: cariflex-config
|
||||||
|
- secretRef:
|
||||||
|
name: cariflex-secrets
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: openadr-ven-service
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: openadr-ven
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
type: ClusterIP
|
||||||
|
```
|
||||||
|
|
||||||
|
## CitrineOS Deployment
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: citrineos-server
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: citrineos-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: citrineos-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: citrineos
|
||||||
|
image: ghcr.io/citrineos/citrineos-server:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: cariflex-config
|
||||||
|
- secretRef:
|
||||||
|
name: cariflex-secrets
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "1"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: citrineos-service
|
||||||
|
namespace: cariflex
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: citrineos-server
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
type: ClusterIP
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ingress
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: cariflex-ingress
|
||||||
|
namespace: cariflex
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- cariflex.digitribe.fr
|
||||||
|
- grafana.digitribe.fr
|
||||||
|
- citrineos.digitribe.fr
|
||||||
|
secretName: cariflex-tls
|
||||||
|
rules:
|
||||||
|
- host: cariflex.digitribe.fr
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: flexmeasures-service
|
||||||
|
port:
|
||||||
|
number: 5000
|
||||||
|
- host: grafana.digitribe.fr
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: grafana-service
|
||||||
|
port:
|
||||||
|
number: 3000
|
||||||
|
- host: citrineos.digitribe.fr
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: citrineos-service
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Commands
|
||||||
|
```bash
|
||||||
|
# Create namespace
|
||||||
|
kubectl apply -f k8s/namespace.yaml
|
||||||
|
|
||||||
|
# Apply config and secrets
|
||||||
|
kubectl apply -f k8s/configmap.yaml
|
||||||
|
kubectl apply -f k8s/secrets.yaml
|
||||||
|
|
||||||
|
# Deploy applications
|
||||||
|
kubectl apply -f k8s/deployments/flexmeasures.yaml
|
||||||
|
kubectl apply -f k8s/deployments/openadr-vtn.yaml
|
||||||
|
kubectl apply -f k8s/deployments/openadr-ven.yaml
|
||||||
|
kubectl apply -f k8s/deployments/citrineos.yaml
|
||||||
|
|
||||||
|
# Apply services
|
||||||
|
kubectl apply -f k8s/services/
|
||||||
|
|
||||||
|
# Apply ingress
|
||||||
|
kubectl apply -f k8s/ingress.yaml
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
kubectl get pods -n cariflex
|
||||||
|
kubectl get svc -n cariflex
|
||||||
|
kubectl get ingress -n cariflex
|
||||||
|
```
|
||||||
142
iac/scripts/deploy.sh
Normal file
142
iac/scripts/deploy.sh
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Cariflex EMS - Multi-Environment Deployment Script
|
||||||
|
# Usage: ./deploy.sh [dev|test|prod] [full|fm|openadr|citrine|grafana]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ENV="${1:-dev}"
|
||||||
|
COMPONENT="${2:-full}"
|
||||||
|
CARIFLEX_HOME="/home/eric/cariflex"
|
||||||
|
FLEXMEASURES_HOME="/home/eric/flexmeasures"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"; }
|
||||||
|
warn() { echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1"; }
|
||||||
|
error() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M-%S')] ERROR:${NC} $1"; exit 1; }
|
||||||
|
|
||||||
|
# Environment-specific configuration
|
||||||
|
case "$ENV" in
|
||||||
|
dev)
|
||||||
|
FM_DOMAIN="cariflex.dev.local"
|
||||||
|
GRAFANA_DOMAIN="grafana.dev.local"
|
||||||
|
CITRINEOS_DOMAIN="citrineos.dev.local"
|
||||||
|
REPLICAS=1
|
||||||
|
DEBUG=true
|
||||||
|
LOG_LEVEL="DEBUG"
|
||||||
|
;;
|
||||||
|
test)
|
||||||
|
FM_DOMAIN="cariflex.test.digitribe.fr"
|
||||||
|
GRAFANA_DOMAIN="grafana.test.digitribe.fr"
|
||||||
|
CITRINEOS_DOMAIN="citrineos.test.digitribe.fr"
|
||||||
|
REPLICAS=1
|
||||||
|
DEBUG=false
|
||||||
|
LOG_LEVEL="INFO"
|
||||||
|
;;
|
||||||
|
prod)
|
||||||
|
FM_DOMAIN="cariflex.digitribe.fr"
|
||||||
|
GRAFANA_DOMAIN="grafana.digitribe.fr"
|
||||||
|
CITRINEOS_DOMAIN="citrineos.digitribe.fr"
|
||||||
|
REPLICAS=2
|
||||||
|
DEBUG=false
|
||||||
|
LOG_LEVEL="WARNING"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unknown environment: $ENV (use dev, test, or prod)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
log "Deploying Cariflex EMS to $ENV environment"
|
||||||
|
log "Component: $COMPONENT"
|
||||||
|
log "FM Domain: $FM_DOMAIN"
|
||||||
|
log "Replicas: $REPLICAS"
|
||||||
|
|
||||||
|
# Function to deploy a docker-compose stack
|
||||||
|
deploy_stack() {
|
||||||
|
local compose_file="$1"
|
||||||
|
local stack_name="$2"
|
||||||
|
|
||||||
|
log "Deploying $stack_name from $compose_file..."
|
||||||
|
|
||||||
|
# Generate environment-specific override
|
||||||
|
cat > "/tmp/docker-compose.${ENV}.override.yml" << EOF
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
server:
|
||||||
|
environment:
|
||||||
|
- LOGGING_LEVEL=${LOG_LEVEL}
|
||||||
|
- FLEXMEASURES_ENV=${ENV}
|
||||||
|
labels:
|
||||||
|
- "traefik.http.routers.${stack_name}.rule=Host(\`${FM_DOMAIN}\`)"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
docker compose -f "$compose_file" -f "/tmp/docker-compose.${ENV}.override.yml" up -d
|
||||||
|
|
||||||
|
log "$stack_name deployed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy based on component
|
||||||
|
case "$COMPONENT" in
|
||||||
|
full)
|
||||||
|
log "Deploying full stack..."
|
||||||
|
deploy_stack "$FLEXMEASURES_HOME/docker-compose.yml" "flexmeasures"
|
||||||
|
deploy_stack "$FLEXMEASURES_HOME/docker-compose.openadr.yml" "openadr"
|
||||||
|
deploy_stack "$CARIFLEX_HOME/config/docker-compose-citrineos.yml" "citrineos"
|
||||||
|
;;
|
||||||
|
fm)
|
||||||
|
deploy_stack "$FLEXMEASURES_HOME/docker-compose.yml" "flexmeasures"
|
||||||
|
;;
|
||||||
|
openadr)
|
||||||
|
deploy_stack "$FLEXMEASURES_HOME/docker-compose.openadr.yml" "openadr"
|
||||||
|
;;
|
||||||
|
citrine)
|
||||||
|
deploy_stack "$CARIFLEX_HOME/config/docker-compose-citrineos.yml" "citrineos"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unknown component: $COMPONENT (use full, fm, openadr, citrine)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Health checks
|
||||||
|
log "Running health checks..."
|
||||||
|
|
||||||
|
check_service() {
|
||||||
|
local name="$1"
|
||||||
|
local url="$2"
|
||||||
|
local max_attempts="${3:-30}"
|
||||||
|
|
||||||
|
for i in $(seq 1 $max_attempts); do
|
||||||
|
if curl -sk "$url" > /dev/null 2>&1; then
|
||||||
|
log "$name is healthy"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
warn "$name health check failed after ${max_attempts} attempts"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_service "FlexMeasures" "https://${FM_DOMAIN}/api/v3_0/sensors" 30
|
||||||
|
check_service "OpenADR VTN" "http://openadr-vtn:8080/OpenADR2/Simple/2.0b" 10
|
||||||
|
check_service "CitrineOS" "http://cariflex-citrineos-server:8080" 10
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
log "Deployment complete!"
|
||||||
|
log ""
|
||||||
|
log "Environment: $ENV"
|
||||||
|
log "URLs:"
|
||||||
|
log " FlexMeasures: https://${FM_DOMAIN}"
|
||||||
|
log " Grafana: https://${GRAFANA_DOMAIN}"
|
||||||
|
log " CitrineOS: https://${CITRINEOS_DOMAIN}"
|
||||||
|
log ""
|
||||||
|
log "Containers:"
|
||||||
|
docker ps --format " {{.Names}}: {{.Status}}" | grep -E "flexmeasures|openadr|citrine|grafana"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -f "/tmp/docker-compose.${ENV}.override.yml"
|
||||||
Reference in New Issue
Block a user