Docker Español

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 16

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

1 de 16

https://github.com/brunocascio/docker-espanol

brunocascio / docker-espanol
Code

Issues 0

Pull requests 0

Watch

Pulse

Star

10

Fork

Graphs

Un tutorial Docker en espaol. Basado en el libro Docker Cookbook de O'reilly


18 commits

1 branch

0 releases

1 contributor
Find file

Bruno Cascio Optimizando el Dockerfile siguiendo buenas prcticas

Latest commit 726ffeb on 23 Apr

vagrant

Optimizando el Dockerfile siguiendo buenas prcticas

3 months ago

LICENSE

Initial commit

6 months ago

.gitignore
README.md

ignore *.pyc

Optimizando el Dockerfile siguiendo buenas prcticas

3 months ago
3 months ago

README.md

Docker
Conceptos importantes:
Docker (daemon)

Docker-machine (client)
Docker Images

Docker Containers

Introduccin

. . . . TODO . . . .

Instalacin

La instalacin puede seguirse desde la Documentacin Oficial.

Empezando
images

Muestra las imagenes locales disponibles.


$ docker images

Podemos eliminarlas con docker rmi <image-name> , siempre y cuando no tenga contenedores asociados (corriendo o no).

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

2 de 16

https://github.com/brunocascio/docker-espanol

events

Podemos ver en tiempo real, los eventos que docker lanza en nuestro servidor, solo basta con:
$ docker events

run

Corremos un contenedor con la imagen base busybox , que ejecuta el comando echo hello world dentro. Luego de esto el
contenedor se detendr, porque de esta forma funciona como un "job".
$ docker run busybox echo hello world

ps

Muestra los contenedores en ejecucin (los que estn corriendo en 2do plano).
$ docker ps

Si lo ejecutamos luego del comando anterior, no mostrar nada porque lo anterior era solo un build, run, die .
Para ver el historial de ejecucin y los contnedores actualmente creados (corriendo o no), ejecutamos:
$ docker ps -a

Esto nos mostrar todos los contendores que se encuentran creados hasta el momento. Podes borrarlos si quisieramos
docker rm <container-id>

run avanzado

Podemos pasar muchas opciones al comando run, las cuales podemos ver con:
$ docker run --help

run interactivo

Probemos de ejecutar y usar una terminal en el contendor:


$ docker run -t -i ubuntu:14.04 /bin/bash
-t : Aloca una tty

-i : Nos comunicamos con el contenedor de modo interactivo.

NOTA: Al salir del modo interactivo el contendor se detendr.


run Detached Mode

Problema: Ya sabemos como correr un contenedor de manera interactiva, pero el problema es que el mismo al terminar de
ejecutar la tarea, finaliza. Si se quieren hacer contenedores que corran servicios (por ejemplo un servidor web) el comando es
el siguiente:

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

Esto ejecuta un servidor python (SimpleHTTPServer module), en el puerto 1234 . El argumento -p 1234:1234 le indica a

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

3 de 16

https://github.com/brunocascio/docker-espanol

docker que tiene que hacer un port forwarding del conetedor hacia el puerto 1234 de la maquina host.
Ahora podemos abrir un browser en la direccin http://localhost:1234 .
Algo ms

La opcin -d hace que el contenedor corra en segundo plano. Esto nos permite ejecutar comandos sobre el mismo en
cualquier momento mientras est en ejecucin. Por ejemplo:
$ docker exec -ti <container-id> /bin/bash

Aqu simplemente se abre una tty en modo interativo . Podran hacerse otras cosas como cambiar el working directory,
setear variables de entorno, etc. La lista completa puede verse de ac

Ciclo de vida de un contenedor

Hasta ahora vimos como ejecutar un contendor tanto en foreground como en background (detached). Ahora veremos como

manejar el ciclo completo de vida de un contenedor. Docker provee de comandos como create , start , stop , kill , y rm .
En todos ellos podra pasarse el argumento -h para ver las opciones disponibles. Ejemplo: docker create -h

Ms arriba vimos como correr un contendor en segundo plano (detached). Ahora veremos en el mismo ejemplo, pero con el
comando create . La nica diferencia que esta vez no especificaremos la opcin -d . Una vez preparado, necesitaremos
lanzar el contendor con docker start .
Ejemplo:

$ docker create -P --expose=8001 python:2.7 python -m SimpleHTTPServer 8001


a842945e2414132011ae704b0c4a4184acc4016d199dfd4e7181c9b89092de13
$ docker ps -a
CONTAINER ID IMAGE
COMMAND
CREATED
... NAMES
a842945e2414 python:2.7 "python -m SimpleHTT 8 seconds ago ... fervent_hodgkin
$ docker start a842945e2414
a842945e2414
$ docker ps
CONTAINER ID IMAGE
COMMAND
... NAMES
a842945e2414 python:2.7 "python -m SimpleHTT ... fervent_hodgkin

