- Instalación de Ubuntu en VMWare Player en Windows 7
- Instalación de Jenkins en Ubuntu
- Instalación GitLab en Ubuntu
- Instalación de Docker y Minikube en Ubuntu
- Desarrollo de un microservicio en Eclipse Windows (1) y (2)
- Angular 6 frontend
- SpringBoot 2.x backend
- Mongo Replicaset (3 replicas)
- Despliegue CI en Minikube utilizando la infraestructura configurada
- Pipeline - Jenkinsfile
- GitLab webhook
- Dockerfile
- Deploy y Service yaml
- Secret
- Ingress
Vamos pues con el cuarto paso, la instalación de Docker en nuestro Ubuntu. Por extensión dejamos la instalación de Minikube para la siguiente entrada.
Instalación Docker
Como siempre, en la medida de lo posible seguimos la documentación oficial, en este caso la de Docker. Accedemos a Ubuntu y abrimos un terminal.
Lo haremos a través del gestor de paquetes "apt". Para ello, primero configuramos el repositorio de donde descargaremos los paquetes necesarios, y a continuación realizamos la instalación propiamente dicha.
Preparación
Update previo
sudo apt-get update
Instalación de paquetes para acceso al repo vía ssl
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
Añadimos la clave GPG (GNU Privacy Guard - Software de encriptación) oficial de Docker para acceso vía SSL
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Validamos
sudo apt-key fingerprint 0EBFCD88
nos deberá aparecer una salida como la siguiente
apt-transport-https \
ca-certificates \
curl \
software-properties-common
Añadimos la clave GPG (GNU Privacy Guard - Software de encriptación) oficial de Docker para acceso vía SSL
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Validamos
sudo apt-key fingerprint 0EBFCD88
nos deberá aparecer una salida como la siguiente
pub rsa4096 2017-02-22 [SCEA]
9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid [desconocida] Docker Release (CE deb) <docker@docker.com>
sub rsa4096 2017-02-22 [S]
Añadimos el repositorio estable de docker
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
Ahora ya podemos proceder a la instalación propiamente dicha.
Instalación
Actualizamos
sudo apt-get update
Instalamos la última versión de Docker
sudo apt-get install docker-ce
Verificamos. Primero lanzamos algunos comandos de testeo
sudo docker images
La salida debe ser vacía (sólo la cabecera)
Ejecutamos una imagen de prueba de la instalación con
sudo docker run hello-world
Al no existir dicha imagen local, lo que hará Docker es descargarla del "Docker Hub" (también "Docker Store"). Es el repositprio público de imágenes. Para los conocedores de java el docker hub viene a ser como el "maven central" para librerías.
Una vez descargada la imagen, se lanza (run) dicha imagen, generando un contenedor (imagen en ejecución), dejándonos un log "Hello from Docker".
Nos dice también cómo podemos ejecutar y entrar en un contenedor ubuntu (docker run -it ubuntu bash), etc...
En nuestro caso, la imagen descargada es sólo de prueba y únicamente contiene el log que aparece en la captura anterior. El contenedor que genera dicho log se para de forma inmediata, por lo que no podemos acceder a su interior. Podemos comprobarlo con
sudo docker ps -a (nos muestra todos los contenedores, tanto los activos como los inactivos)
veremos en la columna "STATUS" algo como "Exited (0) X minutes ago"
si ejecutamos "sudo docker ps" (sólo muestra los contenedores activos) veremos una salida vacía.
Si ejecutamos de nuevo "sudo docker images" veremos la imagen descargada.
Las imágenes se puede "tagear" de forma que su nombre sea
NOMBRE:TAG
Si no se especifica TAG se sobreentiende que es el tag "latest". Por ello, la imagen descargada de ejemplo si hacemos "sudo docker images" vemos el tag "latest"
Para eliminar un contenedor activo primero hemos de pararlo
sudo docker stop ID / NAME (ID de imagen o nombre)
y a continuación lo eliminamos
sudo docker rm ID / NAME
Para ver la configuración de una imagen
sudo docker inspect ID / NAME
Para eliminar una imagen (no ha de haber ningún contenedor activo o inactivo que la referencie)
sudo docker rmi ID / NAME
Si miramos a nivel de procesos veremos que todo funciona al estar activo un daemon, el "dockerd"
ps -ef | grep docker
Post-instalación
Como veis, continuamente hemos de ejecutar los comandos docker con sudo. La causa de tener que usarlo continuamente es que dicho daemon está asociado a un socket Unix, propiedad del usuario root (ver captura anterior).
Si ejectuamos cualquier comando docker sin sudo aparecerá el fatídico error
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.38/containers/json: dial unix /var/run/docker.sock: connect: permission denied
Al final se hace muy farragoso anteponer siempre sudo, por lo que, para evitarlo, seguiremos el proceso de post-instalación indicado en la página oficial de docker.
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.38/containers/json: dial unix /var/run/docker.sock: connect: permission denied
Al final se hace muy farragoso anteponer siempre sudo, por lo que, para evitarlo, seguiremos el proceso de post-instalación indicado en la página oficial de docker.
Validamos que exista el grupo docker mediante
grep docker /etc/group docker
En mi instalación aparece como
docker:x:994:
Entonces ejecutamos
sudo usermod -aG docker $USER
ó
sudo usermod -aG docker $(whoami)
lo cual añade al usuario conectado al grupo docker*. Lo podemos verificar con el comando "id $USER" (o "id $whoami". Veremos que aparece dentro de "grupos=" el grupo docker, en mi caso "....,994(docker)"
Refrescamos la configuración de grupos
newgrp docker
Si ejecutamos ahora
docker images ó docker ps
veremos la misma salida que cuando utilizábamos "sudo".
Si necesitamos parar, reinciar, etc... el daemon lo haremos como con cualquier otro servicio
sudo service docker status/start/stop/restart
o
docker-compose
Vamos a instalar docker-compose ya que es posible que lo necesitemos para instalar de forma conjunta imágenes que trabajan de forma "solidaria" como puede ser ELK, o bien imágenes custom como una app springboot que necesite de postgres o mongo como backend. Etc...
Es decir, para nuestro laboratorio propiamente dicho no necesitaremos ejecutar docker-compose, pero si que es posible que nuestras aplicaciones requieran de otros contenedores activos, levantados mediante docker-compose.
En esta caso no utilizaremos "apt" sino que lo descargaremos a una ruta determinada
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
lo cual instalará como un comando más en la ruta "/usr/local/bin". Se instala sin permiso de ejecución, por lo que se los damos:
sudo chmod +x /usr/local/bin/docker-compose
Si ejecutamos ahora "docker-compose --version" veremos la versión instalada, que en estos momentos es
docker-compose version 1.22.0, build f46880fe
Prueba completa
Veamos de forma más elaborada como funciona el mundo Docker de imágenes y contenedores. Vamos a descargar, ejecutar y modificar una imagen de nginx (servidor web).
Lo primero que hemos de hacer es acceder al docker hub para ver qué imágenes nginx hay disponibles. A ser posible usaremos la oficial. Accedemos a "https://store.docker.com" y usamos el buscador introduciendo "nginx". De las dos que aparecen seleccionamos la oficial
En la página de detalle se nos indican diferentes formas de arrancar nuestra imagen. Haremos dos pruebas, la primera con la configuración "por defecto" y otra un tanto más elaborada (con docker-compose y Dockerfile), modificando la página por defecto.
Con "docker run"
Lanzamos
docker run --name mynginx -p 90:80 -d nginx
Le damos nombre (--name) ya que luego es más sencillo referenciarla sin necesidad de conocer su ID.
El atributo "-d" indica "dettached", de forma que se libere la consola tras su lanzamiento.
El atributo "-p 90:80" indica que mapeamos el port interno 80 (el de arranque de nginx) del contenedor con el puerto 90 local del ubuntu.
Tras unos segundos de descarga (es la primera vez y por tanto ha de descargar la imagen) ya la tenemos activa. Lo revisamos con "docker ps". Ahí tenemos nuestro contenedor activo:
Accedemos vía web http://localhost:90
Podemos ver la imagen descargada con "docker images", o inspeccionarla con "docker inspect nginx"
Podemos acceder al interior del contendor para echar un vistazo. Está desaconsejado hacer modificaciones sobre un contenedor "vivo". Todo lo que se quiera hacer ha de ser vía Dockerfile, ya que lo que se haga en vivo se perderá. Un contenedor es algo de usar y tirar. No tiene vida más allá de su ejecución.
Lo que si es conveniente es, si no está documentado, acceder al contenedor, ver rutas necesarias, etc... para luego generar nuestro Dockerfile y que sea a través de él que se haga cualquier tipo de customización. Esto es lo que vamos a hacer, y la información que saquemos la utilizaremos para la prueba siguiente.
Accedemos con
docker exec -it mynginx bash (abrimos sesión interactiva "-i" con un pseudo tty "-t" y con interprete "bash")
Nos deberá aparecer el prompt del contenedor
root@213dc1f94923:/#
La mayoría de comandos no están instalados, por ejemplo si lanzamos ifconfig, ps, curl, .... veremos que nos aparece un "bash: xxx: comand not found". Si para nuestra inspección necesitamos instalar algún comando lo podremos hacer con "apt" o el gestor de paquetes del sistema (yum, etc...).
Podemos revisar que tipo de linux de nuestro contenedor con "cat /etc/issue". En nuestro caso, la imagen nginx devuelve
Debian GNU/Linux 9 \n \l
Es decir, la imagen nginx se generó en su origin sobre un Debian 9 mínimo.
Pero vamos a lo que nos interesa. Según documentación, el document root de nginx se encuentra en "/usr/share/nginx/html". Vemos que efectivamente, allí encontramos el "index.html".
Probemos a añadir una página nueva con
echo "Otro index" > /usr/share/nginx/html/otroindex.html
Accedemos a "http://localhost:90/otroindex.html"
O modificamos el index.html
echo "mi index" > /usr/share/nginx/html/index.html
y ahí lo tenemos:
Con esto es suficiente, salimos con "exit" y a continuación paramos el contenedor con "docker stop mynginx" y lo eliminamos con "docker rm mynginx"
Que quede claro, si ahora lanzamos de nuevo la imagen con "docker run......" todo esto habrá desaparecido y volveremos a tener el index.html por defecto.
Con "docker-compose"
Vale, con la información extraída de la primera prueba vamos a generar un Dockerfile que sobreescriba el index por defecto y añada un segundo index.
Creamos un directorio de trabajo.
vamos a la home del usuario
cd
creamos el directorio "Desarrollo" y accedemos a él
mkdir Desarrollo && cd $_
creamos el directorio "docker" y accedemos a él
mkdir docker && cd $_
creamos un directorio que contendrá los html's, no accedemos al directorio creado
mkdir custom_html
Creamos el index nuevo
echo "mi index custom" > custom_html/index.html
Creamos un segundo index
echo "mi segundo index custom" > custom_html/otroindex.html
Creamos nuestro Dockerfile con "vi Dockerfile", el cual contendrá la siguiente información:
FROM nginx
MAINTAINER Gines Collado - https://java-ms-cloud.blogspot.com
RUN mv /usr/share/nginx/html/index.html /usr/share/nginx/html/index_back.html
COPY custom_html /usr/share/nginx/html
FROM: la imagen fuente
MAINTAINER: información sobre el autor del Dockerfile
RUN: ejecución de un comando
COPY: copia de ficheros
La configuración del docker-compose.yml
version: '3'
services:
nginx:
build: .
container_name: mynginx
ports:
- "90:80"
Con build indicamos dónde ha de buscar el Dockerfile, en este caso lo tenemos en la misma ruta que el docker-compose.yml. Damos nombre al contenedor y declaramos el mapeo de puertos, 90 local de ubuntu, 80 interior al contenedor.
Lanzamos desde el directorio donde se encuentra el docker-compose.yml
docker-compose up -d --build
nos devuelve algo como lo siguiente:
es decir, se descarga la imagen base, ejecuta los pasos del Dockerfile y nos indica que h finalizado con
"Successfully tagged nginx_nginx:latest". Luego veremos qué significa (ver Extras).
Verificamos, sin acceder al contenedor, los ficheros custom que están en la ruta correcta y que se ha generado un backup del index anterior.
docker exec mynginx ls -lrt /usr/share/nginx/html
userblog@ubuntu:~/Desarrollo/docker/nginx$ docker exec mynginx ls -lrt /usr/share/nginx/html
total 16
-rw-r--r-- 1 root root 612 Jul 24 13:02 index_back.html
-rw-r--r-- 1 root root 537 Jul 24 13:02 50x.html
-rw-r--r-- 1 root root 16 Jul 30 09:06 index.html
-rw-r--r-- 1 root root 24 Jul 30 09:06 otroindex.html
total 16
-rw-r--r-- 1 root root 612 Jul 24 13:02 index_back.html
-rw-r--r-- 1 root root 537 Jul 24 13:02 50x.html
-rw-r--r-- 1 root root 16 Jul 30 09:06 index.html
-rw-r--r-- 1 root root 24 Jul 30 09:06 otroindex.html
Finalmente paramos el contenedor nginx. Podemos hacerlo según lo descrito más arriba (docker stop...) o bien, ya que lo hemos lanzado con docker-compose, con
docker-compose down
Siempre desde el mismo directorio de trabajo que hemos generado para las pruebas. Con este último comando se para y elimina el contenedor arrancado.
Extras
Tras la última prueba vayamos a ver las imágenes. Deberíamos tener sólo una de nginx, la que hemos descargado y que nos ha servido de base para la introducción de nuestros index custom.
Sorpresa, hay dos imágenes nginx
userblog@ubuntu:~/Desarrollo/docker/nginx$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE
nginx_nginx latest 497203bdc980 About an hour ago 109MB
nginx latest c82521676580 5 days ago 109MB
¿Qué ha pasado? Bien, al modificar la imagen (MV y COPY del Dockerfile), se ha generado una nueva, "nginx_nginx" (revisar la salida de la ejecución en el apartado anterior). Esta nueva imagen contiene la imagen base y capas adicionales, con las modificaciones.
Docker procede por capas, de forma que no repite capas de las imágenes base, sino que las "reutiliza".
Veamos las capas o layers de cada imagen. Si es cierto lo que decimos, deberíamos ver dentro de las capas de la nueva imagen "nginx_nginx" todas las de la imagen base "nginx" y alguna más con la parte custom.
Lanzamos
docker image inspect nginx -f '{{.RootFS.Layers}}'
Obtenemos una salida como la siguiente:
[sha256:cdb3f9544e4c61d45da1ea44f7d92386639a052c620d1550376f22f5b46981af sha256:a8c4aeeaa0451a16218376ce6ec0e55094128baeb0dbe122f1b25c3fa81a5a5b sha256:08d25fa0442e3ea585b87bc6e9d41a1aa51624c83aec7fbafc1636f22eecf36f]
Y ahora lanzamos lo mismo pero sobre la nueva imagen
docker image inspect nginx_nginx -f '{{.RootFS.Layers}}'
Obtenemos esta otra salida:
[sha256:cdb3f9544e4c61d45da1ea44f7d92386639a052c620d1550376f22f5b46981af sha256:a8c4aeeaa0451a16218376ce6ec0e55094128baeb0dbe122f1b25c3fa81a5a5b sha256:08d25fa0442e3ea585b87bc6e9d41a1aa51624c83aec7fbafc1636f22eecf36f sha256:310e76377bb19a2ca0d22e0d5fc9af094065024870339ec152e085a5c96f41e4 sha256:e333c6d0c4a212ab2ec89e9c6544723aab4d727f9b081d4317378304f334a901]
Efectivamente, en verde vemos las capas "repetidas", es decir, las capas de la imagen base que persisten en la nueva. Además, vemos dos nuevas capas en la nueva.
Si queremos tener una imagen visual de las diferencias podemos lanzar
docker history nginx
y
docker history nginx_nginx
O bien compararlas con
diff <(docker history nginx) <(docker history nginx_nginx)
Lo cual arroja la siguiente salida:
userblog@ubuntu:~/Desarrollo/docker/nginx$ diff <(docker history nginx) <(docker history nginx_nginx)
userblog@ubuntu:~/Desarrollo/docker/nginx$ diff <(docker history nginx) <(docker history nginx_nginx)
1a2,4
> 4e826b21879e 15 minutes ago /bin/sh -c #(nop) COPY dir:2d04cfb7dded61311… 40B
> 69545e040185 15 minutes ago /bin/sh -c mv /usr/share/nginx/html/index.ht… 612B
> 2189bca3821a 15 minutes ago /bin/sh -c #(nop) MAINTAINER Gines Collado … 0B
donde se muestra precisamente el contenido de nuestro Dockerfile, que ha servido para crear la imagen nueva a partir de la base. Se observa el tamaño de cada uno de los diferentes elementos "nuevos".
> 4e826b21879e 15 minutes ago /bin/sh -c #(nop) COPY dir:2d04cfb7dded61311… 40B
> 69545e040185 15 minutes ago /bin/sh -c mv /usr/share/nginx/html/index.ht… 612B
> 2189bca3821a 15 minutes ago /bin/sh -c #(nop) MAINTAINER Gines Collado … 0B
donde se muestra precisamente el contenido de nuestro Dockerfile, que ha servido para crear la imagen nueva a partir de la base. Se observa el tamaño de cada uno de los diferentes elementos "nuevos".
No hay comentarios:
Publicar un comentario