Capítulo 1. Primeros pasos con Docker

1.0 Introducción

El núcleo de Docker es su motor (Docker engine), que no es más que un ‘demonio’ que nos permite crear y gestionar contenedores. Antes de comenzar a trabajar con el, debemos instalarlo en nuestro sistema.

Las primeras recetas de este capítulo nos guiarán en los pasos para instalarlo y poder comenzar a usarlo en nuestro equipo. La documentación oficial de Docker abarca la instalación en multitud de sistemas operativos. En esta guía veremos los casos de Ubuntu 14.04 y CentOS7. Si queremos probar Docker a través de Vagrant, iremos a la receta 1.3 Docker a través de Vagrant.

Una vez instalado Docker, practicaremos con los comandos básicos para poder crear y mantener contenedores. A continuación, se introduce el concepto de fichero manifiesto; Dockerfile. Y por último, veremos como se gestionan los datos a través de uno o varios contenedores.

1.1 Instalación de Docker en Ubuntu 14.04

Para instalar Docker en Ubuntu 14.04 ejecutaremos los siguientes comandos:

$ sudo apt-get update
$ sudo apt-get install -y wget
$ wget -qO- https://get.docker.com/ | sudo sh

Para comprobar que la instalación se ha realizado correctamente, ejecutamos el comando:

$ sudo docker --version
Docker version 17.07.0-ce
[...]

Se puede parar, iniciar y reiniciar el servicio. Por ejemplo, para reiniciarlo:

$ sudo service docker restart

Para que un usuario sin privilegios pueda hacer uso de Docker, ejecutamos uno de los siguientes comandos:

$ sudo usermod -aG docker %USER
--
$ sudo gpasswd -a $USER docker

1.2 Instalación de Docker en CentOS7

Instalamos Docker a través del gestor de paquetes yum. CentOS usa systemd para gestionar los servicios, por lo que haremos uso del comando systemctl para iniciarlo:

$ sudo yum update -y
$ sudo yum -y install docker
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
-logout-
$ sudo systemctl start docker
$ docker run hello-world

De forma alternativa, podemos hacer uso del script de instalación:

$ sudo yum update -y
$ curl -sSL https://get.docker.com | sudo sh
$ sudo usermod -aG docker $USER
$ sudo systemctl start docker

1.3 Docker a través de Vagrant

En el caso de querer instalar Docker en un sistema operativo diferente al instalado de forma nativa en nuestro equipo, podemos hacer uso de Vagrant, para por ejemplo, en nuestro sistema OS X instalar Docker sobre Ubuntu.

A través de un script de aprovisionamiento podemos configurar automáticamente una nueva máquina virtual. A continuación podemos observar el contenido del fichero Vagrantfile:

VAGRANTFILE_API_VERSION = "2"

$bootstrap=<<SCRIPT
apt-get update
apt-get -y install wget
wget -qO- https://get.docker.com/ | sh
gpasswd -a vagrant docker
service docker restart
SCRIPT

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu/trusty64"

  config.vm.network "private_network", ip: "192.168.33.10"

  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end

  config.vm.provision :shell, inline: $bootstrap

end

Descarga: Vagrantfile

1.4 Probar nuevas funcionalidades de Docker

Si deseamos probar funcionalidades recién publicadas, y que todavía no están en la versión estable, debemos hacer uso de la versión de desarrollo (experimental) [1].

En una distribución Linux ejecutamos los siguientes comandos para obtener las ‘nightly builds’:

$ wget -qO- https://experimental.docker.com/ | sh
$ docker version | grep Version
[...]
[1]https://blog.docker.com/2015/06/experimental-binary/

1.5 ‘Hola Mundo’ en Docker

Una vez instalado Docker, el siguiente paso es la ejecución de nuestro primer contenedor, y dentro del mismo ejecutar el comando echo Hola mundo:

$ docker run busybox echo Hola mundo
[...]

Si queremos ir un poco más allá, y tener acceso a una sesión con terminal, debemos ejecutar /bin/bash dentro del contenedor, y sin olvidarnos de las opciones -t y -i, para poder conectar con dicha terminal de forma interactiva:

$ docker run -ti ubuntu:14.04 /bin/bash

1.6 Ejecutar contenedores en segundo plano

Ahora veremos como ejecutar un contenedor en segundo plano a través de la opción -d:

$ docker run -d -p 1234:1234 python:2.7 python -m SimpleHTTPServer 1234
$ docker ps

Si abrimos un navegador para acceder al puerto 1234 de localhost, veremos el contenido del directorio raíz dentro del contenedor.

1.7 Crear, iniciar, detener y eliminar contenedores

Para ejecutar las diferentes acciones tendremos que utilizar las opciones create, start, stop, kill y rm. Para consultar sus diferentes opciones, haremos uso de la opción -h.

Hasta ahora hemos usando el comando docker run para crear contenedores. Otra opción es usar el comando docker create. Usando el mismo ejemplo del servidor HTTP en python, ahora no indicamos la opción -d. Una vez creado el contenedor, será necesario ejecutar la opción start para iniciarlo:

$ docker create -P --expose=1234 python:2.7 python -m SimpleHTTPServer 1234
$ docker ps -a
$ docker start [ID]
$ docker ps

Para detener un contenedor, podemos escoger entre docker kill (que envía una señal SIGKILL al contenedor) o ddocker stop (que envía una señal SIGTERM, y después de un periodo de gracia, envía un SIGKILL). El resultado es que el contenedor será parado y no aparecerá en la lista de contenedores en ejecución. Como no ha desparecido, podemos volver a iniciarlo con docker restart, o eliminarlo definitivamente con docker rm.

Si tenemos un número elevado de contenedores que queremos eliminar, podemos ejecutar el siguiente comando:

$ docker rm $(docker ps -aq)

1.8 Crear una imagen de Docker con un Dockerfile

Sabemos como crear contenedores a partir de imágenes descargadas. Ahora veremos como modificarlas a nuestro gusto.

Un Dockerfile es un fichero de texto que especifica los pasos necesarios para crear la imagen (instalación de paquetes, nuevos directorios, etc.).

Haremos uso de busybox en la que declararemos una variable de entorno. El contenido del Dockerfile es el siguiente:

FROM busybox
ENV foo=bar

Y a continuación creamos la nueva imagen busybox2 a través del comando docker build:

$ docker build -t busybox2 .
[...]

Una vez finalizado, podemos comprobar que aparece en el listado de docker images, y si creamos un nuevo contenedor basado en esta imagen, tendremos acceso a la variable de entorno foo.

1.9 Compartir datos con los contenedores

Veremos como acceder a los datos de nuestro equipo anfitrión desde dentro de un contenedor. Con la opción -v en el comando docker run se monta un volumen del ‘host’ dentro del contenedor.

Por ejemplo, para compartir el directorio de trabajo del host con el directorio /shared del contenedor:

$ ls
data.txt
$ docker run -ti -v "$PWD":/shared ubuntu:14.04 /bin/bash

Por defecto, el montaje se realiza en modo lectura-escritura. En caso de querer realizar un montaje de sólo-lectura, debemos indicarlo al final de la ruta "$PWD":/shared:ro. Podemos comprobarlo con la opción inspect:

$ docker inspect -f {{.Mounts}} [ID]

1.10 Compartir datos entre contenedores

Tal y como vimos en la receta anterior, si omitimos la ruta de nuestro equipo anfitrión, se crea un contenedor de datos. Ese volumen se crea dentro del contenedor como un sistema de ficheros de lectura-escritura. A pesar de que la gestión del volumen es responsabilidad de Docker, es posible el acceso desde el equipo anfitrión:

$ docker run -ti -v /shared ubuntu:14.04 /bin/bash
root@id:/# touch /shared/foobar
root@id:/# ls /shared
foobar
root@id:/# exit
$ docker inspect -f {{.Mounts}} [ID]
[{.... /var/lib/docker/volumes/id /_data /shared local true}]
$ sudo ls /var/lib/docker/volumes/.....
foobar

Desde el equipo anfitrión es posible acceder al volumen a través de la ruta /var/lib/docker/volumes/. Los cambios pueden ser vistos desde el contenedor:

$ sudo touch /var/lib/docker/volumes/$id/foobar2
$ docker start $id
$ docker exec -ti $id /bin/bash
root@id:/# ls /shared
foobar foobar2

Para poder compartir este volumen con otros contenedores, haremos uso de la opción --volumes-from:

$ docker run -v /data --name data ubuntu:14.04
$ docker ps

$ docker inspect -f {{.Mounts}} data

Aunque el contenedor no se está ejecutando, se puede montar el volumen en otro contenedor:

$ docker run -ti --volumes-from data ubuntu:14.04 /bin/bash
root@id:/# touch /data/foobar
root@id:/# exit
$ sudo ls /var/lib/docker/volumes/$id...
foobar

1.11 Copiar datos desde y hacia contenedores

Si queremos copiar datos a un contenedor que carece de volumen montando, tendremos que utilizar la opción docker cp. Para ver su funcionamiento, ejecutamos los siguientes comandos:

$ docker run -d --name testcopy ubuntu:14.04 sleep 360
$ docker exec -ti testcopy /bin/bash
root@id:/# cd /root
root@id:/# echo 'Estoy en el contenedor' > file.txt
root@id:/# exit

Ahora, para poder acceder al fichero desde el equipo anfitrión:

$ docker cp testcopy:/root/file.txt .
$ cat file.txt
Estoy en el contenedor

Y para copiar un fichero hacia el contenedor:

$ echo 'Estoy en el host' > host.txt
$ docker cp host.txt testcopy:/root/host.txt