[42 Project] → inception

Language
date
Jan 23, 2023
thumbnail
i99DEV_Docker_application_and_NodeJs_application_and_GitLab_app_30dc22e6-f2df-4492-ba02-e83afb61c56d.png
slug
inception
author
status
Public
tags
42Project
summary
type
Post
updatedAt
Aug 21, 2023 05:57 PM
Status
Done
Person

Overview.

This project involves setting up a small infrastructure consisting of various services using Docker Compose on a virtual machine. Each service must run in its own dedicated container, which must be built using the penultimate stable version of Alpine or Debian. The services that must be set up include NGINX with TLSv1.2 or TLSv1.3 only, WordPress with PHP-FPM, and MariaDB. There must also be two volumes, one for the WordPress database and one for the WordPress website files. The containers must be connected through a Docker network and must be able to restart in case of a crash. It is not allowed to use pre-made Docker images or services like DockerHub, and it is not recommended to use any hacky patches or infinite loops in the entrypoint commands or scripts. The domain name for the website must be configured to redirect to the local IP address, and the only entrypoint into the infrastructure must be through port 443 using TLSv1.2 or TLSv1.3. It is mandatory to use environment variables, and it is recommended to store them in a .env file.

Structure Project.

  • srcs
    • nginx (directory for NGINX files)
      • Dockerfile
      • nginx.conf
    • wordpress (directory for WordPress files)
      • Dockerfile
      • wp-config.php
    • mariadb (directory for MariaDB files)
      • Dockerfile
    • docker-compose.yml (file for setting up the Docker containers and network)
  • Makefile (file for building the Docker images and running the application)
  • .env (file for storing environment variables)

Requirements.

  • Docker and Docker Compose: You should be familiar with the concepts of containers, images, and the purpose of Docker Compose in setting up and managing a multi-container application.
  • Linux: You should be comfortable working in a Linux environment, including navigating the filesystem, editing files, and using the command line.
  • Networking: You should understand the basics of networking, including the concept of ports and protocols.
  • Webservers: You should be familiar with the concept of a webserver and how it serves content to clients.
  • NGINX: You should have some familiarity with NGINX, including how to configure it to serve content and how to set up TLS.
  • WordPress: You should have some basic knowledge of WordPress, including how to install and configure it.
  • PHP: You should have some familiarity with PHP, as it is used in WordPress.
  • MariaDB: You should have some understanding of MariaDB and how to set it up and use it as a database.

Docker and Docker Compose.

Overview.

Docker is a platform for building, running, and managing containers. Containers are a lightweight form of virtualization that allow you to package an application and its dependencies into a single, portable unit that can be easily moved from one environment to another.
An example of using Docker is to build a container image for a simple web application. You could create a Dockerfile that defines the steps to install the necessary software (such as a web server and a programming language runtime) and configure the application. You can then use the Docker CLI to build the image and run it as a container, starting the web server and making the application available to clients.
Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to define the services that make up your application (such as databases, queues, and web servers), and then use a single command to create and start all of the containers.
An example of using Docker Compose is to set up a WordPress site with a MariaDB database. You could create a docker-compose.yml file that defines two services for the WordPress application and the MariaDB database. You could then use the docker-compose up command to create and start the containers for both services. The WordPress container would be linked to the MariaDB container and configured to use it as a database backend.

Dockerfile

This Dockerfile starts with a base image that includes Python 3.7 and the Alpine Linux distribution. It then installs some necessary packages, creates a directory, and copies the application files into the container. It installs the dependencies specified in the requirements.txt file and exposes the app's port. Finally, it sets the entrypoint command and the default command to run when the container is started.
FROM python:3.7-alpine

# Install necessary packages and create app directory
RUN apk add --no-cache build-base && \
    mkdir /app

# Set the working directory
WORKDIR /app

# Copy the application files and install dependencies
COPY . .
RUN pip install -r requirements.txt

# Expose the app port and set the entrypoint
EXPOSE 5000
ENTRYPOINT ["python"]
CMD ["app.py"]

Docker-compose.

This docker-compose.yml file defines two services: one for WordPress and one for MariaDB. It specifies the build directories for the corresponding Dockerfiles and sets environment variables for the database connection details. It also specifies volumes for the WordPress and MariaDB data and defines dependencies between the services. Finally, it defines named volumes for the data directories to persist data between container restarts.
version: '3'
services:
  wordpress:
    build: wordpress
    environment:
      WORDPRESS_DB_HOST: mariadb
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: password
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - mariadb
  mariadb:
    build: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: password
    volumes:
      - mariadb_data:/var/lib/mysql
volumes:
  wordpress_data:
  mariadb_data:

Linux.

