thingsboard-developers

Changes

docker/.env 25(+15 -10)

docker/cassandra/Makefile 10(+0 -10)

docker/cassandra-setup/Makefile 12(+0 -12)

docker/cassandra-upgrade/Makefile 12(+0 -12)

docker/cluster-mode-thirdparty.yml 45(+0 -45)

docker/k8s/cassandra.yaml 132(+0 -132)

docker/k8s/cassandra-setup.yaml 43(+0 -43)

docker/k8s/cassandra-upgrade.yaml 45(+0 -45)

docker/k8s/common.yaml 33(+0 -33)

docker/k8s/redis.yaml 93(+0 -93)

docker/k8s/tb.yaml 156(+0 -156)

docker/k8s/zookeeper.yaml 190(+0 -190)

docker/README.md 51(+51 -0)

docker/tb.env 26(+0 -26)

docker/tb/Makefile 12(+0 -12)

docker/tb/run-application.sh 59(+0 -59)

docker/zookeeper/Dockerfile 71(+0 -71)

docker/zookeeper/Makefile 10(+0 -10)

docker/zookeeper/zk-gen-config.sh 153(+0 -153)

msa/docker/.env 13(+0 -13)

msa/docker/docker-compose.yml 177(+0 -177)

msa/docker/tb-node.env 22(+0 -22)

msa/pom.xml 3(+2 -1)

msa/tb/pom.xml 370(+370 -0)

msa/tb/README.md 68(+68 -0)

msa/tb-node/pom.xml 69(+61 -8)

msa/web-ui/pom.xml 67(+59 -8)

Details

docker/.env 25(+15 -10)

diff --git a/docker/.env b/docker/.env
index e330632..17f8af8 100644
--- a/docker/.env
+++ b/docker/.env
@@ -1,13 +1,18 @@
-# cassandra environment variables
-CASSANDRA_DATA_DIR=/home/docker/cassandra_volume
 
-# postgres environment variables
-POSTGRES_DATA_DIR=/home/docker/postgres_volume
-POSTGRES_DB=thingsboard
+DOCKER_REPO=thingsboard
 
-# hsqldb environment variables
-HSQLDB_DATA_DIR=/home/docker/hsqldb_volume
+JS_EXECUTOR_DOCKER_NAME=tb-js-executor
+TB_NODE_DOCKER_NAME=tb-node
+WEB_UI_DOCKER_NAME=tb-web-ui
+MQTT_TRANSPORT_DOCKER_NAME=tb-mqtt-transport
+HTTP_TRANSPORT_DOCKER_NAME=tb-http-transport
+COAP_TRANSPORT_DOCKER_NAME=tb-coap-transport
 
-# environment variables for schema init and insert system and demo data
-ADD_SCHEMA_AND_SYSTEM_DATA=false
-ADD_DEMO_DATA=false
\ No newline at end of file
+TB_VERSION=latest
+
+# Database used by ThingsBoard, can be either local (local HSQLDB), postgres (PostgreSQL), cassandra (Cassandra).
+# In case of postgres or cassandra corresponding docker service will be deployed (see docker-compose.postgres.yml, docker-compose.cassandra.yml for details).
+
+DATABASE=cassandra
+
+KAFKA_TOPICS="js.eval.requests:100:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb.transport.api.requests:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb.rule-engine:30:1"
diff --git a/docker/compose-utils.sh b/docker/compose-utils.sh
new file mode 100755
index 0000000..02a8e39
--- /dev/null
+++ b/docker/compose-utils.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+function additionalComposeArgs() {
+    source .env
+    ADDITIONAL_COMPOSE_ARGS=""
+    case $DATABASE in
+        local)
+        ;;
+        postgres)
+        ADDITIONAL_COMPOSE_ARGS="-f docker-compose.postgres.yml"
+        ;;
+        cassandra)
+        ADDITIONAL_COMPOSE_ARGS="-f docker-compose.cassandra.yml"
+        ;;
+        *)
+        echo "Unknown DATABASE value specified: '${DATABASE}'. Should be either local, postgres or cassandra." >&2
+        exit 1
+    esac
+    echo $ADDITIONAL_COMPOSE_ARGS
+}
+
+function additionalStartupServices() {
+    source .env
+    ADDITIONAL_STARTUP_SERVICES=""
+    case $DATABASE in
+        local)
+        ;;
+        postgres)
+        ADDITIONAL_STARTUP_SERVICES=postgres
+        ;;
+        cassandra)
+        ADDITIONAL_STARTUP_SERVICES=cassandra
+        ;;
+        *)
+        echo "Unknown DATABASE value specified: '${DATABASE}'. Should be either local, postgres or cassandra." >&2
+        exit 1
+    esac
+    echo $ADDITIONAL_STARTUP_SERVICES
+}
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 89a8369..a319606 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -14,40 +14,167 @@
 # limitations under the License.
 #
 
