@sysnee/pgs 0.1.7-rc.1 → 0.1.7-rc.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -188
- package/docker-compose.yml +9 -6
- package/docs/ARCHITECTURE_RECOMMENDATIONS.md +11 -9
- package/docs/CRITICAL_REVIEW.md +10 -8
- package/docs/EXECUTIVE_SUMMARY.md +9 -9
- package/docs/PROJECT.md +130 -77
- package/manager.js +186 -98
- package/package.json +2 -2
- package/traefik.yml +15 -0
- package/haproxy-lua/pg-route.lua +0 -177
- package/haproxy.cfg +0 -35
package/README.md
CHANGED
|
@@ -1,151 +1,164 @@
|
|
|
1
1
|
# PostgreSQL Multi-Tenant Instance Manager
|
|
2
2
|
|
|
3
|
-
Dynamic PostgreSQL multi-tenant management system providing complete database isolation by creating dedicated PostgreSQL instances per tenant, with intelligent routing via
|
|
3
|
+
Dynamic PostgreSQL multi-tenant management system providing complete database isolation by creating dedicated PostgreSQL instances per tenant, with intelligent SNI-based routing via Traefik v3.
|
|
4
4
|
|
|
5
|
-
> 📖 **For detailed project definition, architecture, and comparison with similar solutions, see [PROJECT.md](./PROJECT.md)**
|
|
5
|
+
> 📖 **For detailed project definition, architecture, and comparison with similar solutions, see [docs/PROJECT.md](./docs/PROJECT.md)**
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### Initial Setup
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pgs setup
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This creates the configuration directory at `~/.sysnee-config/` with:
|
|
16
|
+
- `docker-compose.yml` - Container orchestration
|
|
17
|
+
- `traefik.yml` - Traefik static configuration
|
|
18
|
+
- `dynamic.yml` - Traefik dynamic routing configuration
|
|
19
|
+
- `tenant-access.json` - Access control
|
|
20
|
+
- `certs/` - SSL certificates directory
|
|
21
|
+
|
|
22
|
+
### SSL Certificate Setup
|
|
23
|
+
|
|
24
|
+
Place your wildcard SSL certificate in the certs directory:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Using Let's Encrypt
|
|
28
|
+
sudo cp /etc/letsencrypt/live/pgs.YOUR-DOMAIN.com/fullchain.pem ~/.sysnee-config/certs/
|
|
29
|
+
sudo cp /etc/letsencrypt/live/pgs.YOUR-DOMAIN.com/privkey.pem ~/.sysnee-config/certs/
|
|
30
|
+
sudo chown $USER:$USER ~/.sysnee-config/certs/*
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### DNS Configuration
|
|
34
|
+
|
|
35
|
+
Add a wildcard DNS record pointing to your server:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
*.pgs.YOUR-DOMAIN.com → YOUR_SERVER_IP
|
|
39
|
+
```
|
|
6
40
|
|
|
7
41
|
## Usage
|
|
8
42
|
|
|
9
43
|
### Create a new tenant instance
|
|
10
44
|
|
|
11
45
|
```bash
|
|
12
|
-
|
|
46
|
+
pgs create <tenant-id> [--password <password>]
|
|
13
47
|
```
|
|
14
48
|
|
|
15
49
|
Example:
|
|
16
50
|
```bash
|
|
17
|
-
|
|
18
|
-
|
|
51
|
+
pgs create tenant1
|
|
52
|
+
pgs create tenant2 --password mycustompass
|
|
19
53
|
```
|
|
20
54
|
|
|
21
|
-
New tenants are created with external access **
|
|
55
|
+
New tenants are created with external access **enabled** by default.
|
|
22
56
|
|
|
23
57
|
### List all tenants
|
|
24
58
|
|
|
25
59
|
```bash
|
|
26
|
-
|
|
60
|
+
pgs list
|
|
27
61
|
```
|
|
28
62
|
|
|
29
|
-
Shows all tenants with their external access status.
|
|
63
|
+
Shows all tenants with their hostnames and external access status.
|
|
30
64
|
|
|
31
65
|
### Remove a tenant
|
|
32
66
|
|
|
33
67
|
```bash
|
|
34
|
-
|
|
68
|
+
pgs remove <tenant-id>
|
|
35
69
|
```
|
|
36
70
|
|
|
37
71
|
### Start services
|
|
38
72
|
|
|
39
73
|
```bash
|
|
40
|
-
|
|
41
|
-
|
|
74
|
+
pgs start # Start all services (including Traefik)
|
|
75
|
+
pgs start <tenant-id> # Start specific tenant
|
|
42
76
|
```
|
|
43
77
|
|
|
44
78
|
### Stop services
|
|
45
79
|
|
|
46
80
|
```bash
|
|
47
|
-
|
|
48
|
-
|
|
81
|
+
pgs stop # Stop all services
|
|
82
|
+
pgs stop <tenant-id> # Stop specific tenant
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Access Control
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pgs enable-access <tenant-id> # Enable external access
|
|
89
|
+
pgs disable-access <tenant-id> # Disable external access
|
|
49
90
|
```
|
|
50
91
|
|
|
51
92
|
## How it works
|
|
52
93
|
|
|
53
|
-
-
|
|
54
|
-
-
|
|
94
|
+
- **Traefik v3** listens on port 5432 with TLS/SSL enabled
|
|
95
|
+
- Routes connections based on **SNI (Server Name Indication)** hostname
|
|
96
|
+
- Each tenant connects using their unique hostname (e.g., `tenant1-abc123.pgs.domain.com`)
|
|
55
97
|
- External access is controlled via `tenant-access.json`
|
|
56
98
|
- Tenants are isolated in their own PostgreSQL containers on a Docker bridge network
|
|
57
|
-
- Only
|
|
99
|
+
- Only Traefik has external port mapping; PostgreSQL containers are internal only
|
|
58
100
|
|
|
59
101
|
## Connection
|
|
60
102
|
|
|
61
|
-
After creating a tenant
|
|
103
|
+
After creating a tenant:
|
|
62
104
|
|
|
63
105
|
```bash
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
## Project Definition
|
|
68
|
-
|
|
69
|
-
### What It Is
|
|
70
|
-
|
|
71
|
-
A **dynamic PostgreSQL multi-tenant management system** that provides complete database isolation by creating dedicated PostgreSQL instances per tenant. The system uses HAProxy with custom PostgreSQL protocol parsing to route connections intelligently while maintaining complete tenant isolation at the database server level.
|
|
72
|
-
|
|
73
|
-
### Core Concept
|
|
106
|
+
# Using psql
|
|
107
|
+
psql "postgresql://postgres:PASSWORD@TENANT-ID.pgs.YOUR-DOMAIN.com:5432/DATABASE?sslmode=require"
|
|
74
108
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
- **Independent Scaling**: Resources can be allocated per tenant
|
|
79
|
-
- **Enhanced Security**: No risk of cross-tenant data access
|
|
80
|
-
- **Simplified Operations**: Each tenant can be managed independently
|
|
81
|
-
|
|
82
|
-
### Key Features
|
|
83
|
-
|
|
84
|
-
1. **Dynamic Tenant Provisioning**
|
|
85
|
-
- Create new PostgreSQL instances on-demand
|
|
86
|
-
- Automatic volume and network configuration
|
|
87
|
-
- Custom initialization scripts per tenant
|
|
88
|
-
|
|
89
|
-
2. **Intelligent Routing**
|
|
90
|
-
- HAProxy parses PostgreSQL protocol to extract username
|
|
91
|
-
- Routes connections to correct tenant backend automatically
|
|
92
|
-
- Single external port (5432) for all tenants
|
|
93
|
-
|
|
94
|
-
3. **Access Control**
|
|
95
|
-
- Per-tenant external access enable/disable
|
|
96
|
-
- Secure by default (access disabled on creation)
|
|
97
|
-
- Runtime access control without service restart
|
|
109
|
+
# Example
|
|
110
|
+
psql "postgresql://postgres:mypass@tenant1-abc123.pgs.us-central-1.sysnee.com:5432/tenant1-abc123?sslmode=require"
|
|
111
|
+
```
|
|
98
112
|
|
|
99
|
-
|
|
100
|
-
- Separate Docker containers per tenant
|
|
101
|
-
- Isolated volumes for data persistence
|
|
102
|
-
- Network isolation via Docker bridge network
|
|
103
|
-
- No shared processes or memory
|
|
113
|
+
### DBeaver / GUI Clients
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
1. **Host**: `tenant-id.pgs.your-domain.com`
|
|
116
|
+
2. **Port**: `5432`
|
|
117
|
+
3. **Database**: `tenant-id`
|
|
118
|
+
4. **Username**: `postgres`
|
|
119
|
+
5. **Password**: (your password)
|
|
120
|
+
6. **SSL**: Enable SSL, set mode to `require`
|
|
109
121
|
|
|
110
122
|
## Architecture
|
|
111
123
|
|
|
112
124
|
```
|
|
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
|
-
|
|
141
|
-
│
|
|
142
|
-
│
|
|
143
|
-
│
|
|
144
|
-
│
|
|
145
|
-
│
|
|
146
|
-
│
|
|
147
|
-
│
|
|
148
|
-
|
|
125
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
126
|
+
│ External Access │
|
|
127
|
+
│ (tenant-id.pgs.domain.com:5432 + TLS/SNI) │
|
|
128
|
+
└───────────────────────────┬─────────────────────────────────────┘
|
|
129
|
+
│
|
|
130
|
+
▼
|
|
131
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
132
|
+
│ Traefik v3 Proxy │
|
|
133
|
+
│ ┌───────────────────────────────────────────────────────────┐ │
|
|
134
|
+
│ │ EntryPoint: postgres (port 5432) │ │
|
|
135
|
+
│ │ - TLS termination with wildcard certificate │ │
|
|
136
|
+
│ │ - PostgreSQL STARTTLS protocol support │ │
|
|
137
|
+
│ │ - SNI-based routing (HostSNI rule) │ │
|
|
138
|
+
│ │ - Dynamic configuration via dynamic.yml │ │
|
|
139
|
+
│ └───────────────────────────────────────────────────────────┘ │
|
|
140
|
+
└───────────────────────────┬─────────────────────────────────────┘
|
|
141
|
+
│
|
|
142
|
+
┌──────────────────┼──────────────────┐
|
|
143
|
+
│ │ │
|
|
144
|
+
▼ ▼ ▼
|
|
145
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
146
|
+
│ TCP Router │ │ TCP Router │ │ TCP Router │
|
|
147
|
+
│ tenant1 │ │ tenant2 │ │ tenant3 │
|
|
148
|
+
│ HostSNI() │ │ HostSNI() │ │ HostSNI() │
|
|
149
|
+
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
|
150
|
+
│ │ │
|
|
151
|
+
▼ ▼ ▼
|
|
152
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
153
|
+
│ PostgreSQL │ │ PostgreSQL │ │ PostgreSQL │
|
|
154
|
+
│ Container 1 │ │ Container 2 │ │ Container 3 │
|
|
155
|
+
│ │ │ │ │ │
|
|
156
|
+
│ Port: 5432 │ │ Port: 5432 │ │ Port: 5432 │
|
|
157
|
+
│ (internal) │ │ (internal) │ │ (internal) │
|
|
158
|
+
│ │ │ │ │ │
|
|
159
|
+
│ Volume: │ │ Volume: │ │ Volume: │
|
|
160
|
+
│ pgdata_1 │ │ pgdata_2 │ │ pgdata_3 │
|
|
161
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
149
162
|
```
|
|
150
163
|
|
|
151
164
|
## Technical Implementation
|
|
@@ -155,22 +168,16 @@ Instead of sharing a single PostgreSQL instance with multiple databases (shared
|
|
|
155
168
|
1. **Manager Script (manager.js)**
|
|
156
169
|
- Node.js CLI tool for tenant lifecycle management
|
|
157
170
|
- Dynamically generates docker-compose.yml entries
|
|
158
|
-
- Manages
|
|
171
|
+
- Manages Traefik dynamic configuration
|
|
159
172
|
- Controls tenant access permissions
|
|
160
173
|
|
|
161
|
-
2. **
|
|
162
|
-
- TCP-level
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
166
|
-
|
|
167
|
-
3. **PostgreSQL Protocol Parser (pg-route.lua)**
|
|
168
|
-
- Parses binary PostgreSQL startup packet
|
|
169
|
-
- Extracts username and connection parameters
|
|
170
|
-
- Handles SSL negotiation
|
|
171
|
-
- Enforces access control policies
|
|
174
|
+
2. **Traefik v3 Reverse Proxy**
|
|
175
|
+
- TCP-level routing with TLS termination
|
|
176
|
+
- Native PostgreSQL STARTTLS protocol support
|
|
177
|
+
- SNI-based tenant routing
|
|
178
|
+
- Dynamic configuration without restarts
|
|
172
179
|
|
|
173
|
-
|
|
180
|
+
3. **Docker Infrastructure**
|
|
174
181
|
- Separate container per tenant
|
|
175
182
|
- Bridge network for internal communication
|
|
176
183
|
- Persistent volumes for data
|
|
@@ -178,13 +185,22 @@ Instead of sharing a single PostgreSQL instance with multiple databases (shared
|
|
|
178
185
|
|
|
179
186
|
### Connection Flow
|
|
180
187
|
|
|
181
|
-
1. Client connects to `
|
|
182
|
-
2.
|
|
183
|
-
3.
|
|
184
|
-
4.
|
|
185
|
-
5. If
|
|
186
|
-
6.
|
|
187
|
-
|
|
188
|
+
1. Client connects to `tenant-id.pgs.domain.com:5432` with `sslmode=require`
|
|
189
|
+
2. Traefik receives connection and initiates PostgreSQL STARTTLS handshake
|
|
190
|
+
3. Client sends TLS ClientHello with SNI (hostname)
|
|
191
|
+
4. Traefik extracts SNI and matches against configured routers
|
|
192
|
+
5. If tenant has access enabled, routes to backend `pgs_{tenant_id}:5432`
|
|
193
|
+
6. Connection established with complete isolation
|
|
194
|
+
|
|
195
|
+
### Why Traefik v3?
|
|
196
|
+
|
|
197
|
+
PostgreSQL uses a non-standard TLS negotiation (STARTTLS):
|
|
198
|
+
1. Client sends PostgreSQL SSLRequest packet
|
|
199
|
+
2. Server responds 'S' (SSL supported)
|
|
200
|
+
3. Client sends TLS ClientHello with SNI
|
|
201
|
+
4. TLS handshake completes
|
|
202
|
+
|
|
203
|
+
**Traefik v3** is one of the few proxies that natively understands this PostgreSQL-specific flow, allowing SNI-based routing for PostgreSQL connections.
|
|
188
204
|
|
|
189
205
|
## Comparison with Similar Solutions
|
|
190
206
|
|
|
@@ -195,65 +211,29 @@ Instead of sharing a single PostgreSQL instance with multiple databases (shared
|
|
|
195
211
|
- Multiple databases/schemas per instance
|
|
196
212
|
- Shared processes and memory
|
|
197
213
|
- Risk of cross-tenant data access
|
|
198
|
-
- Less isolation
|
|
199
214
|
|
|
200
215
|
**This Solution:**
|
|
201
216
|
- Multiple PostgreSQL instances
|
|
202
217
|
- One instance per tenant
|
|
203
218
|
- Complete process isolation
|
|
204
219
|
- Zero risk of cross-tenant access
|
|
205
|
-
- Maximum isolation
|
|
206
220
|
|
|
207
221
|
### Similar Open Source Solutions
|
|
208
222
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
- **Purpose**: PostgreSQL extension for distributed PostgreSQL
|
|
216
|
-
- **Difference**: Shards data across nodes; this creates separate instances per tenant
|
|
217
|
-
- **Use Case**: Horizontal scaling vs. tenant isolation
|
|
218
|
-
|
|
219
|
-
#### 3. **Patroni + HAProxy**
|
|
220
|
-
- **Purpose**: High availability and load balancing
|
|
221
|
-
- **Difference**: Replicates single database; this creates isolated instances
|
|
222
|
-
- **Use Case**: HA for single database vs. multi-tenant isolation
|
|
223
|
-
|
|
224
|
-
#### 4. **Schema-based Multi-tenancy**
|
|
225
|
-
- **Purpose**: Share database, separate schemas
|
|
226
|
-
- **Difference**: Shared instance; this uses separate instances
|
|
227
|
-
- **Use Case**: Resource efficiency vs. complete isolation
|
|
223
|
+
| Solution | Purpose | Difference |
|
|
224
|
+
|----------|---------|------------|
|
|
225
|
+
| **PgBouncer** | Connection pooling | Pools to single instance; this creates separate instances |
|
|
226
|
+
| **Citus** | Distributed PostgreSQL | Shards data; this isolates tenants completely |
|
|
227
|
+
| **Patroni** | High availability | Replicates single DB; this creates isolated instances |
|
|
228
|
+
| **RLS** | Row-level security | Logic-based separation; this uses infrastructure isolation |
|
|
228
229
|
|
|
229
|
-
|
|
230
|
-
- **Purpose**: Application-level tenant isolation
|
|
231
|
-
- **Difference**: Logic-based separation; this uses infrastructure isolation
|
|
232
|
-
- **Use Case**: Application isolation vs. infrastructure isolation
|
|
230
|
+
### Unique Aspects
|
|
233
231
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
2. **Dynamic provisioning with single external port**
|
|
241
|
-
- No need for port management
|
|
242
|
-
- Automatic routing based on connection parameters
|
|
243
|
-
|
|
244
|
-
3. **Protocol-aware routing**
|
|
245
|
-
- Parses PostgreSQL binary protocol
|
|
246
|
-
- Routes before connection completion
|
|
247
|
-
- Handles SSL negotiation
|
|
248
|
-
|
|
249
|
-
4. **Runtime access control**
|
|
250
|
-
- Enable/disable tenant access without restart
|
|
251
|
-
- No downtime for access changes
|
|
252
|
-
|
|
253
|
-
5. **Docker-native architecture**
|
|
254
|
-
- Leverages container isolation
|
|
255
|
-
- Simple deployment and scaling
|
|
256
|
-
- Resource limits per tenant
|
|
232
|
+
1. **Instance-per-tenant** - Complete process and memory isolation
|
|
233
|
+
2. **SNI-based routing** - Single port, automatic hostname-based routing
|
|
234
|
+
3. **TLS by default** - Secure connections required
|
|
235
|
+
4. **Dynamic provisioning** - Create tenants on-demand via CLI
|
|
236
|
+
5. **Docker-native** - Simple deployment and resource limits per tenant
|
|
257
237
|
|
|
258
238
|
## Use Cases
|
|
259
239
|
|
|
@@ -263,52 +243,39 @@ Instead of sharing a single PostgreSQL instance with multiple databases (shared
|
|
|
263
243
|
- **Healthcare/Finance** applications with compliance requirements
|
|
264
244
|
- **Multi-tenant platforms** needing independent scaling
|
|
265
245
|
- **Development/Testing** environments with isolated databases
|
|
266
|
-
- **Legacy application migration** requiring tenant separation
|
|
267
246
|
|
|
268
247
|
### Not Ideal For
|
|
269
248
|
|
|
270
249
|
- Thousands of tenants (resource overhead)
|
|
271
|
-
- Shared resource requirements
|
|
272
250
|
- Simple multi-tenant applications without strict isolation needs
|
|
273
251
|
- Environments requiring minimal resource usage
|
|
274
252
|
|
|
275
|
-
## Advantages
|
|
276
|
-
|
|
277
|
-
✅ **Maximum Isolation**: Complete process and data separation
|
|
278
|
-
✅ **Security**: Zero risk of cross-tenant data access
|
|
279
|
-
✅ **Flexibility**: Independent scaling and management per tenant
|
|
280
|
-
✅ **Simplicity**: Single external port, automatic routing
|
|
281
|
-
✅ **Compliance**: Easier to meet regulatory requirements
|
|
282
|
-
✅ **Debugging**: Isolated environments simplify troubleshooting
|
|
283
|
-
|
|
284
|
-
## Trade-offs
|
|
285
|
-
|
|
286
|
-
⚠️ **Resource Usage**: Higher memory/CPU per tenant
|
|
287
|
-
⚠️ **Management Overhead**: More containers to manage
|
|
288
|
-
⚠️ **Scaling Limits**: Practical limit on number of tenants per host
|
|
289
|
-
⚠️ **Backup Complexity**: Need to backup multiple instances
|
|
290
|
-
|
|
291
253
|
## Technology Stack
|
|
292
254
|
|
|
293
255
|
- **Runtime**: Node.js (ES Modules)
|
|
294
256
|
- **Container Orchestration**: Docker Compose
|
|
295
|
-
- **Reverse Proxy**:
|
|
257
|
+
- **Reverse Proxy**: Traefik v3 (PostgreSQL STARTTLS + SNI routing)
|
|
296
258
|
- **Database**: PostgreSQL 18+
|
|
297
|
-
- **
|
|
298
|
-
- **Configuration**: YAML (docker-compose.yml), JSON (tenant-access.json)
|
|
259
|
+
- **TLS**: Wildcard SSL certificate
|
|
260
|
+
- **Configuration**: YAML (docker-compose.yml, traefik.yml, dynamic.yml), JSON (tenant-access.json)
|
|
261
|
+
|
|
262
|
+
## Requirements
|
|
263
|
+
|
|
264
|
+
- Docker & Docker Compose
|
|
265
|
+
- Node.js 18+
|
|
266
|
+
- Wildcard SSL certificate for your domain
|
|
267
|
+
- Wildcard DNS record pointing to your server
|
|
299
268
|
|
|
300
269
|
## Future Enhancements
|
|
301
270
|
|
|
302
271
|
- [ ] Health checks and automatic failover
|
|
303
272
|
- [ ] Backup/restore automation per tenant
|
|
304
|
-
- [ ] Resource limits (CPU/memory) per tenant
|
|
305
273
|
- [ ] Monitoring and metrics collection
|
|
306
274
|
- [ ] Tenant migration tools
|
|
307
275
|
- [ ] Kubernetes support
|
|
308
276
|
- [ ] Connection pooling per tenant
|
|
309
|
-
- [ ]
|
|
277
|
+
- [ ] Web dashboard
|
|
310
278
|
|
|
311
279
|
## License & Status
|
|
312
280
|
|
|
313
|
-
This is a custom solution built for specific multi-tenant requirements. It combines open-source tools (
|
|
314
|
-
|
|
281
|
+
This is a custom solution built for specific multi-tenant requirements. It combines open-source tools (Traefik, PostgreSQL, Docker) with SNI-based routing to achieve instance-per-tenant isolation with intelligent connection routing.
|
package/docker-compose.yml
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
version: "3.8"
|
|
2
|
+
|
|
1
3
|
services:
|
|
2
|
-
|
|
3
|
-
image:
|
|
4
|
+
traefik:
|
|
5
|
+
image: traefik:v3.0
|
|
4
6
|
container_name: postgres_proxy
|
|
5
7
|
ports:
|
|
6
|
-
-
|
|
8
|
+
- "5432:5432"
|
|
7
9
|
volumes:
|
|
8
|
-
- ./
|
|
9
|
-
- ./
|
|
10
|
-
- ./
|
|
10
|
+
- ./traefik.yml:/etc/traefik/traefik.yml:ro
|
|
11
|
+
- ./dynamic.yml:/etc/traefik/dynamic.yml:ro
|
|
12
|
+
- ./certs:/etc/traefik/certs:ro
|
|
11
13
|
networks:
|
|
12
14
|
- postgres_network
|
|
13
15
|
restart: unless-stopped
|
|
16
|
+
|
|
14
17
|
networks:
|
|
15
18
|
postgres_network:
|
|
16
19
|
driver: bridge
|
|
@@ -8,9 +8,11 @@ Para transformar esta solução em um produto comercial viável (PaaS de Postgre
|
|
|
8
8
|
2. **Alta Disponibilidade**: Sem replicação → Patroni/pg_auto_failover
|
|
9
9
|
3. **Backup/Recovery**: Inexistente → pgBackRest + S3
|
|
10
10
|
4. **Monitoramento**: Básico → Prometheus + Grafana
|
|
11
|
-
5. **Segurança**:
|
|
11
|
+
5. **Segurança**: ✅ TLS/SNI implementado via Traefik v3 → Adicionar Vault para secrets
|
|
12
12
|
6. **API**: CLI apenas → REST API completa
|
|
13
13
|
|
|
14
|
+
> **Nota**: A solução atual usa Traefik v3 para roteamento SNI com suporte nativo ao protocolo PostgreSQL STARTTLS.
|
|
15
|
+
|
|
14
16
|
---
|
|
15
17
|
|
|
16
18
|
## Abordagem por Fase
|
|
@@ -32,8 +34,8 @@ Host 2 (Região A)
|
|
|
32
34
|
├── docker-compose-3.yml # Tenants 101-150
|
|
33
35
|
└── docker-compose-4.yml # Tenants 151-200
|
|
34
36
|
|
|
35
|
-
Load Balancer (
|
|
36
|
-
├── Roteia para host correto baseado em
|
|
37
|
+
Load Balancer (Traefik v3)
|
|
38
|
+
├── Roteia para host correto baseado em SNI (hostname)
|
|
37
39
|
└── Health checks de todos os hosts
|
|
38
40
|
```
|
|
39
41
|
|
|
@@ -141,12 +143,12 @@ pgs_tenant1_replica:
|
|
|
141
143
|
PATRONI_ROLE: replica
|
|
142
144
|
```
|
|
143
145
|
|
|
144
|
-
#### 2.
|
|
146
|
+
#### 2. Traefik Redundante
|
|
145
147
|
|
|
146
148
|
```
|
|
147
|
-
|
|
149
|
+
Traefik 1 ──┐
|
|
148
150
|
├── Keepalived VIP (Virtual IP)
|
|
149
|
-
|
|
151
|
+
Traefik 2 ──┘
|
|
150
152
|
```
|
|
151
153
|
|
|
152
154
|
#### 3. Backup com pgBackRest
|
|
@@ -301,7 +303,7 @@ spec:
|
|
|
301
303
|
```yaml
|
|
302
304
|
# docker-compose.yml com profiles e múltiplos arquivos
|
|
303
305
|
services:
|
|
304
|
-
|
|
306
|
+
traefik:
|
|
305
307
|
# ...
|
|
306
308
|
|
|
307
309
|
pgs_tenant1:
|
|
@@ -340,7 +342,7 @@ API centralizada gerencia:
|
|
|
340
342
|
|
|
341
343
|
```
|
|
342
344
|
Orquestração: Docker Compose (melhorado)
|
|
343
|
-
Proxy:
|
|
345
|
+
Proxy: Traefik v3 (SNI routing + PostgreSQL STARTTLS)
|
|
344
346
|
Backup: pg_dump + AWS S3
|
|
345
347
|
Monitoring: Prometheus + Grafana
|
|
346
348
|
Secrets: HashiCorp Vault (básico)
|
|
@@ -352,7 +354,7 @@ Database: PostgreSQL 18+
|
|
|
352
354
|
|
|
353
355
|
```
|
|
354
356
|
Orquestração: Kubernetes
|
|
355
|
-
Proxy:
|
|
357
|
+
Proxy: Traefik IngressRoute (TCP + SNI) ou Nginx Ingress
|
|
356
358
|
Backup: pgBackRest + S3/GCS
|
|
357
359
|
Monitoring: Prometheus + Grafana + Alertmanager
|
|
358
360
|
Secrets: HashiCorp Vault (completo)
|
package/docs/CRITICAL_REVIEW.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Esta análise identifica os pontos críticos que precisam ser endereçados para transformar esta solução em um produto comercial viável.
|
|
6
6
|
|
|
7
|
+
> **Nota**: A solução atual utiliza **Traefik v3** para roteamento baseado em SNI (Server Name Indication) com suporte nativo ao protocolo PostgreSQL STARTTLS. Isso permite roteamento por hostname com TLS obrigatório.
|
|
8
|
+
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
## 🔴 PROBLEMAS CRÍTICOS
|
|
@@ -118,8 +120,8 @@ Melhorias possíveis:
|
|
|
118
120
|
- Sem backup automático em tempo real
|
|
119
121
|
- RTO (Recovery Time Objective) alto
|
|
120
122
|
|
|
121
|
-
**b)
|
|
122
|
-
- Se
|
|
123
|
+
**b) Traefik como SPOF**
|
|
124
|
+
- Se Traefik cair, todos os tenants ficam inacessíveis
|
|
123
125
|
- Sem redundância do proxy
|
|
124
126
|
|
|
125
127
|
#### Soluções Necessárias:
|
|
@@ -137,12 +139,12 @@ Primary (writable) ──streaming──> Standby (read-only)
|
|
|
137
139
|
↓ failover ↑ promotion
|
|
138
140
|
```
|
|
139
141
|
|
|
140
|
-
**2.
|
|
142
|
+
**2. Traefik Redundância**
|
|
141
143
|
```
|
|
142
|
-
- Múltiplas instâncias
|
|
144
|
+
- Múltiplas instâncias Traefik
|
|
143
145
|
- Keepalived para VIP (Virtual IP)
|
|
144
|
-
- Health checks entre
|
|
145
|
-
- Load balancing do
|
|
146
|
+
- Health checks entre Traefik instances
|
|
147
|
+
- Load balancing do Traefik
|
|
146
148
|
```
|
|
147
149
|
|
|
148
150
|
**3. Multi-Region (Futuro)**
|
|
@@ -296,7 +298,7 @@ Implementação:
|
|
|
296
298
|
**2. SSL/TLS**
|
|
297
299
|
```
|
|
298
300
|
- Certificados SSL para conexões
|
|
299
|
-
- TLS entre
|
|
301
|
+
- TLS entre Traefik e PostgreSQL (interno)
|
|
300
302
|
- Certificate management automático (Let's Encrypt)
|
|
301
303
|
- TLS 1.2+ obrigatório
|
|
302
304
|
```
|
|
@@ -557,7 +559,7 @@ resource "managed_postgres_tenant" "example" {
|
|
|
557
559
|
```
|
|
558
560
|
✅ Alta Disponibilidade
|
|
559
561
|
- Replicação PostgreSQL (Patroni)
|
|
560
|
-
-
|
|
562
|
+
- Traefik redundante (Keepalived)
|
|
561
563
|
- Auto-failover
|
|
562
564
|
|
|
563
565
|
✅ Backup Avançado
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
|
|
31
31
|
**Problema**: Zero redundância
|
|
32
32
|
- 1 container PostgreSQL = 1 ponto de falha
|
|
33
|
-
-
|
|
33
|
+
- Traefik sem redundância
|
|
34
34
|
- Sem failover automático
|
|
35
35
|
|
|
36
36
|
**Solução**:
|
|
37
37
|
- Replicação PostgreSQL (Patroni/pg_auto_failover)
|
|
38
|
-
-
|
|
38
|
+
- Traefik redundante com Keepalived
|
|
39
39
|
- Auto-failover configurado
|
|
40
40
|
|
|
41
41
|
### 3. Backup e Recovery - ESSENCIAL
|
|
@@ -60,14 +60,13 @@
|
|
|
60
60
|
|
|
61
61
|
### 5. Segurança
|
|
62
62
|
|
|
63
|
-
**
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
63
|
+
**Status Atual** ✅:
|
|
64
|
+
- TLS/SSL implementado via Traefik v3
|
|
65
|
+
- Roteamento SNI (hostname-based)
|
|
66
|
+
- Certificado wildcard
|
|
67
67
|
|
|
68
|
-
**
|
|
68
|
+
**Melhorias Necessárias**:
|
|
69
69
|
- HashiCorp Vault para secrets
|
|
70
|
-
- SSL/TLS obrigatório
|
|
71
70
|
- Rotação automática de senhas
|
|
72
71
|
- Network policies
|
|
73
72
|
|
|
@@ -103,7 +102,8 @@
|
|
|
103
102
|
✅ API REST
|
|
104
103
|
✅ Monitoring básico (Prometheus + Grafana)
|
|
105
104
|
✅ Secrets management básico
|
|
106
|
-
✅ SSL/TLS
|
|
105
|
+
✅ SSL/TLS via Traefik v3 (IMPLEMENTADO)
|
|
106
|
+
✅ SNI-based routing (IMPLEMENTADO)
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
**Custo estimado**: $5K-15K (infraestrutura + desenvolvimento)
|