Linux is a open-source operating system that is widely used on servers and other computing platforms. To be comfortable working in a Linux environment, you should be familiar with the following:
  • Navigating the filesystem: This includes understanding the file and directory structure and being able to use commands such as ls, cd, and pwd to list, change, and print the current directory.
  • Editing files: This includes being able to use text editors such as vi or nano to create and modify files.
  • Using the command line: This includes understanding basic shell commands and being able to use pipes and redirection to combine and manipulate the output of multiple commands.

Environment.

An environment refers to the overall operating context in which a program or script is run. In the context of a Linux system, the environment can include a variety of factors such as the current working directory, the user and group under which a process is running, the system-wide configuration files, and the environment variables that are set.
Environment variables are values that can be passed to programs or scripts at runtime, and they can be used to configure the behavior of the program or script. In a Linux system, environment variables can be set in a number of ways, including in the system-wide configuration files, in the user's shell profile, or on the command line.
Here is an example of setting an environment variable on the command line:
$ export MYVAR="hello world"
$ echo $MYVAR
hello world
In this example, the MYVAR variable is set to the value "hello world" and is then displayed using the echo command. The export command makes the variable available to child processes.
Here is an example of setting an environment variable in a shell profile file:
# ~/.bashrc

export MYVAR="hello world"
In this example, the MYVAR variable is set in the user's .bashrc file, which is executed when the user logs in or opens a new terminal window. The variable will be available to all processes run by the user.

Networking.

Overview.

In the context of Docker, networking refers to the way that containers and host systems communicate with each other and with external networks. Docker uses its own network stack and network drivers to provide isolation and connectivity for containers.
Some basic concepts in Docker networking include:
  • Ports: Containers can expose one or more ports that allow them to listen for connections from other containers or from the host system. For example, a container running a web server might expose port 80 (HTTP) or port 443 (HTTPS).
  • Protocols: Containers can use a variety of protocols to communicate, such as TCP, UDP, and HTTP.
  • Network drivers: Docker provides a number of network drivers that allow containers to be connected in different ways. Some common drivers include bridge, host, and overlay.
Here is an example of using Docker networking:
$ docker run -d --name web -p 80:80 nginx
In this example, the docker run command is used to start a container based on the nginx image and name it web. The -p flag is used to publish the container's port 80 to the host system's port 80, which allows the web server to be accessed from the host. The -d flag runs the container in detached mode, which means it runs in the background.
You can then access the web server from the host system by visiting http://localhost in a web browser.

Dockerfile.

You can use the concepts of ports and protocols in a Dockerfile by using the EXPOSE instruction to specify the ports that the container should expose. For example:
FROM nginx
EXPOSE 80 443
In this example, the EXPOSE instruction tells Docker that the container will listen on ports 80 and 443. This does not actually publish the ports to the host system, but it allows you to use the -p flag with docker run to publish the ports when starting the container.

Docker-Compose.

You can also use the ports field in a docker-compose.yml file to specify the ports to publish for a service. For example:
version: '3'
services:
  web:
    build: .
    ports:
      - "80:80"
      - "443:443"
In this example, the ports field specifies that the container's ports 80 and 443 should be published to the host system's ports 80 and 443, respectively. This allows the service to be accessed from the host system using the published ports.

Web Server.

Overview

A web server is a program that listens for incoming requests from clients, such as web browsers, and sends back responses, such as HTML pages or other content. Web servers are typically used to host websites and serve content to users over the Internet.
In the context of Docker, you can use a web server container to host a website or other web-based application. By building a container image for a web server and deploying it as a container, you can easily set up and manage the server in a consistent and portable way.
Here is an example of using Docker to run a web server:
Copy code
$ docker run -d -p 80:80 nginx
In this example, the docker run command starts a container based on the nginx image and publishes the container's port 80 to the host system's port 80. The -d flag runs the container in detached mode, so it runs in the background.
You can then access the web server from the host system by visiting http://localhost in a web browser.
To host a website with this container, you would need to add the website files to the container and configure the web server to serve the files. This could be done by building a custom image using a Dockerfile that installs the necessary software and copies the website files into the container, or by mounting a volume with the website files into the container at runtime.

DockerFile

To use a Dockerfile to set up a web server that serves a website, you would need to include instructions for installing the necessary software and copying the website files into the container.
Here is an example Dockerfile that sets up a simple web server using the NGINX image:
FROM nginx

# Install the necessary packages
RUN apt-get update && \
    apt-get install -y wget unzip

# Download and unpack the website files
RUN wget https://example.com/website.zip && \
    unzip website.zip -d /usr/share/nginx/html

# Remove the default configuration file and copy in the custom one
RUN rm /etc/nginx/conf.d/default.conf && \
    cp /usr/share/nginx/html/nginx.conf /etc/nginx/conf.d/

# Expose the default HTTP port
EXPOSE 80