-version: '2'
+
+version: '2.2'
 
 services:
+  zookeeper:
+    restart: always
+    image: "wurstmeister/zookeeper"
+    ports:
+      - "2181"
+  kafka:
+    restart: always
+    image: "wurstmeister/kafka"
+    ports:
+      - "9092:9092"
+    environment:
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+      KAFKA_LISTENERS: INSIDE://:9093,OUTSIDE://:9092
+      KAFKA_ADVERTISED_LISTENERS: INSIDE://:9093,OUTSIDE://kafka:9092
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
+      KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
+      KAFKA_CREATE_TOPICS: "${KAFKA_TOPICS}"
+      KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'false'
+      KAFKA_LOG_RETENTION_BYTES: 1073741824
+      KAFKA_LOG_SEGMENT_BYTES: 268435456
+      KAFKA_LOG_RETENTION_MS: 300000
+      KAFKA_LOG_CLEANUP_POLICY: delete
+    depends_on:
+      - zookeeper
+  tb-js-executor:
+    restart: always
+    image: "${DOCKER_REPO}/${JS_EXECUTOR_DOCKER_NAME}:${TB_VERSION}"
+    scale: 20
+    environment:
+      TB_KAFKA_SERVERS: kafka:9092
+    env_file:
+      - tb-js-executor.env
+    depends_on:
+      - kafka
   tb:
-    image: "thingsboard/application:2.1.0"
+    restart: always
+    image: "${DOCKER_REPO}/${TB_NODE_DOCKER_NAME}:${TB_VERSION}"
     ports:
-      - "8080:8080"
-      - "1883:1883"
-      - "5683:5683/udp"
+      - "8080"
+    logging:
+      driver: "json-file"
+      options:
+        max-size: "200m"
+        max-file: "30"
     env_file:
-      - tb.env
+      - tb-node.env
     environment:
-      - ADD_SCHEMA_AND_SYSTEM_DATA=${ADD_SCHEMA_AND_SYSTEM_DATA}
-      - ADD_DEMO_DATA=${ADD_DEMO_DATA}
+      ZOOKEEPER_URL: zk:2181
+      TB_KAFKA_SERVERS: kafka:9092
+      JS_EVALUATOR: remote
+      DATABASE_TS_TYPE: sql
+      DATABASE_ENTITIES_TYPE: sql
+      SQL_DATA_FOLDER: /usr/share/thingsboard/data/db
     volumes:
-      - "${HSQLDB_DATA_DIR}:/usr/share/thingsboard/data/sql"
-    entrypoint: /run-application.sh
-  cassandra:
-    image: "cassandra:3.11.2"
+      - ./tb-node/db:/usr/share/thingsboard/data/db
+      - ./tb-node/conf:/config
+      - ./tb-node/log:/var/log/thingsboard
+    depends_on:
+      - kafka
+  tb-mqtt-transport1:
+    restart: always
+    image: "${DOCKER_REPO}/${MQTT_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
     ports:
-      - "9042"
-      - "9160"
-    volumes:
-      - "${CASSANDRA_DATA_DIR}:/var/lib/cassandra"
-  zk:
-    image: "zookeeper:3.4.10"
+      - "1883"
+    environment:
+      TB_KAFKA_SERVERS: kafka:9092
+    env_file:
+      - tb-mqtt-transport.env
+    depends_on:
+      - kafka
+  tb-mqtt-transport2:
+    restart: always
+    image: "${DOCKER_REPO}/${MQTT_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
     ports:
-      - "2181"
+      - "1883"
+    environment:
+      TB_KAFKA_SERVERS: kafka:9092
+    env_file:
+      - tb-mqtt-transport.env
+    depends_on:
+      - kafka
+  tb-http-transport1:
     restart: always
