docker-hands-on



docker-hands-on

0 0


docker-hands-on

Presentación cosas que hacer en docker

On Github ahvargas / docker-hands-on

Docker

Hands On

Pre-condiciones

Hola Mundo

» docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
03f4658f8b78: Pulling fs layer
a3ed95caeb02: Pulling fs layer
03f4658f8b78: Verifying Checksum
03f4658f8b78: Download complete
a3ed95caeb02: Verifying Checksum
a3ed95caeb02: Download complete
03f4658f8b78: Pull complete
03f4658f8b78: Pull complete
a3ed95caeb02: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
Status: Downloaded newer image for hello-world:latest

Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/userguide/

Hola Mundo

Si analizamos la salida :

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
03f4658f8b78: Pulling fs layer
a3ed95caeb02: Pulling fs layer
03f4658f8b78: Verifying Checksum
03f4658f8b78: Download complete
a3ed95caeb02: Verifying Checksum
a3ed95caeb02: Download complete
03f4658f8b78: Pull complete
03f4658f8b78: Pull complete
a3ed95caeb02: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
Status: Downloaded newer image for hello-world:latest
.......
  • Busca primero si tenemos la imagen disponible.
  • Si no la tiene intenta descargarla de Docker Hub.
  • Una vez descargada crea un contenedor y lo ejecuta.

Hola Mundo

Otra vez :

» docker run hello-world
Hello from Docker.
.............
  • La segunda vez ya encuentra una imagen con lo que no es necesario descargarla.
  • Solo ejecuta el contenedor.
Consultando las imágenes disponibles

Las imágenes se pueden consultar con el siguiente comando :

» docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              690ed74de00f        4 months ago        960 B
  • Las imágenes son reutilizables y solo lectura .

Consultando los contenedores

Las contenedores se pueden consultar con el siguiente comando :

» docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  • Por defecto solo muestra los contenedores en ejecución.
  • Es por eso que no se muestra ningún contenedor.
Consultando todos los contenedores

Todos los contenedores se pueden consultar con el siguiente comando :

» docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
883d35586ea0        hello-world         "/hello"            6 seconds ago       Exited (0) 3 seconds ago                       ecstatic_mirzakhani
a37a719a9956        hello-world         "/hello"            8 seconds ago       Exited (0) 5 seconds ago                       backstabbing_mcnulty
  • Por defecto le asigna un nombre arbitrario.

Buscando imágenes

  • Para buscar imágenes en repositorio por defecto se usa el comando search:
»  docker search ubuntu
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
ubuntu                            Ubuntu is a Debian-based Linux operating s...   3215      [OK]
ubuntu-upstart                    Upstart is an event-based replacement for ...   60        [OK]
torusware/speedus-ubuntu          Always updated official Ubuntu docker imag...   25                   [OK]
............
  • Con el nombre de la imagen podremos ejecutar un contenedor.

Ejecutando Ubuntu

» docker run -it ubuntu:latest /bin/bash
  • -it Asocia el contenedor a la terminal donde lo estamos ejectando.
  • El siguiente parámetro es el nombre del la imagen que queremos instalar (ubuntu:latest).
  • El siguiente parámetro es el comando que ejecutaremos.
  • Este comando nos dejara nuestra terminal en el contenedor que hemos creado.

En el contenedor

root@02705d663a3f:/# lsb_release -s -d
Ubuntu 14.04.4 LTS
  • Una vez en el contendor el prompt nos da información.
  • El usuario que somos (root).
  • El container id de nuestro contenedor (02705d663a3f).
El uso del container id
  • Una vez que nos salimos del proceso veamos que contenedores tenemos :

      CONTAINER ID        IMAGE               COMMAND          NAMES
      02705d663a3f        ubuntu:latest       "/bin/bash"      gloomy_dubinsky
    
  • Podemos volver a iniciar el contenedor por el container id.

    docker start 02705d663a3f
    
  • O por nombre.

    docker start gloomy_dubinsky
    
  • Y luego para volver a estar en el contenedor.

    docker attach gloomy_dubinsky
    
