Skip to content

JavadJan/42-Inception

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This project has been created as part of the 42 curriculum by mkhavari


Description

Project Overview

Inception is a Docker automation project that sets up a complete web infrastructure using containerized services. It demonstrates container orchestration, networking, persistence, and security best practices.

Project Goal

To build and manage a multi-container f environment with:

  • Nginx as a reverse proxy (HTTPS/SSL)
  • WordPress as the main web application
  • MariaDB as the database
  • Redis for caching
  • FTP for file transfer
  • Adminer for database management
  • Portainer for container management
  • React Portfolio as a bonus frontend application

All services communicate via Docker networks, with persistent data in Docker volumes or bind mounts.


Architecture & Design Choices

What is Docker?

Docker is a platform for building, packaging, and running applications inside lightweight, isolated environments called containers.
It allows developers to bundle their code, dependencies, and runtime into a portable unit that behaves the same on any machine.

Docker provides:

  • Images → reusable blueprints for applications

  • Containers → isolated runtime environments created from images

  • Volumes → persistent storage outside the container

  • Networks → virtual communication between containers

With Docker, you can run applications consistently across development, testing, and production without worrying about OS differences or dependency conflicts.

VM vs Docker

  • VMs are an older way to package applications.
  • Docker is a newer way to package applications.
  • Both are virtualization tools.
  • A VM virtualizes the OS (including the kernel) and the application layer.
  • Docker virtualizes the application layer and shares the host OS kernel.

Docker:

######## Virtualized ################
#-----------------------------------#
#  		application layer			#
#-----------------------------------#
#####################################
-------------------------------------
|	 		Kernel OS				|
-------------------------------------
|			HardWare				|
-------------------------------------

VM:

######## Virtualized #################
# ---------------------------------- #
#  		application layer			 #
#------------------------------------#
#		 Kernel OS			 		 #
# ---------------------------------- #
######################################
-------------------------------------
|			HardWare				|
-------------------------------------
  1. VM is large (can be GBs) because it has its own OS kernel.
  2. Docker is lightweight because it includes only the application layer and shares the host OS kernel.

What is a Docker Image?

A Docker image is a blueprint for creating containers. It is built from a build context (your project folder) using a Dockerfile.

  • An image contains:

  • Your application code (copied during docker build)

  • Dependencies (Mariadb, Python, etc.)

  • System libraries

  • A minimal filesystem (user‑space only)

  • Instructions on how to run the app (CMD, ENTRYPOINT)

Images are read‑only and reusable.

What is a container?

  • It is a way to package an application with all necessary dependencies and configuration.
  • The package is portable and can be easily shared and moved around.
  • It makes development and deployment more efficient.
  • A container is a running instance of an image.
    • A container has:

    • Its own processes (Node, MongoDB, etc.)

    • Its own network namespace (IP, ports)

    • Its own environment variables

    • Its own isolated filesystem (based on the image) docker exec -it bash

     		$> ls
     		app  boot  etc	 lib	media  opt   root  sbin  sys  usr
     		bin  dev   home  lib64	mnt    proc  run   srv	 tmp  var
    But it shares the host’s kernel, which makes it lightweight.

What is a Volume?

A volume is persistent storage outside the container.

Used for:

  • Databases (MongoDB, MySQL)

  • Uploaded files

  • Logs

  • Anything that must survive container deletion

If a container is removed, the volume stays and can be reused.

Where do containers come from?

Image => Container

you can build unlimited container from the same Image

What resources does a container use from the host?

A container uses:

  • Host kernel (shared)

  • Host CPU

  • Host RAM

  • Host disk (for volumes)

  • Host network (via port mapping)

Everything else is isolated.

What is the “skeleton” of a container?

A container’s skeleton is:

  • The image filesystem (root FS)
  • The process namespace
  • The network namespace
  • The mount namespace
  • The cgroup limits (CPU, RAM)

Together, these create a lightweight “mini‑OS” environment.