Siguiendo el ejemplo, para detener el contenedor se puede ejecutar cualquiera de los siguientes comandos:
$ docker kill a842945e2414 (enva SIGKILL)

$ docker stop a842945e2414 (enva SIGTERM).

As mismo, pueden reiniciarse (Hace un docker stop a842945e2414 y luego un docker start a842945e2414 ):
$ docker restart a842945e2414

destruirse:

$ docker rm a842945e2414

Crear una imagen Docker con un Dockerfile

Problema:

Ya entendemos como se descargan las imgenes del Docker Registry. Que pasa si ahora quisiramos armar nuestras propias
imagenes? (Para compartir, obvio
)
Solucin:

Usando un Dockerfile. Un Dockerfile es un archivo de texto, que describe los pasos (secuenciales) a seguir para preparar una
imagen Docker. Esto incluye instalacin de paquetes, creacin de directorios, definicin de variables de entorno, ETC. Toda
imagen que creemos, parte de una base image. Como en otro de los ejemplos, usbamos la imagen busybox la cual combina

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

4 de 16

https://github.com/brunocascio/docker-espanol

utilidades UNIX en un nico y simple ejecutable.


Comenzando:

Crearemos nuestra propia imagen con la imagen base busybox y setearemos slo una variable de entorno para mostrar el
funcionamiento.

Crea el directorio pepe y se posiciona dentro de l:


$ mkdir pepe && cd $_

Creamos el Dockerfile:
$ touch Dockerfile

Escribimos las siguietes lneas dentro del Dockerfile :


FROM busybox
ENV foo=bar

Hecho esto, haremos un build de la imagen con el nombre my-busybox :


$ docker build -t my-busybox . (Chequear el . al final)

Si todo sali bien al hacer docker images , deberamos encontrar nuestra imagen. WAL!

Ejemplo Real: Wordpress Dockerizado.

Es un setup bsico, no lo usara en produccin :)

Para esto usaremos MySql y HTTPD (apache o nginx).


Problema:

Como Docker ejecuta procesos en foreground, necesitamos encontrar la forma de ejecutar varios de estos simultaneamente.
La directiva CMD que veremos ms adelante, slo ejecutar una instruccin. Es decir, si tenemos varios CMD dentro de un
Dockerfile, ejecutar slo el ltimo.
Solucin:

Usando Supervisor para monitorear y ejecutar MySql y HTTPD. Supervisor se encarga de controlar varios procesos y se
ejecuta como cualquier otro programa.

Veremos diferentes formas de hacer esto. En principio crearemos todo dentro de un nico contenedor, pero luego
explotaremos al mximo los principios y caractersticas de Docker para hacerlo, por ejemplo separar servicios en diferentes
contenedores y linkearlos.

Usando Supervisor y en un nico contenedor

Creamos el Dockerfile, con este contenido:


# Imagen Base
FROM ubuntu:14.04

# Instalamos dependencias
# apache2: Servidor Web
# php5: Lenguaje de programacion PHP
# php5-mysql: Driver de MySql para PHP
# supervisor: Lanzadaror y Monitor de procesos
# wget: Utilidad para obtener archivos via HTTP
RUN apt-get update && apt-get -y install \

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

5 de 16

https://github.com/brunocascio/docker-espanol