Obteniendo información del contenedor
» docker inspect gloomy_dubinsky
[
    {
        "Id": "02705d663a3f3f7629a8d294564a64729ed046e0f6113038653e2fdfc079817d",
        "Created": "2016-02-18T09:14:15.183905642Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 2422,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2016-02-18T09:37:08.345230382Z",
            "FinishedAt": "2016-02-18T09:34:40.115875051Z"
        },
        "Image": "sha256:14b59d36bae04ba5e4c2bb3ff2906c16d6beac3b6c3ea15273f7458bb5687a3d",
        "ResolvConfPath": "/mnt/sda1/var/lib/docker/containers/02705d663a3f3f7629a8d294564a64729ed046e0f6113038653e2fdfc079817d/resolv.conf",
        "HostnamePath": "/mnt/sda1/var/lib/docker/containers/02705d663a3f3f7629a8d294564a64729ed046e0f6113038653e2fdfc079817d/hostname",
        "HostsPath": "/mnt/sda1/var/lib/docker/containers/02705d663a3f3f7629a8d294564a64729ed046e0f6113038653e2fdfc079817d/hosts",
        "LogPath": "/mnt/sda1/var/lib/docker/containers/02705d663a3f3f7629a8d294564a64729ed046e0f6113038653e2fdfc079817d/02705d663a3f3f7629a8d294564a64729ed046e0f6113038653e2fdfc079817d-json.log",
        "Name": "/gloomy_dubinsky",
        "RestartCount": 0,
        "Driver": "aufs",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "ShmSize": 67108864,
            "ConsoleSize": [
                25,
                80
            ],
            "Isolation": "",
            "CpuShares": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "KernelMemory": 0,
            "Memory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null
        },
        "GraphDriver": {
            "Name": "aufs",
            "Data": null
        },
        "Mounts": [],
        "Config": {
            "Hostname": "02705d663a3f",
            "Domainname": "",
            "User": "",
            "AttachStdin": true,
            "AttachStdout": true,
            "AttachStderr": true,
            "Tty": true,
            "OpenStdin": true,
            "StdinOnce": true,
            "Env": [],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "ubuntu:latest",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {},
            "StopSignal": "15"
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "6683cafc8194e29b442bcefca1708776605fa52f76083829a979b5a5a9017356",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/6683cafc8194",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "9707946741ea21a9b6cdc38d64353bda44e6ecf57b74cea74042fb85bca23064",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "000b7539541a310f6580518aec22390aace3f32c5c0e9b5862a63326f9e75c10",
                    "EndpointID": "9707946741ea21a9b6cdc38d64353bda44e6ecf57b74cea74042fb85bca23064",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02"
                }
            }
        }
    }
]

Limpiando imágenes

  • Se pueden ir eliminando imágenes de nuestro sistema , el comando es el siguiente :

      » docker rmi nombre_imagen
    
  • En nuestro caso :

      » docker rmi hello-world
    
      » Failed to remove image (hello-world):
      Error response from daemon: conflict: unable to remove repository reference
       "hello-world" (must force) - c ....
    
  • Docker valida que no se eliminen imágenes de las que existan contenedores activos.

Limpiando contenedores

  • Igual se pueden ir eliminando contenedores, el comando es el siguiente :

      » docker rm <CONTAINER ID> | <NAME>
    
  • En nuestro caso :

      » docker rm 883d35586ea0 a37a719a9956
    
  • Y ahora si :

      » docker rmi hello-world
    
  • Con esto hemos eliminado la imagen , si se vuelve a ejecutar un contenedor de esa imagen, sera necesario volver a descargarla.

Creando imágenes

  • Y que pasaría si necesitamos una imagen con Ubuntu actualizado y apache.
  • Ejecutamos un contenedor y actualizamos el contenido:
» docker run -it --name "webserver" ubuntu:latest /bin/bash
  • El parámetro name sirve para identificar nuestro contenedor.
  • Ahora actualizamos el ubuntu(en el contenedor) :