Where does a Image live?

  • It lives in a container repository/registry:
    1. Public registry (e.g., Docker Hub: https://hub.docker.com/)
    2. Private registry

How containers improved the development process?

Before

  1. The installation process for each developer differed depending on the operating system.
  2. Everyone had to follow a different setup process even when working on the same project (e.g., if an application needs 10 services, each developer must install/configure those 10 services on their own OS).

After

  • You don't need to install all those services directly on your operating system.
  • Everything is packaged with the required configuration.
  • One command is enough instead of running many different installation commands.
  • Developers and Operations work together to package the application into one container.
  • No environment configuration is needed (except Docker at runtime).
  • Architecture diagram

What is a container, technically?

  • It is made up of images, which are stacked layers on top of each other.

  • The base layer is a Linux distribution such as Alpine.

  • It is important that the base layer is small, because it keeps the container size small.

      	---------------------
      	|	Application		|
      	---------------------
      	| 		...			|
      	---------------------
      	| intermidate Layer |
      	---------------------
      	| Linux:alpine3.10	|
      	---------------------
    

Container VS Images

Aspect Image Container
Definition A template (blueprint) used to create containers A running instance created from an image
Nature Static, read-only Dynamic, read-write
State Immutable (does not change after build) Mutable (can change during execution)
Creation Time Built during image build process Created when the image is executed
Lifecycle Exists as a file on disk or in a registry Runs as a process; removed unless persisted
Purpose Provides application environment and dependencies Executes the application inside the environment
Analogy Recipe for a cake The actual baked cake

Docker Secrets vs Environment Variables

Aspect Secrets Environment Variables
Security Sensitive data encrypted, passed via filesystem Visible in ps, env, logs
Use Case Passwords, API keys, sensitive credentials Configuration, non-sensitive settings
Visibility Only readable by containers with secret access Visible to all processes in container
In Project Used for: db_password, wp_admin_password, ftp_password Used for: DOMAIN_NAME, WORDPRESS_DB_HOST
Implementation WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password DOMAIN_NAME: ${DOMAIN_NAME}

Design Choice: This project uses Docker Secrets for all sensitive credentials (passwords) and Environment Variables for non-sensitive configuration (hostnames, usernames).

Docker Network vs Host Network

Aspect Docker Network (inception) Host Network
Isolation Containers isolated, communicate via network Containers share host network stack
Communication Service-name DNS resolution (e.g., mariadb:3306) Direct access to host ports
Security Better isolation between services Exposes all containers to host
Port Conflicts No conflicts (each container has own namespace) Risk of port conflicts
Default Bridge Custom inception bridge network network_mode: host
In Project networks: - inception (correct) ❌ NOT USED (would fail evaluation)

Design Choice: This project uses a custom Docker bridge network (inception) for secure container communication, preventing direct exposure to the host network.

Docker Volumes vs Bind Mounts

Aspect Docker Volumes Bind Mounts
Location Managed by Docker (/var/lib/docker/volumes/) Any location on host filesystem
Performance Optimized for Docker, faster Depends on host filesystem
Portability Portable across machines Tied to host filesystem structure
Permissions Managed by Docker daemon Host filesystem permissions apply
In Project mariadb:/var/lib/mysql (database persistence) ./requirements/bonus/static/portfolio:/app (React dev)
Use Case Production databases, generated data Development, source code, config files

Design Choice: This project uses:

  • Docker Volumes for persistent database data (mariadb volume, wordpress volume)
  • Bind Mounts for development (React portfolio source code for live reload)
  • Volumes for Portainer data (portainer_data)

Instructions

Prerequisites

  • Docker and Docker Compose installed
  • Make installed
  • Linux system (tested on Debian 13)
  • Domain name in /etc/hosts: 127.0.0.1 mkhavari.42.fr

Setup & Getting Started

1. Clone the Repository

git clone <repo-url>
cd inception

2. Configure Environment

Copy the .env.example to .env and update variables:

cp srcs/.env.example srcs/.env
# Edit srcs/.env with your domain, usernames, etc.

3. Build and Start Services

make all

This will:

  • Add domain to /etc/hosts
  • Create data directories
  • Generate random secrets
  • Build all Docker images
  • Start all containers

4. Access the Services

Service URL Credentials
WordPress https://mkhavari.42.fr User: mkhavari / Pass: see secrets/wp_admin_password.txt
WordPress Admin https://mkhavari.42.fr/wp-admin Same as above
Adminer http://localhost:8080/adminer.php User: wp_user, Host: mariadb, DB: wordpress
Portainer https://localhost:9443 Create on first login
React Portfolio http://localhost:5173 Direct access
FTP localhost:21 User: ftpuser / Password: in secrets/ftp_password.txt

5. Useful Commands

make ps          # List running containers
make logs        # View container logs
make restart     # Restart all services
make stop        # Stop all services
make start       # Start stopped services
make down        # Stop and remove containers
make clean       # Remove containers, images, volumes
make fclean      # Full clean + remove data directories
make re          # Full rebuild from scratch

Docker Images — CRUD Table

Operation Meaning Command
Create Build a new image from a Dockerfile docker build -t <name>:<tag> .
Read List all local images docker images
Update Rebuild image (use --no-cache to refresh layers) docker build --no-cache -t <name>:<tag> .
Delete Remove an image docker rmi <image_id>
Delete (Force) Remove image even if used by a container docker rmi -f <image_id>
Export Save image to a tar archive docker save -o <file>.tar <image>
Import Load image from a tar archive docker load -i <file>.tar
Prune Remove all dangling images docker image prune

Docker Containers — CRUD Table

Operation Meaning Command
Create Create container (don't start) docker create --name <name> <image>
Create + Run Create and start container (detached) docker run -d --name <name> <image>
Read (Running) List only running containers docker ps
Read (All) List all containers (including stopped) docker ps -a
Update (Start) Start a stopped container docker start <name_or_id>
Update (Restart) Restart a container docker restart <name_or_id>
Update (Exec) Run a command inside a running container docker exec -it <name_or_id> bash
Delete (Stop) Stop a running container docker stop <name_or_id>
Delete (Remove) Remove a stopped container docker rm <name_or_id>
Delete (Force) Force stop and remove container docker rm -f <name_or_id>
Logs View container logs (follow) docker logs -f <name_or_id>
Prune Remove all stopped containers docker container prune

Building and Running Your App

Build an image from your code

Run this in the folder containing your Dockerfile:

	docker build -t client-image .

This:

  • Reads your Dockerfile
  • Copies your code into the image
  • Installs dependencies
  • Produces a reusable image

Run a container from the image

	docker run -d -p 5000:5000 --name my-app-container my-app-image

Explanation:

  • -d → run in background
  • -p 5000:5000 → hostPort:containerPort
  • --name → readable container name

client-image → the image you built

What is Dockerfile, and used for?

Redis Cache Testing

Test Command Expected Result
Connection status docker exec -it wordpress wp redis status --allow-root --path=/var/www/html Status: Connected
Key count (before visit) docker exec -it redis redis-cli dbsize 0
Key count (after visit) docker exec -it redis redis-cli dbsize > 0 (cache populated)
Live monitor docker exec -it redis redis-cli monitor Shows GET/SET on browser request
List cached keys docker exec -it redis redis-cli keys "*" wp_:options, wp_:posts, etc.
Read cached value docker exec -it redis redis-cli get "wp_:options:siteurl" "https://mkhavari.42.fr"

Some additional command that help you to debuge your services:

test wordpress has connection to maraidb: docker exec -it wordpress bash -c 'mariadb -hmariadb -u wp_user -p"$(cat /run/secrets/db_password)" -e "SELECT 1;"'

Rebuild WordPress (no cache!)

docker compose build --no-cache wordpress docker compose up

./secrets/credentials.txt :
  • This file contains environment variable definitions for configuring a WordPress instance.
  • WORDPRESS_DB_NAME: Specifies the name of the WordPress database.
  • WORDPRESS_DB_USER: Defines the username used to connect to the database.
  • WORDPRESS_DB_PASSWORD_FILE: Points to the file containing the database password for enhanced security.
  • WORDPRESS_DB_HOST: Specifies the database host and port (e.g., hostname:port).
  • Note: The database password is stored in an external file for security purposes.

What is Dockerfile?

Dockerfile is a blueprint to create environment images
Dockerfile of Wordpress:
FROM debian:bullseye

RUN apt-get update && apt-get install -y \
	php7.4 \
	php7.4-fpm \
	php7.4-mysql \
	mariadb-client \
	wget \ # to download wordpress 
	curl \ 
	tar \ # to extract wordpress tar
	&& rm -rf /var/lib/apt/lists/*
	
RUN mkdir -p /var/www/html && \
wget https://wordpress.org/latest.tar.gz -O /tmp/wordpress.tar.gz && \
tar -xzf /tmp/wordpress.tar.gz -C /var/www/html --strip-components=1 && \
rm /tmp/wordpress.tar.gz # delete the download file no longer need, reduce the final image size
	

RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \
	&& chmod +x wp-cli.phar \
	&& mv wp-cli.phar /usr/local/bin/wp

# Copy php-fpm config
COPY conf/www.conf /etc/php/7.4/fpm/pool.d/www.conf

# Copy entrypoint script
COPY tools/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 9000

ENTRYPOINT ["/entrypoint.sh"]
CMD ["php-fpm7.4", "-F"]

how entrypoint run, for the first time?

for the first time the entrypoint will run when container start it will runs with ENTRYPOINT ["/entrypoint.sh"]

This script is a database bootstrapper: it prepares MariaDB the first time the container runs, creates the WordPress database and user, and then starts MariaDB in the foreground.

Workflow when a request send with browser:
Browser requests: https://mkhavari.42.fr/wp-login.php
     │
     ▼
Nginx receives it
     │
Is it a .php file?
     │
YES ─┘
     │
     ▼
fastcgi_pass wordpress:9000
(sends the .php file path to PHP-FPM)
     │
     ▼
PHP-FPM (www-data) executes the .php file
WordPress talks to MariaDB if needed
     │
     ▼
PHP-FPM returns pure HTML back to Nginx
     │
     ▼
Nginx sends HTML to Browser
3 user rule in wordpress:
https://mkhavari.42.fr
    │
    ├── mkhavari  ──► full admin access (manages everything)
    │
    ├── javad     ──► author access (writes posts only)
    │
    └── wp_user   ──► NOT a WordPress user (only talks to MariaDB)

How to test what PID 1 is inside your container?

docker exec -it ps -ef or docker exec -it ps aux then you will see: PID COMMAND 1 nginx: master process nginx -g daemon off; 12 nginx: worker process

How to test signal handling (SIGTERM, SIGINT)?

with command:
docker stop <name_container> => if stoped with delay them container PID is not triggerd by SIGTERM
or :
docker kill --signal=SIGTERM <name_container>

How to test zombie reaping?

go in container: docker exec -it sh thne: for i in $(seq 1 5); do (sleep 1 &) done if you see: PID 1 is not reaping zombies → broken container.

access to the pointer: https://localhost:9443

access to wordplress admin ? address: https://mkhavari.42.fr/wp-login.php or https://mkhavari.42.fr/wp-admin admin user: mkhavari password secrets/wp_admin_password.txt


Resources

Documentation & References

Docker

Services Used

Security


AI Usage Disclosure

Tasks Where AI Was Used

1. Docker Configuration & Architecture

  • Designing multi-service Docker Compose setup
  • Defining optimal networking strategy (bridge network vs host)
  • Planning volume/bind mount strategy for persistence and development
  • Choosing appropriate base images (Debian vs Alpine)

2. Entrypoint Scripts

  • Generating bash scripts for service initialization
  • Implementing retry logic for service dependencies (MariaDB wait-for-readiness)

3. Nginx Configuration

  • SSL/TLS certificate generation command
  • PHP-FPM FastCGI proxy configuration
  • URL rewriting rules for WordPress
  • Security headers and best practices

4. React Portfolio Frontend

  • Tailwind CSS styling for responsive design
  • React hooks usage (useState, useEffect)
  • Hot Module Reload (HMR) configuration in Vite

5. Documentation & README

  • Explaining Docker concepts and comparisons
  • Writing comprehensive README structure
  • Creating CRUD operation tables
  • Design choice explanations
  • Instruction formatting and organization

Parts Created by Student

Fully Implemented by Student:

  • Project conception and planning
  • Overall architecture decisions
  • Dockerfile builds and customization
  • Service integration and testing
  • Debugging and troubleshooting
  • Makefile automation
  • Environment variable management
  • Security decisions (Secrets vs Environment Variables)

About

Inception is a Docker‑based system‑administration project where I build a full WordPress stack using Docker Compose. Each service runs in its own container (Nginx, MariaDB, WordPress‑PHP‑FPM), with custom Dockerfiles, volumes, and networks to create a secure, reproducible infrastructure.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors