jueves, 1 de marzo de 2018

Docker (4): Contenedores

1. Introducción

Vamos a seguir la guia de docker.
Los niveles en docker són:

  1. Stack (pila)
  2. Services (servicios)
  3. Containers (contenedores)
Como vemos el container es el nivel mas bajo y es el que vamos a ver en este post.

Tenemos que saber también estos conceptos:

  • repository: Es una colección de "images" como un GitHub, pero el código ya esta compilado (built).
  • registry: Es un conjunto de "repositories"

2. Crear un Dockerfile


Un "dockerfile" define lo va en el "environment" (entorno) en tu contenedor, como por ejemplo acceso a recursos como discos duros, network etc. Estos recursos se virtualizan y se aislan del resto del sistema. Por tanto se requiere mapear puertos para comunicarse con el mundo exterior. Pero te permite que la aplicación creada con este dockerfile se comporte de la misma manera donde quiera que la ejecutes.

Vamos a crear un dockerfile. Para ello:

1. Crear un directorio nuevo

mkdir mydocker

3. Crear un fichero llamado Dockerfile y copiar y pegar este contenido:

# Use an official Python runtime as a parent image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Si te conectas mediante un proxy:

1. Averigua cuales son los host:puerto para http y https
2. Coloca estas líneas antes del comando pip. Siendo host:port los valores reales del proxy

# Set proxy server, replace host:port with values for your servers
ENV http_proxy host:port
ENV https_proxy host:port
Este dockerfile hace referencia a 2 ficheros que no hemos creado aún:
  • app.py
  • requirements.txt
Copiar este contenido a requirements.txt
Flask
Redis
Copiar este contenido a app.py

from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"

    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

El fichero requirements.txt nos informa de los requisitos, y la instalación se hace mediante el comando de Dockerfile pip install -r requirements.txt 

3. Hacer un build de la aplicación

Verificar que estamos en nuestro directorio de prueba mydocker,

Para crear la "image" y darle el nombre "friendlyhello" por ejemplo, ejecutar el comando (sin olvidar el "punto" final

docker build -t friendlyhello .

Para ver si se ha creado

docker image ls
Y nos sale


REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
friendlyhello       latest              0b0e63dce66e        19 seconds ago      148MB
python              2.7-slim            52ad41c7aea4        13 days ago         139MB
hello-world         latest              f2a91732366c        3 months ago        1.85kB

4. Correr la aplicación (run)

Vamos a correr la aplicación pero:

  • Mapeamos el puerto 80 del contenedor al puerto 4000 de nuestra máquina
  • Para ello usamos la opción -p 

docker run -p 4000:80 friendlyhello

Nos contesta:
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

Pero en realidad debe correr en el puerto 4000 de nuestra máquina



Como Redis no está corriendo, ya que solo hemos instalado Python y no Redis, nos va a dar un error cuando intentemos acceder a ella.

Tambien podemos ejecutar esta orden para ver el mismo contenido

curl http://localhost:4000

Y nos devuelve:

<h3>Hello World!</h3><b>Hostname:</b> 1d56760bd269<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>

Para terminar la aplicación basta con hacer CTRL+C

También se puede ejecuta la aplicación en "background" (desatendida)  en modo "detached"

Para ver los "containers" en marcha

docker container ls

Y sale


CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                  NAMES
f930900febff        friendlyhello       "python app.py"     About a minute ago   Up About a minute   0.0.0.0:4000->80/tcp   wizardly_albattani


Y este container ID  debe coincidir con el Hostname que aprece tras refrescar el navegador

Para parar la ejecución, anotamos el container ID y ejecutamos

docker container stop f930900febff

5. Compartir la imagen

Vamos a obtener una cuenta "Docker account", firmando en cloud.docker.com

Anotamos usuario y contraseña y entramos

docker login
Nos pide usuario y contraseña

Para asociar una "image" local con un "repository" en un "register" es

username/repository:tag

Siendo tag opcional, pero casi necesaria para saber la versión. Dar valores que den cierto significado como "get-started:part2". De esta forma se colooca la "image" en el "repository" "get-started" y la "tag" es "part2"

por ejemplo ejecutamos

docker tag friendlyhello ximodante/get-started:part2
 y para ver las imágenes

docker image ls
Y sale


REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
friendlyhello           latest              0b0e63dce66e        About an hour ago   148MB
ximodante/get-started   part2               0b0e63dce66e        About an hour ago   148MB
python                  2.7-slim            52ad41c7aea4        13 days ago         139MB
hello-world             latest              f2a91732366c        3 months ago        1.85kB


Ahora queda:

6. Publicar la imagen

Subir la imagen etiquetada al "repository" (docker push username/repository:tag)

docker push ximodante/get-started:part2

Y sale:


The push refers to repository [docker.io/ximodante/get-started]
f85a5baf41ba: Pushed 
728d44a64a71: Pushed 
1db758961ede: Pushed 
03cd3fb86dd2: Mounted from library/python 
630d02da980e: Mounted from library/python 
b2f046b20847: Mounted from library/python 
cf051be4e149: Mounted from library/python 
part2: digest: sha256:0e691ecddf8589cce361d0db30f37f9e6ffa24f2a14dfa3f12a0d9d6c48439dd size: 1787

Si entramos en Docker Hub y nos identificamos sale esta pantalla con nuestra imagen


A partir de ahora, en cualquier máquina que tenga instalado docker, podemos ejecutar esta "image"


docker run -p 4000:80 ximodante/get-started:part2

Si la imagen no está disponible en el contenedor local, Docker la recoge desde el repositorio

No importa desde que máquina ejecutes el docker run. Se recoge la "image" juto con todas las dependencias de requirements.txt y ejecuta el código, y no necesitas instalar nada, docker lo hace por ti



No hay comentarios :

Publicar un comentario