The nem-docker is a Docker configuration with accompanying helper scripts published on GitHub. It is one of the easiest solutions to securely deploy and keep a NEM node up to date. This blog post will explain its structure and how it was developed.
Running in a container brings benefits like isolation, but it also has some caveats. Some examples are a lack of permanent storage, a specific network setup, and no init system. This config and accompanying scripts help get you up and running with a minimum of fuss, and even follows strict best practice, like checking the hash of the downloaded NEM software (do you do that when installing manually? ;-)). Let's see how it works.
Two Ways of Running Docker
Before running a docker container, you first need to build an image for it. You can see this step as building the filesystem of the container. There are two ways of doing this. You can build the image locally, or you can download an image from Docker Hub.
Pulling the Image from Docker Hub
The NIS image is actually used by the Deploy on Azure scripts.
Each live in a specific git branch on GitHub (respectively named NIS and NCC). Both branches are based on a third branch named hub. Most changes take place in the hub branch, and the NIS and NCC branch only hold changes regarding which software needs to be started by default.
You can also build the image locally. The Docker config is held in the master branch on GitHub.
Building the image and running the container off of it is facilitated by the helper scripts is possible. This is actually the best-tested deployment method, and it is recommended that you do it this way.
Building the image
We will focus our attention on the locally built image because the repo holding the Dockerfile also includes sample config files, but differences with the images published on Dockerhub are minimal. For information on how to download the image, see the section below about "Running with Dockerhub images".
To run a Docker container, you first need to describe the image it will run off. This is done in the file name Dockerfile.
It then proceeds by adding a nem user and creating some directories where the NEM software data will be stored.
The servant is also downloaded and installed, making this config suitable to run a supernode.
Docker is made to run one command per container. To work around this, which is needed if you want to run a supernode, the command run in our container is supervisord, which will control what software to run in the container.
Following this, the Dockerfile announces which ports the container will listen on and then indicates which command will be run by the container.
Running the container
Now that we have built the image, we can run the container with the command
sudo docker run. However, there are some important things you need to know first.
All changes done on the filesystem of the container are specific to that container. When you want to upgrade to the latest NEM version, you will build a new image, and start a new different container, which will not have the changes specific to the old container. When running NIS, that would mean re-downloading the whole blockchain every upgrade.
The solution to this is to use docker volumes. The best way to use this is to mount a directory from the host to the container. This lets you inspect the content of the directory as the container runs. This is simply done by using the flags
-v /path/to/host/dir:/home/nem/nem, as the NEM software data is saved in the container in
You certainly want to have custom configs passed to the NEM software running in the container. This is easily done because similarly to mounting a directory in the container, we can also mount an individual file in the container. It is just a matter of mounting the right config file at the right location in the container. Here are the config file locations in the container:
- NIS: /package/nis/config-user.properties
- NCC: /package/ncc/config-user.properties
- Servant: /servant/config.properties
- Supervisord: /etc/supervisord.conf
If you have a custom config located at
/home/tom/nis.xml, you can use it by passing the option
Software running in the container will open TCP ports. Mapping these container ports to the host’s ports is done by the
-p container_port:host_port flag passed to
For example, to map the NIS port, pass the option
-p 7890:7890 to docker run.
Let's now build our image and run a Docker container with NIS.
First, let's clone the repo:
git clone https://github.com/rb2nem/nem-docker.git
then build the image:
cd nem-docker/ sudo docker build -t nem_image .
After some time you should see the last line starting with
We will run NIS in the container, and we want it to start automatically when we run the container. For that we need to update the supervisord config:
cp custom-configs/supervisord.conf.sample custom-configs/supervisord.conf edit custom-configs/supervisord.conf
This last line opens the file in vim on my system, but you may replace the
edit command by your preferred editor. For beginners,
nano is very simple to use.
In the section
[program:nis] of that file, change the
autostart line to
autostart=true and save the file.
For demonstration purpose, I will store the NEM data in
/tmp/nem (do not do this for your production setup, choose a base directory other than
/tmpor you'll lose those files at your next reboot...). Create that directory...
All is now setup for running the container. To run NIS you need to publish port 7890 with
-p 7890:7890, mount the NEM data directory from the host with
-v "/tmp/nem:/home/nem/nem", and mount the custom supervisord config with
-v "$PWD/custom-configs/supervisord.conf:/etc/supervisord.conf". Note that mounting files and directories in a container requires passing absolute directories, hence the use of
$PWD. which is the current working directory. Lastly, name the container
nem. The full command is:
sudo docker run -d -p 7890:7890 \ -v "/tmp/nem:/home/nem/nem" \ -v "$PWD/custom-configs/supervisord.conf:/etc/supervisord.conf" \ --name nem \ nem_image
-d runs the container as a daemon, giving you the shell command prompt back.
The container will change the owner of the
nem directory to the
nem user in the container, which has user id 1000, and it will give read, write and execute to the group of said directory. This should let go in the directory even if your user id is not 1000 on the host.
After a couple of seconds you should be able to request the running NIS on port 7890 of your localhost with this command (install curl on your host if needed, or use a web browser):
If you receive an error like this one:
curl: (56) Recv failure: Connection reset by peer
If is probably because NIS is still starting up. When NIS is up, you get this response:
Code 5 means
The local node is booted (implies NIS is running).. You can check the meaning of other codes.
If you don’t get a successful answer even after a couple of minutes, you can check the NIS logs in the file
When NIS is runnig,
curl http://localhost:7890/node/infogives you info about your node.
You can now safely stop and remove the container:
sudo docker stop nem sudo docker rm nem
Because no data is stored in the container, it can be safely removed. Next time you want to run it you issue the exact same
sudo docker run command, and it will start nearly immediately as it uses cached data to create the container and use the blockchain it has already downloaded.
Running with Docker Hub Images
Here are the commands to do the same as above using images published on Dockerhub rather than building your own.
As the rb2nem/nis image is configured to start NIS automatically, you don't have to change the supervisord config:
mkdir /tmp/nem sudo docker run -d -p 7890:7890\ -v "/tmp/nem:/home/nem/nem" \ --name nem \ rb2nem/nis
However, you still might want to override the default config files used in the container. To get the sample config file, just check out the repo and look under the
git clone https://github.com/rb2nem/nem-docker.git
Remember that in those sample configs, no service is autostarted. Don't forget to change the
An Easier Way?
We've seen how we can run NEM in a Docker container, but it requires running cumbersome commands. Couldn't we make it easier to use by using a script passing all these parameters as needed? Of course we can! The good news is that those scripts exist. We'll take a look at them in the next post covering NEM in a docker container.
The NEM Team would like to thank RB2 for contributing this blog.