apache2 \
php5 \
php5-mysql \
supervisor \
wget
# mysql-server se instala con internvencin del usuario,
# pero como no es modo interactivo lo que hacemos es setearle las variables
# con un valor.
# Para simplificar hemos usado como usuario y contrasea de mysql 'root'
RUN echo 'mysql-server mysql-server/root_password password root' | \
debconf-set-selections && \
echo 'mysql-server mysql-server/root_password_again password root' | \
debconf-set-selections
# Procesdemos ahora si, a instalar mysql-server
RUN apt-get install -qqy mysql-server
# Preparamos Wordpress
# Obtenemos la ltima versin de wordpress
# Descomprimimos
# Copiamos el contenido dentro del root del servidor
# Removemos el viejo index.html (mensaje de bienvenida de apache)
RUN wget http://wordpress.org/latest.tar.gz && \
tar xzvf latest.tar.gz && \
cp -R ./wordpress/* /var/www/html && \
rm /var/www/html/index.html
# De esto se encargara supervisor, pero como necesitamos crear la base de datos
# ejecutamos a mysql en background y creamos la base de datos llamada wordpress
RUN (/usr/bin/mysqld_safe &); sleep 5; mysqladmin -u root -proot create wordpress
# Reemplazamos el archivo wp-config.php (ms abajo lo creamos) a la carpeta de wordpress
# Este archivo contiene la configuracin de nuestro sitio
COPY wp-config.php /var/www/html/wp-config.php
# Copiamos el archivo de configuracin de supervisor (ms abajo lo creamos)
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Le decimos al contenedor que tiene que hacer accesible al puerto 80 (en el que corre HTTPD)
# para as nosotros poder acceder al mismo desde fuera
EXPOSE 80
# Lanzamos Supervisor como proceso Foreground de Docker
# Este se encargar de lanzar simultaneamente los dems :D
CMD ["/usr/bin/supervisord"]

Creamos el archivo supervisor.conf con este contenido:


[supervisord]
nodaemon=true
[program:mysqld]
command=/usr/bin/mysqld_safe
autostart=true
autorestart=true
user=root
[program:httpd]
command=/bin/bash -c "rm -rf /run/httpd/* && /usr/sbin/apachectl -D FOREGROUND"

Creamos el archivo wp-config.php con este contenido:


<?php
/**

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

6 de 16

https://github.com/brunocascio/docker-espanol

* The base configurations of the WordPress.


*
* This file has the following configurations: MySQL settings, Table Prefix,
* Secret Keys, and ABSPATH. You can find more information by visiting
* {@link http://codex.wordpress.org/Editing_wp-config.php Editing wp-config.php}
* Codex page. You can get the MySQL settings from your web host.
*
* This file is used by the wp-config.php creation script during the
* installation. You don't have to use the web site, you can just copy this file
* to "wp-config.php" and fill in the values.
*
* @package WordPress
*/
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', 'root');
/** MySQL hostname */
define('DB_HOST', 'localhost');
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
/**#@+
* Authentication Unique Keys and Salts.
*
* Change these to different unique phrases!
* You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
* You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
*
* @since 2.6.0
*/
define('AUTH_KEY',
'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY',
'put your unique phrase here');
define('NONCE_KEY',
'put your unique phrase here');
define('AUTH_SALT',
'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT',
'put your unique phrase here');
define('NONCE_SALT',
'put your unique phrase here');
/**#@-*/
/**
* WordPress Database Table prefix.
*
* You can have multiple installations in one database if you give each a unique
* prefix. Only numbers, letters, and underscores please!
*/
$table_prefix = 'wp_';
/**
* For developers: WordPress debugging mode.
*
* Change this to true to enable the display of notices during development.
* It is strongly recommended that plugin and theme developers use WP_DEBUG
* in their development environments.
*/

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

7 de 16

https://github.com/brunocascio/docker-espanol

define('WP_DEBUG', false);
/* That's all, stop editing! Happy blogging. */
/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
define('ABSPATH', dirname(__FILE__) . '/');
/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

Ahora slo queda realizar el build de nuestra imagen y luego ejecutar un contenedor :)
$ docker build -t wordpress .
$ docker run -d -p 80:80 wordpress

Una vez funcionando, ingresando en http://<IP_OF_DOCKER_HOST> deberamos visualizar la pgina de instalacin de


wordpress.
Nota:

Usar Supervisor para ejecutar varios servicios dentro del mismo contenedor, podra trabajar perfectamente, pero es mejor
usar mltiples contenedores. Estos proveen del aislamiento (isolation) ente otras bondades de Docker, y nos ayuda adems a
crear una aplicacin basada en microservicios. Por ltimo, tambin esto nos ayuda a escalar y a recuperarnos de posibles
fallas.

Corriendo Wordpress usando 2 contenedores linkeados.

Problema:

Hasta ahora ejecutamos una instancia de wordpress con su servidor y su base de datos, en un mismo contenedor. El
problema es queno explotamos al mximo a Docker, y no mantenemos tampoco el concepto de Separation of concerns.
Necesitamos desacoplar el contendor lo mas fino posible.
Solucin:

Usar 2 contenedors. Uno para Wordpress y otro para MySql. Luego se interconectaran mediante la opcin de docker --link .
Manos a la obra:

Para este ejemplo usaremos las imagenes docker oficiales de wordpress y mysql.
$ docker pull wordpress:latest
$ docker pull mysql:latest

Ejecutamos un contenedor MySql


$ docker run --name mysqlwp -e MYSQL_ROOT_PASSWORD=wordpressdocker \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress \
-e MYSQL_PASSWORD=wordpresspwd \
-v /db/mysql:/var/lib/mysql \
-d mysql

NOTA: Aqu hay nuevas opciones:

