This article gives an example of how to deploy MQTT Client, Broker, Publisher and the correspoding database.

Basic

docker ps --filter "status=exited"
docker ps -a grep 
docker inspect  --format='{{.State.ExitCode}}'

Docker Compose Exit Code

  • Exit Code 0: Absence of an attached foreground process
  • Exit Code 1: Indicates failure due to application error
  • Exit Code 137: Indicates failure as container received SIGKILL (Manual intervention or ‘oom-killer’ [OUT-OF-MEMORY])
  • Exit Code 139: Indicates failure as container received SIGSEGV
  • Exit Code 143: Indicates failure as container received SIGTERM

Makefile

  1. sample example fromMakefile

Makefile

# import config.
# You can change the default config with `make cnf="config_special.env" build`
cnf ?= config.env
include $(cnf)
export $(shell sed 's/=.*//' $(cnf))

# import deploy config
# You can change the default deploy config with `make cnf="deploy_special.env" release`
dpl ?= deploy.env
include $(dpl)
export $(shell sed 's/=.*//' $(dpl))

# grep the version from the mix file
VERSION=$(shell ./version.sh)


# HELP
# This will output the help for each task
# thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.PHONY: help

help: ## This help.
    @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.DEFAULT_GOAL := help


# DOCKER TASKS
# Build the container
build: ## Build the container
    docker build -t $(APP_NAME) .

build-nc: ## Build the container without caching
    docker build --no-cache -t $(APP_NAME) .

run: ## Run container on port configured in `config.env`
    docker run -i -t --rm --env-file=./config.env -p=$(PORT):$(PORT) --name="$(APP_NAME)" $(APP_NAME)


up: build run ## Run container on port configured in `config.env` (Alias to run)

stop: ## Stop and remove a running container
    docker stop $(APP_NAME); docker rm $(APP_NAME)

release: build-nc publish ## Make a release by building and publishing the `{version}` ans `latest` tagged containers to ECR

# Docker publish
publish: repo-login publish-latest publish-version ## Publish the `{version}` ans `latest` tagged containers to ECR

publish-latest: tag-latest ## Publish the `latest` taged container to ECR
    @echo 'publish latest to $(DOCKER_REPO)'
    docker push $(DOCKER_REPO)/$(APP_NAME):latest

publish-version: tag-version ## Publish the `{version}` taged container to ECR
    @echo 'publish $(VERSION) to $(DOCKER_REPO)'
    docker push $(DOCKER_REPO)/$(APP_NAME):$(VERSION)

# Docker tagging
tag: tag-latest tag-version ## Generate container tags for the `{version}` ans `latest` tags

tag-latest: ## Generate container `{version}` tag
    @echo 'create tag latest'
    docker tag $(APP_NAME) $(DOCKER_REPO)/$(APP_NAME):latest

tag-version: ## Generate container `latest` tag
    @echo 'create tag $(VERSION)'
    docker tag $(APP_NAME) $(DOCKER_REPO)/$(APP_NAME):$(VERSION)

# HELPERS

# generate script to login to aws docker repo
CMD_REPOLOGIN := "eval $$\( aws ecr"
ifdef AWS_CLI_PROFILE
CMD_REPOLOGIN += " --profile $(AWS_CLI_PROFILE)"
endif
ifdef AWS_CLI_REGION
CMD_REPOLOGIN += " --region $(AWS_CLI_REGION)"
endif
CMD_REPOLOGIN += " get-login --no-include-email \)"

# login to AWS-ECR
repo-login: ## Auto login to AWS-ECR unsing aws-cli
    @eval $(CMD_REPOLOGIN)

version: ## Output the current version
    @echo $(VERSION)

version.sh

# Example version script.
# Please choose one version or create your own

# Node.js: grep the version from a package.json file with jq
jq -rM '.version' package.json

# Elixir: grep the version from a mix file
cat mix.exs | grep version | grep '\([0-9]\+\.\?\)\{3\}' -o

Dockerfile and Docker-compose

docker-compose.yml

version: "3.9"

services:
  mqtt_client:
    build: 
      context: services/mqtt_client/.
    env_file:
      - ./env.dev
  broker:
    build: services/development_broker/.
    ports:
      - "1883:1883"
  db:
    image: postgres:12-alpine
    ports:
      - "5432:5432"
    volumes:
        - db-data:/var/lib/postgresql/data/
    environment:
        - POSTGRES_USER=test
        - POSTGRES_PASSWORD=test
        - POSTGRES_DB=test
  s3:
    image: minio/minio
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - s3-data:/data
    environment: 
      - MINIO_ROOT_USER=develop
      - MINIO_ROOT_PASSWORD=develop1
    entrypoint: minio server /data  --console-address ":9001"

volumes:
  s3-data:
  db-data:

env.dev

DATABASE_URL=postgresql://test:test@db:5432

MQTT_BROKER_URL=broker
MQTT_TOPIC=raw-frames

S3_URL=s3:9000
S3_ACCESS_KEY=develop
S3_SECRET_KEY=develop1
S3_BUCKET_NAME=raw-frames
S3_FORCE_SSL=False

Dockerfile-MQTT CLient

FROM python as intermediate
RUN git clone https://gitlab+deploy-token-819163:soMJjpdajTYA51PAThqG@gitlab.com/incoretex/libraries/pycoretex.git
RUN cd /pycoretex && git checkout 5-package

FROM python
COPY --from=intermediate /pycoretex /src/pycoretex
RUN (cd /src/pycoretex && pip3 install .)
COPY src/* /src/app/
WORKDIR /src/app/
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD python3 client.py

requirement.txt

boto3==1.21.0
botocore==1.24.0
certifi==2021.10.8
jmespath==0.10.0
minio==7.1.3
numpy==1.22.2
paho-mqtt==1.6.1
protobuf==3.19.4
psycopg2==2.9.3
python-dateutil==2.8.2
s3transfer==0.5.1
six==1.16.0
SQLAlchemy==1.4.31
urllib3==1.26.8

Dockerfile-MQTT Broker

FROM eclipse-mosquitto:2.0.14
COPY mosquitto.conf /mosquitto/config/mosquitto.conf

mosquitto.conf

allow_anonymous true
listener 1883
persistence true

to be continue ...