Aller au contenu principal

Containerization and Deployment

Overview

The Notes App uses Docker containerization to package and deploy the application components. This approach ensures consistent environments across development, testing, and production while simplifying deployment and scaling.

What is Containerization?

Containerization is a method of packaging applications that:

  • Encapsulates applications with their dependencies and runtime environment
  • Ensures consistency across different deployment environments
  • Simplifies deployment by providing portable, self-contained units
  • Enables scalability through orchestration tools
  • Isolates applications from the host system and other containers

Docker Architecture

The Notes App uses a multi-container architecture with three main services:

  1. Frontend Container: React application served by Vite development server
  2. Backend Container: Node.js API server with Express.js
  3. Database Container: MongoDB database for data persistence

Docker Compose Configuration

File: docker-compose.yml

Docker Compose orchestrates multiple containers and defines their relationships.

version: '3.8'

services:
notes-front-app:
container_name: notes-front-app
build:
context: ./frontend/notes-app
dockerfile: Dockerfile
ports:
- "5173:5173"
depends_on:
- notes-api

mongo-local:
image: mongo:latest
container_name: mongo-local
ports:
- "27017:27017"

notes-api:
image: notes-api
build: ./backend/
container_name: notes-api
ports:
- "8000:8000"
depends_on:
- mongo-local

Configuration Breakdown

Version Declaration

version: '3.8'
  • Compose file version: Specifies Docker Compose file format version
  • Feature compatibility: Version 3.8 supports modern Docker features

Frontend Service

notes-front-app:
container_name: notes-front-app
build:
context: ./frontend/notes-app
dockerfile: Dockerfile
ports:
- "5173:5173"
depends_on:
- notes-api

Service Configuration:

  • container_name: Sets a custom name for the container
  • build.context: Specifies the build directory containing source code
  • build.dockerfile: Points to the Dockerfile for building the image
  • ports: Maps host port 5173 to container port 5173
  • depends_on: Ensures the API service starts before the frontend

Database Service

mongo-local:
image: mongo:latest
container_name: mongo-local
ports:
- "27017:27017"

Database Configuration:

  • image: Uses the official MongoDB Docker image
  • latest tag: Always pulls the most recent MongoDB version
  • Port mapping: Exposes MongoDB on standard port 27017

Backend Service

notes-api:
image: notes-api
build: ./backend/
container_name: notes-api
ports:
- "8000:8000"
depends_on:
- mongo-local

API Configuration:

  • build: Builds custom image from backend directory
  • Port mapping: Exposes API on port 8000
  • Database dependency: Waits for MongoDB to start first

Backend Dockerfile

File: backend/Dockerfile

Defines how to build the backend API container.

# Use Node.js image as the base image
FROM node:18-alpine

# Set working directory
WORKDIR /app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the backend API code to the working directory
COPY . .

# Expose the port that the backend API will be running on
EXPOSE 8000

# Start the backend API
CMD ["npm", "start"]

Dockerfile Instructions Explained

Base Image

FROM node:18-alpine
  • FROM: Specifies the base image to build upon
  • node:18-alpine: Official Node.js version 18 on Alpine Linux
  • Alpine Linux: Lightweight Linux distribution, smaller image size

Working Directory

WORKDIR /app
  • WORKDIR: Sets the working directory inside the container
  • Path consistency: All subsequent commands run from /app

Dependency Installation

COPY package*.json ./
RUN npm install
  • COPY package*.json: Copies package.json and package-lock.json
  • Wildcard pattern: * matches both package.json and package-lock.json
  • RUN npm install: Installs Node.js dependencies
  • Layer optimization: Dependencies installed before copying source code

Source Code Copy

COPY . .
  • COPY . .: Copies all remaining files from build context
  • Efficient layering: Source changes don't invalidate dependency layer

Port Exposure

EXPOSE 8000
  • EXPOSE: Documents which port the container listens on
  • Metadata only: Doesn't actually publish the port (done in docker-compose)

Startup Command

CMD ["npm", "start"]
  • CMD: Defines the default command to run when container starts
  • Array syntax: Preferred format for command specification
  • npm start: Runs the start script defined in package.json