-e es para setear variables de entorno. Esas variables estn definidas dentro del Dockerfile de MySql, por lo que

nosotros le damos valor, para que el contendor a ejecutar, use esos datos.

-v es para montar un volumen entre el host y el contenedor. En este caso en el host se populara el volumen /db/mysql/

con la info de /var/lib/mysql .

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

8 de 16

https://github.com/brunocascio/docker-espanol

Los volmenes tienen diferentes usos:


Se crean cuando se inicializa el contenedor

Compartir informacin entre diferentes contenedores

Mantener la info luego de haber borrado el contendor

Cambios en los volmenes son directamente aplicados (no hay que hacer nada con adicional con el contendor
para actualizar)

Los cambios de un volumen no se incluirn en la actualizacin de la imagen

Ejecutamos y linkeamos a wordpress

$ docker run --name wordpress --link mysqlwp:mysql -p 80:80 \


-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=wordpresspwd \
-d wordpress

NOTA: La imagen de wordpress, expone el puerto 80 y lo que hacemos es mapearlo con el 80 del nuestro Host. Como en la

imagen de MySql, en wordpress tambien contamos con algunas variables de entorno, stas para la configuracin del mismo.
Bsicamente seteamos las credenciales de la base de datos anteriormente creada, para que wordpress use las mismas.

Haciendo backups de la base de datos de un contenedor

Problema:

Tenemos un contenedor de mysql ejecutando, pero necesitamos hacer un backup de la base de datos que se ejecuta dentro
del contenedor
Solucion:

Usar el comando docker exec para ejecutar en el contenedor MySql el comando mysqldump
Chequeamos en nuestro host que existe la carpeta /db/mysql
$ ls /db/mysql

Ahora, para hacer un backup de la base de datos de ese contenedor ejecutamos:


docker exec mysqlwp mysqldump --all-databases --password=wordpressdocker > wordpress.backup

Ahora ejecutamos $ ls y veremos el archivo wordpress.backup :)

Compartir informacin entre el Docker Host y los contenedores

Problem:

Tenemos informacin local, que queremos que este disponible en un contenedor.


Solucin:

Usando volmenes (opcin -v antes vista) para montar uno entre le host y el contenedor.

Por ejemplo si queremos compartir nuestro directorio de trabajo, con un directorio particular del contenedor podramos
hacer:
docker run -ti -v "$PWD":/pepe ubuntu:14.04 /bin/bash

Lo que hicimos con ese comando, fue montar como volumen nuestro directorio actual con el directorio /pepe en el

contenedor (OJO, / referencia al root del filesystem). Adems como vimos antes con el -ti levantamos un tty y de modo
interativo ejecutamos una instancia de bash.
Algo ms:

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

9 de 16

https://github.com/brunocascio/docker-espanol

Docker provee de un comando docker inspect que sirve para observar la informacin de un contendor.
docker inspect -f {{.Mounts}} <container-id>

Con el comando anterior, filtramos de toda la informacin, solo los puntos de montaje. Como salida obtendremos algo como:
[{ /path/to/pwd /pepe true}]

Compartir informacin entre contenedores

Problema:

Ya sabemos como montar un volumen de nuestro Host en un contenedor. Pero ahora quisiramos compartir ese volumen
definido en el contenedor con otros contenedores.
Solucin:

Usando data containers. Cuando queremos montar un volmen en un contenedor lo que hacemos es con el argumento -v

decirle el directorio X del host que debe montarse en el el path Y del contenedor. El volmen especificado se crea como de
lectura-escritura dentro del contenedor y no como las capas de slo lectura usadas para crear el contenedor, pudindose
modificar tambin desde la maquina host.
$ docker run -ti --name=cont1 -v /pepe ubuntu:14.04 /bin/bash
root@cont1:/# touch /pepe/foobar
root@cont1:/# ls pepe/
foobar
root@cont1:/# exit
exit
bash-4.3$ docker inspect -f {{.Mounts}} cont1
[{dbba7caf8d07b862b61b39... /var/lib/docker/volumes/dbba7caf8d07b862b61b39... \
/_data /pepe local true}]
$ sudo ls /var/lib/docker/volumes/dbba7caf8d07b862b61b39...
foobar

Y ahora ejecutamos otro contenedor con el volumen anteriormente creado.


