HumansBestFriend: Docker-based Distributed Application Project
In my virtualization class at ESIEA, we were tasked with deploying a distributed application using Docker. The application, named “HumansBestFriend,” consists of five components: a front end, back end, function, cache, and database. This project provided a hands-on experience with Docker and Docker Compose, and I’m excited to share what I learned.
The repository for this project can be found here.
Project Overview
The HumansBestFriend application is a simple distributed system where users can vote between two options (cats or dogs). The architecture involves multiple services written in different languages, including Python, Node.js, and .NET, and utilizes Redis for caching and Postgres for storage.
Components
-
Vote Service (Python)
- A web app that lets users vote between two options.
- Dockerfile for vote service:
FROM python:3.11-slim AS base RUN apt-get update && \ apt-get install -y --no-install-recommends curl && \ rm -rf /var/lib/apt/lists/* WORKDIR /usr/local/app COPY requirements.txt ./requirements.txt RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 80 CMD ["gunicorn", "app:app", "-b", "0.0.0.0:80", "--log-file", "-", "--access-logfile", "-", "--workers", "4", "--keep-alive", "0"]
-
Worker Service (.NET)
- Consumes votes from Redis and stores them in the Postgres database.
- Dockerfile for worker service:
FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/dotnet/sdk:7.0 as build ARG TARGETPLATFORM ARG TARGETARCH ARG BUILDPLATFORM WORKDIR /source COPY *.csproj . RUN dotnet restore -a $TARGETARCH COPY . . RUN dotnet publish -c release -o /app -a $TARGETARCH --self-contained false --no-restore FROM mcr.microsoft.com/dotnet/runtime:7.0 WORKDIR /app COPY --from=build /app . ENTRYPOINT ["dotnet", "Worker.dll"]
-
Result Service (Node.js)
- Displays the results of the voting in real time.
- Dockerfile for result service:
FROM node:18-slim RUN apt-get update && \ apt-get install -y --no-install-recommends curl tini && \ rm -rf /var/lib/apt/lists/* WORKDIR /usr/local/app RUN npm install -g nodemon COPY package*.json ./ RUN npm ci && \ npm cache clean --force && \ mv /usr/local/app/node_modules /node_modules COPY . . ENV PORT 80 EXPOSE 80 ENTRYPOINT ["/usr/bin/tini", "--"] CMD ["node", "server.js"]
-
Redis Service
- Used for collecting new votes.
- Configuration:
services: redis: image: redis:alpine healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 5s retries: 3
-
Postgres Service
- Stores votes data.
- Configuration:
services: db: image: postgres:15-alpine volumes: - "db-data:/var/lib/postgresql/data" - "./healthchecks:/healthchecks" healthcheck: test: /healthchecks/postgres.sh interval: "5s"
Deployment
Using Docker Commands
To deploy the application using Docker commands without Docker Compose, follow these steps:
-
Build the images:
docker build -t vote ./vote docker build -t worker ./worker docker build -t result ./result docker build -t redis ./redis docker build -t db ./db
-
Create a network:
docker network create cats-or-dogs-network
-
Run the services:
docker run -d --name redis --network cats-or-dogs-network redis:alpine docker run -d --name db --network cats-or-dogs-network -v db-data:/var/lib/postgresql/data -v ./healthchecks:/healthchecks postgres:15-alpine docker run -d --name vote --network cats-or-dogs-network -p 5002:80 -v ./vote:/usr/local/app vote docker run -d --name result --network cats-or-dogs-network -p 5001:80 -v ./result:/usr/local/app result docker run -d --name worker --network cats-or-dogs-network worker
Using Docker Compose
To deploy the application using Docker Compose, follow these steps:
-
Create a
docker-compose.yml
file:version: '3.8' services: redis: image: redis:alpine networks: - back-tier healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 5s retries: 3 db: image: postgres:15-alpine volumes: - "db-data:/var/lib/postgresql/data" - "./healthchecks:/healthchecks" networks: - back-tier healthcheck: test: /healthchecks/postgres.sh interval: "5s" vote: image: vote volumes: - ./vote:/usr/local/app ports: - "5002:80" networks: - front-tier - back-tier healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 15s timeout: 5s retries: 3 start_period: 10s result: image: result volumes: - ./result:/usr/local/app ports: - "5001:80" networks: - front-tier - back-tier healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 15s timeout: 5s retries: 3 start_period: 10s worker: image: worker depends_on: redis: condition: service_healthy db: condition: service_healthy networks: - back-tier networks: front-tier: back-tier: volumes: db-data:
-
Run the Compose file:
docker-compose up
What I Learned
This project was incredibly instructive, and I learned several key concepts and skills:
- Docker Fundamentals: Gained hands-on experience in creating Dockerfiles, building images, and running containers.
- Service Dependencies: Learned how to manage service dependencies and health checks in Docker Compose.
- Networking: Understood how to set up and manage Docker networks to allow inter-container communication.
- Distributed Systems: Gained insight into building and deploying distributed applications using multiple services and languages.
- Practical DevOps Skills: Developed practical DevOps skills that are highly valuable in the industry.
This project not only enhanced my technical skills but also gave me a deeper understanding of the complexities involved in deploying distributed applications. If you’re interested, you can check out the full repository here.
Thank you for reading! I hope this overview provides a clear understanding of the HumansBestFriend Docker project and the valuable learning experience it provided.