Renombrar volumen Docker

El cliente docker tiene un conjunto de opciones destinadas a administrar volúmenes (docker volume), pero ninguna de ellas permite renombrar un volumen existente.

Me puse a investigar cómo hacerlo y me fui a ver el filesystem y a buscar la carpeta que representa el volumen y hacer el cambio allí, pero cuando investigaba para no dañar la configuración me encontré con esta solución que me pareció muy filosofía docker, inclusive es lo que se hace para copiar un disco en una nueva unidad:

docker volume create --name <nuevo_volumen>
docker run --rm -it -v <viejo_volumen>:/from -v <nuevo_volumen>:/to alpine ash -c "cd /from ; cp -av . /to"
docker volume rm <viejo_volumen>

En definitiva se trata de crear un nuevo volumen, lanzar un contenedor que monta el volumen viejo y el volumen nuevo y copia los datos de uno a otro, y finalizar borrando el viejo volumen. Simple, seguro, y elegante.

La idea no es mía, la obtuve de este issue de Github, donde incluso alguien propone un script:

$ docker-rename-vol viejo-volumen nuevo-volumen

#/bin/bash
docker volume create --name $2
docker run --rm -it -v $1:/from -v $2:/to alpine ash -c "cd /from ; cp -av . /to"
[ $? -eq 0 ] && docker volume rm $1

Y ahora, está aquí mi blog para tenerlo presente.

corona-stats.online

Un API para obtener los datos de la pandemia del Coronavirus COVID-19 se puede acceder para consultas en el sitio

https://corona-status.online

Algunas de las consultas:

