Getting Started

Getting Started on the Raspberry Pi 3 B/B+

In resinOS all application logic and services are encapsulated in Docker containers. In this getting started guide we will walk you through setting up one of our pre-built development OS images and creating a simple application container. In the guide we will use the resin CLI tool to make things super easy. However, for those that like to do things the hard way, we got you covered as well.

Download an Image

To get a resinOS device setup, we will first need to flash a system image on to the device, so head over to resinos.io and grab the development OS for your board. Currently resinOS supports 20 different boards and several different architectures. See the Supported Boards section for more details.

Once the download is finished, make sure to decompress it and keep it somewhere safe, we will need it very soon!

$ wget$device.download_url

Install the Resin CLI

The resin cli, is a collection of utilities which helps us to develop resinOS based application containers. It’s not strictly necessary, but makes life so so much sweeter, but if you like doing things the hard way, skip over to the next section.

Currently the CLI is a node.js based command line tool which requires that our system has the following dependencies installed and in our path:

Note: Depending on you node.js installation, you may need to use administrative privileges to install the CLI.

Configure the Image

To allow resinOS images to be easily configurable before boot, some key config files are added to boot partition. In this step we will use the CLI to configure the network, set our hostname to resin and disable persistent logging, because we don’t want to kill our poor flash storage with excessive writes.

If you only want to use an ethernet connection on your device, you don't need to add anything. The device will automatically set up an ethernet connection by default.

Get the Device Up and Running

Okay, so now we have a fully configured image ready to go, so let’s burn and boot this baby. For this step the CLI provides a handy flashing utility, you can however flash this image using etcher.io or dd if you must.

Flash SD card

To get flashing, just point the resin local flash command to the image we just downloaded and follow the prompts. If you hate prompts, the CLI also allows you to skip them, check the resin CLI docs on how to do this.

NOTE:resin local flash requires administrative privileges because it needs to access the SD card.

$ sudo resin local flash ~/Downloads/resin.img
Password:
x No available drives were detected, plug one in!

Once you plug in your SD card, the CLI should detect it and show you the following selection dialog. Make sure to select the correct drive if you have a few listed, as this will completely write over the drive.

Once you are happy you have selected the correct drive, hit enter and wait while your new OS is written to the drive.
It should only take about 3 minutes, depending on the quality of your drive, so this is a great time to go grab a caffeinated beverage.

Running your first Container

Clone a demo Project

Get a Container Running

$ sudo resin local push resin.local --source .

This command will use the image specified by the Dockerfile in the root of your project directory (--source specifies where to find your project). The build of this image will happen on your resinOS device and once completed, the command will start up a container from that newly built image. For more details look at the Creating a Project from Scratch section below.

Poking Around resinOS

To help explore resinOS devices and application containers more easily, the resin CLI has an ssh command which will help you connect either to the HostOS or a running container on the device.

Going Further

Advanced Settings

Alternatively you can add “persistentLogging”: true to config.json in your boot partition of the SD card.

To Enable persistent logs in a running device, add “persistentLogging”: true to /mnt/boot/config.json and reboot.

The journal can be found at /var/log/journal/ which is bind mounted to root-overlay/var/log/journal in the resin-conf partition.
When logging is not persistent, the logs can be found at /run/log/journal/ and this log is volatile so you will loose all logs when you power the device down.

Creating a Project from Scratch

Alright! So we have an awesome container machine up and running on our network. So let’s start pushing some application containers onto it. In this section we will do a quick walk through of setting up a Dockerfile and make a simple little node.js webserver.

To get started, let’s create a new project directory called “myapp” and create a new file called Dockerfile.

$ mkdir -p myapp &&touch Dockerfile

Now we will create a minimal node.js container based on the slim Alpine Linux distro. We do this by adding the following lines to our Dockerfile.

The FROM tells Docker what our container will be based on. In this case an Alpine Linux userspace with just the bare essentials needed for the node.js runtime. The CMD just defines what our container runs on startup. In this case, it’s not very exciting yet.

Now to get our application running on our device we can use the resin local push functionality.

This command will discover your resinOS-dev device on the network and start a build of whatever you have in the --source directory. In the example above, we have just told it to build from the root of the directory we are in, in this case myapp.

A number of things have happened in this step, so let’s pause here and dig in a little more. When we first run resin local push we are asked to define a name for our app and after that, it starts a Docker build on your device. At the same time, the CLI has added a file to our project called .resin-sync.yml which stores all the project defaults. Let’s have a quick look at that:

We can see that for our local resinOS device we have an app called “myapp” which will map over to a Docker image and container on our device. The next interesting section is build-triggers. This is a list of files and their hashes, which will result in a Docker build. In our case it’s just the Dockerfile, so when we change things here, the CLI will rebuild our app. This will be important a bit later.

So now that we are building, let’s start adding some actual code! We will just add main.js file in the root of our myapp directory.

//main.js
console.log("Hey… I’m a node.js app running in a container!!");

We then make sure our Dockerfile copies this source file into our container context by replacing our current CMD [“cat”,”/etc/os-release”] in our Dockerfile with the following.

This puts all the contents of our myapp directory into /usr/src/app in our running container and says we should start main.js when the container starts.

Alright, so we have a simple javascript container, but that’s pretty boring, let’s add some dependencies and complexity. To add dependencies in node.js we need a package.json, the easiest way to whip up one is to just run npm init in the root of our myapp directory. After a nice little interactive dialog we have the following package.json in directory.

Great, so now we are almost ready to go, but we want to make sure anytime we add a dependency to our package.json that we rebuild the container and install those dependencies. So to do this we need two things.

1.) We need to add package.json to our build triggers list, with an empty hash, like this:

NOTE: Add node_modules to your .dockerignore file, otherwise your local modules might be copied to the device with the above Dockerfile, and they are likely the wrong architecture for your application!

We can now deploy our new webserver container again with:

$ sudo resin local push -s .

You should now be able to point your web browser on your laptop to the IP address of your device and see the "Hello, World!" message.