In this example, the Dockerfile starts with the nginx image and installs some necessary packages using the RUN instruction. It then downloads and unpacks the website files using wget and unzip, and copies a custom NGINX configuration file into place. Finally, it exposes the default HTTP port (port 80) using the EXPOSE instruction.
To build and run this container, you can use the docker build and docker run commands:
$ docker build -t mywebsite .
$ docker run -d

NGINX.

Overview

NGINX is a popular open-source web server and reverse proxy that is often used in conjunction with Docker. When used as a web server, NGINX can serve static content, such as HTML, CSS, and JavaScript files, as well as dynamic content generated by application servers. When used as a reverse proxy, NGINX can route incoming requests to one or more backend servers, allowing you to scale your web applications horizontally.
To use NGINX with Docker, you will need to have some familiarity with how to configure NGINX to serve content and set up TLS (Transport Layer Security). This can involve editing configuration files, such as nginx.conf, and specifying options for serving content and setting up TLS.

Requirements for using NGINX with Docker.

  • Configuration files: You will need to include any necessary NGINX configuration files in your container. This can include the main nginx.conf file, as well as any additional configuration files for your site or application.
  • Content files: If you are using NGINX as a web server, you will need to include the content files for your site or application in the container. This can include HTML, CSS, and JavaScript files, as well as any other necessary assets.
  • TLS certificates: If you are using NGINX with TLS, you will need to include the necessary TLS certificates in the container. This can include a certificate and private key for the server, as well as any intermediate certificates.
  • Port publishing: You will need to publish the relevant ports from the container to the host system using the p flag with docker run. For example, to expose the default HTTP port (80) and HTTPS port (443), you would use p 80:80 -p 443:443.

nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
This nginx.conf file sets up a basic NGINX server with default settings. It includes directives for specifying the user and number of worker processes, as well as options for logging and connection handling. It also includes a http block that defines basic HTTP settings, such as the MIME types to include and the default content type, as well as options for logging and sendfile.
You can customize this file to suit your specific needs by adding or modifying directives as needed. For example, you might want to add a server block to specify the location of your site's content files and set up TLS.

site.conf

server {
    listen       80;
    server_name  example.com;

    root   /usr/share/nginx/html/example;
    index  index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}
In this example, the server block specifies that the server should listen on port 80 and that the server name is example.com. The website's content files' root directory and the default index files default index file. The location block specifies that requests for any URI should be served from the root directory if a matching file is found, or return a 404 error if no matching file is foucustomise
You can customize this file to suit your specific needs by adding or modifying directives as needed. For example, you might want to add a location block to handle specific URI patterns or set up TLS.

WordPress.

Overview.

WordPress is a popular open-source content management system (CMS) that is often used with Docker. When used with Docker, WordPress can be easily set up and managed in a consistent and portable way. To use WordPress with Docker, you will need to have some basic knowledge of how to install and configure WordPress. This can involve downloading and extracting the WordPress files, creating a database, and editing the WordPress configuration file to specify the database connection details.
FROM php:7.4-fpm

# Install necessary packages and PHP extensions
RUN apt-get update && \
    apt-get install -y \
        libfreetype6-dev \
        libjpeg-dev \
        libpng-dev \
        libzip-dev \
        unzip && \
    docker-php-ext-install -j$(nproc) \
        mysqli \
        pdo \
        pdo_mysql \
        zip && \
    docker-php-ext-configure gd --with-freetype --with-jpeg && \
    docker-php-ext-install -j$(nproc) gd

# Download and extract WordPress
RUN mkdir -p /usr/src/wordpress && \
    wget https://wordpress.org/latest.zip && \
    unzip latest.zip -d /usr/src/wordpress && \
    rm latest.zip

# Copy the WordPress files into the web root directory
RUN cp -a /usr/src/wordpress/. /var/www/html/

# Set the ownership and permissions for the WordPress files
RUN chown -R www-data:www-data /var/www/html/ && \
    find /var/www/html/ -type d -exec chmod 755 {} \; && \
    find /var/www/html

wp-config.php

The wp-config.php file is a WordPress configuration file that is used to specify the database connection details and other settings for a WordPress site.
Here is an example of a basic wp-config.php file:
<?php
/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the installation.
 * You don't have to use the web site, you can copy this file to "wp-config.php"
 * and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * Database settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @link https://wordpress.org/support/article/editing-wp-config-php/
 *
 * @package WordPress
 */

// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'database_name_here' );

/** Database username */
define( 'DB_USER', 'username_here' );

/** Database password */
define( 'DB_PASSWORD', 'password_here' );

/** Database hostname */
define( 'DB_HOST', 'localhost' );

/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8' );

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