root@fd0e7e29afc2:/# apt-get -y update
root@fd0e7e29afc2:/# apt-get -y upgrade
root@fd0e7e29afc2:/# apt-get -y install apache2 curl
root@fd0e7e29afc2:/# service apache2 start
root@fd0e7e29afc2:/# curl localhost
root@fd0e7e29afc2:/# echo "service apache2 start" >> /etc/bash.bashrc
  • No se puede utilizar update-rc.d apache2 defaults . El contenedor no hace un arranque normal.

Creando imágenes

  • Ahora tenemos un contendor con lo que necesitamos, pero un contendor no es lo mismo que una imagen.
  • Primero vamos a ver los cambios que hay del contenedor vs la imagen :

      » docker diff webserver
    
  • C: Cambio , A : Nuevo , D: Eliminación

      C /var/log
      A /var/log/apache2
      A /var/log/apache2/access.log
      A /var/log/apache2/error.log
      A /var/log/apache2/other_vhosts_access.log
      C /var/log/apt
      ......
    

Creando imágenes

  • Ahora si para crear una imagen de un contenedor :

      » docker commit webserver ahvargas/ubuntu:webserver
    
  • Esto creara una imagen nueva :

      » docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    ahvargas/ubuntu     webserver           22f7cad7e7b1        10 seconds ago      227.5 MB
    ubuntu              latest              14b59d36bae0        19 hours ago        188 MB
    
  • Y con esto podemos ejecutar contenedores de nuestras imágenes :

      » docker run -it --name "webserver2" ahvargas/ubuntu:webserver /bin/bash
    
      » docker ps -a
      CONTAINER ID        IMAGE                       COMMAND        NAMES
      245091d9795a        ahvargas/ubuntu:webserver   "/bin/bash"    webserver2
      3e943c669432        ubuntu:latest               "/bin/bash"    webserver
    

Creando imágenes

  • ¿Y si ahora necesitamos php ?
  • Podríamos agregar php a nuestra imagen : ahvargas/ubuntu:webserver y crear una nueva con php.
  • Esto ofrece flexibilidad para tener un repositorio de imágenes con el software necesario para nuestros contenedores.
  • También podríamos buscar en el repositorio de imágenes si encontramos una imagen que cumpla nuestros requisitos.
  • De todos modos esta no es la mejor manera de crear imágenes. Existe una manera de ejecutar estos comandos con mas orden. Dockerfile

Dockerfile

  • Los mismos requerimientos pero desde un fichero.(ubuntu/apache/curl)

      FROM ubuntu:latest
      MAINTAINER Abraham Vargas <ahvargas@mailinator.com>
      RUN apt-get update
      RUN apt-get install -y apache2 curl
      RUN echo "service apache2 start" >> /etc/bash.bashrc
    
  • FROM : La imagen de donde se va a empezar

  • MAINTAINER : Quien es el que mantiene la imagen
  • RUN : Ejecuta el comando.
  • Hay muchos mas parámetros, hablaremos de algunos pero todos se pueden revisar en la documentación.

Dockerfile

  • Ahora el comando:

      » docker build . ##Desde donde este el Dockerfile
      Sending build context to Docker daemon 32.62 MB
      Step 1 : FROM ubuntu:latest
       ---> 14b59d36bae0
      Step 2 : MAINTAINER Abraham Vargas <ahvargas@mailinator.com>
       ---> Running in b0367e5fb8a3
       ---> 6973c4f73b1a
      Removing intermediate container b0367e5fb8a3
      Step 3 : RUN apt-get update
       ---> Running in 76ccb7cc68c9
      Ign http://archive.ubuntu.com trusty InRelease
      Get:1 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB]
      .....
      Removing intermediate container 76ccb7cc68c9
      Step 4 : RUN apt-get install -y apache2 curl
       ---> Running in 274e38b31840
      Reading package lists...
      Building dependency tree...
      ---> 8956e164ab93
      Removing intermediate container 274e38b31840
      Step 5 : RUN echo "service apache2 start" >> /etc/bash.bashrc
       ---> Running in 5c50a1efa3c1
       ---> 5af475290d96
      Removing intermediate container 5c50a1efa3c1
      Successfully built 5af475290d96
    
  • Si vemos la salida Docker internamente va creando y desechando contenedores intermedios.