$ docker run --volumes-from=cont1 --name=cont2 ubuntu:14.04
$ docker inspect -f {{.Mounts}} cont2
[{4ee1d9e3d453e843819c6ff... /var/lib/docker/volumes/4ee1d9e3d453e843819c6ff... \
/_data /pepe local true]

Copiando datos entre el host desde y para los contenedores

Problema:

Tenemos un contenedor que no tiene volmenes cofigurados, y queremos copiar archivos desde y en el contenedor.
Solucin:

Usando docker cp para pasar informacin desde y para un contenedor en ejecucin.


Podemos ver ms opciones con docker cp --help slo docker cp .

Por ejemplo, para pasar archivos desde el docker host hacia el contenedor:
$ docker run -d --name testcopy ubuntu:14.04 sleep 360
$ touch pepe.txt
$ docker cp pepe.txt testcopy:/root/file.txt

Y pasando del contenedor hacia el docker host:

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

10 de 16

https://github.com/brunocascio/docker-espanol

$ docker cp testcopy:/root/file.txt pepe.txt


$ ls
pepe.txt

Crear y compartir Docker Images


Despues de crear varios contenedores, tal vez quisiramos crear nuestras propias imgenes tambin. Cuando iniciamos un
contenedor, al mismo lo iniciamos desde una imagen base. Una vez con el contenedor en ejecucin nosotros podramos

hacer cambios, por ejemplo instalarle ciertas librerias o dependencias (ejemplo correr apt install htop vim git dentro de

un contenedor que tiene de imagen base, ubuntu ). Luego de haber ejecutado este comando, el contenedor ha modificado su
filesystem. Nosotros a futuro tal vez quisereramos ejecutar contenedores iguales al anterior, por lo que Docker nos provee

del comando commit para a partir de un contenedor, crear una imagen. Docker mantiene las diferencias entre la imagen base
y la que se quiere crear, creando una nueva layer usando UnionFS. Similar a git.

Crearemos un contenedor de ubuntu, y al mismo le actualizaremos la lista de repositorios. Luego de ello, haremos un docker
commit , para definir la nueva imagen para mantener una imagen mas actualizada.
$ docker run -t -i --name=contenedorPrueba ubuntu:14.04 /bin/bash
root@69079aaaaab1:/# apt update

Cuando salgamos de este contenedor, el mismo se detendr, pero seguir estando disponibles a menos que lo eliminemos
explcitamente con docker rm . Ahora commitiemos el contenedor, para crear una nueva imagen.
$ docker commit contenedorPrueba ubuntu:update
13132d42da3cc40e8d8b4601a7e2f4dbf198e9d72e37e19ee1986c280ffcb97c
$ docker images
REPOSITORY
TAG
IMAGE ID
CREATED
VIRTUAL SIZE
ubuntu
update 13132d42da3c 5 days ago ... 213 MB

NOTA: Esto ubuntu:update especifica <nombre_imagen>:<tag_del_commit> .

Luego ya podremos lanzar contenedores basados en la nueva imagen ubuntu:update .


ADICIONAL

Podemos chequear las diferencias con docker diff .


$ docker diff contenedorPrueba
C /root
A /root/.bash_history
C /tmp
C /var
C /var/cache
C /var/cache/apt
D /var/cache/apt/pkgcache.bin
D /var/cache/apt/srcpkgcache.bin
C /var/lib
C /var/lib/apt
C /var/lib/apt/lists
...

Guardando Images y Containers como archivos .tar para compartir


Problema: Tenemos creados imagenes o tenemos contenedores que queremos mantener y nos gustara compartirlo con
nuestros colaboradores.
Solucin:

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

11 de 16

https://github.com/brunocascio/docker-espanol

Para las images : Usar los comandos save y load para crear el archivo comprimido de la imagen anteriormente creada.
Para los containers : Usar los comandos import y export .

Comencemos con un container creado y exportndolo en un archivo .tar (tarball).


$ docker ps -a
CONTAINER ID IMAGE
COMMAND
CREATED
77d9619a7a71 ubuntu:14.04 "/bin/bash"
10 seconds ago
$ docker export 77d9619a7a71 > update.tar
$ ls
update.tar

...
...

NAMES
high_shockley

Se puede hacer commit de este contenedor como una nueva imagen local, pero tambien se podra usar el comando import :
$ docker import - update < update.tar
157bcbb5fdfce0e7c10ef67ebdba737a491214708a5f266a3c74aa6b0cfde078
$ docker images
REPOSITORY TAG
IMAGE ID
...
VIRTUAL SIZE
update
latest 157bcbb5fdfc ...
188.1 MB

Si se quiere compartir esta imagen con uno de sus colaboradores, podra subirse el tarball a un webserver y decirle al
colaborar que descarga tal, y use el comando import en su Docker Host. Si se prefiere usar imagenes que ya se han
comitiado, se puede usar los comandos load y save mencionados anteriormente.
Entonces, Cul es la diferencia?

Los 2 mtodos son similares; La diferencia est en que guardando una imagen mantenemos el historial de cambios, y
exportndola como contenedor NO.

A mi punto de vista, tal vez lo mejor sera slo mantener los cambios cuando ya es algo en produccin y deseamos hacer

actualizacin de software. Por ejemplo del SO o de APACHE/NGINX, donde si ocurre una falla o incompatibilidad, podra
volverse atrs. En cambio mientras estamos haciendo el desarrollo, mantener los cambios tal vez no sea tan importante.

Escribiendo Nuestro primer DockerFile

Problema:

Ejecutar contenedores en modo interactivo, hacer algunos cambios y para luego comitear estos en una nueva imagen,
funciona bien. Pero en la mayora de los casos, tal vez quieras automatizar este proceso de creacin de nuestra propia imagen
y compartir estos pasos con otros.
Solution:

Para automatizar el proceso de creacin de imgenes Docker, prepararemos tales paso en un archivo de manifiesto, llamado
Dockerfile. Este archivo de texto est compuesto por una serie de instrucciones que describe cual es la imagen base de la que
el nuevo contenedor se basar, que pasos necesitan llevarse a cabo para instalar las dependencias de la aplicacin, qu
archivos necesitan estar presentes en la imagen, qu puertos sern expuestos por el contenedor y que comando ejecutar
cuando se ejecuta el contenedor, entre otras cosas.

Para ilustrar esto, crearemos un simple Dockerfile. La imagen resultante nos permitir crear un contenedor que ejecuta el
comando /bin/echo .
FROM ubuntu:14.04
ENTRYPOINT ["/bin/echo"]

La instruccin FROM dice de que imagen base partimos para crear la nuestra. En este caso ubuntu:14.04 , que la primera vez
ser descargada del repositorio del Docker Hub.

La instruccin ENTRYPOINT dice cual es el comando a ejecutar cuando el contendor basado en esta imagen, sea ejecutado.

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

12 de 16

https://github.com/brunocascio/docker-espanol

Para hacer build de esta imagen, ejecutamos docker build .

Hecho el build, ejecutamos un nuevo contenedor a partir de esta imagen:


docker images
REPOSITORY
<none>

TAG
<none>

IMAGE ID
99fac58824c2

CREATED
5 minutes ago

VIRTUAL SIZE
187.9 MB

docker run 99fac58824c2 Hi Docker!


Hi Docker !

Lo que hemos hecho es ejecutar un contenedor a partir de la imagen previamente creada, pasndole como argumento Hi

Docker! . El contenedor al ejecutarse, corri el comando definido por el ENTRYPOINT , seguido por el argumento anteriormente

mencionado. Una vez que el comando ha finalizado (la tarea finaliza), el contenedor es finalizado tambin.

Tambien podemos usar la instruccin CMD en un Dockerfile. Esta tiene la ventaja que se puede sobreescribir cuando este se
ejecuta, pasndolo como argumento. Por ejemplo:
FROM ubuntu:14.04
CMD ["/bin/echo" , "Hi Docker !"]

Construimos la nueva imagen:


docker build .

Ejecutamos un contenedor a partir de esta:


docker run 99fac58824c2
Hi Docker!

Y ahora sobreescribiendo el comando:


docker run 99fac58824c2 /bin/date
Thu Mar 17 00:14:00 UTC 2016

Si el Dockerfile utiliza la instruccin ENTRYPOINT y necesitamos hacer override, se le puede pasar la opcin --entrypoint al
docker run .

Tenemos una imagen creada, pero como vern no tiene un tag y siempre nos referimos a ella por su IMAGE ID . Para esto
podemos hacer un rebuild usando la opcin -t .

$ docker build -t ubuntu-echo:1.0.0 .


...
...
REPOSITORY
TAG
IMAGE ID
ubunntu-echo
1.0.0
99fac58824c2
...

CREATED
About an hour ago

VIRTUAL SIZE
187.9 MB

Podemos colocarle el nombre que querramos, pero siempre es mejor seguir las convenciones :)
<name-of-recipe>:<version-of-recipe>