$ curl -s https://corona-stats.online/UY?format=json | jq
[
  {
    "country": "Uruguay",
    "province": "",
    "countryCode": "UY",
    "confirmed": 94,
    "recovered": 0,
    "deaths": 0,
    "confirmedByDay": [
      0,
      0,
      0,
      4,
      4,
      8,
      29,
      50,
      79,
      94
    ],

Y por terminal se pueden conseguir unos resultados interesantes, como muestran estas capturas:

Si deseas colaborar, el proyecto se puede forkear a partir de este repositorio

https://github.com/sagarkarira/coronavirus-tracker-cli

Gracias a este twit tuve noticia de esta iniciativa:

https://twitter.com/radhios/status/1241374172674220034

Docker tags

Buscar una imágen en docker es fácil con el comando docker search, pero luego que encuentras la imágen localizar las etiquetas disponibles ya no está al alcance del comando rápido… se requiere un consultar la respuesta json de una URL del registry.

Agregando este bloque de función al .bashrc

es posible tener un comando docker_tags que recibe por parámetro la imágen que se va a buscar y devuelve la lista de etiquetas disponibles:

$ docker_tags alpine
"20190707"
"20190809"
"20190925"
"3"
"3.10"
"3.10.1"
"3.10.2"
"3.8.4"
"edge"
"latest"

Si encuentras una mejora a esto, agradezco lo compartas en los comentarios.

Sobre escribir variables al invocar el shell script

Todos utilizamos variables de tipo constantes en nuestros shell scripts, que en principio no son modificables pues están en el código, un ejemplo simple:

#!/bin/bash
HOLA="Hola, soy el script"
echo $HOLA

así en cada ejecución de este script se mostrará el contenido de la variable HOLA:

$ ./hola
hola soy el script
$

Pero al definir/crear la variable podemos hacerlo con un contenido por defecto, que se usa en caso que la variable no tenga otro valor, mediante esta sintaxis de definición:

HOLA=${HOLA:-"Hola, soy el script"}

de esta forma HOLA tomará el valor que ya traiga o, en caso de ser nula, asignará el string indicado luego del :-

Esta sintaxis para la definición de las variables en nuestros script permite que se le pueda cambiar el valor al invocar el script, así:

$ HOLA="Hola, soy el shell" ./hola
Hola, soy el shell
$

También esta sintaxis de valor por defecto de las variables puede ser asignado directamente al invocarlas, utilizando una sintaxis equivalente:

#!/bin/bash
echo ${HOLA:-"Hola, soy el script"}

lo que simplifica el script, aunque puede distribuir los valores de las variables a lo largo y ancho del código así que a usarlo con cuidado.

Obviamente es algo muy documentado y explicado, aquí unos ejemplos:

Publicar la llave pública SSH

Los principales repositorios (Gitlab y Github) exponen las llaves públicas SSH de sus usuarios de forma que están accesibles para descarga:

https://(gitlab|github).com/<usuario>.keys

Es la URL de donde se obtienen, y aquí las mías:

La ventaja es tener un sitio disponible donde está nuestra clave (y la de nuestros colegas) para usar en automatismos como esta task de Ansible:

- name: Enable pilasguru root access
  authorized_key:
    user: root
    state: present
    key: https://gitlab.com/pilasguru.keys
    validate_certs: False

Enviar correo SMTP por telnet

Nada nuevo, esto está por todo internet explicado en muchas formas, tamaños y colores. Pero sucede que lo utilizo mucho y lo que siempre hago es entrar a mi blog y hacer una búsqueda por el término «telnet» y ahi me doy cuenta que tengo todas las formas de telnet para correo, menos la común y corriente. Eso motiva este artículo.

Como enviar un correo electrónico al puerto 25 por telnet:

# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 mail.mydomain.com ESMTP

HELO yourdomain.com
250 mail.mydomain.com

MAIL FROM: you@server.com
250 2.1.0 Ok

RCPT TO: rpilas@mydomain.com
250 2.1.5 Ok

DATA
354 End data with <CR><LF>.<CR><LF>
From: "Some One" <you@server.com>
To: "Rodolfo Pilas" <rpilas@mydomain.com>
Subject: Testing
MIME-Version: 1.0
Content-Type: multipart/alternative;
        boundary="boundary-type-1234567892-alt"
--boundary-type-1234567890
--boundary-type-1234567892-alt
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable


Testing the text to see if it works!

--boundary-type-1234567892-alt
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable


<html>Does this actually work?</html>

--boundary-type-1234567892-alt--
--boundary-type-1234567890
Content-Transfer-Encoding: base64
Content-Type: text/plain;name="Here2.txt"
Content-Disposition: attachment;filename="Here2.txt"

KiAxMyBGRVRDSCAoQk9EWVtURVhUXSB7NjU5fQ0KLS1fZjZiM2I1ZWUtMjA3YS00ZDdiLTg0NTgtNDY5YmVlNDkxOGRhXw0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PSJpc28tODg1OS0xIg0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogcXVvdGVkLXByaW50YWJsZQ0KDQoNCkp1c3Qgc2VlaW5nIHdoYXQgdGhpcyBhY3R1
YWxseSBjb250YWlucyEgCQkgCSAgIAkJICA9DQoNCi0tX2Y2YjNiNWVlLTIwN2EtNGQ3Yi04NDU4LTQ2OWJlZTQ5MThkYV8NCkNvbnRlbnQtVHlwZTogdGV4dC9odG1sOyBjaGFyc2V0PSJpc28tODg1OS0xIg0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogcXVvdGVkLXByaW50YWJsZQ0KDQo8aHRtbD4NCjxoZWFkPg0KPHN0eWxlPjwhLS0N
Ci5obW1lc3NhZ2UgUA0Kew0KbWFyZ2luOjBweD0zQg0KcGFkZGluZzowcHgNCn0NCmJvZHkuaG1tZXNzYWdlDQp7DQpmb250LXNpemU6IDEwcHQ9M0INCmZvbnQtZmFtaWx5OlRhaG9tYQ0KfQ0KLS0+PC9zdHlsZT48L2hlYWQ+DQo8Ym9keSBjbGFzcz0zRCdobW1lc3NhZ2UnPjxkaXYgZGlyPTNEJ2x0cic+DQpKdXN0IHNlZWluZyB3aGF0IHRo
aXMgYWN0dWFsbHkgY29udGFpbnMhIAkJIAkgICAJCSAgPC9kaXY+PC9ib2R5Pg0KPC9odG1sPj0NCg0KLS1fZjZiM2I1ZWUtMjA3YS00ZDdiLTg0NTgtNDY5YmVlNDkxOGRhXy0tDQopDQpmbHlubmNvbXB1dGVyIE9LIEZFVENIIGNvbXBsZXRlZA


--boundary-type-1234567890--


.
QUIT
250 2.0.0 Ok: queued as 1EDE71400DE

221 2.0.0 Bye
Connection closed by foreign host.

(esto lo he extraido de internet)

Openstack CLI y autocompletar en bash

Hace ya tiempo que utilizo el comando integrado openstack para vincularme con nubes en Openstack de distintos proveedores y siempre extrañe que en algunas distribuciones de GNU/Linux no estuviera disponible el autocompletar en Bash.

El comando openstack ofrece el parámetro complete que genera el script para que bash-completion lo cargue y quede funcional.

Ejecutar como usuario con permiso sudo:

$ openstack complete | sudo  tee /etc/bash_completion.d/osc.bash_completion > /dev/null

o también como root:

# openstack complete > /etc/bash_completion.d/osc.bash_completion

El parámetro complete implementado en el comando openstack utiliza el framework cliff – Command Line Interface Formulation Framework para obtener la salida del script de bash-completion.

Cambiando vencimiento llave GPG

Las llaves GPG que me identifican les coloco un vencimiento anual.

Mi llave pública GPG en keybase

entonces cada año en esta época debo proceder a renovar la llave, que lo que hago es correrle un año para adelante el vencimiento y vovler a sincronizar con los keyservers.

Este es el proceso total que ejecuto:

Buscar mi llame en mi llavero:

$ gpg --list-keys Rodolfo
pub   rsa2048 2014-09-07 [SC] [caduca: 2017-09-14]
      FCE66FC5849DA0F6E30DD1FCA33C4E6423B5BE7B
uid           [  absoluta ] Rodolfo Pilas <rodolfo@>
uid           [  absoluta ] Rodolfo Pilas <rodolfo@>
uid           [  absoluta ] Rodolfo Pilas <rpilas@>
uid           [  absoluta ] [jpeg image of size 4579]
uid           [  absoluta ] [jpeg image of size 13611]
sub   rsa2048 2014-09-07 [E] [caduca: 2017-09-14]

Editar la llave:

$ gpg --edit-key FCE66FC5849DA0F6E30DD1FCA33C4E6423B5BE7B

Clave secreta disponible.

sec  rsa2048/A33C4E6423B5BE7B
     creado: 2014-09-07  caduca: 2017-09-14  uso: SC
     confianza: absoluta      validez: absoluta
ssb  rsa2048/65841C4E15CF2ADC
     creado: 2014-09-07  caduca: 2017-09-14  uso: E
[  absoluta ] (1). Rodolfo Pilas <rodolfo@>
[  absoluta ] (2)  Rodolfo Pilas <rodolfo@>
[  absoluta ] (3)  Rodolfo Pilas <rpilas@>
[  absoluta ] (4)  [jpeg image of size 4579]
[  absoluta ] (5)  [jpeg image of size 13611]

Está editando la key 0 o sea la que se identifica como A33C4E6423B5BE7B

gpg> expire
Cambiando caducidad de clave primaria.
Por favor, especifique el per'iodo de validez de la clave.
         0 = la clave nunca caduca
      <n>  = la clave caduca en n d'ias
      <n>w = la clave caduca en n semanas
      <n>m = la clave caduca en n meses
      <n>y = la clave caduca en n a~nos
?Validez de la clave (0)? 1y
La clave caduca Tue Sep 11 17:26:48 2018 -03
?Es correcto? (s/n) s

sec  rsa2048/A33C4E6423B5BE7B
     creado: 2014-09-07  caduca: 2018-09-11  uso: SC
     confianza: absoluta      validez: absoluta
ssb  rsa2048/65841C4E15CF2ADC
     creado: 2014-09-07  caduca: 2017-09-14  uso: E
[  absoluta ] (1). Rodolfo Pilas <rodolfo@>
[  absoluta ] (2)  Rodolfo Pilas <rodolfo@>
[  absoluta ] (3)  Rodolfo Pilas <rpilas@>
[  absoluta ] (4)  [jpeg image of size 4579]
[  absoluta ] (5)  [jpeg image of size 13611]

Ya quedo cambiada la caducidad de la llave primaria, ahora la secundaria 65841C4E15CF2ADC:

gpg> key 1

sec  rsa2048/A33C4E6423B5BE7B
     creado: 2014-09-07  caduca: 2018-09-11  uso: SC
     confianza: absoluta      validez: absoluta
ssb* rsa2048/65841C4E15CF2ADC
     creado: 2014-09-07  caduca: 2017-09-14  uso: E
[  absoluta ] (1). Rodolfo Pilas <rodolfo@>
[  absoluta ] (2)  Rodolfo Pilas <rodolfo@>
[  absoluta ] (3)  Rodolfo Pilas <rpilas@>
[  absoluta ] (4)  [jpeg image of size 4579]
[  absoluta ] (5)  [jpeg image of size 13611]

gpg> expire
Cambiando fecha de caducidad de subclave.
Por favor, especifique el per'iodo de validez de la clave.
         0 = la clave nunca caduca
      <n>  = la clave caduca en n d'ias
      <n>w = la clave caduca en n semanas
      <n>m = la clave caduca en n meses
      <n>y = la clave caduca en n a~nos
?Validez de la clave (0)? 1y
La clave caduca Tue Sep 11 17:27:37 2018 -03
?Es correcto? (s/n) s

sec  rsa2048/A33C4E6423B5BE7B
     creado: 2014-09-07  caduca: 2018-09-11  uso: SC
     confianza: absoluta      validez: absoluta
ssb* rsa2048/65841C4E15CF2ADC
     creado: 2014-09-07  caduca: 2018-09-11  uso: E
[  absoluta ] (1). Rodolfo Pilas <rodolfo@>
[  absoluta ] (2)  Rodolfo Pilas <rodolfo@>
[  absoluta ] (3)  Rodolfo Pilas <rpilas@>
[  absoluta ] (4)  [jpeg image of size 4579]
[  absoluta ] (5)  [jpeg image of size 13611]

Guardar la llave editada y salir de gpg

gpg> save

Subir la llave al keyserver, para que los cambios se repliquen

$ gpg --keyserver pgp.mit.edu --send-keys FCE66FC5849DA0F6E30DD1FCA33C4E6423B5BE7B
gpg: enviando clave A33C4E6423B5BE7B a hkp://pgp.mit.edu

Y aprovechar a actualizar todas las demas llaves de mi llavero, pero eso ya es otra tarea.

LXC en Debian con Ansible

Desde antes del 2013 vengo insitiendo con las ventajas de los containers en Linux, ya que permiten un rápido despliegue de muchos sistemas Linux corriendo en forma independiente.

En 2014 había hecho experiencias para tener con una máquina virtual de DigitalOcean muchos contenedores Linux instalados y prestando servicios y en 2016 tuve la oportunidad de compartir en forma práctica con la comunidad de Paysandú un ejemplo de uso de contenedores.

Hace unos meses atrás armé un perfil de vagrant (Vagrantfile) que permite levantar una máquina virtual con Debian e instalar (aprovisionar) un servidor de contenedores LXC, y un primer contenedor de pruebas.

Este artículo tiene por objetivo, compartir esa configuración, para que la pueda usar quién desee.

Repositorio: debian-lxc-ansible

El aprovisionamiento se realiza mediante Ansible, por lo que es fácil de parametrizar y adaptar.

Una vez levantado el primer contenedor (que ya queda en el aprovisionamiento inicial, luego de correr vagrant up) es muy fácil levantar más contenedores con los comandos normales.

También, en el directorio /vagrant/utils se entregan scripts (requieren revisión y adaptación a la instalación particular) que sirven cómo muestra de cómo levantar containers para producción:

a) Levantar un container con sitio web funcional

/vagrant/utils/create-container.sh name

b) Borrar el container creado con el script anterior