Dockerfile

  • Ahora con esto tenemos una nueva imagen.

      »  docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    <none>              <none>              5af475290d96        14 seconds ago      227.4 MB
    ahvargas/ubuntu     webserver           22f7cad7e7b1        40 minutes ago      227.5 MB
    ubuntu              latest              14b59d36bae0        20 hours ago        188 MB
    
  • Como no le hemos puesto nombre solo tiene Image ID. Vamos a nombrarla :
      »  docker tag 5af475290d96 ahvargas/ubuntu:latest
    

Historia de las imágenes

  • Docker guarda una historia de las imágenes.
  • Es decir cada uno de los comandos ejecutados para crear una imagen.
    »   docker history ahvargas/ubuntu:latest
    IMAGE               CREATED             CREATED BY                                      SIZE
    5af475290d96        43 minutes ago      /bin/sh -c echo "service apache2 start" >> /e   2.199 kB
    8956e164ab93        43 minutes ago      /bin/sh -c apt-get install -y apache2 curl      17.94 MB
    e790eafc6ea8        43 minutes ago      /bin/sh -c apt-get update                       21.55 MB
    6973c4f73b1a        44 minutes ago      /bin/sh -c #(nop) MAINTAINER Abraham Vargas <   0 B
    14b59d36bae0        21 hours ago        /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
    <missing>           21 hours ago        /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
    <missing>           21 hours ago        /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   194.5 kB
    <missing>           21 hours ago        /bin/sh -c #(nop) ADD file:620b1d9842ebe18eaa   187.8 MB
    
  • Como vemos guarda el id de las imágenes intermedias.

Exponiendo los puertos al mundo

  • Ahora que tenemos un servidor apache , necesitamos exponer el puerto 80, para poder verlo.
>> docker run -it --name "webserver3" -p 8000:80  ahvargas/ubuntu:latest  /bin/bash
  • Si estamos utilizando docker-machine , para saber la ip.
>>  docker-machine env default
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://X:X:X::2376"
export DOCKER_CERT_PATH=".........t"
export DOCKER_MACHINE_NAME="default"
  • Ahora en un navegador vamos a la ip.

Mejorando nuestro Dockerfile

  • Hasta ahora todas las imágenes las hemos ejecutado de manera interactiva.
  • Básicamente en cada ejecutamos un shell de bash al que nos conectamos.
  • Ahora veremos como hacer para ejecutar nuestros contenedores en segundo plano.
      FROM ubuntu:latest
      MAINTAINER Abraham Vargas <ahvargas@mailinator.com>
      RUN apt-get update
      RUN apt-get install -y apache2 curl
      ##Ya no se necesita hacer un hook aqui
      ##RUN echo "service apache2 start" >> /etc/bash.bashrc
      CMD /usr/sbin/apache2ctl -D FOREGROUND
      EXPOSE 80
    
    docker build -t ahvargas/apache:latest .
Ejecutando varias instancias
  • Vamos a levantar un contenedor de nuestra imagen.

  • Pero esta vez en segundo plano :

 >> docker run -d  ahvargas/apache:latest -p :80
 >> docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                   NAMES
15136a5e7c60        ahvargas/apache:latest   "/bin/sh -c '/usr/sbi"   13 seconds ago      Up 9 seconds        0.0.0.0:32768->80/tcp   elated_mahavira
  • Si al parámetro -p no se les especifica nada , Docker le asignara un puerto aleatorio.
  • Si queremos un puerto especifico:
 >> docker run -d  ahvargas/apache:latest -p 8000:80
Ejecutando varias instancias
  • Ahora vamos a levantar 5 instancias de nuestro contenedor :
 >> for i in `seq 1 5`; docker run -d -p :80 --name apache$i ahvargas/apache:latest
 >> docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                   NAMES
