Testing an upgrade against production because staging is "basically the same" is how weekends get ruined. Cloning a container properly takes a few minutes and gives you a real copy.
What has to be copied, and what must not be
Copy: the image and tag, the environment, the volume data, the resource limits, the network topology.
Do not copy: the published host ports (they will collide), the domain binding, anything that talks to the outside world — payment webhooks, mail delivery, push notifications, cron jobs that touch third-party APIs. A staging copy that still holds the production Stripe key and still fires the real webhook is worse than no staging at all.
By hand
The
Via the panel
The step everybody skips
After the clone, change the credentials in the copy. Same database password, same API tokens, same admin account: now you have doubled the number of places from which production can be reached, and one of them is a machine you were planning to be careless with. Rotate at least the outbound keys before you touch anything.
And clean up. Stale staging containers are the top source of "why is this server out of memory" on a box that was fine last month. If your clone is still running two weeks after the test, it is not staging, it is a leak.
How is everyone else handling staging for containerised apps — parallel stack on the same host, or a separate machine?
What has to be copied, and what must not be
Copy: the image and tag, the environment, the volume data, the resource limits, the network topology.
Do not copy: the published host ports (they will collide), the domain binding, anything that talks to the outside world — payment webhooks, mail delivery, push notifications, cron jobs that touch third-party APIs. A staging copy that still holds the production Stripe key and still fires the real webhook is worse than no staging at all.
By hand
Code:
# 1. a consistent copy of the data, using a dump not a file copy
docker exec -t app-db pg_dumpall -c -U postgres > staging.sql
# 2. bring up a parallel stack on different ports and a different network
docker compose -p app-staging -f docker-compose.staging.yml up -d
# 3. load the data
docker exec -i app-staging-db psql -U postgres < staging.sql
The
-p project name is what keeps the two stacks from colliding in Compose. Skip it and you are not creating a staging environment, you are reconfiguring production.Via the panel
POST /docker/containers/:id/clone does the container side of this and tags the result with panelica.cloned_from and panelica.clone_date labels, so six months later you can still tell which containers were copies and delete them without archaeology. Volumes are cloned rather than shared, which is the part that matters — a staging container pointed at the production volume is not staging, it is production with an extra process writing to it.The step everybody skips
After the clone, change the credentials in the copy. Same database password, same API tokens, same admin account: now you have doubled the number of places from which production can be reached, and one of them is a machine you were planning to be careless with. Rotate at least the outbound keys before you touch anything.
And clean up. Stale staging containers are the top source of "why is this server out of memory" on a box that was fine last month. If your clone is still running two weeks after the test, it is not staging, it is a leak.
How is everyone else handling staging for containerised apps — parallel stack on the same host, or a separate machine?