@sysnee/pgs 0.1.0
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 +314 -0
- package/docker-compose.yml +16 -0
- package/docs/ARCHITECTURE_RECOMMENDATIONS.md +480 -0
- package/docs/CRITICAL_REVIEW.md +748 -0
- package/docs/EXECUTIVE_SUMMARY.md +210 -0
- package/docs/PROJECT.md +250 -0
- package/haproxy-lua/pg-route.lua +177 -0
- package/manager.js +510 -0
- package/manifest.json +32 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# PostgreSQL Multi-Tenant Instance Manager
|
|
2
|
+
|
|
3
|
+
Dynamic PostgreSQL multi-tenant management system providing complete database isolation by creating dedicated PostgreSQL instances per tenant, with intelligent routing via HAProxy.
|
|
4
|
+
|
|
5
|
+
> 📖 **For detailed project definition, architecture, and comparison with similar solutions, see [PROJECT.md](./PROJECT.md)**
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
### Create a new tenant instance
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm run create <tenant-id> [--password <password>]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
```bash
|
|
17
|
+
npm run create tenant1
|
|
18
|
+
npm run create tenant2 --password mycustompass
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
New tenants are created with external access **disabled** by default.
|
|
22
|
+
|
|
23
|
+
### List all tenants
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run list
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Shows all tenants with their external access status.
|
|
30
|
+
|
|
31
|
+
### Remove a tenant
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm run remove <tenant-id>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Start services
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm run start # Start all services (including HAProxy)
|
|
41
|
+
npm run start -- --tenant tenant1 # Start specific tenant
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Stop services
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run stop # Stop all services
|
|
48
|
+
npm run stop -- --tenant tenant1 # Stop specific tenant
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## How it works
|
|
52
|
+
|
|
53
|
+
- HAProxy listens on port 5432 and routes connections based on the PostgreSQL username
|
|
54
|
+
- Each tenant connects using their tenant ID as the username (e.g., `tecnolab`)
|
|
55
|
+
- External access is controlled via `tenant-access.json`
|
|
56
|
+
- Tenants are isolated in their own PostgreSQL containers on a Docker bridge network
|
|
57
|
+
- Only HAProxy has external port mapping; PostgreSQL containers are internal only
|
|
58
|
+
|
|
59
|
+
## Connection
|
|
60
|
+
|
|
61
|
+
After creating a tenant and enabling external access:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
psql -h localhost -p 5432 -U <tenant-id> -d <tenant-id>
|
|
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
|
|
74
|
+
|
|
75
|
+
Instead of sharing a single PostgreSQL instance with multiple databases (shared database architecture), this system creates **one PostgreSQL container per tenant**, ensuring:
|
|
76
|
+
|
|
77
|
+
- **Complete Data Isolation**: Each tenant has its own PostgreSQL process and data directory
|
|
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
|
|
98
|
+
|
|
99
|
+
4. **Complete Isolation**
|
|
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
|
|
104
|
+
|
|
105
|
+
5. **Zero-Downtime Operations**
|
|
106
|
+
- Graceful HAProxy reloads
|
|
107
|
+
- Independent tenant management
|
|
108
|
+
- No impact on other tenants during operations
|
|
109
|
+
|
|
110
|
+
## Architecture
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
┌─────────────────────────────────────────────────────────┐
|
|
114
|
+
│ External Access │
|
|
115
|
+
│ (localhost:5432) │
|
|
116
|
+
└──────────────────────┬──────────────────────────────────┘
|
|
117
|
+
│
|
|
118
|
+
▼
|
|
119
|
+
┌─────────────────────────────────────────────────────────┐
|
|
120
|
+
│ HAProxy Proxy │
|
|
121
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
122
|
+
│ │ Frontend: postgres_frontend │ │
|
|
123
|
+
│ │ - Listens on port 5432 │ │
|
|
124
|
+
│ │ - Parses PostgreSQL protocol (Lua script) │ │
|
|
125
|
+
│ │ - Extracts username from startup packet │ │
|
|
126
|
+
│ │ - Checks tenant-access.json for permissions │ │
|
|
127
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
128
|
+
└──────────────────────┬──────────────────────────────────┘
|
|
129
|
+
│
|
|
130
|
+
┌──────────────┼──────────────┐
|
|
131
|
+
│ │ │
|
|
132
|
+
▼ ▼ ▼
|
|
133
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
134
|
+
│ Backend │ │ Backend │ │ Backend │
|
|
135
|
+
│ pgs_tenant1 │ │ pgs_tenant2 │ │ pgs_tenant3 │
|
|
136
|
+
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
|
137
|
+
│ │ │
|
|
138
|
+
▼ ▼ ▼
|
|
139
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
140
|
+
│ PostgreSQL │ │ PostgreSQL │ │ PostgreSQL │
|
|
141
|
+
│ Container 1 │ │ Container 2 │ │ Container 3 │
|
|
142
|
+
│ │ │ │ │ │
|
|
143
|
+
│ Port: 5432 │ │ Port: 5432 │ │ Port: 5432 │
|
|
144
|
+
│ (internal) │ │ (internal) │ │ (internal) │
|
|
145
|
+
│ │ │ │ │ │
|
|
146
|
+
│ Volume: │ │ Volume: │ │ Volume: │
|
|
147
|
+
│ pgdata_1 │ │ pgdata_2 │ │ pgdata_3 │
|
|
148
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Technical Implementation
|
|
152
|
+
|
|
153
|
+
### Components
|
|
154
|
+
|
|
155
|
+
1. **Manager Script (manager.js)**
|
|
156
|
+
- Node.js CLI tool for tenant lifecycle management
|
|
157
|
+
- Dynamically generates docker-compose.yml entries
|
|
158
|
+
- Manages HAProxy configuration
|
|
159
|
+
- Controls tenant access permissions
|
|
160
|
+
|
|
161
|
+
2. **HAProxy Reverse Proxy**
|
|
162
|
+
- TCP-level load balancer and router
|
|
163
|
+
- Custom Lua script for PostgreSQL protocol parsing
|
|
164
|
+
- Routes based on extracted username
|
|
165
|
+
- Per-tenant access control
|
|
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
|
|
172
|
+
|
|
173
|
+
4. **Docker Infrastructure**
|
|
174
|
+
- Separate container per tenant
|
|
175
|
+
- Bridge network for internal communication
|
|
176
|
+
- Persistent volumes for data
|
|
177
|
+
- Isolated execution environments
|
|
178
|
+
|
|
179
|
+
### Connection Flow
|
|
180
|
+
|
|
181
|
+
1. Client connects to `localhost:5432` with username `tenant_id`
|
|
182
|
+
2. HAProxy receives connection and invokes Lua script
|
|
183
|
+
3. Script parses PostgreSQL startup packet and extracts username
|
|
184
|
+
4. Script checks `tenant-access.json` for permission
|
|
185
|
+
5. If allowed, routes to backend `pgs_{tenant_id}`
|
|
186
|
+
6. Backend forwards to PostgreSQL container on internal network
|
|
187
|
+
7. Connection established with complete isolation
|
|
188
|
+
|
|
189
|
+
## Comparison with Similar Solutions
|
|
190
|
+
|
|
191
|
+
### Shared Database Architecture
|
|
192
|
+
|
|
193
|
+
**Traditional Multi-Tenant PostgreSQL:**
|
|
194
|
+
- Single PostgreSQL instance
|
|
195
|
+
- Multiple databases/schemas per instance
|
|
196
|
+
- Shared processes and memory
|
|
197
|
+
- Risk of cross-tenant data access
|
|
198
|
+
- Less isolation
|
|
199
|
+
|
|
200
|
+
**This Solution:**
|
|
201
|
+
- Multiple PostgreSQL instances
|
|
202
|
+
- One instance per tenant
|
|
203
|
+
- Complete process isolation
|
|
204
|
+
- Zero risk of cross-tenant access
|
|
205
|
+
- Maximum isolation
|
|
206
|
+
|
|
207
|
+
### Similar Open Source Solutions
|
|
208
|
+
|
|
209
|
+
#### 1. **PgBouncer**
|
|
210
|
+
- **Purpose**: Connection pooling, not tenant isolation
|
|
211
|
+
- **Difference**: Pools connections to single instance; this creates separate instances
|
|
212
|
+
- **Use Case**: Different - PgBouncer optimizes connections; this isolates tenants
|
|
213
|
+
|
|
214
|
+
#### 2. **Citus**
|
|
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
|
|
228
|
+
|
|
229
|
+
#### 5. **Row-level Security (RLS)**
|
|
230
|
+
- **Purpose**: Application-level tenant isolation
|
|
231
|
+
- **Difference**: Logic-based separation; this uses infrastructure isolation
|
|
232
|
+
- **Use Case**: Application isolation vs. infrastructure isolation
|
|
233
|
+
|
|
234
|
+
### Unique Aspects of This Solution
|
|
235
|
+
|
|
236
|
+
1. **Instance-per-tenant at infrastructure level**
|
|
237
|
+
- Not just database or schema separation
|
|
238
|
+
- Complete process and memory isolation
|
|
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
|
|
257
|
+
|
|
258
|
+
## Use Cases
|
|
259
|
+
|
|
260
|
+
### Ideal For
|
|
261
|
+
|
|
262
|
+
- **SaaS Applications** requiring strict tenant data isolation
|
|
263
|
+
- **Healthcare/Finance** applications with compliance requirements
|
|
264
|
+
- **Multi-tenant platforms** needing independent scaling
|
|
265
|
+
- **Development/Testing** environments with isolated databases
|
|
266
|
+
- **Legacy application migration** requiring tenant separation
|
|
267
|
+
|
|
268
|
+
### Not Ideal For
|
|
269
|
+
|
|
270
|
+
- Thousands of tenants (resource overhead)
|
|
271
|
+
- Shared resource requirements
|
|
272
|
+
- Simple multi-tenant applications without strict isolation needs
|
|
273
|
+
- Environments requiring minimal resource usage
|
|
274
|
+
|
|
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
|
+
## Technology Stack
|
|
292
|
+
|
|
293
|
+
- **Runtime**: Node.js (ES Modules)
|
|
294
|
+
- **Container Orchestration**: Docker Compose
|
|
295
|
+
- **Reverse Proxy**: HAProxy with Lua scripting
|
|
296
|
+
- **Database**: PostgreSQL 18+
|
|
297
|
+
- **Protocol Parsing**: Custom Lua script
|
|
298
|
+
- **Configuration**: YAML (docker-compose.yml), JSON (tenant-access.json)
|
|
299
|
+
|
|
300
|
+
## Future Enhancements
|
|
301
|
+
|
|
302
|
+
- [ ] Health checks and automatic failover
|
|
303
|
+
- [ ] Backup/restore automation per tenant
|
|
304
|
+
- [ ] Resource limits (CPU/memory) per tenant
|
|
305
|
+
- [ ] Monitoring and metrics collection
|
|
306
|
+
- [ ] Tenant migration tools
|
|
307
|
+
- [ ] Kubernetes support
|
|
308
|
+
- [ ] Connection pooling per tenant
|
|
309
|
+
- [ ] SSL/TLS termination
|
|
310
|
+
|
|
311
|
+
## License & Status
|
|
312
|
+
|
|
313
|
+
This is a custom solution built for specific multi-tenant requirements. It combines open-source tools (HAProxy, PostgreSQL, Docker) with custom routing logic to achieve instance-per-tenant isolation with intelligent connection routing.
|
|
314
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
services:
|
|
2
|
+
haproxy:
|
|
3
|
+
image: haproxy:latest
|
|
4
|
+
container_name: postgres_proxy
|
|
5
|
+
ports:
|
|
6
|
+
- '5432:5432'
|
|
7
|
+
volumes:
|
|
8
|
+
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
|
|
9
|
+
- ./haproxy-lua:/etc/haproxy/lua:ro
|
|
10
|
+
- ./tenant-access.json:/etc/haproxy/tenant-access.json:ro
|
|
11
|
+
networks:
|
|
12
|
+
- postgres_network
|
|
13
|
+
restart: unless-stopped
|
|
14
|
+
networks:
|
|
15
|
+
postgres_network:
|
|
16
|
+
driver: bridge
|