/**#@+
 * Authentication unique keys and salts.
 *
 * Change these to different unique phrases! You can generate these using
 * the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
 *
 * You can change these at any point in time to invalidate all existing cookies.
 * This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define( 'AUTH_KEY',         'put your unique phrase here' );
define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
define( 'NONCE_KEY',        'put your unique phrase here' );
define( 'AUTH_SALT',        'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
define( 'NONCE_SALT',       'put your unique phrase here' );

/**#@-*/

/**
 * WordPress database table prefix.
 *
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = 'wp_';

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 *
 * For information on other constants that can be used for debugging,
 * visit the documentation.
 *
 * @link https://wordpress.org/support/article/debugging-in-wordpress/
 */
define( 'WP_DEBUG', false );

/* Add any custom values between this line and the "stop editing" line. */



/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
	define( 'ABSPATH', __DIR__ . '/' );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
In this wp-config.php file, you can specify the database connection details, such as the database name, username, and password, as well as other settings, such as the database table prefix and WordPress debugging mode. You can also set up unique keys and salts for security purposes.

wp-config.php and Dockerfile

To set the WordPress configuration file with Docker build, you can use a combination of a Dockerfile and an environment file.
Here is an example of using a Dockerfile to set the WordPress configuration file with Docker build:
Copy code
FROM wordpress:latest

# Copy the WordPress configuration file
COPY wp-config.php /var/www/html/wp-config.php

# Set the ownership and permissions for the configuration file
RUN chown www-data:www-data /var/www/html/wp-config.php && \
    chmod 640 /var/www/html/wp-config.php

In this example, the COPY instruction is used to copy the wp-config.php configuration file from the build context into the /var/www/html directory in the container. The RUN instructions are then used to set the ownership and permissions for the configuration file.
To set the WordPress configuration file using an environment file, you can use the env_file option in the docker-compose.yml file:
Copy code
version: '3'
services:
  wordpress:
    image: wordpress:latest
    env_file: .env
    volumes:
      - ./wp-config.php:/var/www/html/wp-config.php

In this example, the env_file option is used to specify an environment file that contains the necessary environment variables for the WordPress container. The volumes option is then used to mount the wp-config.php configuration file from the host system into the /var/www/html directory in the container.
You can then edit the environment file and the configuration file on the host system and they will be reflected in the running container. This can be useful for testing and debugging, as it allows you to make changes without rebuilding the image.

MariaDB

MariaDB is a popular open-source database management system that is used with Docker to provide a reliable and scalable database solution.
To use MariaDB with Docker, you will need to have some understanding of how to set it up and use it as a database. This can involve installing and configuring MariaDB, creating and managing databases and tables, and running SQL queries to manipulate and retrieve data.
Here is an example of using a Dockerfile to set up a MariaDB container:
FROM mariadb:latest

# Copy the MariaDB configuration file
COPY my.cnf /etc/mysql/my.cnf

# Set the ownership and permissions for the configuration file
RUN chown mysql:mysql /etc/mysql/my.cnf && \
    chmod 640 /etc/mysql/my.cnf

# Set up a volume for the MariaDB data directory
VOLUME /var/lib/mysql

In this example, the COPY instruction is used to copy the my.cnf configuration file from the build context into the /etc/mysql directory in the container. The RUN instructions are then used to set the ownership and permissions for the configuration file. The VOLUME instruction is used to set up a volume for the MariaDB data directory, which will allow the data to be persisted even if the container is stopped or removed.
To set up volumes for the MariaDB database in the docker-compose.yml file, you can use the volumes option:
version: '3'
services:
  mariadb:
    image: mariadb:latest
    volumes:
      - ./database:/var/lib/mysql

In this example, the volumes option is used to mount a host directory called database into the /var/lib/mysql directory in the container. This will allow the data in the MariaDB database to be persisted on the host system.

Volumes Case.

In Docker, volumes are used to persist data generated by and used by Docker containers. When a volume is created, it creates a new directory on the host file system and mounts it into the container at a specified location. Any data written to the volume is stored on the host system and is persisted even if the container is stopped or removed.
For example, consider the following docker-compose.yml file:
version: '3'
services:
  wordpress:
    image: wordpress:latest
    volumes:
      - ./wp-content:/var/www/html/wp-content

In this example, the volumes option is used to mount a host directory called wp-content into the /var/www/html/wp-content directory in the WordPress container. This allows the WordPress content, such as plugins, themes, and media files, to be persisted on the host system.
Host folders or files can be used with Docker volumes to store data that is generated by and used by Docker containers. This can be useful for testing and debugging, as it allows you to make changes to the data on the host system and have them reflected in the running container.
It is important to note that volumes are only persisted as long as the volume exists. If the volume is deleted, the data stored in the volume will be lost.

References

Here are some references that you may find useful when working with Docker and the various technologies: