Octopus enjoying a Raspberry Pi

Deploy .NET Core applications to a Raspberry Pi with Octopus

Ben Pearce

Octopus enjoying a Raspberry Pi

Update February 2020
Out of the box support for Linux ARM and Linux ARM64 SSH targets was included in Octopus Server 2019.11.2 and 2020.2.0, respectively.

This post was originally published in February 2018, but a few things have changed since, and this is an updated version of the original post.

.NET Core has come a long way in the last few years, and Octopus Deploy has too. We recently added support for running Calamari without Mono, and in this post I will you through how to deploy .NET Core applications on to a Raspberry Pi 3+ without Mono.

In this post, I will show you that it is possible to deploy and run .NET Core applications on the Raspberry Pi 3+, and I'll also describe some of the different ways you can interact with your Octopus Deploy server.

Requirements before you start

ASP.NET includes NodeServices in its bundle, which requires Node to be installed before it can serve any requests. When you install Node.js on the Raspberry Pi, it installs version 4.x and the executable is called nodejs, but NodeServices is looking for node in your path. You can fix this by creating a symlink:

sudo ln -s /usr/bin/nodejs /usr/bin/node

Build the application

Create a basic .NET Core application

dotnet new angular

Modify the application to listen for external requests

By default, an ASP.NET Core application will only serve requests to http://localhost:5000. To allow the web host to serve requests to your local network, add the following after the .UseStartup<Startup>() in Program.cs:

.UseKestrel(options => {
    options.Listen(System.Net.IPAddress.Any, 5000);
})

For more information on configuring the Kestrel Web Host, check the docs.

Build the application

npm install
dotnet build
mkdir publish
dotnet publish -o publish --self-contained -r linux-arm

replace linux-arm with linux-arm64 if you are targeting a distribution which supports 64-bit on the Raspberry Pi

Package the application

The simplest way to create a package of a .NET Core application is using the Octopus CLI tool.

Create an artifacts directory and then use the octo pack command to create the package:

mkdir artifacts
octo pack --id core4pi --version 1.0.0 --format zip --outFolder artifacts --basePath publish

Using the Octopus CLI again, push the package to the server:

octo push --server http://octopus/ --apikey API-ABCDEF123456 --package artifacts\core4pi.1.0.0.zip

Building a service definition

To get the application to run as a service, see Microsoft’s documentation for hosting .NET Core on Linux.

Create a file called core4pi.service containing the following text:

[Unit]
Description=core4pi

[Service]
WorkingDirectory=#{Octopus.Action[deploy web site].Output.Package.InstallationDirectoryPath}
ExecStart=/usr/local/bin/dotnet "#{Octopus.Action[deploy web site].Output.Package.InstallationDirectoryPath}/core4pi.dll"
Restart=always
RestartSec=10
User=pi
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

The [deploy web site] strings in the core4pi.service text above, represents the name of the step that deploys the package.
This output variable will contain the path to the newly installed service. This will ensure when the service is installed it is looking at the latest version.

Create a package for the service definition and push it to the Octopus Server:

octo pack --id core4pi.service --version 1.0.0 --format zip --outFolder artifacts
octo push --server http://octopus/ --apikey API-ABCDEF123456 --package artifacts\core4pi.service.1.0.0.zip

Create infrastructure

If you don't already have an Octopus environment configured for your Raspberry Pi, create one either at the command line:

octo create-environment --server http://octopus/ --apikey API-ABCDEF123456 --name "Pi Dev"

Or using the web interface via Infrastructure ➜ Environments ➜ Add Environments.

Next, create an account to access the Pi, this can either be a Username/Password account or an SSH Key in the **Infrastructure ➜ Accounts**section in the Octopus web portal.

Finally, create a deployment target under Infrastructure ➜ Deployment Targets ➜ Add Deployment Target as an SSH target.

Set the targets role to something that represents the responsibility of the target, e.g, PiWeb.

After adding the details (IP Address or DNS name, SSH port, and account), under the .NET section, ensure you select Mono not installed, and select linux-arm or linux-arm64 as the platform.

Create the deployment project

Create a new project via the Projects section in the Octopus web portal or with the command line:

octo create-project --server http://octopus/ --apikey API-ABCDEF123456 --name "PiWeb" --projectgroup "All projects" --lifecycle "Default Lifecycle"

Create a deployment step for the application

In the new PiWeb project, define your deployment process.

Add a Deploy a Package step, called deploy web site.

The step name here will allow the values in the service definition file to be updated correctly.

Set the Environment to the Pi Dev environment.

Set the Role to the PiWeb role.

Under the Package section, select the package you pushed to the server: core4pi.

We don't need to complete the other options so save the step.

Create a deployment step for the service definition

Add another Deploy a Package step. This one will install a service on the target to run the application.

For the package selection, select the core4pi.service package from the Octopus Server (built in) package feed.

You will need to Configure Features for this step:

In the Substitute Variables in Files feature add the name of the service definition file core4pi.service:

Under the Configuration Scripts feature, select Bash, paste the script below into the Deployment Script section:

#!/bin/bash
if [ -e /lib/systemd/system/core4pi.service ]
then
    echo stopping service
    sudo systemctl stop core4pi.service
fi

echo installing service
sudo cp core4pi.service /lib/systemd/system/
sudo chmod 644 /lib/systemd/system/core4pi.service
sudo systemctl daemon-reload
sudo systemctl enable core4pi.service
echo starting service
sudo systemctl start core4pi.service

This script performs the service installation and will be executed during the step execution. It will require the user you are using to connect to the Raspberry Pi to have sudo rights.

Deploy it

From the Project navigation menu, select Create Release.

The Create Release page will allow you to set a version number for the release, you can just leave the default. It will also allow to pick which versions of the packages you want to deploy, by default it will pick the latest version.

Press Save and then press Deploy to PI Dev and then Deploy to start the deployment process.

Create Release can also be performed from the command line:

octo create-release --server http://octopus/ --apikey API-ABCDEF123456 --project "PiWeb"
octo deploy-release --server http://octopus/ --apikey API-ABCDEF123456 --project "PiWeb" --deployto="Pi Dev" --version "0.0.1"

The first time you deploy, Octopus Server will update Calamari on the target machine, this may take a couple of minutes.

Test it

After the deployment has finished, navigate to the IP address or DNS name of your Raspberry Pi on port 5000, and you should see the application:

Conclusion

With the alignment of a number of different technologies, deploying .NET to a Raspberry Pi is supported, and Octopus Deploy makes it painless. Throughout this post, you have also seen a number of different ways that you can integrate with your Octopus Server, including the command line and the web portal.

Loading...