Taula de continguts

Dockerització d'aplicacions Symfony

Docker ens permet simplificar la construcció d'un entorn de desenvolupament igual per a tots els membres del nostre equip. A més, ens permet tenir diferents versions de les mateixes eines coexistint en la mateixa màquina i sense conflictes entre elles.

En aquest article es veurà com dockeritzar un projecte Symfony amb accés a una base de dades MariaDB.

, , , , , , , , , ,

Requeriments previs

Abans de començar a treballar s'ha de tenir instal·lat a l'ordinador els programes Docker i Docker Compose, per generar el contenidors, i un editor/entorn de desenvolupament, per poder escriure codi.

Preparació de l'entorn

L'entorn de desenvolupament que es farà servir constarà de dos contenidors, un per l'SGBD MariaDB i un altre on es desenvoluparà i s'executarà l'aplicació. Aquest darrer contenidor es generarà a partir d'una imatge de Symfony creada per Bitnami.

Els passos a seguir són els següents:

  1. Crear el directori per al projecte.
    $ mkdir paraules
  2. Descarregar, a dins del directori creat, l'arxiu docker-compose.yml
    $ cd paraules
    $ curl -LO https://raw.githubusercontent.com/bitnami/bitnami-docker-symfony/master/docker-compose.yml
  3. Modificar l'arxiu per adaptar-lo al nou projecte.
docker-compose.yml
  1. version: '2'
  2.  
  3. services:
  4.   mariadb:
  5.   image: docker.io/bitnami/mariadb:10.6
  6.   environment:
  7. # ALLOW_EMPTY_PASSWORD is recommended only for development.
  8. - ALLOW_EMPTY_PASSWORD=yes
  9. - MARIADB_USER=alumne
  10. - MARIADB_DATABASE=paraules_db
  11.   myapp:
  12.   image: docker.io/bitnami/symfony:6.1
  13.   ports:
  14. - '8000:8000'
  15.   environment:
  16. # ALLOW_EMPTY_PASSWORD is recommended only for development.
  17. - ALLOW_EMPTY_PASSWORD=yes
  18. - SYMFONY_DATABASE_HOST=mariadb
  19. - SYMFONY_DATABASE_PORT_NUMBER=3306
  20. - SYMFONY_DATABASE_USER=alumne
  21. - SYMFONY_DATABASE_NAME=paraules_db
  22.   volumes:
  23. - './paraules:/app'
  24.   depends_on:
  25. - mariadb

Es crearan dos serveis (contenidors), mariadb i myapp, que estaran connectats en una xarxa interna. Al servei mariadb se li ha definit el nom de l'usuari que accedirà a la base de dades (línia 9) i el nom que tindrà la base de dades (línia 10). Al servei myapp també se li ha de donar aquesta informació (línies 20 i 21) perquè pugui connectar-se a la base de dades. A més, es vincularà el directori paraules del host amb el directori /app del contenidor (línia 23) per poder editar el codi i permetre que sigui persistent.

mariadb i myapp (línies 4 i 11) són el nom dels dos serveis que ens proporcionaran els contenidors. Aquests noms no venen definits per docker, es poden canviar al gust de cadascú.

Aixecar els contenidors

Ara ja es poden aixecar els contenidors. Per fer-ho, estant al directori principal del projecte, s'ha d'executar la comanda:

$ docker-compose up

Si tot va bé, s'haurà creat un nou directori paraules amb tot el codi base del nou projecte. A més hi hauran dos serveis nous funcionant.

NAME                 COMMAND                  SERVICE             STATUS              PORTS
paraules-mariadb-1   "/opt/bitnami/script…"   mariadb             running             3306/tcp
paraules-myapp-1     "/opt/bitnami/script…"   myapp               running             0.0.0.0:8000->8000/tcp, :::8000->8000/tcp

Per provar que funciona es pot carregar en un navegador la URL http://localhost:8000

El resultat hauria de ser:

Interaccionant amb els contenidors

Les comandes symfony s'hauran d'executar al terminal del contenidor, així que serà necessari poder accedir. La manera de fer-ho és amb la comanda:

$ docker-compose exec <servei> <comanda>

Servei mariadb

$ docker-compose exec mariadb mysql -u alumne

Obre un terminal on es podran escriure comandes pròpies del client de MariaDB:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| paraules_db        |
| test               |
+--------------------+
3 rows in set (0.002 sec)
 
MariaDB [(none)]> 

Servei myapp

$ docker-compose exec myapp /bin/bash  

Aquesta comanda obre un terminal bash a dins del contenidor amb el directori de treball /app.

root@16d8a6cd179e:/app# ls
bin	       docker-compose.override.yml  public	  tests
composer.json  docker-compose.yml	    src		  translations
composer.lock  migrations		    symfony.lock  var
config	       phpunit.xml.dist		    templates	  vendor
root@16d8a6cd179e:/app#