El comando build tiene una serie de opciones configurables y pueden verse con la opcion -h
$ docker build -h

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

13 de 16

Usage:

https://github.com/brunocascio/docker-espanol

docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile


--build-arg=[]
--cpu-shares=0
--cgroup-parent=
--cpu-period=0
--cpu-quota=0
--cpuset-cpus=
--cpuset-mems=
--disable-content-trust=true
-f, --file=
--force-rm=false
--help=false
-m, --memory=
--memory-swap=
--no-cache=false
--pull=false
-q, --quiet=false
--rm=true
-t, --tag=
--ulimit=[]

Set build-time variables


CPU shares (relative weight)
Optional parent cgroup for the container
Limit the CPU CFS (Completely Fair Scheduler) period
Limit the CPU CFS (Completely Fair Scheduler) quota
CPUs in which to allow execution (0-3, 0,1)
MEMs in which to allow execution (0-3, 0,1)
Skip image verification
Name of the Dockerfile (Default is 'PATH/Dockerfile')
Always remove intermediate containers
Print usage
Memory limit
Total memory (memory + swap), '-1' to disable swap
Do not use cache when building the image
Always attempt to pull a newer version of the image
Suppress the verbose output generated by the containers
Remove intermediate containers after a successful build
Repository name (and optionally a tag) for the image
Ulimit options

Empaquetando una aplicacin Flask en un contenedor

Problema

Tenemos una aplicacin web buildeada en Flask corriendo en nuestro Ubuntu 14.04 y queremos correrla en un contenedor.
Solucin

Como un ejemplo, vamos a usar una simple aplicacion Flask Hello World
Para instalar el modulo Flask simplemente corremos este comando
$ pip install Flask
#!/usr/bin/env python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)

Para tener esta aplicacin corriendo en un contenedor Docker, necesitamos escribir un Dockerfile que instale las

dependencias de este framework (comando RUN ), y poder correr nuesta app. Tambien necesitamos exponer el puerto del

contenedor (comando EXPOSE ). Tambien necesitamos mover nuestra aplicacin al Filesystem del contendor (comando ADD ).
El Dockerfile quedara de la siguiente forma:
FROM ubuntu:14.04
# Actualizamos repositorios e instalamos dependencias.
RUN apt-get update
RUN apt-get install -y python python-pip
RUN apt clean all

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

14 de 16

https://github.com/brunocascio/docker-espanol

RUN pip install flask


# Agregamos nuestra aplicacin al Filesystem del contenedor.
ADD hello.py /tmp/hello.py
# Exponemos el puerto del contenedor
EXPOSE 5000
# Comando por default que se ejecuta cuando se corre el contenedor
CMD ["python","/tmp/hello.py"]

Nota: Este Dockerfile no est optimizado, intencionalmente. Para optimizarlo lo veremos ms adelante, pero esto slo es para
entender lo bsico.

El comando RUN permite ejecutar comandos especficos durante el build de la imagen del contenedor. Para copiar nuestra
aplicacion dentro de la imagen del contenedor, usamos el comando ADD . En nuestro caso, copia el archivo hello.py al

directorio /tmp de la imagen del contenedor. La aplicacin usa el puerto 5000 , y tenemos que exponer este puerto al Docker
Host. Finalmente, el comando CMD especifica que el contenedor debe ejecutar python /tmp/hello.py cuando se ejecute.
Procedemos a hacer build de la imagen.
$ docker build -t flask .

Esto cre una imagen Docker flask:


$ docker images
REPOSITORY
TAG
flask
latest
...

IMAGE ID
d381310506ed

CREATED
3 seconds ago

VIRTUAL SIZE
354.6 MB

Para correr esta aplicacin usaremos la opcin -d , la cual daemonizar el contenedor. Tambien pasaremos el argumento -P
para decirle a Docker que elija un puerto en el Docker Host para forwardear al puerto expuesto por el contenedor.
$ docker run -d -P flask
5ac72ed12a72f0e2bec0001b3e78f11660905d20f40e670d42aee292263cb890

$ docker ps
CONTAINER ID
5ac72ed12a72

IMAGE
flask:latest

COMMAND
"python /tmp/hello.py

...
...

PORTS
0.0.0.0:49153->5000/tcp

El contendor retornado, est daemonizado y no con nosotros logueados en una shell interativa dentro. La seccin PORTS nos
muestra el mapeo de puertos del contendor en cuestin. En este caso mapea el puerto 49153 del Docker Host al puerto 5000
del contenedor. Si ahora ingresamos en http://localhost:49153, deberamos ver el mensaje hello world! .
Nota: Notar que no se le pas un comando a ejecutar en el comando run , esto se debe a que ejecutar el CMD definido en
el Dockerfile. Tambin podriamos sobreescribir el comando, por ejemplo:
$ docker run -t -i -P flask /bin/bash
root@fc1514ced93e:/# ls -l /tmp
total 4
-rw-r--r-- 1 root root 194 Dec 8 13:41 hello.py
root@fc1514ced93e:/#

Optimizando el Dockerfile siguiendo buenas prcticas

Problema

Se quiere seguir las buenas pacticas para crear Dockerfiles y optimizar las imgenes Docker.
Solucin

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

15 de 16

https://github.com/brunocascio/docker-espanol

