Crear un contenedor con Docker en Linux

Crear un contenedor con Docker en Linux

Crear un contenedor con Docker nos recuerda al paradigma de programación POO, donde creamos una clase y luego la instanciamos en un objeto. En Docker es algo parecido, primero creamos una imagen y luego la instanciamos en un contenedor.

Para este laboratorio didáctico, vamos a desplegar con Docker un proyecto llamado ‘proyecto-php‘ desarrollado con RoadRunner PHP, que es un servidor de aplicaciones PHP de alto rendimiento, administrador de procesos y balanceador de carga escrito en Go. Nuestro ‘proyecto-php‘ trabaja junto con una base de datos MySQL.

Damos por sentado que el proyecto con RoadRunner ya funciona perfectamente antes de contenerizarlo, y que ya tenemos a Docker instalado, si no, el siguiente artículo nos muestra cómo hacerlo.

Instalar Docker en Kubuntu Linux

Crear un contenedor con Docker en Linux


El objetivo: El contenedor Docker deberá contener la app en PHP corriendo con RoadRunner, y la base de datos MySQL se mantendrá instalada directamente en el sistema operativo (no vamos a contenerizar a MySQL).

Antes de comenzar a ‘volear comandos’, debemos tener listo nuestro archivo Dockerfile (archivo llamado igual, Dockerfile) dentro del directorio del proyecto:

cd proyecto-php
touch Dockerfile

Este es el contenido de nuestro Dockerfile:

# Dockerfile Final y Robusto (Modo Workers/Pipes)

# 1. IMAGEN BASE
FROM php:8.3-cli

# 2. INSTALACIÓN DE DEPENDENCIAS DEL SISTEMA
RUN apt-get update && apt-get install -y \
 git \
 unzip \
 libzip-dev \
 libpq-dev \
 default-mysql-client \
 && rm -rf /var/lib/apt/lists/*

# 3. INSTALACIÓN DE EXTENSIONES DE PHP
RUN docker-php-ext-install -j$(nproc) pdo pdo_mysql pdo_pgsql zip mysqli

# 4. INSTALACIÓN DE COMPOSER
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html

# 5. COPIA DE CÓDIGO Y BINARIO DE ROADRUNNER
COPY . .

# 6. INSTALACIÓN DE ROADRUNNER
# Copiamos el binario 'rr' desde el directorio del proyecto
# y lo movemos a una ubicación que está en el PATH del contenedor.
COPY rr /usr/local/bin/rr
RUN chmod +x /usr/local/bin/rr

# 7. INSTALACIÓN DE DEPENDENCIAS DE LA APLICACIÓN
# RUN composer clear-cache
# RUN composer install --no-dev --optimize-autoloader

# 8. EXPOSICIÓN Y COMANDO DE INICIO
EXPOSE 8080
# Como 'rr' está en /usr/local/bin, se ejecuta directamente
CMD ["rr", "serve", "-c", ".rr.yaml"]

Pasos para la creación del contenedor


1- Entramos al directorio de nuestro proyecto

2- Construimos la imagen (yo la llame proyecto-rr):

sudo docker build -t proyecto-rr .

3- Creamos el contenedor

sudo docker run --rm -p 9090:8080 --name proyecto-php --add-host host.docker.internal:172.17.0.1 proyecto-rr

(Como el comando docker run es para crear instancias, el volverlo a usar por segunda con el mismo nombre de instancia – proyecto-php – nos dará error, por eso usamos la opción --rm, para que al detenerlo borre esa instancia. Usamos la opción --rm cuando estamos en proceso de desarrollo. La mejor práctica es crear la instancia docker run y para volverla a ejecutar usamos docker start proyecto-php)

Al comando docker run podemos adicionar la opción --restart unless-stopped para que el contenedor se vuelva a ejecutar cuando se reinicie la máquina.

4- Como la app necesita conectarse a la BD directamente, debemos conocer la IP del de nuestro contenedor, esto con el fin de relacionarla con el usuario MySQL. Entonces ejecutamos:

sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' proyecto-php

(me arroja la 172.17.0.2)

Crear un contenedor con Docker en Linux

Permisos vistos desde Webmin

5- Vamos al archivo de configuración de MySQL Server, y cambiamos el parámetro bind-address para que MySQL acepte las solicitudes desde esa IP:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 172.17.0.2

Por ende, la dirección IP del gateway de Docker es la 172.17.0.1, para confirmarlo ejecutamos:

sudo docker network inspect bridge --format='{{(index .IPAM.Config 0).Gateway}}

6- Instanciar el proyecto en productivo: Con la IP del gateway de Docker instanciamos el contenedor para productivo:

sudo docker run --rm -p 9090:8080 --name proyecto-php --add-host host.docker.internal:172.17.0.1 proyecto-rr

Cuando instanciamos el contenedor para productivo, la estamos ejecutamos sin volumen, para que la imagen queda estática. Esto le da máxima portabilidad al ser complemente independiente, pero los cambios que hagamos en nuestro proyecto de PHP no se verán reflejados en productivo. Para que los cambios se vean reflejados en Productivo, debemos construir de nuevo la imagen y ejecutar el docker estático nuevamente con docker run. En mi caso, voy a crear una nueva imagen del proyecto solo para la instancia Productivo, asi:

sudo docker build -t proyecto-rr:prod .

7- Instanciar el proyecto en modo desarrollo:

sudo docker run --rm -p 9090:8080 --name proyecto-php --add-host host.docker.internal:172.17.0.1 -v /home/usuario/proyecto:/var/www/html proyecto-rr

La opción -v /home/usuario/proyecto enlaza el directorio de nuestro proyecto con el directorio de trabajo del contenedor, es decir, es como un acceso directo, no es que haga una copia. Así, cualquier cambios que realicemos en nuestro proyecto se verá reflejado automáticamente en el contenedor.

La conexión de PHP a la base de datos

La conexión a MySQL de forma procedimental luce generalmente así:

$con = mysqli_connect('localhost', 'produccion', 'contraseña', 'base_de_datos');
if (!$con) {
// Es mejor usar $worker->error() para notificar a RoadRunner un error fatal al inicio
Worker::create()->error("❌ Error de conexión a MySQL: " . mysqli_connect_error());
exit(1);
}
Ahora la misma conexión pero a través de Docker:

$con = mysqli_connect('host.docker.internal', 'produccion', 'contraseña', 'base_de_datos');
if (!$con) {
// Es mejor usar $worker->error() para notificar a RoadRunner un error fatal al inicio
Worker::create()->error("❌ Error de conexión a MySQL: " . mysqli_connect_error());
exit(1);
}

En Resumen


Creamos un contenedor instanciando la imagen

sudo docker run

En adelante seguimos ejecutando el contenedor con:

sudo docker start

Listamos los contenedores creados:

sudo docker ps -a

Listamos la imágenes:

sudo docker image ls

Borramos un contenedor:

sudo docker rm id_del_contenedor

Borramos una imagen:

sudo docker image rm

NO se puede borrar una imagen sin antes borrar los contenedores que se instanciaron a partir de ella.

Y eso es todo.

Comparte esto en
Publicado en Desarrollo Web.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *