We created this GitHub action to be able to have zero-downtime rolling updates of our Linux-based clusters running ASP.NET Core applications.
The target application is assumed to be using systemd to run, as shown here.
The service definition MUST include WorkingDirectory and define the ASPNETCORE_URLS environment variable, so that the action can test that the service came back online. If this is not desired, you can set healthcheck: false.
The execution flow is:
- Connect to host.
- If
fingerprintsare set, verify them, or fail. - Transfer the built files from
sourceto/tmp/{serviceName}.{github.run_number}.{gitub.run_attempt}using a tgz archive. - If the service is running, stop it.
- Delete
{WorkingDirectory}.last, if it exists. - Move
{WorkingDirectory}to{WorkingDirectory}.last, if it exists. - Extract the tgz file to
{WorkingDirectory}. - Set permissions and ownership to
{WorkingDirectory}. - Start service.
- Probe the first binding found, path
/api/healthfor a200status code, every 1 sec for 1 min.
If probing is successful, the next host is updated.
If probing fails until the end of the tries, then a rollback is initiated for all hosts that succeeded and the host that was being updated when the failure occurred:
- If
{WorkingDirectory.last}does not exist, abort. - If the service is running, stop it.
- Delete
{WorkingDirectory}. - Move
{WorkingDirectory}.lastback to{WorkingDirectory}. - Start service.
- Probe the first binding found, path
/api/healthfor a200status code, every 1 sec for 1 min.
If the rollback fails to get a healthy response, the action fails.
[Unit]
Description=App service
[Service]
WorkingDirectory=/opt/my-app
ExecStart=/usr/bin/dotnet /opt/my-app/My.App.dll
SyslogIdentifier=my-app
User=my-app
Restart=always
RestartSec=5
KillSignal=SIGINT
AmbientCapabilities=CAP_NET_BIND_SERVICE # only needed if binding to ports less than 1024
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
Environment=ASPNETCORE_URLS=http://*:5000
[Install]
WantedBy=multi-user.target
EOT
...
- uses: zerotomvp/rolling-systemd-update@v1-alpha.17
with:
serviceName: my-app
hosts: host1,host2,host3
key: ${{ secrets.DEPLOY_OPENSSH_KEY }}
source: my-app/publish