-  postgres:
-    image: "postgres:9.6"
+    image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
     ports:
-    - "5432"
+      - "8081"
     environment:
-      - POSTGRES_DB=${POSTGRES_DB}
+      TB_KAFKA_SERVERS: kafka:9092
+    env_file:
+      - tb-http-transport.env
+    depends_on:
+      - kafka
+  tb-http-transport2:
+    restart: always
+    image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
+    ports:
+      - "8081"
+    environment:
+      TB_KAFKA_SERVERS: kafka:9092
+    env_file:
+      - tb-http-transport.env
+    depends_on:
+      - kafka
+  tb-coap-transport:
+    restart: always
+    image: "${DOCKER_REPO}/${COAP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
+    ports:
+      - "5683:5683/udp"
+    environment:
+      TB_KAFKA_SERVERS: kafka:9092
+    env_file:
+      - tb-coap-transport.env
+    depends_on:
+      - kafka
+  tb-web-ui1:
+    restart: always
+    image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}"
+    ports:
+      - "8080"
+    environment:
+      TB_HOST: tb
+      TB_PORT: 8080
+    env_file:
+      - tb-web-ui.env
+  tb-web-ui2:
+    restart: always
+    image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}"
+    ports:
+      - "8080"
+    environment:
+      TB_HOST: tb
+      TB_PORT: 8080
+    env_file:
+      - tb-web-ui.env
+  web:
+    restart: always
+    container_name: haproxy-certbot
+    image: nmarus/haproxy-certbot
     volumes:
-      - "${POSTGRES_DATA_DIR}:/var/lib/postgresql/data"
+     - ./haproxy/config:/config
+     - ./haproxy/letsencrypt:/etc/letsencrypt
+     - ./haproxy/certs.d:/usr/local/etc/haproxy/certs.d
+    ports:
+     - "80:80"
+     - "443:443"
+     - "1883:1883"
+     - "9999:9999"
+    cap_add:
+     - NET_ADMIN
+    environment:
+      HTTP_PORT: 80
+      HTTPS_PORT: 443
+      MQTT_PORT: 1883
+    links:
+        - tb-web-ui1
+        - tb-web-ui2
+        - tb-mqtt-transport1
+        - tb-mqtt-transport2
+        - tb-http-transport1
+        - tb-http-transport2

docker/README.md 51(+51 -0)

diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..e8fd55e
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,51 @@
+# Docker configuration for ThingsBoard Microservices 
+
+This folder containing scripts and Docker Compose configurations to run ThingsBoard in Microservices mode.
+
+## Installation
+
+Execute the following command to run DataBase installation:
+
+` 
+$ ./docker-install-tb.sh --loadDemo
+` 
+
+- `--loadDemo`              - optional argument. Whether to load additional demo data.
+
+## Running
+
+Execute the following command to run services:
+
+` 
+$ ./docker-start-services.sh
+` 
+
+Execute the following command to stop services:
+
+` 
+$ ./docker-stop-services.sh
+` 
+
+Execute the following command to stop and completely remove deployed docker containers:
+
+` 
+$ ./docker-remove-services.sh
+` 
+
+Execute the following command to update particular services (pull newer docker image and rebuild container):
+
+` 
+$ ./docker-update-service.sh [SERVICE...]
+` 
+
+## Upgrading 
+
+In case when database upgrade is needed, execute the following commands:
+
+```
+$ ./docker-stop-services.sh
+$ ./docker-upgrade-tb.sh --fromVersion=[FROM_VERSION]
+$ ./docker-start-services.sh
+```
+
+- `FROM_VERSION`              - from which version upgrade should be started.
diff --git a/docker/tb-node.env b/docker/tb-node.env
new file mode 100644
index 0000000..311428a
--- /dev/null
+++ b/docker/tb-node.env
@@ -0,0 +1,3 @@
+# ThingsBoard server configuration
+
+TRANSPORT_TYPE=remote
diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml
index 6f11df1..e673a53 100644
--- a/msa/js-executor/pom.xml
+++ b/msa/js-executor/pom.xml
@@ -287,16 +287,27 @@
                         <goals>
                             <goal>build</goal>
                         </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
                     </execution>
                 </executions>