Docker expone en su documentacin una seccin de buenas prcticas para ecribir Dockerfiles. Estas pacticas nos ayudaran a
crear imgenes de forma ms eficiente, modulares y con menor esfuerzo.
Estas son algunas instrucciones para crear buenas Docker Images .

1. Ejecutar un nico proceso por contenedor. De todas formas podramos correr multiples procesos por contendor, como
se vi cuando usamos supervisor . En este caso, supervisor es el nico proceso de cara al contenedor, pero ste
levanta internamente otros procesos. Seguir la prctica de un nico proceso por contenedor, nos permite hacer

aplicaciones desacopladas que podran escalar. Esto nos permite ademas usar container links u otras tcnicas de
container networking que veremos ms adelante.

2. No asumir que nuestros contenedores estarn siempre corriendo; Estos son efmeros y sern parados y reiniciados. Se
debera tratarlos como entidades inmutables, lo que significa que no deberamos modificarlos mientras estan en

ejecucin, sino modificar el Dockerfile reconstruir la imagen y levantar un contenedor con esa imagen actualizada. Por lo
tanto, se recomienda manejar datos y configuraciones de ejecucin fuera del contenedor y por lo tanto de su imagen.
Para esto, usamos Docker Volumes .

3. Usar un archivo .dockerignore . Cuando creamos imagenes, Docker copiar el contenido del working directory donde se
encuentra el Dockerfile, dentro de la imagen. Con los archivos .dockerignore obtenemos un funcionamiento como el

.gitignore y basicamente lo que logramos es excluir archivos (basura o sensibles) que no queremos que estn dentro

de la imagen. El uso del .dockerignore es opcional, pero si no lo usamos, aseguremosnos de copiar lo mnimo y
necesario. Podemos chequear la syntaxis del mismo en este link.

4. Usar imgenes oficiales del Docker Hub, en lugar de escribiar las nuestras desde cero. Estas imgenes estn mantenidas
por quienes las empresas autoras de ese software. Tambien podemos usar ONBUILD images , para simplicar el proceso de
creacin de nuestras imagenes.

5. Finalmente, y de los ms importantes, minimizar el nmero de capas de nuestras imgenes usando la cach de imagen.
Docker usa union filesystems para almacenar las imgenes. Esto quiere decir que cada imagen se hace a partir de una
imagen base ms una coleccin de diffs que agregan los cambios requeridos. Cada diff representa una capa adicional en
una imagen. Esto tiene un impacto directo en como nosotros escribimos nuestro Dockerfile y las directivas que usamos.
En la seccin siguiente veremos este punto.

Con estos puntos, haremos unos pequeos cambios en la imagen creada en la seccin anterior:
Tenemos el Dockerfle de esta forma:
FROM ubuntu:14.04
# Actualizamos repositorios e instalamos dependencias.
RUN apt-get update
RUN apt-get install -y python python-pip
RUN apt clean all
RUN pip install flask
# Agregamos nuestra aplicacin al Filesystem del contenedor.
ADD hello.py /tmp/hello.py
# Exponemos el puerto del contenedor
EXPOSE 5000
# Comando por default que se ejecuta cuando se corre el contenedor
CMD ["python","/tmp/hello.py"]

Aplicamos unos cambios:


FROM ubuntu:14.04
RUN apt-get update && apt-get install -y \
python
python-pip

22-07-2016 11:36

GitHub - brunocascio/docker-espanol: Un tutorial Docker en espaol. Ba...

16 de 16

https://github.com/brunocascio/docker-espanol

RUN pip install flask


COPY hello.py /tmp/hello.py
EXPOSE 5000
CMD ["python","/tmp/hello.py"]

Usar multiples comandos RUN es una mala prctica, ya que genera una nueva capa por cada uno. Tambin cambiamos el

comando ADD por COPY ya que ADD es para operaciones de copiado ms complejas, y nosotros slo copiamos de manera
simple.

Aun as podramos aplicar ms optimizaciones como la siguiente:


FROM python:2.7.10
RUN pip install flask
COPY hello.py /tmp/hello.py
EXPOSE 5000
CMD ["python","/tmp/hello.py"]

Entre los cambios, se puede ver que cambiamos a ubuntu por python como imagen base (aplicando el punto 2. de

optimizacines). Eliminando toda la instalacin de dependencias para python. Estas optimizaciones aun podran ser ms

optimizables como por ejemplo usar la imagen base de Flask , pero la idea es que se note la diferencia entre un Dockerfile
y otro optimizado.

2016 GitHub, Inc.

Terms

Privacy

Security

Status

Help

Contact GitHub

API

Training

Shop

Blog

About

22-07-2016 11:36

También podría gustarte