3bf41ea79c21        ahvargas/apache:latest   "/bin/sh -c '/usr/sbi"   7 seconds ago       Up 2 seconds        0.0.0.0:32773->80/tcp   apache5
89dbf94ff0fc        ahvargas/apache:latest   "/bin/sh -c '/usr/sbi"   7 seconds ago       Up 2 seconds        0.0.0.0:32772->80/tcp   apache4
929faca29dfc        ahvargas/apache:latest   "/bin/sh -c '/usr/sbi"   7 seconds ago       Up 2 seconds        0.0.0.0:32771->80/tcp   apache3
a52728384054        ahvargas/apache:latest   "/bin/sh -c '/usr/sbi"   7 seconds ago       Up 3 seconds        0.0.0.0:32770->80/tcp   apache2
fd7f05e5694f        ahvargas/apache:latest   "/bin/sh -c '/usr/sbi"   7 seconds ago       Up 3 seconds        0.0.0.0:32769->80/tcp   apache1

Interactuando con los contenedores

  • Algunos comandos útiles :

    • Pausa un proceso. No enviá un SIGSTOP(ni ninguna otra señal) al proceso.

        >> docker pause apache1
        >> docker unpause apache1
      
    • Para un proceso , enviá SIGTERM y después de un tiempo enviá SIGKILL

        >> docker stop apache1
      
    • Mata un proceso , enviá SIGKILL.

        >> docker kill apache1
        >> docker start apache1
      

Interactuando con los contenedores

  • Algunos comandos útiles :

    • Parar todos los contenedores :

        >> docker stop $(docker ps -a -q)
      
    • Eliminar todos los los contenedores:

        >> docker rm  $(docker ps -a -q)
      
Archivos en los contenedores
  • Ahora como desplegamos un sitio en nuestro servidor.
  • Vamos a empezar utilizando un directorio del sistema como un volumen. Hay varias maneras de hacerlo, pero en esta presentación solo mostraremos esta.
  • Es decir vamos a 'montar' un directorio de nuestro SO en nuestro contenedor.
  • Para esto vamos a descargarnos un pequeño sitio de github que desplegaremos.
Archivos en los contenedores
  • Por ejemplo:
    »   git clone https://github.com/BlackrockDigital/startbootstrap-one-page-wonder.git
    
  • Y ahora compartimos el directorio:
    »   docker run  -d -p :80 -v \
     /c/Users/ahvargas/work/trash/startbootstrap-one-page-wonder/:/var/www/html/  \
     ahvargas/apache:latest
    
  • Con la opcion v se monta el volumen <PATH_LOCAL>:<PATH_CONTENEDOR>
  • Esto comparte el directorio, si modificamos el archivo en local veremos los cambios en el contenedor y viceversa.
  • Si queremos que el contendor sea solo lectura hay que agregar ro.
Archivos en los contenedores
    »   docker run  -d -p :80 -v \
       /c/Users/ahvargas/work/trash/startbootstrap-one-page-wonder/:/var/www/html/:ro  \
       ahvargas/apache:latest
  • Y ahora en la info podemos ver :

      »   docker inspect -f "{{ .Mounts }}"
    
          { /c/Users/ahvargas/work/trash/startbootstrap-one-page-wonder
              /var/www/html
            ro false rprivate}
    
  • Para entender un poco mas como funciona en los entornos donde se utiliza docker-machine revisar el siguiente enlace

Export / Import

  • Las imagenes se pueden guardar con el siguiente comando:

      » docker save -o <DEST> <IMAGE_ID>
    
      » docker save -o ahvargas.apache.tgz ahvargas:apache
    
  • Y se pueden importar a otra instalacion de docker:

      » docker save -o <FILE> <IMAGE_TAG>
    
      » docker import ahvargas.apache.tgz ahvargas/apache:v2
    
      » docker images ahvargas/apache
      REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
      ahvargas/apache     v2                  b820b96a060c        About a minute ago   238 MB
      ahvargas/apache     latest              cb68a9840b0a        19 hours ago         227.4 MB
    
Seguir leyendo

Fin

Docker Hands On