Contingut del projecte

Ja estan tots els elements preparats per començar el desenvolupament.

Creació d'una entitat

Les comandes necessàries per crear l'entitat i fer la migració s'han d'executar al terminal bash associat al servei myapp.

Es pot crear una entitat amb la comanda make:entity tal com es mostra a continuació.

  1. root@16d8a6cd179e:/app# php bin/console make:entity
  2.  
  3. Class name of the entity to create or update (e.g. TinyGnome):
  4. > Paraula
  5.  
  6. created: src/Entity/Paraula.php
  7. created: src/Repository/ParaulaRepository.php
  8.  
  9. Entity generated! Now let's add some fields!
  10. You can always add more fields later manually or by re-running this command.
  11.  
  12. New property name (press <return> to stop adding fields):
  13. > paraula
  14.  
  15. Field type (enter ? to see all types) [string]:
  16. > string
  17.  
  18. Field length [255]:
  19. > 60
  20.  
  21. Can this field be null in the database (nullable) (yes/no) [no]:
  22. > no
  23.  
  24. updated: src/Entity/Paraula.php
  25.  
  26. Add another property? Enter the property name (or press <return> to stop adding fields):
  27. >
  28.  
  29.  
  30. Success!
  31.  
  32. Next: When you're ready, create a migration with php bin/console make:migration
  33.  
  34. root@16d8a6cd179e:/app#

Després d'executar la comanda, s'hauran generat dues classes noves: l'entitat (src/Entity/Paraula.php) i la classe que ens permetrà treballar amb els objectes d'aquesta entitat (src/Repository/ParaulaRepository.php).

El següent pas és preparar la migració:

$ php bin/console make:migration

I finalment es porta a terme aquesta migració:

$ php bin/console doctrine:migrations:migrate

S'ha creat la taula associada a l'entitat?

A partir d'aquí i fins al final de l'apartat les comandes s'han d'executar al terminal associat al servei mariadb.

Es pot comprovar. Primer s'estableix la connexió a la base de dades.

MariaDB [(none)]> connect paraules_db

Per observar quines taules té creades es pot fer servir la comanda:

MariaDB [paraules_db]> show tables;
+-----------------------------+
| Tables_in_paraules_db       |
+-----------------------------+
| doctrine_migration_versions |
| messenger_messages          |
| paraula                     |
+-----------------------------+

També es poden inserir dades:

INSERT INTO paraula(paraula) VALUES ('Aneto'), ('Montserrat');

I comprovar que s'ha guardat tot a la base de dades.

SELECT * FROM paraula;

Amb el resultat:

+----+------------+
| id | paraula    |
+----+------------+
|  1 | Aneto      |
|  2 | Montserrat |
+----+------------+

Tasca 1: Afegeix un nou servei que permeti tenir un PHPMyadmin funcionant i connectat a la base de dades.

Creació d'una pàgina d'inici

Les comandes necessàries per crear la pàgina d'inici s'han d'executar al terminal bash associat al servei myapp.

Totes les peticions que es fan a una APP Symfony les rep un controlador, que s'encarrega d'obtenir l'informació demanada i generar la vista fent servir una plantilla.

Les plantilles de Symfony estan escrites en el llenguatge twig.

Per crear el controlador i la plantilla associada s'ha d'executar la comanda:

$ php bin/console make:controller IniciController

Després d'executar la comanda s'hauran generat dos arxius nous:

Modifica el controlador perquè s'assembli al següent:

IniciController.php
<?php
 
namespace App\Controller;
 
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
 
class IniciController extends AbstractController
{
    #[Route('/inici', name: 'app_inici')]
    public function index(): Response
    {
      $data = date('d/m/Y');
      $hora = date('H:i:s');
        return $this->render('inici/index.html.twig', [
            'data' => $data,
            'hora' => $hora,
        ]);
    }
}

Modifica la plantilla perquè sigui com la següent:

index.html.twig
{% extends 'base.html.twig' %}
 
{% block title %}Hello IniciController!{% endblock %}
 
{% block body %}
<style>
  article{width: 500px; margin:5em auto; background-color:DeepSkyBlue; text-align: center; padding: 1em; border-radius:15px;border:2px solid black;}
  h1{font-size: 3em; color:white; text-shadow: 0 0 3px #000000;}
  p{font-size:1.5em;color:white;text-shadow: 0 0 2px #000000;}
</style>
 
<article>
  <h1>Hello World!!!!</h1>
  <hr>
  <p>He nascut el dia <b>{{ data }}</b> a las <b>{{ hora }}</b>
  <hr>
</article>
{% endblock %}

Ara ja es pot carregar la pàgina al navegador amb la següent adreça: http://localhost:8000/inici

Tasca 2: Crea una nova pàgina que mostri una llista no ordenada <ul> amb totes les paraules de la taula paraula.