/vagrant/utils/destroy-container.sh name

c) Crear una página web para ver el status de los containers a través de web en el servidor lxc

/vagrant/utils/status.sh

Toda esta instalación, obviamente puede ser modificada y mejorada. Si desean compartir sus mejoras conmigo lo pueden hacer a través de Merge Request.

Actualización y los 4 millones de archivos

Un tiempo atrás actualicé un sistema Debian en forma rutinaria y hace un par de días comenzó a producir problemas extraños en las aplicaciones: desde pérdida de sesión al editar páginas web, errores para escribir en las bases de datos, hasta problemas de permisos en los archivos temporales.

El problema resultó ser la temida y oscura: tabla de inodos llena.

# df -i
Filesystem      Inodes    IUsed           IFree IUse% Mounted on
/dev/sda1       5120000 5120000     0        100%   /

Entonces, a salir a buscar dónde estaban los millones de archivos que ocupaban todos los inodos:

# find / -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -n
...
3945231  /var/lib/php5/

y resulta que en ese directorio se mantenían unos casi cuatro millones de archivos llamados como sess_dn5m6oc4fcpfo0c95pq1se4rp0.

Aparte de iniciar un proceso de borrado masivo:

# cd /var/lib/php5
# find . -name "sess_*" -print | xargs rm -v

