Docker Compose

De Wiki personal d'en Guillem Serrat
La revisió el 16:33, 20 gen 2026 per Guseba (discussió | contribucions) (Generació de Dockerfiles)
(dif.) ← Versió més antiga | Versió actual (dif.) | Versió més nova → (dif.)

Creació d'arxius i directoris

Per començar a treballar amb Docker Compose crearem la següent estructura de directoris

6.3/
└── lemp
    ├── docker-compose.yml
    ├── nginx-conf
    │   └── nginx.conf
    ├── php-dockerfile
    └── php-files
        ├── 00_connect.php
        └── index.php

En el fitxer index.php trobarem la informació de PHP.

<?php phpinfo(); ?>

En el fitxer de configuració d'Nginx definirem la configuració del servidor web Nginx

server {
   listen 80 default_server; # Escoltem pel port 80, tot i que després el port 80 del Docker es converteix en el 8090 del host
   listen [::]:80 default_server;

   server_name localhost;

   root /var/www/html;
   index index.php index.html;

   location / {
       try_files $uri $uri/ /index.php?$args;
   }

   location ~* \.php$ {
       fastcgi_pass php:9000;
       include fastcgi_params;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_param SCRIPT_NAME $fastcgi_script_name;
   }
}

Generació de Dockerfiles

Per aquesta pràctica generarem un Dockerfile que recuperarà la imatge de PHP i instal·larà els mòduls necessaris per executar codi PHP

FROM php:8.1-fpm

# Installing dependencies for the PHP modules
RUN apt-get update && \
   apt-get install -y zip libzip-dev libpng-dev

# Installing additional PHP modules
RUN docker-php-ext-install mysqli pdo pdo_mysql gd zip

Docker Compose

Quan treballem amb Dockers, sobretot quan necessitem una xarxa de Dockers conectada entre sí, fem servir el que s’anomena Docker Compose

Docker compose treballa amb fitxers docker-compose.yml, els quals descriuen:

  • Serveis (o contenidors)
  • Imatges d’aquests serveis
  • Ports, xarxes, volums i variables d’entorn
  • Dependències entre serveis

