Back to projects
Dec 18, 2023
5 min read

HumansBestFriend: Docker-based Distributed Application Project

An overview of my virtualization class project, deploying a multi-component application using Docker and Docker Compose.

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

  1. 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"]
  2. 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"]
  3. 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"]
  4. 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
  5. 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:

  1. 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
  2. Create a network:

    docker network create cats-or-dogs-network
  3. 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:

  1. 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:
  2. 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.