######refarch-cloudnative-micro-inventory
###Spring Boot Netflix OSS Microservice Apps Integration with ElasticSearch and MySQL Database Server
This project is part of the 'IBM Cloud Native Reference Architecture' suite, available at https://github.com/ibm-cloud-architecture/refarch-cloudnative
##Table of Contents
- Introduction
- Pre-requisites
- Deploy Inventory and Catalog Microservices using DevOps Toolchain
- Run Inventory and Catalog Locally
- Deploy Inventory and Catalog on local Docker Containers
- Deploy Inventory and Catalog on Bluemix Containers
- Using Compose for Production Databases
##Introduction
This project is built to demonstrate how to build two Microservices applications using Spring Boot and Docker container.. The first application (Inventory) uses MySQL database as its datasource. The second and publicly available application (Catalog) serves as a cache to Inventory by leveraging Elasticsearch as its datasource.
Here is an overview of the project's features:
- Leverage
Spring Bootframework to build a Microservices application. - Use
Spring Data JPAto persist data to MySQL database and Elasticsearch. - Uses
MySQLas the inventory database. Elasticsearchis used as theCatalogmicroservice's data source.- Uses
MessageHubto receive messages that act as triggers to synchronize Inventory database withElasticsearch. - Integrate with
Netflix Eurekaframework. - Deployment option for
IBM Bluemix Containerruntime.
Architecture Diagram
###APIs You can use cURL or Chrome POSTMAN to send get/post/put/delete requests to the application.
-
Get all items in inventory:
http://<catalog_hostname>/micro/items -
Get item by id:
http://<catalog_hostname>/micro/items/{id} -
Example curl command to get al items in localhost:
curl -X GET "http://localhost:8081/micro/items"
##Pre-requisites:
-
Clone git repository before getting started.
git clone http://github.com/refarch-cloudnative-micro-inventory.git cd refarch-cloudnative-micro-inventory -
You need a docker engine running on localhost to host container(s). Click for instructions.
-
You need to Provision
MessageHubservice instance.
###Message Hub
- Provision an instance of Message Hub into your Bluemix space.
- Select name for your instance.
- Click the
Createbutton.
- Refresh the page until you see
Status: Ready. - Now obtain
Message Hubservice credentials.
- Click on
Service Credentialstab. - Then click on the
View Credentialsdropdown next to the credentials.
- You will need the following:
- kafka_rest_url: Needed to query and create
topics. - api_key: Needed to use the Message Hub REST API.
- user: Message Hub user.
- password: Message Hub password.
- kafka_brokers_sasl: Message Hub kafka brokers, which are in charge of receiving and sending messages for specific topics.
- Keep those credential handy as they will be needed throughout the rest of this document.
##Deploy Inventory and Catalog Microservices using DevOps Toolchain You can use the following button to deploy the Inventory and Catalog microservices to Bluemix, or you can follow the manual instructions in the following sections. If you decide on the toolchain button, you have to fulfill the following pre-requisites:
- Provision a Message Hub service instance in your Bluemix Space.
- The toolchain will automatically pick up
Message Hubcredentials.
- The toolchain will automatically pick up
- Deploy MySQL in your Bluemix Space.
- Options:
- The toolchain will ask you to enter the
username,password,ip,port, anddatabasefor MySQL.
- Deploy Elasticsearch in your Bluemix Space.
- Options:
- The toolchain will ask you to enter the
username,password, andURLfor Elasticsearch.
##Run Inventory and Catalog Locally In this section you will learn how to build and run the Inventory and Catalog apps locally.
-
Change to the mysql directory.
# cd mysql -
Create MySQL container with database
inventorydb. This database can be connected at<docker-host-ipaddr/hostname>:3306asdbuserusingpassword.# docker build -t cloudnative/mysql . # docker run --name mysql -d -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=admin123 \ -e MYSQL_USER=dbuser \ -e MYSQL_PASSWORD=password \ -e MYSQL_DATABASE=inventorydb \ cloudnative/mysql -
Create
itemstable and load sample data. You should see Data loaded to inventorydb.items.# docker exec -it mysql bash load-data.sh -
Verify, there should be 12 rows in the table.
# docker exec -it mysql bash # mysql -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE} mysql> select * from items; mysql> quit # exit -
Get container Private IP Address. This will be used when Running inventory from local docker container.
# docker inspect mysql | grep -i ipaddress "SecondaryIPAddresses": null, "IPAddress": "172.17.0.2", "IPAddress": "172.17.0.2", -
Use
jdbc:mysql://{mysql_ip}:3306/inventorydbas yourspring.datasource.urlwhen deployingInventory on local Docker Container.
Inventory database is now setup in local container.
###Deploy Elasticsearch on local docker container
-
Run docker container locally. This will download the elasticsearch image (if it does not exist already) and run it.
docker run --name elasticsearch -d -p 9200:9200 elasticsearch -
Validate.
# curl http://localhost:9200
{
"name" : "1-LsU37",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "1fn3QtZpTOWOhEpEM01ZAw",
"version" : {
"number" : "5.2.0",
"build_hash" : "24e05b9",
"build_date" : "2017-01-24T19:52:35.800Z",
"build_snapshot" : false,
"lucene_version" : "6.4.0"
},
"tagline" : "You Know, for Search"
}
- Use
http://localhost:9200as yourelasticsearch.urlwhen runningCatalogandInventorylocally.
###Run Inventory Service application on localhost In this section you will run the Spring Boot application to run on your localhost.
-
Change to
inventorydirectory.cd inventory -
If not already done, Deploy
MySQLon local docker container.
- Open
src/main/resources/application.yml, go todatasourcesection. - Type
urlasjdbc:mysql://127.0.0.1/inventorydb, where127.0.0.1meanslocalhost - Make sure the
user,password, andportmatch those of local container.
- If not already done, Deploy
Elasticsearchon local docker container.
- Open
src/main/resources/application.yml, go toelasticsearchsection. - Type
http://localhost:9200on theurlfield.
- If not already done, Provision
Message Hubservice instance.
- After provisioning, go to instance
Service Credentialstab on Bluemix, then pressView credentials. - Open
src/main/resources/application.yml, go tomessage_hubsection, then copy and paste requiredmessage_hubfields using credentials from above.
-
Build the application.
# ./gradlew build -x test -
Run the application on localhost.
# java -jar build/libs/micro-inventory-0.0.1.jar -
Validate. You should get a list of all inventory items.
# curl http://localhost:8080/micro/inventory
###Run Catalog Service application on localhost In this section you will run the Catalog Spring Boot application to run on your localhost.
-
Change to
catalogdirectory.cd catalog -
If not already done, Deploy
Elasticsearchon local docker container.
- Open
src/main/resources/application.yml, go toelasticsearchsection. - Type
http://localhost:9200on theurlfield.
-
Build the application.
# ./gradlew build -x test -
Run the application on localhost.
# java -jar build/libs/micro-catalog-0.0.1.jar -
Validate. You should get a list of all catalog items.
# curl http://localhost:8081/micro/items
##Deploy Inventory and Catalog on local Docker Containers In this section you will learn how to package the Inventory and Catalog apps as docker images and deploy in local Docker environment.
###Run Inventory Service application on local docker container
-
Change to
inventorydirectory.cd inventory -
If not already done, Deploy
MySQLon local docker container.
- Obtain the MySQL
Container Private IP Address,database username, anddatabase passwordfrom link above and have them ready for deployment inStep 6.
- If not already done, Deploy
Elasticsearchon local docker container.
- Obtain the Elasticsearch
Container Private IP Addressfrom link above and have it ready for deployment inStep 6.
- If not already done, Provision
Message Hubservice instance.
- After provisioning, go to instance
Service Credentialstab on Bluemix, then pressView credentials. - Obtain the Message HUB
user,password,api_key,kafka_rest_url, andkafka_brokers_saslfrom link above and have them ready for deployment inStep 6.
-
Build container image
# ./gradlew build -x test # ./gradlew docker # cd docker # docker build -t cloudnative/inventoryservice . -
Start the application in docker container.
# docker run -d -p 8080:8080 --name inventoryservice \
-e "spring.datasource.url=jdbc:mysql://{mysql_ip}:3306/inventorydb" \
-e "spring.datasource.username={mysql_user}" \
-e "spring.datasource.password={mysql_password}" \
-e "elasticsearch.url={es_url}" \
-e "message_hub.user={mh_user}" \
-e "message_hub.password={mh_password}" \
-e "message_hub.api_key={mh_api_key}" \
-e "message_hub.kafka_rest_url={mh_kafka_rest_url}" \
-e "message_hub.kafka_brokers_sasl[0]={mh_kafka_broker_0}" \
-e "message_hub.kafka_brokers_sasl[1]={mh_kafka_broker_1}" \
-e "message_hub.kafka_brokers_sasl[2]={mh_kafka_broker_2}" \
-e "message_hub.kafka_brokers_sasl[3]={mh_kafka_broker_3}" \
-e "message_hub.kafka_brokers_sasl[4]={mh_kafka_broker_4}" \
cloudnative/inventoryservice
- Replace
{mysql_container_ip}with the MySQL container instance IP address. - Replace
{mysql_user}with database username. - Replace
{mysql_password}with database user password. - Replace
{es_url}with the Bluemix container private ip address. - Replace
{mh_user}with Message Hubuser. - Replace
{mh_password}with Message Hubpassword. - Replace
{mh_api_key}with Message Hubapi_key. - Replace
{mh_kafka_rest_url}with Message Hubkafka_rest_url. - Replace all the
{mh_kafka_broker[x]}with all the URLs listed in Message Hubkafka_brokers_sasl.
- Validate. You should get a list of all inventory items.
# curl http://localhost:8080/micro/inventory
###Run Catalog Service application on local docker container In this section you will deploy the Catalog Spring Boot application to run in a local docker container.
-
Change to
catalogdirectory.cd catalog -
If not already done, Deploy Elasticsearch on local docker container.
- Obtain the Elasticsearch
Container Private IP Addressfrom link above and have it ready for deployment inStep 4.
-
Build container image
# ./gradlew build -x test # ./gradlew docker # cd docker # docker build -t cloudnative/catalogservice . -
Start the application in docker container.
# docker run -d -p 8081:8081 --name catalogservice \
-e "eureka.client.fetchRegistry=false" \
-e "eureka.client.registerWithEureka=false" \
-e "elasticsearch.url={es_url}" \
cloudnative/catalogservice"
- Replace
{es_url}with the Bluemix container private ip address.
- Validate. You should get a list of all catalog items.
# curl http://localhost:8081/micro/items
##Deploy Inventory and Catalog on Bluemix Containers In this section you will learn how to deploy the Inventory and Catalog apps in Bluemix containers.
###Deploy MySQL on Bluemix container
-
Log in to your Bluemix account.
# cf login -a <bluemix-api-endpoint> -u <your-bluemix-user-id> -
Set target to use your Bluemix Org and Space.
# cf target -o <your-bluemix-org> -s <your-bluemix-space> -
Log in to IBM Containers plugin.
# cf ic login -
Check that your organization has set a namespace.
# cf ic namespace get -
If there is no namespace set for your , then set a namespace.
# cf ic namespace get -
Change to the mysql directory.
# cd mysql -
Build docker image using the Dockerfile from repo.
# docker build -t cloudnative/mysql . -
Tag and push mysql database server image to your Bluemix private registry namespace.
# docker tag cloudnative/mysql registry.ng.bluemix.net/$(cf ic namespace get)/mysql:cloudnative # docker push registry.ng.bluemix.net/$(cf ic namespace get)/mysql:cloudnative -
Create MySQL container with database
inventorydb. This database can be connected at<docker-host-ipaddr/hostname>:3306asdbuserusingPass4dbUs3R.It is recommended to change the default passwords used here.
# cf ic run -m 512 --name mysql -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=Pass4Admin123 \ -e MYSQL_USER=dbuser \ -e MYSQL_PASSWORD=Pass4dbUs3R \ -e MYSQL_DATABASE=inventorydb \ registry.ng.bluemix.net/$(cf ic namespace get)/mysql:cloudnative -
Before loading sample data. Check that mysql container is running.
# cf ic ps | grep mysql 7618b4a1-6d9 registry.ng.bluemix.net/chrisking/mysql:cloudnative "" 4 minutes ago Running 3306/tcp mysql -
Create
itemstable and load sample data. You should see message Data loaded to inventorydb.items.# cf ic exec -it mysql bash load-data.sh -
Verify, there should be 12 rows in the table.
# cf ic exec -it mysql bash # mysql -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE} mysql> select * from items; mysql> quit # exit -
Get container Private IP Address. This will be used when running Inventory Service application from IBM Bluemix container.
# cf ic inspect mysql | grep -i ipaddress "IPAddress": "172.29.0.240", "IPAddress": "172.29.0.240"
Inventory database is now setup in IBM Bluemix Container.
###Deploy Elasticsearch on Bluemix container
-
Log in to your Bluemix account.
# cf login -a <bluemix-api-endpoint> -u <your-bluemix-user-id> -
Set target to use your Bluemix Org and Space.
# cf target -o <your-bluemix-org> -s <your-bluemix-space> -
Log in to IBM Containers plugin.
# cf ic login -
Check that your organization has set a namespace.
# cf ic namespace get -
If there is no namespace set for your , then set a namespace.
# cf ic namespace get -
Pull elasticsearch docker image.
docker pull elasticsearch -
Tag image.
docker tag elasticsearch registry.ng.bluemix.net/$(cf ic namespace get)/elasticsearch -
Push image to Bluemix Docker image registry.
docker push registry.ng.bluemix.net/$(cf ic namespace get)/elasticsearch -
Create single Elasticsearch container.
cf ic run -m 4096 --name elasticsearch -p 9200:9200 registry.ng.bluemix.net/$(cf ic namespace get)/elasticsearch -
Verify container is
Running.# cf ic ps | grep elasticsearch-container a9a5a80c-bff registry.ng.bluemix.net/chrisking/elasticsearch:latest "" About an hour ago Running 169.46.17.110:9200->9200/tcp elasticsearch-container -
Get container Private IP Address.
# cf ic inspect elasticsearch-container | grep -i ipaddress "IPAddress": "172.29.0.240", "IPAddress": "172.29.0.240" -
Use
http(s)://CONTAINER_IP_ADDRESS:9200as yourelasticsearch.urlwhen deployingCatalogandInventory.
###Deploy Inventory Service application on Bluemix container In this section you will deploy both the database server and the Spring Boot application to run in IBM Bluemix containers.
-
Change to
inventorydirectory.cd inventory -
Log in to your Bluemix account.
# cf login -a <bluemix-api-endpoint> -u <your-bluemix-user-id> -
Set target to use your Bluemix Org and Space.
# cf target -o <your-bluemix-org> -s <your-bluemix-space> -
Log in to IBM Containers plugin.
# cf ic login -
Build container image
# ./gradlew build -x test # ./gradlew docker # cd docker # docker build -t cloudnative/inventoryservice . -
Tag and push the local docker image to bluemix private registry.
# docker tag cloudnative/inventoryservice registry.ng.bluemix.net/$(cf ic namespace get)/inventoryservice:cloudnative # docker push registry.ng.bluemix.net/$(cf ic namespace get)/inventoryservice:cloudnative -
If not already done, Deploy
MySQLon IBM Bluemix container.
- Obtain the MySQL
Container Private IP Address,database username, anddatabase passwordfrom link above and have them ready for deployment inStep 10.
- If not already done, Deploy
Elasticsearchon Bluemix container.
- Obtain the Elasticsearch
Container Private IP Addressfrom link above and have it ready for deployment inStep 10.
- If not already done, Provision
Message Hubservice instance.
- After provisioning, go to instance
Service Credentialstab on Bluemix, then pressView credentials. - Obtain the Message HUB
user,password,api_key,kafka_rest_url, andkafka_brokers_saslfrom link above and have them ready for deployment inStep 10.
- Start the application in IBM Bluemix container.
# cf ic group create -p 8080 -m 1024 --min 1 --auto --name micro-inventory-group \
-e "spring.datasource.url=jdbc:mysql://{mysql_ip}:3306/inventorydb" \
-e "spring.datasource.username={mysql_user}" \
-e "spring.datasource.password={mysql_password}" \
-e "elasticsearch.url={es_url}" \
-e "message_hub.user={mh_user}" \
-e "message_hub.password={mh_password}" \
-e "message_hub.api_key={mh_api_key}" \
-e "message_hub.kafka_rest_url={mh_kafka_rest_url}" \
-e "message_hub.kafka_brokers_sasl[0]={mh_kafka_broker_0}" \
-e "message_hub.kafka_brokers_sasl[1]={mh_kafka_broker_1}" \
-e "message_hub.kafka_brokers_sasl[2]={mh_kafka_broker_2}" \
-e "message_hub.kafka_brokers_sasl[3]={mh_kafka_broker_3}" \
-e "message_hub.kafka_brokers_sasl[4]={mh_kafka_broker_4}" \
-n inventoryservice \
-d mybluemix.net registry.ng.bluemix.net/$(cf ic namespace get)/inventoryservice:cloudnative
- Replace
{mysql_ip}with the MySQL Bluemix container instance IP address. - Replace
{mysql_user}with database username. - Replace
{mysql_password}with database user password. - Replace
{es_url}with the Elasticsearch Bluemix container private ip address. - Replace
{mh_user}with Message Hubuser. - Replace
{mh_password}with Message Hubpassword. - Replace
{mh_api_key}with Message Hubapi_key. - Replace
{mh_kafka_rest_url}with Message Hubkafka_rest_url. - Replace all the
{mh_kafka_broker[x]}with all the URLs listed in Message Hubkafka_brokers_sasl.
- Optional. If using Compose for Elasticsearch and/or MySQL, the command will look like this:
# cf ic group create -p 8080 -m 1024 --min 1 --auto --name micro-inventory-group \
-e "spring.datasource.url=jdbc:mysql://{mysql_ip}:{msql_port}/inventorydb" \
-e "spring.datasource.username={mysql_user}" \
-e "spring.datasource.password={mysql_password}" \
-e "elasticsearch.url={es_url}" \
-e "elasticsearch.user={es_user}" \
-e "elasticsearch.password={es_password}" \
-e "message_hub.user={mh_user}" \
-e "message_hub.password={mh_password}" \
-e "message_hub.api_key={mh_api_key}" \
-e "message_hub.kafka_rest_url={mh_kafka_rest_url}" \
-e "message_hub.kafka_brokers_sasl[0]={mh_kafka_broker_0}" \
-e "message_hub.kafka_brokers_sasl[1]={mh_kafka_broker_1}" \
-e "message_hub.kafka_brokers_sasl[2]={mh_kafka_broker_2}" \
-e "message_hub.kafka_brokers_sasl[3]={mh_kafka_broker_3}" \
-e "message_hub.kafka_brokers_sasl[4]={mh_kafka_broker_4}" \
-n inventoryservice \
-d mybluemix.net registry.ng.bluemix.net/$(cf ic namespace get)/inventoryservice:cloudnative
- Replace
{mysql_ip}with the MySQL Compose host. - Replace
{mysql_port}with the MySQL Compose port. - Replace
{mysql_user}with MySQL Compose user. - Replace
{mysql_password}with MySQL Compose user password. - Replace
{es_url}with the Elasticsearch Compose URL in the format ofhttps://host:port. - Replace
{es_user}with the Elasticsearch Compose username`. - Replace
{es_password}with the Elasticsearch Compose password. - Replace
{mh_user}with Message Hubuser. - Replace
{mh_password}with Message Hubpassword. - Replace
{mh_api_key}with Message Hubapi_key. - Replace
{mh_kafka_rest_url}with Message Hubkafka_rest_url. - Replace all the
{mh_kafka_broker[x]}with all the URLs listed in Message Hubkafka_brokers_sasl.
-
Validate. You should get a list of all inventory items.
# curl http://{container-group-route-name}/micro/inventory -
Unmap public route.
# cf ic route unmap -n inventoryservice -d mybluemix.net micro-inventory-group
###Deploy Catalog Service application on Bluemix container
In this section you will deploy the Catalog Spring Boot application in IBM Bluemix containers.
-
Change to
catalogdirectory.cd catalog -
Log in to your Bluemix account.
# cf login -a <bluemix-api-endpoint> -u <your-bluemix-user-id> -
Set target to use your Bluemix Org and Space.
# cf target -o <your-bluemix-org> -s <your-bluemix-space> -
Log in to IBM Containers plugin.
# cf ic login -
Build container image
# ./gradlew build -x test # ./gradlew docker # cd docker # docker build -t cloudnative/catalogservice . -
Tag and push the local docker image to bluemix private registry.
# docker tag cloudnative/catalogservice registry.ng.bluemix.net/$(cf ic namespace get)/catalogservice:cloudnative # docker push registry.ng.bluemix.net/$(cf ic namespace get)/catalogservice:cloudnative -
If not already done, Deploy Elasticsearch on Bluemix container.
- Obtain the Elasticsearch
Container Private IP Addressfrom link above and have it ready for deployment inStep 8.
- Start the application in IBM Bluemix container.
# cf ic group create -p 8080 -m 1024 --min 1 --auto --name micro-catalog-group \
-e "eureka.client.fetchRegistry=true" \
-e "eureka.client.registerWithEureka=true" \
-e "eureka.client.serviceUrl.defaultZone=http://netflix-eureka-$(cf ic namespace get).mybluemix.net/eureka/" \
-e "elasticsearch.url={es_url}" \
-n catalogservice \
-d mybluemix.net registry.ng.bluemix.net/$(cf ic namespace get)/catalogservice:cloudnative
- Replace
{es_url}with the Elasticsearch Bluemix container private ip address.
- Optional. If using Compose for Elasticsearch, the command will look like this:
# cf ic group create -p 8080 -m 1024 --min 1 --auto --name micro-catalog-group \
-e "eureka.client.fetchRegistry=true" \
-e "eureka.client.registerWithEureka=true" \
-e "eureka.client.serviceUrl.defaultZone=http://netflix-eureka-$(cf ic namespace get).mybluemix.net/eureka/" \
-e "elasticsearch.url={es_url}" \
-e "elasticsearch.user={es_user}" \
-e "elasticsearch.password={es_password}" \
-n catalogservice \
-d mybluemix.net registry.ng.bluemix.net/$(cf ic namespace get)/catalogservice:cloudnative
- Replace
{es_url}with the Elasticsearch Compose URL in the format ofhttps://host:port. - Replace
{es_user}with the Elasticsearch Compose username`. - Replace
{es_password}with the Elasticsearch Compose password.
-
Validate. You should get a list of all catalog items.
# curl http://{container-group-route-name}/micro/items -
Unmap public route.
# cf ic route unmap -n catalogservice -d mybluemix.net micro-catalog-group
##Using Compose for Production Databases Compose is an IBM service that provides production ready Cloud Hosted Databases. In this section you will learn how to deploy both a MySQL and Elasticsearch databases using Compose from Bluemix Catalog.
###Deploy MySQL on Bluemix using Compose
- Provision and instance of MySQL into your Bluemix space.
- Select name for your instance.
- Click the
Createbutton.
- Refresh the page until you see
Status: Ready. - Now obtain
MySQLservice credentials.
- Click on
Service Credentialstab. - Then click on the
View Credentialsdropdown next to the credentials.
- See the
urifield, which has the formatmysql://user:password@host:port/database, and extract the following:
- user: MySQL user.
- password: MySQL password.
- host: MySQL host.
- port: MySQL port.
- database: MySQL database.
- Keep those credential handy and feel free to use them when deploying Inventory Service application on Bluemix container.
- Create
itemstable and load sample data. You should see message Data loaded to inventorydb.items.# cd mysql/scripts # bash load-data-compose.sh {USER} {PASSWORD} {HOST} {PORT}
- Replace
{USER}with MySQL user. - Replace
{PASSWORD}with MySQL password. - Replace
{HOST}with MySQL host. - Replace
{PORT}with MySQL port.
Inventory database is now setup in Compose.
###Deploy Elasticsearch on Bluemix using Compose
- Provision and instance of Elasticsearch into your Bluemix space.
- Select name for your instance.
- Click the
Createbutton.
- Refresh the page until you see
Status: Ready. - Now obtain
Elasticsearchservice credentials.
- Click on
Service Credentialstab. - Then click on the
View Credentialsdropdown next to the credentials.
- See the
urifield, which has the formathttps://user:password@host:port/, and extract the following:
- user: Elasticsearch user.
- password: Elasticsearch password.
- host: Elasticsearch host.
- port: Elasticsearch port.
- Keep those credential handy and feel free to use them when provisioning Inventory and Catalog services on Bluemix Containers.
Inventory database is now setup in Compose.