En aquest cas, generarem un docker-compose.yml on definirem

  1. Un contenidor anomenat PHP
    1. La imatge del contenidor serà a partir del Dockerfile (el propi compose fa el build)
    2. Un volum compartit entre la carpeta host ./php-files i /var/www/html
      1. Un volum compartit té la funció de mantenir els mateixos arxius en els directoris especificats entre el host i el docker
    3. Dependència del contenidor “mariadb”
      1. Aquest contenidor no es posarà en marxa fins que el contenidor mariadb no ho estigui
  2. Un contenidor anomenat Nginx
    1. La imatge del contenidor serà la imatge oficial de Nginx, de dockerhub
    2. Els ports exposats seran
      1. El port 8090 de la màquina host dirigirà el port 80 del Docker
    3. Links (tot i que avui en dia no cal especificar-ho, ja que el propi compose crea una xarxa interna
      1. Un link al contenidor “php”, per permetre que tots dos contenidors es puguin comunicar
    4. Volums
      1. El contingut de ./php-files del host es compartirà amb el directori /var/www/html del Docker
      2. El contingut de ./nginx-conf del host es compartirà amb el directori /etc/nginx/conf.d del Docker
    5. Dependència del contenidor amb nom “php”
      1. Aquest contenidor no es posarà en marxa fins que el contenidor php no ho estigui
  3. Un contenidor anomenat mariadb (contenidor que únicament serà accesible des de la xarxa del docker compose i no des de l’exterior, i per això no cal exposar cap port)
    1. La imatge del contenidor serà la imatge oficial de MariaDB, de dockerhub
    2. Variables d’entorn
      1. La contrasenya de ROOT de MariaDB serà fjeclot
    3. Volums
      1. El contingut de /var/lib/mysql es desarà a un volum intern de Docker anomenat mysqldata (no es un directori del projecte, és un volum intern de docker, els quals s'acustuma a desar-se a /var/lib/docker/volumes)
  4. Un contenidor anomenat phpmyadmin
    1. La imatge del contenidor serà la imatge oficial de phpmyadmin, de dockerhub
    2. Variables d’entorn
      1. El hostname de la BD serà el nom del contenidor mariadb (Docker compose pot resoldre hostnames amb el nom del propi contenidor)
    3. Dependència del contenidor “mariadb”
      1. Aquest contenidor no es posarà en marxa fins que el contenidor mariadb no ho estigui
# version: '3.8' # L'atribut version ja no és necessari en l'última versió de docker

services:

   php:
       build:
           dockerfile: php-dockerfile #Construim el Docker a partir de la imatge pròpia
       volumes:
           - './php-files:/var/www/html' # Definim un volum. Els documents del directori ./php-files del host es compartiran amb el directori /var/www/html del Docker
       depends_on:
           - mariadb # Requerim que el servei mariadb estigui operatiu

   nginx:
       image: nginx:latest # Utilitzem la imatge oficial de nginx, la última versió
       ports:
           - 8090:80 # El port 8090 del host dirigirà al port 80 del Docker
       links: # Avui en dia no cal especificar-ho, ja que docker compose ja crea una xarxa interna
           - 'php' # Permet que el Docker Nginx es pugui comunicar amb el Docker "php"
       volumes:
           - './php-files:/var/www/html' # El contingut de ./php-files del host es compartirà amb el directori /var/www/html del Docker
           - './nginx-conf:/etc/nginx/conf.d' # El contingut de ./nginx-conf del host es compartirà amb el directori /etc/nginx/conf.d del Docker
       depends_on:
           - php # Requerim que el servei php estigui operatiu

   mariadb: # No exportem cap port ja que la BD no cal que sigui accesible des de l'exterior, sinó que únicament des dels altres Dockers
       image: mariadb:10.9 # Fem servir la imatge oficial de mariadb
       environment:
           MYSQL_ROOT_PASSWORD: fjeclot # Definim la contrasenya de root de MariaDB
       volumes:
           - mysqldata:/var/lib/mysql # El contingut de /var/lib/mysql es desarà a un volum intern de Docker anomenat mysqldata (NO ÉS UN DIRECTORI DEL PROJECTE, ÉS UN VOLUM INTERN DE DOCKER)

   phpmyadmin:
       image: phpmyadmin/phpmyadmin:latest # Fem servir la imatge de PHPMyAdmin
       ports:
           - 8091:80 # El port 8091 del host dirigirà al port 80 del Docker
       environment:
           PMA_HOST: mariadb # Indiquem el hostname de la BD, en aquest cas el nom del docker
       depends_on:
           - mariadb # Requerim que el servei mariadb estigui operatiu

# Definim els volums INTERNS de Docker
volumes:
 mysqldata: # Els arxius dels volumns interns de Docker s'acustuma a desar-se a /var/lib/docker/volumes

Un cop hem realitzat totes les configuracions necessàries, posarem en marxa tots els contenidors del docker compose

docker compose up -d # Al mateix directori on es troba el docker compose

Amb l’ordre docker compose ps -a comprovarem que s’han creat els 4 dockers a partir del compose.

guseba@phpDebianAzure:/var/www/html/php/exercicis/practica6/6.3/lemp$ docker compose ps -a NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS lemp-mariadb-1 mariadb:10.9 "docker-entrypoint.s…" mariadb 42 hours ago Up 38 minutes 3306/tcp lemp-nginx-1 nginx:latest "/docker-entrypoint.…" nginx 42 hours ago Up 38 minutes 0.0.0.0:8090->80/tcp, [::]:8090->80/tcp lemp-php-1 lemp-php "docker-php-entrypoi…" php 42 hours ago Up 38 minutes 9000/tcp lemp-phpmyadmin-1 phpmyadmin/phpmyadmin:latest "/docker-entrypoint.…" phpmyadmin 42 hours ago Up 38 minutes 0.0.0.0:8091->80/tcp, [::]:8091->80/tcp

Amb l’ordre sudo netstat -putan | grep 80 podem comprovar que els ports definits anteriorment estan escoltant en el nostre localhost, i tenen de nom de servei docker-proxy

guseba@phpDebianAzure:/var/www/html/php/exercicis/practica6/6.3/lemp$ sudo netstat -putan | grep 80 | grep LISTEN tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 2067/docker-proxy tcp 0 0 0.0.0.0:8090 0.0.0.0:* LISTEN 1564/docker-proxy tcp 0 0 0.0.0.0:8091 0.0.0.0:* LISTEN 1715/docker-proxy tcp6 0 0 :::80  :::* LISTEN 756/apache2 tcp6 0 0 :::8080  :::* LISTEN 2072/docker-proxy tcp6 0 0 :::8090  :::* LISTEN 1570/docker-proxy tcp6 0 0 :::8091  :::* LISTEN 1720/docker-proxy

Connexió de dos Dockers amb un Docker compose (PHP + MariaDB)

Un cop tenim tots els contenidors en marxa a partir del docker compose, tots els contenidors del mateix compose poden comunicar-se i fer servir els seus serveis.

En aquest cas, disposem d'un contenidor web i un contenidor de MariaDB, i realitzarem una prova de connexió a la BD del contenidor de MariaDB

Per connectar-nos a una BD hem de saber el nom o la IP del servidor amb MariaDB, en aquest cas, en ser un Docker, haurem de saber la IP del docker.

docker exec -it lemp-mariadb-1 bash -l

# Dins del docker
ip a

Recordem que tots els Dockers d’un mateix compose comparteixen subxarxa, per tant, tant Nginx com PhpMyAdmin tindran també una IP de la mateixa xarxa. Aprofitant que estem dins del contenidor amb MariaDB, crearem la BD aula310

mysql -u root -p
CREATE DATABASE aula310;

Seguidament, modificarem el fitxer 00_connect.php i escriurem un codi per provar la connexió a la BD. A servername, enlloc d’especificar “localhost” com hem fet fins ara, especificarem la IP del docker abans trobada.

<!DOCTYPE html>
<html lang="ca">
    <head>
        <title>Exemple PDO Docker Guillem Serrat</title>
        <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <?php
            // Definim els paràmetres per realitzar la connexió
            $servername = "172.18.0.2";      // El servidor on ens connectarem
            $username = "root";             // L'usuari de MariaDB
            $password = "fjeclot";          // La contrasenya de l'usuari
            $dbname = "aula310";            // La base de dades que farem servir

            try {
            // Definim un nou objecte de la classe PDO amb els atributs: host al que ens connectarem, la base de dades, el nom d'usuari i contrasenya.
            $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);

            // A través de la funció setAttribute, agafem el tipus d'error en cas de que n'hi hagi algun
            $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            echo "Connectat a la base de dades.";

            } catch(PDOException $e) {                                      // En cas de que hi hagi un error, PHP llença una PDOException, i la variable $e agafa aquesta excepció
                echo "No es pot connectar. Motiu: " . $e->getMessage();     // Es mostra el missatge
            }

            $conn = null;                                                   // Tanca la connexió amb la BBDD
        ?>
    </body>
</html>

I per últim, si entrem a localhost:8090 (port del Nginx) i obrim el fitxer 00_connect.php, comprovarem que ens hem connectat a la BD de forma exitosa.