An open API service indexing awesome lists of open source software.

https://github.com/bendahl/docker-todo

Simple Multi Container Docker App
https://github.com/bendahl/docker-todo

docker docker-compose java multi-container-docker openapi spring-boot

Last synced: about 1 month ago
JSON representation

Simple Multi Container Docker App

Awesome Lists containing this project

README

          

# Cheat Sheet
This cheat sheet is meant to provide a high level overview of the project and help you to get started with the Docker
examples provided.

## Motivation
This project aims to provide a simple playground for multi container Docker projects and to serve as a starting point to
further examine Docker.

## Prerequisites
This project uses Java (11), Maven and Docker along with Docker Compose.
You will only need to install Java on your system if you're planning on building the applications without using Docker (for local development, etc...).
Otherwise, the provided Dockerfiles will take care of this, by using [multistage builds](https://docs.docker.com/develop/develop-images/multistage-build/).
If you're not using Maven, don't worry, simply
use one of the wrapper scripts (mvnw*) in order to build the project. For all other dependencies you'll find links that
will provide further information here:

* Docker: https://docs.docker.com/engine/installation/
* Docker Compose: https://docs.docker.com/compose/install/
* Java [optional]: https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html

__IMPORTANT__: If you're working on Linux, do not simply install Docker and Docker Compose straight from your distro's
repositories, as the versions found there may be outdated. Make sure to check the version first. All examples were
created and tested using Version 1.13 of Docker and Docker Compose. So anything >= Version 1.13 should be ok.

## Project Structure
The below tree shows the basic project file structure and gives a few hints on what you will find where. Use this as your
map. More details are explained further on in the document.

.
├── backend // the backend service project root
│   ├── Dockerfile // this Dockerfile will build an image for the backend - note that you'll need to perform a Maven build first
│   ├── mvnw // Maven wrapper script for Mac/Linux/Cygwin
│   ├── mvnw.cmd // Maven wrapper script for Windows
│   ├── pom.xml // Maven pom.xml with the basic build settings
│   └── src // Java sources
│      ├── main
│      │   ├── java
│      │   │   └── de
│      │   │   └── bendahl
│      │   │   ├── SwaggerConfig.java // Swagger setup (for more information see: http://swagger.io/)
│      │   │   ├── TodoApplication.java // the main entry point of the app
│      │   │   ├── TodoEndpoint.java // REST endpoint
│      │   │   ├── Todo.java // the Todo entity class for DB and JSON mapping
│      │   │   └── TodoRepository.java // Spring JPA repository that handles data access
│      │   └── resources // non-code resources used by the backend project
│      │   ├── application.properties // app settings
│      │   └── data.sql // initial data to populate the in H2 DB
│      └── test
│      └── java
│      └── de
│      └── bendahl
│      └── TodoApplicationTests.java // standard unit test generated by Spring Boot
├── docker-compose.yml // basic docker-compose file that will deploy frontend and backend, using the Docker Hub repositories
├── frontend // the frontend service project root
│   ├── Dockerfile // this Dockerfile will build an image for the frontend - note that you'll need to perform a Maven build first
│   ├── mvnw // Maven wrapper script for Mac/Linux/Cygwin
│   ├── mvnw.cmd // Maven wrapper script for Windows
│   ├── pom.xml // Maven pom.xml with the basic build settings
│   └── src // Java sources
│      ├── main
│      │   ├── java
│      │   │   └── de
│      │   │   └── bendahl
│      │   │   ├── DemoFrontendApplication.java // Main entry point of the frontend application
│      │   │   ├── TodoChangeListener.java // interface used to create a change event binding
│      │   │   ├── Todo.java // todo class that maps to and from JSON
│      │   │   ├── TodoLayout.java // layout that is used to display the todo list items
│      │   │   ├── TodoList.java // controls the behavior of the actual todo list
│      │   │   ├── TodoService.java // the service that handles all backend calls
│      │   │   └── TodoUI.java // setup of basic layout and components of the application
│      │   └── resources
│      │   ├── application.properties // app settings - the backend URL is setup here
│      │   ├── static // not needed in this case - generated by Spring Boot
│      │   └── templates // not needed in this case - generated by Spring Boot
│      └── test
│      └── java
│      └── de
│      └── bendahl
│      └── DemoFrontendApplicationTests.java // standard unit test generated by Spring Boot
└── README.MD // Start here ;-)

### The Backend
The backend consists of a REST service that is built on top of Spring Boot. OpenAPI is integrated in the service in order
to make it easy to play around with a few simple requests and get a feel for what it actually does. Besides Java and Spring
Boot, H2 DB is used as a data store in order to keep things simple and not require an addtional database(container) to be set up.
The backend listens on port 8081 and the base URL is: _http://HOSTNAME_GOES_HERE:8081/todos_. The swagger web ui is located
at: _http://HOSTNAME_GOES_HERE:8081/swagger-ui.html_. The OpenApi schema is located at: _http://localhost:8081/v3/api-docs_.
The health status of the backend service is exposed using the Spring Boot Actuator and exposed at
_http://localhost:8080/actuator/health_.

Note that the H2 DB is set up to use file storage, in order to be able to use this project to not only demonstrate
networking in Docker, but also some storage basics. As long as the backend container is not removed, the data will not
be lost upon container restart/stop. The default storage location of the db is the file `/tmp/todo.mv.db` within the
container (see application.properties for details). This should be a sensible default in most cases. If, however, you
wish to override this behavior, it's as simple as setting the environment variable `DB_FILENAME` in order to change it.
The format of the filename is `/`, where filename will automatically be expanded to "filename.mv.db".

Building the Docker image:
* cd into the backend directory first
* then enter the following (omitting the ":1.0" will create an image tagged as "latest"):
`docker build -t todo-backend:1.0 .`

Creating and running a container based on your local image:
`docker run -d --name backend -p 8081:8081 todo-backend:1.0`

This will essentially create and immediately start a new container named "backend" based on your local image created above.
You can now connect to it on the exposed port 8081.

__Useful commands__:

- `docker ps`: See a list of all running containers

- `docker stop [CONTAINER]`: Stop a container

- `docker ps -a`: See a list of all containers (running or not) and their status

- `docker rm [CONTAINER]`: Delete a container

- `docker rmi [IMAGE:TAG]`: Delete an image

### The Frontend
The frontend application is a basic Vaadin Todo app, largely taken from https://github.com/vaadin-marcus/spring-boot-todo/.
It also uses Java, Spring Boot and Maven as its stack. It is exposed on port 8080 by default. Simply navigate to the url
_http://HOSTNAME_GOES_HERE:8080_ in your favorite browser to see the web ui.

In order to successfully run the frontend, make sure that the backend is up and running and listening for connections
on port 8081 (default setting of the backend). You will also need to specify the environment variable _BACKEND_HOSTNAME_,
since the frontend uses this variable to retrieve the actual host name of the backend application.

Additional information:
When using Docker, a container's host name usually matches its name. Therefore, if you started the backend container like
described above, its host name will be "backend". Also note that the two containers will have to be on the same bridge
network or, alternatively, use the host network (not recommended) in order to communicate with each other. All in all this
can be achieved in three easy steps, described in the following section.

__Running frontend and backend (not using docker-compose)__:

- Create a bridge network (called 'matrix' in this example): `docker network create matrix`
- Run the backend container: `docker run -d --name backend --network matrix todo-backend:1.0 backend/.`
- Run the frontend container: `docker run -d --name frontend --network matrix -p 80:8080 -e BACKEND_HOSTNAME=backend todo-frontend:1.0 frontend/.`

This will essentially create a new bridge network called 'matrix' and connect two containers (frontend and backend) to it.
Since both containers are on the same bridge network, they will be able to reach each other over tcp. Therefore there is
no need to expose any port for the backend. The frontend, on the other hand, will need to be reachable from the host network,
so you can navigate to the web ui using your browser. That's the reason for the '-p 80:8080' in the frontend call above.
Also, don't forget to set the environment variable _BACKEND_HOSTNAME_ when running the frontend. Otherwise the service
will fail to startup, since it doesn't know the backend's host name.

__Useful commands__:

- `docker ps`: See a list of all running containers

- `docker stop [CONTAINER]`: Stop a container

- `docker ps -a`: See a list of all containers (running or not) and their status

- `docker rm [CONTAINER]`: Delete a container

- `docker rmi [IMAGE:TAG]`: Delete an image

- `docker network create [NETWORK]`: Create a new network

- `docker network ls`: List existing networks

- `docker network rm [NETWORK]`: Delete existing network

### Docker Compose File
If you wold like to run the full example (front- and backend) without going through the hassle of creating your own network
and manually running the containers, you may also use docker-compose to automate the whole process, including the creation
of the two images. Note, however, that you will need to successfully build the two jar files (frontend and backend) first
in order to build the images.

__Running the examples via docker-compose__:

- Build the backend: `cd backend && mvn clean install && cd ..`
- Build the frontend: `cd frontend && mvn clean install && cd ..`
- Now run the example using docker-compose: `docker-compose up -d` (the -d ensures that the processes run in the background)
- Open up http://localhost in your favorite browser to see the result

**NOTE THAT THIS WILL FAIL WHEN USING ROOTLESS DOCKER, SINCE PORT 80 IS A PRIVILEGED PORT. EITHER USE ANOTHER PORT IN THE COMPOSE FILE OR USE DOCKER WITH ROOT.**

__Useful commands__:
- `docker-compose up`: Run containers according to the docker-compose.yml. Stdout will be forwarded.
- `docker-compose up -d`: Run containers according to the docker-compose.yml. Processes will be run in the background.
- `docker-compose ps`: View running containers and their status.
- `docker-compose stop`: Stop the running containers.
- `docker-compose down`: Stop and delete the running containers and the newly created network.

## Credits
Special thanks goes to Marcus Hellberg for his excellent Vaadin example that really did prove to be a great time saver when creating the frontend application. The original
Vaadin project is located here on Github at: https://github.com/vaadin-marcus/spring-boot-todo/

## Miscellaneous
I hope that this little project will be useful for you in your quest to learn more about Docker and hopefully provide a fun playground to get started with multi container apps.
Let me know if you've got any further ideas/suggestions! Feel free to clone the heck out of this repo and reuse whatever part you want. Cheers!