Weather Station – Docker configuration

docker-compose

As I wrote in my previous article, it came time to describe building and running process of my whole Weather Station application. My solution is based on Docker and Docker Compose which is running on Raspberry Pi 4. So let’s start from beginning and clone my repository.

Building frontend application

After cloning repository you have to install all necessary dependencies. Next you have to build common libraries and finally you can build main application. You can read about it in this article.

cd app

npm ci

npm run build:core
npm run build:weather-stations

npm build

After that in directory /dist/app you should see compiled application to JavaScript files.

Building backend application

As you know from my previous articles my backend application contains two services:

  • MQTT – listen on different events from my Weather Station devices
  • WEB – is responsible for serving frontend application and necessary API

So let’s go to building above applications:

cd server

npm ci

npm run build:weather-stations-module

npm run build:weather-stations-subscriber
npm run build:weather-stations-microservice

These above commands will build common wheater-station module and than it will build MQTT and WEB service. All produced files will be write in below directories:

  • /server/dist/apps/weather-stations-subscriber – server MQTT
  • /server/dist/apps/weather-stations-microservice – server WEB

In both directories you can find files:

  • main.js – application file
  • package.json – all necessary dependiences

Docker Compose

We build all kind of applications, so now we are ready to compose our environment. To do that I used Docker and Docker Compose, which allows me to create config YAML file containing three containers:

  • database
  • MQTT service
  • WEB service

Depends on what kind of architecture you use, you have to find matching version of each container image. In my case I use configuration for Raspberry Pi 4 with Ubuntu Server on which I have installed Docker and Docker Composer.

Database

version: '2.4'
services:
  database:
    container_name: ws-database
    image: webhippie/mariadb
    environment:
      - TZ=Europe/Warsaw
      - MARIADB_ROOT_PASSWORD=password
      - MARIADB_DATABASE=database_name
      - MARIADB_USERNAME=username
      - MARIADB_PASSWORT=password
    restart: always
    volumes:
      - ./mysql/conf.d:/etc/mysql/conf.d
      - ./mysql/mysql:/var/lib/mysql
      - ./mysql/backup:/var/lib/backup
    expose:
      - 3306
    ports:
      - 3308:3306
    mem_limit: 512m
    mem_reservation: 256m

Database container is based on webhippie/mariadb and you need to set some configuration:

  • container_name – it is very important, because it allows other container to communicate with it directly
  • environment (time zone, database name, database user name, database user password)
  • volumes – here you need add links between container directories and host directories to store database files on host machine (to not lose them during restart container)
  • expose and forward ports – you have to expose default MySQL ort 3306 and redirect it to some port on host machine, in that case it is 3308
  • memory limits – because of Raspberry Pi have only 4GB RAM, you have to limit memory for each container to protect your host machine before memory leak), for this container I set that memory usage could be between 256MB and 512MB.

Additional docker image for Node.js applications

As we know from previous part of this article my WEB server needs to be run as Node.js application also it needs to install some dependencies which can change in time. So I decided to create my own image which prepare environments and allows to run some script inside the container.

To do that I use balenalib/raspberrypi4-64-debian-node:latest image and modify it a bit. I create a Dockerfile as below.

FROM balenalib/raspberrypi4-64-debian-node:latest

WORKDIR /usr/src/app

COPY ./start-app.sh /usr/local/bin

RUN npm -v
RUN /bin/bash -c "node -v"

EXPOSE 8080

The first line of that file is reponsible for downloading an image which will be the base of my image. After that we create inside container working directory /usr/src/app (in the future we will link here our application). Next step is to copy start-app.sh script.

#!/usr/bin/env bash
echo "install npm ..."
npm i
node main.js

This script as you can see is very simple. Its main responsibility is to install npm dependencies and run application using main.js file.

So let’s back to our Dockerfile. Next two steps displays current version of npm and node installed inside the container, but the last line is very important. It exposes container port 8080 and we are able to call some service from the container which is listen on that port. As you probably know on that port is running MQTT and WEB service.

Generally that is all, now we are able to create our image and register it under node-web-app.

docker build -t node-web-app ./

From that moment we can use this image in all ours projects.

Server WEB

If we have our node-web-app image created we are able to prepare second container configuration – that’s time will be WEB server.

api:
    container_name: ws-api
    image: node-web-app:latest
    environment:
      - TZ=Europe/Warsaw
    volumes:
      - ./www/api/:/usr/src/app
    ports:
      - 8080:8080
    links:
      - "database:database"
    command:
      - start-app.sh
    mem_limit: 256m
    mem_reservation: 128m

As it was previously that this time we need to set up some configuration

  • environment – this time only time zone is necessary
  • volumes – I think it is most important thing, because we link our lokal directory with our build application with working directory inside container where will be run script start-app.sh.
  • ports – we map container 8080 port to our host machine port 8080
  • links – we set link to our database container as “database” so our ws-api container will be able to access to database container using hostname “database”
  • commands – we set command wchich should be run after the container will be up
  • memory – as previously in database container we set memory limits, but this time it is twice time less

MQTT Server

MQTT server configuration is almost the same as WEB server.

  mqtt:
    container_name: ws-mqtt
    image: node-web-app:latest
    environment:
      - TZ=Europe/Warsaw
    volumes:
      - ./www/mqtt/:/usr/src/app
    ports:
      - 8081:8080
    links:
      - "database:database"
    command:
      - start-app.sh
    mem_limit: 256m
    mem_reservation: 128m

The difference is only in volumes map and ports forwarding.

So our whole docker-compose.yaml file is presents as below:

version: '2.4'
services:
  database:
    container_name: ws-database
    image: webhippie/mariadb
    environment:
      - TZ=Europe/Warsaw
      - MARIADB_ROOT_PASSWORD=password
      - MARIADB_DATABASE=database_name
      - MARIADB_USERNAME=username
      - MARIADB_PASSWORT=password
    restart: always
    volumes:
      - ./mysql/conf.d:/etc/mysql/conf.d
      - ./mysql/mysql:/var/lib/mysql
      - ./mysql/backup:/var/lib/backup
    expose:
      - 3306
    ports:
      - 3308:3306
    mem_limit: 512m
    mem_reservation: 256m

  api:
    container_name: ws-api
    image: node-web-app:latest
    environment:
      - TZ=Europe/Warsaw
    volumes:
      - ./www/api/:/usr/src/app
    ports:
      - 8080:8080
    links:
      - "database:database"
    command:
      - start-app.sh
    mem_limit: 256m
    mem_reservation: 128m

  mqtt:
    container_name: ws-mqtt
    image: node-web-app:latest
    environment:
      - TZ=Europe/Warsaw
    volumes:
      - ./www/mqtt/:/usr/src/app
    ports:
      - 8081:8080
    links:
      - "database:database"
    command:
      - start-app.sh
    mem_limit: 256m
    mem_reservation: 128m

The structure of our Docker directory should be:

  • docker-composer.yaml – containers configuration
  • www/mqtt – directory with MQTT compiled applications
  • www/api – directory with WEB compiled application
  • www/api/app – directory with frontend compiled application
  • mysql/mysql – directory for database files

That is all, now you need to run only bellow command

docker-compose up -d

and our application should be available on ports 8080 and 8081.

Summary

This kind of solutions has few benefits:

  • it is easy to set up
  • it is safe for any problems with image container
  • it is easy to upgrade (both containers and applications)
  • it is easy to move to other location (host machine)

If you have any questions, doubts do not hesitate to contact me via email or comments below.

Weather Station – Docker configuration
Scroll to top