Cómo crear una imagen para Docker usando un Dockerfile

Escrito por picodotdev el , actualizado el .
gnu-linux planeta-codigo
Enlace permanente Comentarios

Podemos usar los contenedores disponibles en Docker Hub, donde están disponibles las aplicaciones de bases de datos, servidores de aplicaciones de múltiples lenguajes, servidores web más populares y entre otras muchas herramientas. Pero también podemos definir nuestras propias imágenes personalizadas con las necesidades que tengamos. Lo que necesitamos es escribir un archivo que contenga la receta para construir la imagen del contenedor, este archivo es el Dockerfile.

Las imágenes de Docker son el sistema de archivos que usa el proceso o procesos que se arrancan en los contenedores. Si nos convencen las características de Docker y estamos decididos a usarlo y ya sabemos como administrar de forma básica los contenedores si queremos disponer de una imagen adaptada a los servicios que necesitamos para iniciar contenedores tendremos que crearla, en este artículo explicaré cómo crear una imagen para docker personalizada.

Antes de crear una imagen para docker podemos buscar en el registro de imágenes de Docker que han creado otros usuarios y los han compartido por si hay alguna que ya se adapte a nuestras necesidades, si nos sirve alguna y es algo popular nos evitaremos tener que modificarla nosotros mismos según salgan nuevas versiones de los servicios que use. El registro de imágenes de docker es un servicio en el que las organizaciones publican versiones oficiales junto a otros usuarios que comparten y colaboran en la creación de las imágenes. Para los servicios más conocidos dispondremos ya de las imágenes como podrían ser: mysql, redis, postgresql, ubuntu, wordpress, nginx, mongodb, …

Si no hay ninguna que se adapte totalmente a nuestras necesidades, no nos gusta como están construidas las existes o no confiamos en el mantenimiento que puedan tener esas imágenes podemos crear las nuestras propias. Para crear una imagen de docker se necesita una receta en forma de archivo Dockerfile que contiene la descripción e instrucciones para construir la imagen. Para crear un dockerfile podemos basarnos en los de las imágenes del registro de docker.

Archivo Dockerfile

Este podría ser el contenido y la receta de un dockerfile si quisiésemos crear una imagen de docker con el servidor web nginx como servicio basada en la distribución Ubuntu.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
FROM ubuntu:20.04
MAINTAINER picodotdev <pico.dev@gmail.com>

RUN apt-get -y update && \
    apt-get -y install nginx
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
Dockerfile

Los archivos Dockerfile son archivos de texto con una secuencia de directivas:

  • FROM: indica la imagen base a partir de la cual crearemos la imagen que construirá el Dockerfile.
  • MAINTAINER: documenta el creador de la imagen.
  • ENV: establece el valor de una variable de entorno para los siguientes comandos RUN.
  • RUN: permite ejecutar una instrucción en el contenedor, por ejemplo, para instalar algún paquete mediante el gestor de paquetes (apt-get, yum, rpm, …).
  • ADD: permite añadir un archivo al contenedor, en muchas ocasiones se utiliza para proporcionar la configuración de los servicios (ssh, mysql, …).
  • VOLUME: establece puntos de montaje que al usar el contenedor se pueden proporcionar, los volúmenes son al forma de externalizar un determinado directorio y proporcionar persistencia (las imágenes de docker son de solo lectura y no almacenan datos entre diferentes ejecuciones).
  • EXPOSE: indica los puertos TCP/IP por los que se pueden acceder a los servicios del contenedor, los típicos son 22 (SSH), 80 (HTTP) u 443 (HTTP).
  • CMD: establece el comando del proceso de inicio que se usará si no se indica uno al iniciar un contenedor con la imagen.

Construir una imagen de Docker

Las instrucciones RUN y ADD permiten aprovisionar la imagen a partir de la imagen base, ejecutando comandos para instalar paquetes como Nginx y añadir archivos de configuración si los hubiera copiados de la máquina anfitrión. El archivo Dockerfile es la receta con la que se construye una imagen de Docker.

1
2
#!/usr/bin/env bash
docker build -t "picodotdev/nginx:1.0" .
docker-build.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Sending build context to Docker daemon  10.75kB
Step 1/6 : FROM ubuntu:20.04
 ---> f643c72bc252
Step 2/6 : MAINTAINER picodotdev <pico.dev@gmail.com>
 ---> Using cache
 ---> 58c7c960b513
Step 3/6 : RUN apt-get -y update &&     apt-get -y install nginx
 ---> Running in a3dd3d05b2b9
Get:1 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]
Get:2 http://security.ubuntu.com/ubuntu focal-security InRelease [109 kB]
...
Setting up nginx (1.18.0-0ubuntu1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.1) ...
Removing intermediate container a3dd3d05b2b9
 ---> efa07d7c2e15
Step 4/6 : RUN ln -sf /dev/stdout /var/log/nginx/access.log     && ln -sf /dev/stderr /var/log/nginx/error.log
 ---> Running in feb46051e784
Removing intermediate container feb46051e784
 ---> bf5cf443326a
Step 5/6 : EXPOSE 80
 ---> Running in 5ee72ef91b9d
Removing intermediate container 5ee72ef91b9d
 ---> 7c5f47295134
Step 6/6 : CMD ["nginx", "-g", "daemon off;"]
 ---> Running in 6dc6c8054938
Removing intermediate container 6dc6c8054938
 ---> d76e74522ce5
Successfully built d76e74522ce5
Successfully tagged picodotdev/nginx:1.0
docker-build.out

La imagen construida queda almacenada en el registro local de imágenes.

1
2
$ docker images

docker-images.sh
1
2
REPOSITORY                        TAG         IMAGE ID       CREATED             SIZE
picodotdev/nginx                  1.0         d76e74522ce5   About an hour ago   158MB
docker-images.out

Iniciar un contenedor con la imagen

El siguiente comando inicia una instancia del contenedor con un servidor web virtual para el dominio www.127.0.0.1.xip.io.

1
2
3
4
5
6
#!/usr/bin/env bash
docker run -it --rm \
    -v "${PWD}/www.127.0.0.1.xip.io.conf:/etc/nginx/conf.d/www.127.0.0.1.xip.io.conf:ro" \
    -v "${PWD}/nginx/log:/var/log/nginx" \
    -p "80:80" \
    picodotdev/nginx:1.0
docker-run.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
log_format nginx_vcombined '$host:$server_port ' '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';

server {
    listen 80;
    server_name www.127.0.0.1.xip.io;

    access_log /dev/stdout nginx_vcombined;
    access_log /var/log/nginx/nginx-access.log nginx_vcombined;
    error_log /var/log/nginx/nginx-error.log;
    error_log /dev/stderr;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
www.127.0.0.1.xip.io.conf

Otra forma de iniciar el contenedor es con un archivo de Docker Compose que básicamente contiene los mismos parámetros del comando docker run.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: "3.9"
services:
  nginx:
    image: nginx
    ports:
      - "80:80"
    volumes:
      - ${PWD}/www.127.0.0.1.xip.io.conf:/etc/nginx/conf.d/www.127.0.0.1.xip.io.conf:ro
      - ${PWD}/nginx/log:/var/log/nginx

docker-compose.yml
1
2
#!/usr/bin/env bash
docker-compose up
docker-compose-up.sh

Accediendo con el navegador al servidor nginx del contenedor se devuelve la página por defecto.

Para aprender más sobre Docker es buena idea seguir un manual de referencia como el libro Docker in Action.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./docker-build.sh

Comparte el artículo: