142 lines
4.0 KiB
Markdown
142 lines
4.0 KiB
Markdown
# Production migration and rollback
|
|
|
|
This runbook moves the titan deployment from the Python source tree at
|
|
`/root/repo/urlshortener` to the published `sodium/ushort` image. The final
|
|
server-side application directory is `/root/compose/ushort`; no source checkout
|
|
is required on titan.
|
|
|
|
Do not cut over until the exact image tag has been built for both `linux/amd64`
|
|
and `linux/arm64`, pushed, and recorded by digest.
|
|
|
|
## 1. Prepare without affecting production
|
|
|
|
Create this layout on titan:
|
|
|
|
```text
|
|
/root/compose/ushort/
|
|
├── docker-compose.yml
|
|
├── config.toml
|
|
└── data/
|
|
```
|
|
|
|
Copy `deploy/compose.production.yml` to the server as `docker-compose.yml`.
|
|
Convert the live JSON
|
|
settings to TOML using `config.example.toml` as the reference, with these
|
|
cutover-specific rules:
|
|
|
|
- keep the live `base_url`, limits, retention, and rate-limit values;
|
|
- set `db_path = "data/urlshort.db"`;
|
|
- set `production = false` so the binary serves its embedded frontend; and
|
|
- generate a new API key, because the old key existed in the legacy Git
|
|
history.
|
|
|
|
Keep `config.toml` owned by `1001:1001` with mode `0400`, matching the
|
|
container identity. Do not copy it into Git or a container image.
|
|
|
|
Validate the deployment file before stopping anything:
|
|
|
|
```bash
|
|
cd /root/compose/ushort
|
|
chown 1001:1001 config.toml
|
|
chmod 0400 config.toml
|
|
docker-compose config
|
|
docker pull sodium/ushort:0.1.1
|
|
```
|
|
|
|
## 2. Take a consistent database copy
|
|
|
|
The final copy must be made while the Python service is stopped so no committed
|
|
row is missed and no SQLite journal is in flight:
|
|
|
|
```bash
|
|
cd /root/repo/urlshortener
|
|
docker-compose stop urlshort
|
|
|
|
cp -a data/urlshort.db /root/compose/ushort/data/urlshort.db
|
|
cp -a data/urlshort.db /root/compose/ushort/data/urlshort.db.pre-rust
|
|
chown -R 1001:1001 /root/compose/ushort/data
|
|
chmod 0750 /root/compose/ushort/data
|
|
chmod 0640 /root/compose/ushort/data/urlshort.db*
|
|
```
|
|
|
|
Do not delete or alter the original database during the initial soak period.
|
|
|
|
## 3. Start and validate ushort locally
|
|
|
|
```bash
|
|
cd /root/compose/ushort
|
|
docker-compose up -d
|
|
docker-compose ps
|
|
docker-compose logs --tail=100 ushort
|
|
|
|
curl -i http://127.0.0.1:18082/s/api/health
|
|
curl -I http://127.0.0.1:18082/s/
|
|
```
|
|
|
|
Expected results are HTTP 200 health JSON and HTTP 200 HTML. Confirm the
|
|
container does not restart and the database remains writable.
|
|
|
|
## 4. Switch nginx
|
|
|
|
Replace the old `include /root/repo/urlshortener/nginx.conf;` in the `xcel.me`
|
|
vhost with the location blocks from the new `nginx.conf`. Those blocks proxy
|
|
the frontend as well as API/redirect traffic to `127.0.0.1:18082`; they do not
|
|
refer to a source or static-file directory.
|
|
|
|
Test before reload:
|
|
|
|
```bash
|
|
docker exec nginx nginx -t
|
|
docker exec nginx nginx -s reload
|
|
```
|
|
|
|
Then validate through the public endpoint:
|
|
|
|
```bash
|
|
curl -i https://xcel.me/s/api/health
|
|
curl -I https://xcel.me/s/
|
|
curl -I https://xcel.me/s/static/app.js
|
|
```
|
|
|
|
Check that `/s/` is `no-store`, static assets are `no-cache`, an existing short
|
|
code still returns the original 302 target, and its visit count increments once.
|
|
|
|
## 5. Soak and clean up
|
|
|
|
During the soak period, monitor:
|
|
|
|
```bash
|
|
cd /root/compose/ushort
|
|
docker-compose ps
|
|
docker-compose logs --tail=200 ushort
|
|
```
|
|
|
|
After the rollback window closes:
|
|
|
|
1. retain a protected database backup;
|
|
2. remove the obsolete `/root/repo/urlshortener` source tree;
|
|
3. remove its `/srv/urlshortener` bind mount from the global nginx Compose
|
|
file; and
|
|
4. recreate nginx and re-run `nginx -t`.
|
|
|
|
At that point, application source exists only in Gitea, while titan contains
|
|
only the Compose file, TOML config, and data under `/root/compose/ushort`.
|
|
|
|
## Rollback
|
|
|
|
If validation fails before public traffic is enabled:
|
|
|
|
```bash
|
|
cd /root/compose/ushort
|
|
docker-compose down
|
|
cd /root/repo/urlshortener
|
|
docker-compose start urlshort
|
|
```
|
|
|
|
Restore the old nginx include and reload nginx.
|
|
|
|
If public writes occurred after cutover, stop ushort first and copy its current
|
|
database back to the legacy data path before starting Python; otherwise those
|
|
new short URLs would be lost. The schema is deliberately identical, so no
|
|
reverse schema migration is required.
|