-                <configuration>
-                    <skip>${dockerfile.skip}</skip>
-                    <repository>${docker.repo}/${docker.name}</repository>
-                    <tag>${project.version}</tag>
-                    <verbose>true</verbose>
-                    <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
-                    <contextDirectory>${project.build.directory}</contextDirectory>
-                </configuration>
             </plugin>
         </plugins>
     </build>
@@ -334,6 +345,46 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
     <repositories>
         <repository>

msa/pom.xml 3(+2 -1)

diff --git a/msa/pom.xml b/msa/pom.xml
index 59f954a..5fd2212 100644
--- a/msa/pom.xml
+++ b/msa/pom.xml
@@ -32,11 +32,12 @@
 
     <properties>
         <main.dir>${basedir}/..</main.dir>
-        <docker.repo>local-maven-build</docker.repo>
+        <docker.repo>thingsboard</docker.repo>
         <dockerfile.skip>true</dockerfile.skip>
     </properties>
 
     <modules>
+        <module>tb</module>
         <module>js-executor</module>
         <module>web-ui</module>
         <module>tb-node</module>
diff --git a/msa/tb/docker/install-tb.sh b/msa/tb/docker/install-tb.sh
new file mode 100644
index 0000000..e22ec58
--- /dev/null
+++ b/msa/tb/docker/install-tb.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+while [[ $# -gt 0 ]]
+do
+key="$1"
+
+case $key in
+    --loadDemo)
+    LOAD_DEMO=true
+    shift # past argument
+    ;;
+    *)
+            # unknown option
+    ;;
+esac
+shift # past argument or value
+done
+
+if [ "$LOAD_DEMO" == "true" ]; then
+    loadDemo=true
+else
+    loadDemo=false
+fi
+
+CONF_FOLDER="${pkg.installFolder}/conf"
+jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
+configfile=${pkg.name}.conf
+upgradeversion=${DATA_FOLDER}/.upgradeversion
+
+source "${CONF_FOLDER}/${configfile}"
+
+echo "Starting ThingsBoard installation ..."
+
+java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \
+                    -Dinstall.load_demo=${loadDemo} \
+                    -Dspring.jpa.hibernate.ddl-auto=none \
+                    -Dinstall.upgrade=false \
+                    -Dlogging.config=/usr/share/thingsboard/bin/install/logback.xml \
+                    org.springframework.boot.loader.PropertiesLauncher
+
+echo "${pkg.upgradeVersion}" > ${upgradeversion}
diff --git a/msa/tb/docker/logback.xml b/msa/tb/docker/logback.xml
new file mode 100644
index 0000000..87f9bf4
--- /dev/null
+++ b/msa/tb/docker/logback.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+
+    Copyright © 2016-2018 The Thingsboard Authors
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<!DOCTYPE configuration>
+<configuration scan="true" scanPeriod="10 seconds">
+
+    <appender name="fileLogAppender"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>/var/log/thingsboard/thingsboard.log</file>
+        <rollingPolicy
+                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>/var/log/thingsboard/thingsboard.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+            <totalSizeCap>3GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="org.thingsboard.server" level="INFO" />
+    <logger name="akka" level="INFO" />
+
+    <root level="INFO">
+        <appender-ref ref="fileLogAppender"/>
+        <appender-ref ref="STDOUT"/>
+    </root>
+
+</configuration>
\ No newline at end of file
diff --git a/msa/tb/docker/start-tb.sh b/msa/tb/docker/start-tb.sh
new file mode 100755
index 0000000..37f5e3a
--- /dev/null
+++ b/msa/tb/docker/start-tb.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+start-db.sh
+
+CONF_FOLDER="${pkg.installFolder}/conf"
+jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
+configfile=${pkg.name}.conf
+firstlaunch=${DATA_FOLDER}/.firstlaunch
+
+source "${CONF_FOLDER}/${configfile}"
+
+if [ ! -f ${firstlaunch} ]; then
+    install-tb.sh --loadDemo
+    touch ${firstlaunch}
+fi
+
+echo "Starting ThingsBoard ..."
+
+java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardServerApplication \
+                    -Dspring.jpa.hibernate.ddl-auto=none \
+                    -Dlogging.config=${CONF_FOLDER}/logback.xml \
+                    org.springframework.boot.loader.PropertiesLauncher
+
+stop-db.sh
\ No newline at end of file
diff --git a/msa/tb/docker/thingsboard.conf b/msa/tb/docker/thingsboard.conf
new file mode 100644
index 0000000..85d7cfd
--- /dev/null
+++ b/msa/tb/docker/thingsboard.conf
@@ -0,0 +1,24 @@
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+export JAVA_OPTS="$JAVA_OPTS -Dplatform=deb -Dinstall.data_dir=/usr/share/thingsboard/data"
+export JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/thingsboard/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
+export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10"
+export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
+export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled"
+export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExitOnOutOfMemoryError"
+export LOG_FILENAME=thingsboard.out
+export LOADER_PATH=/usr/share/thingsboard/conf,/usr/share/thingsboard/extensions
diff --git a/msa/tb/docker-cassandra/Dockerfile b/msa/tb/docker-cassandra/Dockerfile
new file mode 100644
index 0000000..175ad9a
--- /dev/null
+++ b/msa/tb/docker-cassandra/Dockerfile
@@ -0,0 +1,59 @@
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+FROM openjdk:8-jre
+
+RUN apt-get update
+RUN apt-get install -y curl nmap procps
+RUN echo 'deb http://www.apache.org/dist/cassandra/debian 311x main' | tee --append /etc/apt/sources.list.d/cassandra.list > /dev/null
+RUN curl https://www.apache.org/dist/cassandra/KEYS | apt-key add -
+RUN apt-get update
+RUN apt-get install -y cassandra cassandra-tools
+RUN update-rc.d cassandra disable
+RUN sed -i.old '/ulimit/d' /etc/init.d/cassandra
+
+COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.sh install-tb.sh ${pkg.name}.deb /tmp/
+
+RUN chmod a+x /tmp/*.sh \
+    && mv /tmp/start-tb.sh /usr/bin \
+    && mv /tmp/upgrade-tb.sh /usr/bin \
+    && mv /tmp/install-tb.sh /usr/bin \
+    && mv /tmp/start-db.sh /usr/bin \
+    && mv /tmp/stop-db.sh /usr/bin
+
+RUN dpkg -i /tmp/${pkg.name}.deb
+
+RUN update-rc.d ${pkg.name} disable
+
+RUN mv /tmp/logback.xml ${pkg.installFolder}/conf \
+    && mv /tmp/${pkg.name}.conf ${pkg.installFolder}/conf
+
+ENV DATA_FOLDER=/data
+
+ENV HTTP_BIND_PORT=9090
+ENV DATABASE_TS_TYPE=cassandra
+ENV DATABASE_ENTITIES_TYPE=cassandra
+
+ENV CASSANDRA_HOST=localhost
+ENV CASSANDRA_PORT=9042
+
+EXPOSE 9090
+EXPOSE 1883
+EXPOSE 5683/udp
+
+VOLUME ["/data"]
+
+CMD ["start-tb.sh"]
diff --git a/msa/tb/docker-postgres/Dockerfile b/msa/tb/docker-postgres/Dockerfile
new file mode 100644
index 0000000..9447d51
--- /dev/null
+++ b/msa/tb/docker-postgres/Dockerfile
@@ -0,0 +1,62 @@
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+FROM openjdk:8-jre
+
+RUN apt-get update
+RUN apt-get install -y postgresql postgresql-contrib
+RUN update-rc.d postgresql disable
+
+RUN mkdir -p /var/log/postgres
+RUN chown -R postgres:postgres /var/log/postgres
+
+COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.sh install-tb.sh ${pkg.name}.deb /tmp/
+
+RUN chmod a+x /tmp/*.sh \
+    && mv /tmp/start-tb.sh /usr/bin \
+    && mv /tmp/upgrade-tb.sh /usr/bin \
+    && mv /tmp/install-tb.sh /usr/bin \
+    && mv /tmp/start-db.sh /usr/bin \
+    && mv /tmp/stop-db.sh /usr/bin
+
+RUN dpkg -i /tmp/${pkg.name}.deb
+
+RUN update-rc.d ${pkg.name} disable
+
+RUN mv /tmp/logback.xml ${pkg.installFolder}/conf \
+    && mv /tmp/${pkg.name}.conf ${pkg.installFolder}/conf
+
+ENV DATA_FOLDER=/data
+
+ENV HTTP_BIND_PORT=9090
+ENV DATABASE_TS_TYPE=sql
+ENV DATABASE_ENTITIES_TYPE=sql
+
+ENV PGDATA=/data/db
+
+ENV SPRING_JPA_DATABASE_PLATFORM=org.hibernate.dialect.PostgreSQLDialect
+ENV SPRING_DRIVER_CLASS_NAME=org.postgresql.Driver
+ENV SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard
+ENV SPRING_DATASOURCE_USERNAME=postgres
+ENV SPRING_DATASOURCE_PASSWORD=postgres
+
+EXPOSE 9090
+EXPOSE 1883
+EXPOSE 5683/udp
+
+VOLUME ["/data"]
+
+CMD ["start-tb.sh"]
diff --git a/msa/tb/docker-tb/Dockerfile b/msa/tb/docker-tb/Dockerfile
new file mode 100644
index 0000000..df7e692
--- /dev/null
+++ b/msa/tb/docker-tb/Dockerfile
@@ -0,0 +1,48 @@
+#
+# Copyright © 2016-2018 The Thingsboard Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+FROM openjdk:8-jre
+
+COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.sh install-tb.sh ${pkg.name}.deb /tmp/
+
+RUN chmod a+x /tmp/*.sh \
+    && mv /tmp/start-tb.sh /usr/bin \
+    && mv /tmp/upgrade-tb.sh /usr/bin \
+    && mv /tmp/install-tb.sh /usr/bin \
+    && mv /tmp/start-db.sh /usr/bin \
+    && mv /tmp/stop-db.sh /usr/bin
+
+RUN dpkg -i /tmp/${pkg.name}.deb
+
+RUN update-rc.d ${pkg.name} disable
+
+RUN mv /tmp/logback.xml ${pkg.installFolder}/conf \
+    && mv /tmp/${pkg.name}.conf ${pkg.installFolder}/conf
+
+ENV DATA_FOLDER=/data
+
+ENV HTTP_BIND_PORT=9090
+ENV DATABASE_TS_TYPE=sql
+ENV DATABASE_ENTITIES_TYPE=sql
+ENV SQL_DATA_FOLDER=/data/db
+
+EXPOSE 9090
+EXPOSE 1883
+EXPOSE 5683/udp
+
+VOLUME ["/data"]
+
+CMD ["start-tb.sh"]

msa/tb/pom.xml 370(+370 -0)

diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml
new file mode 100644
index 0000000..6ea7beb
--- /dev/null
+++ b/msa/tb/pom.xml
@@ -0,0 +1,370 @@
+<!--
+
+    Copyright © 2016-2018 The Thingsboard Authors
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.thingsboard</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+        <artifactId>msa</artifactId>
+    </parent>
+    <groupId>org.thingsboard.msa</groupId>
+    <artifactId>tb</artifactId>
+    <packaging>pom</packaging>
+
+    <name>ThingsBoard Docker Images</name>
+    <url>https://thingsboard.io</url>
+    <description>ThingsBoard Docker Images</description>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <main.dir>${basedir}/../..</main.dir>
+        <pkg.name>thingsboard</pkg.name>
+        <tb.docker.name>tb</tb.docker.name>
+        <tb-postgres.docker.name>tb-postgres</tb-postgres.docker.name>
+        <tb-cassandra.docker.name>tb-cassandra</tb-cassandra.docker.name>
+        <pkg.user>thingsboard</pkg.user>
+        <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder>
+        <pkg.upgradeVersion>2.1.1</pkg.upgradeVersion>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.thingsboard</groupId>
+            <artifactId>application</artifactId>
+            <version>${project.version}</version>
+            <classifier>deb</classifier>
+            <type>deb</type>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-tb-deb</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.thingsboard</groupId>
+                                    <artifactId>application</artifactId>
+                                    <classifier>deb</classifier>
+                                    <type>deb</type>
+                                    <destFileName>${pkg.name}.deb</destFileName>
+                                    <outputDirectory>${project.build.directory}/docker-tb</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-tb-postgres-deb</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.thingsboard</groupId>
+                                    <artifactId>application</artifactId>
+                                    <classifier>deb</classifier>
+                                    <type>deb</type>
+                                    <destFileName>${pkg.name}.deb</destFileName>
+                                    <outputDirectory>${project.build.directory}/docker-postgres</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-tb-cassandra-deb</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.thingsboard</groupId>
+                                    <artifactId>application</artifactId>
+                                    <classifier>deb</classifier>
+                                    <type>deb</type>
+                                    <destFileName>${pkg.name}.deb</destFileName>
+                                    <outputDirectory>${project.build.directory}/docker-cassandra</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-docker-tb-config</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/docker-tb</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>docker</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                                <resource>
+                                    <directory>docker-tb</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-docker-tb-postgres-config</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/docker-postgres</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>docker</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                                <resource>
+                                    <directory>docker-postgres</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-docker-tb-cassandra-config</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/docker-cassandra</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>docker</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                                <resource>
+                                    <directory>docker-cassandra</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>dockerfile-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>build-docker-tb-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${tb.docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}/docker-tb</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-tb-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${tb.docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>build-docker-tb-postgres-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${tb-postgres.docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}/docker-postgres</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-tb-postgres-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${tb-postgres.docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>build-docker-tb-cassandra-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${tb-cassandra.docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}/docker-cassandra</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-tb-cassandra-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${tb-cassandra.docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-tb-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${tb.docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-tb-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${tb.docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-latest-docker-tb-postgres-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${tb-postgres.docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-tb-postgres-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${tb-postgres.docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-latest-docker-tb-cassandra-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${tb-cassandra.docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-tb-cassandra-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${tb-cassandra.docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <repositories>
+        <repository>
+            <id>jenkins</id>
+            <name>Jenkins Repository</name>
+            <url>http://repo.jenkins-ci.org/releases</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+</project>

msa/tb/README.md 68(+68 -0)

diff --git a/msa/tb/README.md b/msa/tb/README.md
new file mode 100644
index 0000000..d165fa7
--- /dev/null
+++ b/msa/tb/README.md
@@ -0,0 +1,68 @@
+# ThingsBoard single docker images 
+
+This project provides the build for the ThingsBoard single docker images.
+
+* `thingsboard/tb` - single instance of ThingsBoard with embedded HSQLDB database.
+* `thingsboard/tb-postgres` - single instance of ThingsBoard with PostgreSQL database.
+* `thingsboard/tb-cassandra` - single instance of ThingsBoard with Cassandra database.
+
+## Running
+
+Execute the following command to run this docker directly:
+
+` 
+$ docker run -it -p 9090:9090 -p 1883:1883 -p 5683:5683/udp -v ~/.mytb-data:/data --name mytb thingsboard/tb
+` 
+
+Where: 
+    
+- `docker run`              - run this container
+- `-it`                     - attach a terminal session with current ThingsBoard process output
+- `-p 9090:9090`            - connect local port 9090 to exposed internal HTTP port 9090
+- `-p 1883:1883`            - connect local port 1883 to exposed internal MQTT port 1883    
+- `-p 5683:5683`            - connect local port 5683 to exposed internal COAP port 5683 
+- `-v ~/.mytb-data:/data`   - mounts the host's dir `~/.mytb-data` to ThingsBoard DataBase data directory
+- `--name mytb`             - friendly local name of this machine
+- `thingsboard/tb`          - docker image
+    
+After executing this command you can open `http://{yor-host-ip}:9090` in you browser. You should see ThingsBoard login page.
+Use the following default credentials:
+
+- **Systen Administrator**: sysadmin@thingsboard.org / sysadmin
+- **Tenant Administrator**: tenant@thingsboard.org / tenant
+- **Customer User**: customer@thingsboard.org / customer
+    
+You can always change passwords for each account in account profile page.
+
+You can detach from session terminal with `Ctrl-p` `Ctrl-q` - the container will keep running in the background.
+
+To reattach to the terminal (to see ThingsBoard logs) run:
+
+`
+$ docker attach mytb
+`
+
+To stop the container:
+
+`
+$ docker stop mytb
+`
+
+To start the container:
+
+`
+$ docker start mytb
+`
+
+## Upgrading
+
+In order to update to the latest image, execute the following commands:
+
+```
+$ docker pull thingsboard/tb
+$ docker stop mytb
+$ docker run -it -v ~/.mytb-data:/data --rm thingsboard/tb upgrade-tb.sh
+$ docker start mytb
+```
+
+**NOTE**: replace host's directory `~/.mytb-data` with directory used during container creation. 

msa/tb-node/pom.xml 69(+61 -8)

diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml
index 18a81f3..fc62189 100644
--- a/msa/tb-node/pom.xml
+++ b/msa/tb-node/pom.xml
@@ -111,19 +111,72 @@
                         <goals>
                             <goal>build</goal>
                         </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
                     </execution>
                 </executions>
-                <configuration>
-                    <skip>${dockerfile.skip}</skip>
-                    <repository>${docker.repo}/${docker.name}</repository>
-                    <tag>${project.version}</tag>
-                    <verbose>true</verbose>
-                    <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
-                    <contextDirectory>${project.build.directory}</contextDirectory>
-                </configuration>
             </plugin>
         </plugins>
     </build>
+    <profiles>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
     <repositories>
         <repository>
             <id>jenkins</id>
diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml
index 94399c7..26eaa30 100644
--- a/msa/transport/coap/pom.xml
+++ b/msa/transport/coap/pom.xml
@@ -111,19 +111,72 @@
                         <goals>
                             <goal>build</goal>
                         </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
                     </execution>
                 </executions>
-                <configuration>
-                    <skip>${dockerfile.skip}</skip>
-                    <repository>${docker.repo}/${docker.name}</repository>
-                    <tag>${project.version}</tag>
-                    <verbose>true</verbose>
-                    <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
-                    <contextDirectory>${project.build.directory}</contextDirectory>
-                </configuration>
             </plugin>
         </plugins>
     </build>
+    <profiles>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
     <repositories>
         <repository>
             <id>jenkins</id>
diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml
index 6bbfc3f..6d1707c 100644
--- a/msa/transport/http/pom.xml
+++ b/msa/transport/http/pom.xml
@@ -111,19 +111,72 @@
                         <goals>
                             <goal>build</goal>
                         </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
                     </execution>
                 </executions>
-                <configuration>
-                    <skip>${dockerfile.skip}</skip>
-                    <repository>${docker.repo}/${docker.name}</repository>
-                    <tag>${project.version}</tag>
-                    <verbose>true</verbose>
-                    <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
-                    <contextDirectory>${project.build.directory}</contextDirectory>
-                </configuration>
             </plugin>
         </plugins>
     </build>
+    <profiles>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
     <repositories>
         <repository>
             <id>jenkins</id>
diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml
index 0a3b077..d51c51c 100644
--- a/msa/transport/mqtt/pom.xml
+++ b/msa/transport/mqtt/pom.xml
@@ -111,19 +111,72 @@
                         <goals>
                             <goal>build</goal>
                         </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
                     </execution>
                 </executions>
-                <configuration>
-                    <skip>${dockerfile.skip}</skip>
-                    <repository>${docker.repo}/${docker.name}</repository>
-                    <tag>${project.version}</tag>
-                    <verbose>true</verbose>
-                    <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
-                    <contextDirectory>${project.build.directory}</contextDirectory>
-                </configuration>
             </plugin>
         </plugins>
     </build>
+    <profiles>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
     <repositories>
         <repository>
             <id>jenkins</id>

msa/web-ui/pom.xml 67(+59 -8)

diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml
index 805bf8b..83124df 100644
--- a/msa/web-ui/pom.xml
+++ b/msa/web-ui/pom.xml
@@ -311,16 +311,27 @@
                         <goals>
                             <goal>build</goal>
                         </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <verbose>true</verbose>
+                            <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
+                            <contextDirectory>${project.build.directory}</contextDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>tag-docker-image</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>tag</goal>
+                        </goals>
+                        <configuration>
+                            <skip>${dockerfile.skip}</skip>
+                            <repository>${docker.repo}/${docker.name}</repository>
+                            <tag>${project.version}</tag>
+                        </configuration>
                     </execution>
                 </executions>
-                <configuration>
-                    <skip>${dockerfile.skip}</skip>
-                    <repository>${docker.repo}/${docker.name}</repository>
-                    <tag>${project.version}</tag>
-                    <verbose>true</verbose>
-                    <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
-                    <contextDirectory>${project.build.directory}</contextDirectory>
-                </configuration>
             </plugin>
         </plugins>
     </build>
@@ -358,6 +369,46 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>push-docker-image</id>
+            <activation>
+                <property>
+                    <name>push-docker-image</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>push-latest-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>latest</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-version-docker-image</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <tag>${project.version}</tag>
+                                    <repository>${docker.repo}/${docker.name}</repository>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
     <repositories>
         <repository>