|
1 | 1 | # Deployment |
2 | 2 |
|
3 | | -## Docker |
| 3 | +## Docker Compose |
4 | 4 |
|
5 | 5 | ### docker-compose.yml |
6 | 6 |
|
@@ -68,6 +68,188 @@ docker compose up |
68 | 68 | └─ Phoenix server starts on :4000 |
69 | 69 | ``` |
70 | 70 |
|
| 71 | +## Standalone Docker |
| 72 | + |
| 73 | +For users who already have PostgreSQL and S3-compatible storage and just need to run the control plane container. |
| 74 | + |
| 75 | +### Prerequisites |
| 76 | + |
| 77 | +- PostgreSQL 15+ (managed or self-hosted) |
| 78 | +- S3-compatible storage (AWS S3, MinIO, DigitalOcean Spaces, etc.) |
| 79 | +- Docker |
| 80 | + |
| 81 | +### Pull or Build the Image |
| 82 | + |
| 83 | +```bash |
| 84 | +# Build from source |
| 85 | +docker build -t zentinel-cp . |
| 86 | +``` |
| 87 | + |
| 88 | +### Run Migrations and Seed |
| 89 | + |
| 90 | +Before starting the application for the first time, run database migrations and seed the default admin user: |
| 91 | + |
| 92 | +```bash |
| 93 | +docker run --rm \ |
| 94 | + -e DATABASE_URL="ecto://user:pass@db-host:5432/zentinel_cp" \ |
| 95 | + -e SECRET_KEY_BASE="$(openssl rand -base64 48)" \ |
| 96 | + zentinel-cp bin/zentinel_cp eval "ZentinelCp.Release.migrate()" |
| 97 | + |
| 98 | +docker run --rm \ |
| 99 | + -e DATABASE_URL="ecto://user:pass@db-host:5432/zentinel_cp" \ |
| 100 | + -e SECRET_KEY_BASE="$(openssl rand -base64 48)" \ |
| 101 | + zentinel-cp bin/zentinel_cp eval "ZentinelCp.Release.seed()" |
| 102 | +``` |
| 103 | + |
| 104 | +### Start the Control Plane |
| 105 | + |
| 106 | +```bash |
| 107 | +docker run -d \ |
| 108 | + --name zentinel-cp \ |
| 109 | + -p 4000:4000 \ |
| 110 | + -e DATABASE_URL="ecto://user:pass@db-host:5432/zentinel_cp" \ |
| 111 | + -e SECRET_KEY_BASE="$(mix phx.gen.secret)" \ |
| 112 | + -e PHX_HOST="cp.example.com" \ |
| 113 | + -e S3_ENDPOINT="https://s3.amazonaws.com" \ |
| 114 | + -e S3_BUCKET="zentinel-bundles" \ |
| 115 | + -e S3_ACCESS_KEY_ID="AKIA..." \ |
| 116 | + -e S3_SECRET_ACCESS_KEY="..." \ |
| 117 | + -e S3_REGION="us-east-1" \ |
| 118 | + -e FORCE_SSL="true" \ |
| 119 | + zentinel-cp |
| 120 | +``` |
| 121 | + |
| 122 | +The entrypoint automatically runs migrations and seeds on startup, so the separate migration step is only needed if you want to run migrations independently. |
| 123 | + |
| 124 | +### Healthcheck |
| 125 | + |
| 126 | +The container includes a built-in healthcheck: |
| 127 | + |
| 128 | +```bash |
| 129 | +curl -f http://localhost:4000/health |
| 130 | +``` |
| 131 | + |
| 132 | +### Rollback Migrations |
| 133 | + |
| 134 | +```bash |
| 135 | +docker run --rm \ |
| 136 | + -e DATABASE_URL="ecto://user:pass@db-host:5432/zentinel_cp" \ |
| 137 | + -e SECRET_KEY_BASE="any-value" \ |
| 138 | + zentinel-cp bin/zentinel_cp eval "ZentinelCp.Release.rollback(ZentinelCp.Repo, 20240101000000)" |
| 139 | +``` |
| 140 | + |
| 141 | +Replace the version number with the migration timestamp you want to roll back to. |
| 142 | + |
| 143 | +## From Source (Bare Metal / VM) |
| 144 | + |
| 145 | +For users who want to build and run a native OTP release without Docker. |
| 146 | + |
| 147 | +### Prerequisites |
| 148 | + |
| 149 | +- Elixir 1.16+ and Erlang/OTP 26+ |
| 150 | +- PostgreSQL 15+ |
| 151 | +- S3-compatible storage |
| 152 | +- `zentinel` CLI binary (for bundle validation/compilation) |
| 153 | +- Node.js (for asset compilation) |
| 154 | + |
| 155 | +### Build the Release |
| 156 | + |
| 157 | +```bash |
| 158 | +git clone https://github.com/zentinelproxy/zentinel-control-plane.git |
| 159 | +cd zentinel-control-plane |
| 160 | + |
| 161 | +export MIX_ENV=prod |
| 162 | + |
| 163 | +mix deps.get --only prod |
| 164 | +mix compile |
| 165 | +mix assets.deploy |
| 166 | +mix release |
| 167 | +``` |
| 168 | + |
| 169 | +The release is built to `_build/prod/rel/zentinel_cp/`. |
| 170 | + |
| 171 | +### Run Migrations and Seed |
| 172 | + |
| 173 | +```bash |
| 174 | +export DATABASE_URL="ecto://user:pass@localhost:5432/zentinel_cp" |
| 175 | +export SECRET_KEY_BASE="$(mix phx.gen.secret)" |
| 176 | + |
| 177 | +_build/prod/rel/zentinel_cp/bin/zentinel_cp eval "ZentinelCp.Release.migrate()" |
| 178 | +_build/prod/rel/zentinel_cp/bin/zentinel_cp eval "ZentinelCp.Release.seed()" |
| 179 | +``` |
| 180 | + |
| 181 | +### Start the Server |
| 182 | + |
| 183 | +```bash |
| 184 | +export DATABASE_URL="ecto://user:pass@localhost:5432/zentinel_cp" |
| 185 | +export SECRET_KEY_BASE="your-secret-key-base" |
| 186 | +export PHX_HOST="cp.example.com" |
| 187 | +export S3_ENDPOINT="https://s3.amazonaws.com" |
| 188 | +export S3_BUCKET="zentinel-bundles" |
| 189 | +export S3_ACCESS_KEY_ID="AKIA..." |
| 190 | +export S3_SECRET_ACCESS_KEY="..." |
| 191 | +export ZENTINEL_BINARY="/usr/local/bin/zentinel" |
| 192 | + |
| 193 | +PHX_SERVER=true _build/prod/rel/zentinel_cp/bin/zentinel_cp start |
| 194 | +``` |
| 195 | + |
| 196 | +### systemd Service |
| 197 | + |
| 198 | +Create `/etc/systemd/system/zentinel-cp.service`: |
| 199 | + |
| 200 | +```ini |
| 201 | +[Unit] |
| 202 | +Description=Zentinel Control Plane |
| 203 | +After=network.target postgresql.service |
| 204 | +Requires=postgresql.service |
| 205 | + |
| 206 | +[Service] |
| 207 | +Type=exec |
| 208 | +User=zentinel |
| 209 | +Group=zentinel |
| 210 | +WorkingDirectory=/opt/zentinel-cp |
| 211 | +ExecStart=/opt/zentinel-cp/bin/zentinel_cp start |
| 212 | +ExecStop=/opt/zentinel-cp/bin/zentinel_cp stop |
| 213 | +Restart=on-failure |
| 214 | +RestartSec=5 |
| 215 | + |
| 216 | +Environment=PHX_SERVER=true |
| 217 | +Environment=PORT=4000 |
| 218 | +Environment=PHX_HOST=cp.example.com |
| 219 | +Environment=FORCE_SSL=true |
| 220 | +Environment=POOL_SIZE=10 |
| 221 | +Environment=ZENTINEL_BINARY=/usr/local/bin/zentinel |
| 222 | + |
| 223 | +EnvironmentFile=/etc/zentinel-cp/env |
| 224 | + |
| 225 | +[Install] |
| 226 | +WantedBy=multi-user.target |
| 227 | +``` |
| 228 | + |
| 229 | +Store secrets in `/etc/zentinel-cp/env` (mode `0600`): |
| 230 | + |
| 231 | +```bash |
| 232 | +DATABASE_URL=ecto://zentinel:password@localhost:5432/zentinel_cp |
| 233 | +SECRET_KEY_BASE=your-secret-key-base-here |
| 234 | +S3_ENDPOINT=https://s3.amazonaws.com |
| 235 | +S3_BUCKET=zentinel-bundles |
| 236 | +S3_ACCESS_KEY_ID=AKIA... |
| 237 | +S3_SECRET_ACCESS_KEY=... |
| 238 | +``` |
| 239 | + |
| 240 | +Enable and start: |
| 241 | + |
| 242 | +```bash |
| 243 | +sudo systemctl daemon-reload |
| 244 | +sudo systemctl enable zentinel-cp |
| 245 | +sudo systemctl start zentinel-cp |
| 246 | +sudo journalctl -u zentinel-cp -f |
| 247 | +``` |
| 248 | + |
| 249 | +## Connecting Proxies |
| 250 | + |
| 251 | +After deployment, see [PROXY-REGISTRATION.md](PROXY-REGISTRATION.md) for a complete guide on registering zentinel proxy instances with the control plane. |
| 252 | + |
71 | 253 | ## Rollout Strategies |
72 | 254 |
|
73 | 255 | ### Rolling (Default) |
|
0 commit comments