Inicié la búsqueda de las causas de fondo para evitar que el problema se vuelva a repetir en el futuro.

En Debian/Ubuntu el encargado de mantener los archivos de sesiones que se generan en /var/lib/php5 es el script

# cat /etc/cron.d/php5
# /etc/cron.d/php5: crontab fragment for php5
#  This purges session files older than X, where X is defined in seconds
#  as the largest value of session.gc_maxlifetime from all your php.ini
#  files, or 24 minutes if not defined.  See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -x /usr/lib/php5/sessionclean ] && [ -d /var/lib/php5 ] && /usr/lib/php5/sessionclean /var/lib/php5 $(/usr/lib/php5/maxlifetime)

que como se puede ver, utiliza la salida de la ejecución de /usr/lib/php5/maxlifetime para determinar el tiempo de mantenimiento de los archivos de sesión de php.

El problema se generó en la ejecución de /usr/lib/php5/maxlifetime que producía el error de al ejecutar por la presencia de la directiva safe_mode en el archivo php.ini:

#  grep safe_mode /etc/php5/apache2/php.ini
safe_mode = On

en razón de que:

42 | WARNING | INI directive ‘safe_mode’ is deprecated from PHP 5.3 and forbidden from PHP 5.4.

Así la actualización a PHP 5.4 hizo que el archivo /usr/lib/php5/maxlifetime dejara de devolver un valor para devolver un error. Entonces el proceso de limpieza, dejó de limpiar y se juntaron cuatro millones de archivos que llenaron la tabla de inodos.

Solución permanente: comentar safe_mode = On en el archivo php.ini.