Frontend Dockerfile

File: frontend/notes-app/Dockerfile

Defines how to build the frontend React container.

# Use Node.js official image as the base image
FROM node:18-alpine AS build

# Set working directory inside the container
WORKDIR /app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code to the working directory
COPY . .

# Expose the port the app will run on
EXPOSE 5173

# Command to start the development server
CMD ["npm", "run", "dev", "--", "--host"]

Frontend-Specific Configuration

Multi-stage Build Setup

FROM node:18-alpine AS build
  • AS build: Names this stage for potential multi-stage builds
  • Development setup: Currently configured for development mode

Development Server Command

CMD ["npm", "run", "dev", "--", "--host"]
  • npm run dev: Starts Vite development server
  • --host flag: Allows external connections to the container
  • Development mode: Enables hot reloading and development features

Build Tools Configuration

Vite Configuration

File: frontend/notes-app/vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
plugins: [react()],
})

Vite Features:

  • Fast development server: Hot module replacement for quick development
  • React plugin: Enables JSX transformation and React features
  • Modern build tool: Optimized for modern JavaScript development

Tailwind CSS Configuration

File: frontend/notes-app/tailwind.config.js

export default {
content: ['./index.html','./src/**/*.{js,ts,jsx,tsx}',],
theme: {
extend: {
colors: {
primary: "#2B85FF",
secondary: "#EF863E"
}
},
},
plugins: [],
}

Configuration Details:

  • content: Specifies files to scan for CSS classes
  • theme.extend.colors: Defines custom color palette
  • Purging: Only includes CSS for classes actually used in the application

PostCSS Configuration

File: frontend/notes-app/postcss.config.js

export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

PostCSS Plugins:

  • tailwindcss: Processes Tailwind CSS directives
  • autoprefixer: Adds vendor prefixes for browser compatibility

Container Networking

Service Communication

Internal Network: Docker Compose creates a default network for service communication

# Backend connects to database using service name
connectionString: "mongodb://mongo-local:27017/"

Service Discovery: Containers can reach each other using service names

  • Frontend → Backend: http://notes-api:8000
  • Backend → Database: mongodb://mongo-local:27017

Port Mapping

Host to Container Mapping:

  • Frontend: localhost:5173notes-front-app:5173
  • Backend: localhost:8000notes-api:8000
  • Database: localhost:27017mongo-local:27017

Deployment Workflow

Development Deployment

  1. Build and Start: docker-compose up --build
  2. Service Startup Order:
    • MongoDB container starts first
    • Backend API starts after database
    • Frontend starts after backend API
  3. Access Points:

Container Lifecycle

Startup Sequence:

  1. Image Building: Docker builds custom images for frontend and backend
  2. Network Creation: Docker Compose creates internal network
  3. Container Startup: Containers start in dependency order
  4. Service Registration: Services become available on internal network

Shutdown Process:

  1. Graceful Shutdown: docker-compose down stops all containers
  2. Network Cleanup: Removes the created network
  3. Container Removal: Removes stopped containers (images remain)

Benefits of This Architecture

Development Benefits

  • Consistent Environment: Same setup across all developer machines
  • Easy Setup: Single command starts entire application stack
  • Isolation: No conflicts with other projects or system dependencies
  • Hot Reloading: Development servers support live code updates

Production Benefits

  • Scalability: Individual services can be scaled independently
  • Portability: Containers run consistently across different environments
  • Resource Efficiency: Containers share host OS kernel
  • Service Isolation: Failures in one service don't affect others

Operational Benefits

  • Simple Deployment: Single command deploys entire application
  • Version Control: Infrastructure defined as code
  • Rollback Capability: Easy to revert to previous versions
  • Monitoring: Container logs and metrics available through Docker tools

Connection to Other Components

Application Architecture

  • Frontend Container: Serves React application and static assets
  • Backend Container: Runs Express.js API and handles business logic
  • Database Container: Provides MongoDB data persistence

Configuration Management

  • Environment Variables: Managed through Docker Compose
  • Build Context: Source code and dependencies packaged in images
  • Network Configuration: Service discovery and communication handled automatically