FerryDocs
Guides

Deploys and rollbacks

Follow a deploy step by step, fix a failed health check, restart, roll back or cancel a deploy.

Edit on GitHub

A puts one version of your online. Ferry starts the new version next to the old version, tests it, then moves the traffic. If the new version fails, the old version stays online.

Terminal
ferry deploy api --follow

--follow shows the log until the deploy is live. If the deploy fails, the command stops with the 1.

What starts a deploy

Each deploy records its : the cause that started it.

TriggerCause
createYou create a service with a repository or an image. Add --no-deploy to prevent this deploy.
manualferry deploy, or Manual deploy in the dashboard.
uploadferry up sends a local folder.
webhookA push to the branch, when auto-deploy is on.
deploy_hookA request to the of the service: ferry deploy-hook show api prints its URL.
blueprintferry blueprint apply creates the service, or changes its build or deploy settings.
rollbackferry rollback, or Roll back to this deploy.
restartferry restart, or Restart service.
env_changeYou save variables with a restart: ferry env set, ferry env unset, or Save & restart.

A manual deploy builds the newest of the branch, pulls the Docker image again, or uses the last upload. It depends on the source of the service.

Terminal
ferry deploy api --commit <sha>     # build this exact commit (git services)
ferry deploy api --clear-cache      # build without the Docker cache

The steps of a deploy

StepWhat Ferry does
QueueThe deploy waits for its turn. A service runs one deploy at a time.
BuildFerry gets your code and makes an .
StartFerry starts new . The old instances continue to answer.
Health checkEach new instance must pass a test.
SwitchThe sends the traffic to the new instances. The deploy is live.
DrainFerry stops the old instances and removes them.

The same steps show in the . The lines that start with ==> come from Ferry:

Deploy log
==> Starting deploy dep-ba5a7fce730d4061aaa7 (trigger: upload)
==> Build successful ๐ŸŽ‰
==> Starting 1 instance(s)
==> Waiting for 1 instance(s) to become healthy: the port must accept TCP connections (timeout 120s)
==> Health check passed
==> Routing traffic to the new instance(s)
==> Stopping 1 old instance(s)
==> Your service is live ๐ŸŽ‰

If a step fails, Ferry removes the new instances. It does not touch the old instances. Your service stays online.

See the deploys of a service

Terminal
ferry deploys api                                  # the 20 newest deploys (-n for more)
ferry logs --deploy dep-ba5a7fce730d4061aaa7 -f    # the log of one deploy
ID                         STATUS          TRIGGER      COMMIT   CREATED   DURATION
dep-fad68a5ea71b43ae9820   live            upload       -        7m ago    2s
dep-d21d077ff8464b4a9501   deactivated     manual       -        11m ago   2s
dep-ca4bc7b5862742959b70   deploy_failed   upload       -        17m ago   1s
โœ— dep-ca4bc7b5862742959b70: instance d1c6b8 crashed (exit code 1)
StatusMeaning
queued, building, deployingThe deploy is in progress.
liveThe deploy gets the traffic. A service has one live deploy at most.
deactivatedThe deploy was live. A newer deploy replaced it.
build_failedFerry could not get the source, or could not build or pull the image.
deploy_failedThe image is good, but the new instances did not become healthy.
canceledYou canceled it, or a newer deploy in the queue replaced it.

The cause of a failure is at the end of the list. In the dashboard, open the deploy from the Deploys page and read the Why it failed box.

Health checks

A is the test that a new instance must pass before it gets traffic. Ferry tests each new instance one time each second.

ServiceTest
Web, private or static, with a health check pathGET <path> must answer with a status below 400.
Web, private or static, with no pathThe port must accept a TCP connection and keep it open.
Background workerThe process must run for 5 seconds.

Set a path for a better test. Make an endpoint only for this test. It must answer quickly when the app is ready.

Terminal
ferry update api --health /healthz

In the dashboard, use Health check path in the settings of the service. The path applies at the next deploy.

When the health check fails

If no good answer comes before the timeout (120 seconds), the deploy gets the status deploy_failed. Ferry removes the new instances, and the old instances continue to answer. To find the cause, read the deploy log:

  • Each 10 seconds, the log tells you why an instance is not healthy.
  • If an instance stops during the test, the deploy fails immediately. Ferry copies the last 50 lines of its output into the log.
  • If an instance uses too much memory, the error is instance ab12cd ran out of memory (limit 512 MiB) โ€” raise the service's memory limit.

A frequent cause is an app that listens on 127.0.0.1 or on a different port. Your app must listen on 0.0.0.0 and on the port in PORT. The log shows the port that Ferry chose:

Deploy log
==> Using port 8000 (EXPOSEd by the image)

To give a slow app more time, start ferryd with --health-check-timeout. After the deploy, Ferry does not use the health check path again.

The zero-downtime switch

Your serverBrowserProxyOld instanceversion 1New instanceversion 2

The old instance answers the requests.

1 / 5

With , your app answers during the full deploy. The proxy moves the traffic in one step, after all the new instances pass their health check. The previous live deploy becomes deactivated.

Then Ferry stops the old instances. For a web service or a static site, Ferry first waits 2 seconds for the requests in progress. Then each old instance has 10 seconds to stop.

A service with a disk stops during a deploy

A service with a has one instance. Ferry stops the old instance before it starts the new instance. Thus the service is offline for a short time.

Redeploy or restart

To build your code again, run ferry deploy. To start new instances from the live image with the current settings and variables, run ferry restart. A restart builds nothing, and it also has zero downtime.

Terminal
ferry restart api --follow

A live deploy keeps a of its settings. Thus a change applies only at the next deploy or restart:

You changeIt applies
Variables (ferry env set, ferry env unset)Immediately: Ferry restarts the service. With --no-restart, Ferry only saves them.
Build and deploy settings (ferry update)At the next deploy. If no build is necessary, run ferry restart.
Memory and CPU limitsAt the next deploy or restart.
The number of instances (ferry scale)Immediately.

You cannot restart a service that has no live deploy and no deploy in progress. Deploy it first.

Roll back to a previous deploy

A is a new deploy that uses the image of an earlier deploy. Ferry builds nothing.

Terminal
ferry deploys api                                      # find the id of a good deploy
ferry rollback api dep-3493c505ea9b4415b359 --follow

In the dashboard, open Deploys. In the menu of a deploy, choose Roll back to this deploy.

  • You can roll back only to a deploy with the status live or deactivated. A failed or canceled deploy was never live.
  • A rollback gives you the old code. The instances start with the current settings and variables.
  • Ferry keeps the 5 newest images of each service, and the live image. To keep more, start ferryd with --keep-images.

If Ferry removed the image, the rollback fails and shows the cause. Then deploy from the source again.

Cancel a deploy

Terminal
ferry cancel dep-7d2d938ff3614c238ecb

You can cancel a deploy until the proxy sends traffic to the new version. The dashboard has a Cancel deploy button on the page of the deploy.

The deploy isA cancel
queuedCancels the deploy immediately.
buildingStops the build.
deploying, before the switchRemoves the new instances. The old instances continue to answer.
After the switchFails. The deploy is live. Roll back to undo it.
Deploy log
==> Build canceled
==> Deploy canceled: canceled by user
Too late
error: too late to cancel: traffic was already switched to deploy dep-817fc76633764f7181c0 (roll back to undo it) (conflict)

A new deploy also cancels the older deploys of the same service that wait in the queue.

On this page