Updated approach Building Simple Multi-Container Application with Docker

Roman Ceresnak, PhD
CodeX
Published in
3 min readFeb 20, 2023

In the first part, I showed you how to build a simple cluster with Docker technology. The procedure I mentioned is correct, but it is not so-called “user friendly.” Let’s modify this procedure and simplify the whole process.

In the first part, we showed a method that works, but repeatedly running commands that are sometimes 3 lines or 4 lines is something that many beginners often make a mistake. As much as I’m in favor of simplifying life, let’s show you how to tune the first part.

With docker technology, there is a mechanism that will help us a lot in this step. The mentioned technology is called docker compose.

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

Compose works in all environments: production, staging, development, testing, as well as CI workflows. It also has commands for managing the whole lifecycle of your application:

  • Start, stop, and rebuild services
  • View the status of running services
  • Stream the log output of running services
  • Run a one-off command on a service
version: "3.8"
services:
mongodb:
image: 'mongo'
volumes:
- data:/data/db
container_name: mongodb
environment:
- MONGO_INITDB_ROOT_USERNAME=roman
- MONGO_INITDB_ROOT_PASSWORD=secret
backend:
build: ./backend
ports:
- '80:80'
volumes:
- logs:/app/logs # write data inside container
- ./backend:/app # bind mounts( map code inside the container)
- /app/node_moudels # anonymous values
container_name: backend
env_file:
- ./env/backend.env
depends_on:
- mongodb
frontend:
build: ./frontend
ports:
- '3000:3000'
volumes:
- ./frontend/src:/app/src
container_name: frontend
stdin_open: true
tty: true
depends_on:
- backend

volumes:
data:
logs:

We rewrote the entire method, but the logic remains exactly the same. The application still consists of 3 parts:

  • mongo database
  • backend (written in nodejs)
  • frontend (written in angularjs)

I rewrite the part for MongoDB following way. The following command

docker run — — name mongodb -v data:/data/db — — rm — d — — network medium-net -e MONGO_INITDB_ROOT_USERNAME=roman -e MONGO_INITDB_ROOT_PASSWORD=secret mongo

version: "3.8"
services:
mongodb:
image: 'mongo'
volumes:
- data:/data/db
container_name: mongodb
environment:
- MONGO_INITDB_ROOT_USERNAME=roman
- MONGO_INITDB_ROOT_PASSWORD=secret
volumes:
data:

As you can see, we did not define tags such as — — rm and -d. It is completely fine; we do not have to define when we use Docker compose. The third thing we failed to define adequately was the network. Yes, you got the point, but let me explain. Actually, we do not have to. Docker compose creates a default network where all defined services will communicate.

For the backend part, I did the same. So let me show you. The following command

docker run — — name backend-con -v C:\Users\romanceresnak\Downloads\Docker\medium\backend/:app -v logs:/app/logs -v /app/node_modules -d — — rm -p 80:80 — — network medium-net backend-app

is rewrite command in docker-compose.yaml file

version: "3.8"
services:
backend:
build: ./backend
ports:
- '80:80'
volumes:
- logs:/app/logs # write data inside container
- ./backend:/app # bind mounts( map code inside the container)
- /app/node_moudels # anonymous values
container_name: backend
env_file:
- ./env/backend.env
depends_on:
- mongodb
volumes:
data:
logs:

I didn’t want to show the MONGODB_USERNAME and MONGODB_PASSWORD values, so I created a separate file called backend.env and referenced it in the docker-compose file. Backend.env looks following.

MONGODB_USERNAME=roman
MONGODB_PASSWORD=secret

For the frontend part, I did the same. So let me show you. The following command

docker run — — name frontend-con -v C:\Users\romanceresnak\Downloads\Docker\medium\frontend/:app — — rm -p 3000:3000 -it frontend-app

version: "3.8"
services:
frontend:
build: ./frontend
ports:
- '3000:3000'
volumes:
- ./frontend/src:/app/src
container_name: frontend
stdin_open: true
tty: true
depends_on:
- backend

There is one issue. I wanted to rewrite flag -it. For that part I had to define 2 values

stdin_open: true
tty: true

I saved all the changes and run following command:

  • docker-compose up

What do you think ? Instead of running 3 commands where it is quite big chance that we or me make error we can run everything with one command. Of course, for delete images and containers we can use same approach and run following command:

  • docker-compose down

Conclusion

Docker technology offers various development possibilities and sometimes it is really difficult to know the aspects of the given technology. I hope you liked the article. Bye bye.

--

--

Roman Ceresnak, PhD
CodeX
Writer for

AWS Cloud Architect. I write about education, fitness and programming. My website is pickupcloud.io