Recompilando imágenes Docker x86amd64 para Swarm ARM

Tras finalizar los recientes artículos sobre cómo compilar swarm Docker en ARM (https://goo.gl/2FjP8f) y (https://goo.gl/ZTXcp), me encontré con que quería activar servicios, para los cuales no había imagen ARM disponible, o no había ninguna imagen ARM con una versión reciente. Las alternativas son tres: 1) prescindir de lo que quería, 2) conformarme con una versión anterior, o 3) averiguar cómo compilar lo que quería. Soy un poco chapucero y me gusta tener al menos un conocimiento básico de mis herramientas, así que me decanté por la tercera opción. En su mayor parte, se trata un proceso bastante sencillo, aunque de vez en cuando, terminas modificando algunas cosas. No te deje intimidar por ello, porque realmente merece la pena, y no es tan difícil. Para facilitar las cosas, configuremos una pila Graphite. Para esta pila, necesitaré varios elementos, además de un poco de soporte en forma de registro de imágenes alojado internamente.

Un registro

Usaremos una imagen ya creada para esto de http://dockr.ly/2kmNgod. El registro proporciona un lugar para almacenar e implementar tus imágenes personalizadas. Se trata de un excelente escenario antes de enviar tu producto final a https://hub.docker.com o a cualquier otro registro que elijas.

El front end del registro es simplemente un pequeño servicio muy útil para poner en marcha un registro (http://dockr.ly/2D5DRt3). No entraremos en funciones avanzadas como eliminar imágenes, lo cual requiere una configuración adicional en el registro, pero podremos navegar por nuestras imágenes y obtener información sobre ellas.

Utilizaré go-carbon para el caché (https://goo.gl/hgjGZo). La razón fue simple, go-carbon usa más de un núcleo en una única instancia. Es realmente fácil de configurar, y si tienes alguna definición de esquema, puede funcionar muy bien y también es compatible con el formato pickle.

Utilizaré graphite-api para el punto final de la API de renderizado https://goo.gl/P43pHC. Hay otras opciones como carbonserver y carbonzipper. Creo que go-carbon ahora tiene soporte para carbonserver, pero aún no lo he probado. Creo que ir en modo stock no es tan malo en este caso. Solo se consulta de vez en cuando, así que no se necesita tener un rendimiento tan alto como el caché.

Usaré grafana para la interfaz de usuario de la pantalla, ya que es bastante común (https://grafana.com). Podríamos usar el paquete graphite-web, aunque las posibilidades de representación gráfica son las mismas, son bastante menos accesibles que las de Grafana. También existen otras opciones, si bien deberías analizarlas antes de tomar cualquier decisión sobre lo que más te conviene.

Implementar la infraestructura

Dado que el swarm es realmente de alta disponibilidad con balanceo de carga de esos servicios (tanto a nivel de hardware como de red), los servicios que hemos enumerado anteriormente se lanzarán como servicios independientes. Ten en cuenta que hay múltiples opciones para cada uno, de modo que cubrirlas todas es demasiado para este artículo. Una vez dicho esto, centrémonos en nuestras necesidades de infraestructura e implementemos nuestro registro:

$ docker service create --name=docker-registry --publish=5000:5000/tcp cblomart/rpi-registry
Una vez que se complete el comando, dispondremos de un registro. Sin embargo, tenemos el problema de que ninguna de nuestras instancias Docker lo usará porque no es seguro. Tenemos dos opciones: la primera es configurar tus instancias docker para que usen un registro inseguro (concretamente una lista blanca), y la segunda es obtener un certificado (autofirmado o públicamente verificable). Este es un registro interno. Para ir avanzando, he optado por la primera opción. Para hacerlo así en todos los nodos docker, añadí lo siguiente a /etc/docker/daemon.json, asumiendo que dispones de una configuración por defecto y que el archivo está completo:
{
    "insecure-registries": ["10.0.0.15:5000"]
}

Interfaz de Usuario del Registro Docker

Ahora vamos a movernos para que la interfaz del registro esté en su lugar, lo cual nos permitirá compilar nuestra primera imagen. Ten en cuenta que yo he usado el nombre de host swarm. Esto es lo correcto para mi configuración, ya que tengo un registro CNAME en mi servidor DNS, aunque tu configuración puede ser diferente:

$ git clone https://github.com/parabuzzle/craneoperator.git
$ cd craneoperator
$ docker build -t docker-registry-ui .
$ docker tag docker-registry-ui swarm:5000/docker-registry-ui-arm
$ docker push swarm:5000/docker-registry-ui-arm
Ahora podemos lanzar nuestro servicio. Éste, como muchos otros, utiliza variables de entorno que influyen en su funcionamiento. Por supuesto, tendrás que editarlas para apreciar los cambios:
$ docker service create --name=docker-registry-ui --publish=8081:80/tcp -e REGISTRY_HOST=swarm -e REGISTRY_PROTOCOL=http -e SSL_VERIFY=false swarm:5000/docker-registry-ui-arm

Caché Carbon y API renderizado

Go-carbon es una aplicación Go que requiere Go 1.8+. Para evitar problemas innecesarios nos basaremos en una versión reciente de Go que está disponible en mi gestor de paquetes favorito, simplemente colocaremos la última versión en una ubicación personalizada. En este momento, Go 1.9.2 es la última versión, así que la usaremos. Además, doy por hecho que estás ejecutando Linux en una máquina ARM, como un ODROID-XU4, que es una maravillosa estación de trabajo. Manejo cada uno de mis 3 monitores con un XU4, y uso x2x para poder compartir el teclado y el mouse, aunque esto da para un artículo que escribiremos en otro momento.

$ cd ~
$ mkdir -p ~/.golang/path
$ wget https://redirector.gvt1.com/edgedl/go/go1.9.2.linux-armv6l.tar.gz
$ tar -zxf go1.9.2.linux-armv6l.tar.gz
$ mv go .golang/root
$ export GOROOT=${HOME}/.golang/root
$ export GOPATH=${HOME}/.golang/path
$ export PATH=${GOROOT}/bin:${GOPATH}/bin:${PATH}
Ahora estamos listos para empezar a trabajar en go-carbon. Este es realmente bueno, puesto que dispone de un archivo Dockerfile ya creado, y lo único que tenemos que hacer es compilar el binario y preparar nuestros archivos de configuración. Obtener la fuente y compilar el binario se puede hacer de una sola vez:
$ go get -v github.com/lomik/go-carbon
Ahora que tenemos esto hecho, vamos a compilar nuestra imagen Docker:
$ cd ${GOPATH}/src/github.com/lomik/go-carbon
$ cp ${GOPATH}/bin/go-carbon .
$ mkdir config-examples
Seguimos adelante y nos detendremos aquí, ya que necesitamos modificar el archivo de configuración. Hay un gran número de opciones, pero es probable que no necesites modificar ninguna. Dejaré que seas tú el que se ocupe más adelante de las personalizaciones, simplemente daré por sentado que los valores por defecto son lo suficientemente buenos por ahora. La única modificación que haremos es apuntar al archivo de esquemas correcto y a nuestro directorio de datos. Podemos hacer esto con un simple comando sed:
$ ./go-carbon -config-print-default | sed -E 's,(schemas-file =).*,\1 "/data/graphite/go-carbon-schemas.conf",g' | sed -E 's,(data-dir =).*,\1 "/data/graphite/whisper",' > ./conf-examples/go-carbon.conf
A continuación, podemos conseguir nuestro archivo de esquemas en /conf-examples/go-carbon-schemas.conf:
[default]
pattern = .*
retentions = 10s:1h, 30s:3h, 60s:6h, 1h:1d, 6h:1w, 12h:1m, 24h:1y
Esto nos proporciona mucho espacio para que nuestras estadísticas se almacenen y se mantengan en el tiempo. Llegados a este punto, estamos listos para empezar a compilar nuestra imagen Docker. Supongo que, a afectos de este artículo, te encuentras en la misma máquina en la que compilaste go-carbon y en la que tienes instalado Docker.
$ docker build -t go-carbon . && \
$ docker tag go-carbon swarm:5000/go-carbon-arm && \
$ docker push swarm:5000/go-carbon-arm
Ahora podemos publicar nuestro servicio para nuestro swarm. Ya lo hemos hecho varias veces, así que debería serte familiar:
$ docker service create --name=carbon-cache --publish=2003:2003/tcp --publish=2003:2003/udp swarm:5000/go-carbon-arm
Sin embargo, ahora nos encontramos con otro inconveniente. Necesitamos tener instalada la graphite-api en la imagen, ya que necesitamos disponer de acceso a los archivos whisper. Podríamos crear un sistema de archivos compartido y montarlo tanto para la memoria caché como para las imágenes API, pero en este caso, creo que es mejor que simplemente modifiquemos nuestra imagen go-carbon para que soporte ambos. Lo primero a tener en cuenta es que la imagen docker se llame “busybox”. Como necesito Python, decidí mover esto a ‘debian: stretch’. Lo primero es conseguir nuestro graphite-api.yaml, que se encuentra en ./conf-examples/graphite-api.yaml:
search_index: /data/graphite/index
finders:
  - graphite_api.finders.whisper.WhisperFinder
functions:
  - graphite_api.functions.SeriesFunctions
  - graphite_api.functions.PieFunctions
whisper:
  directories:
    - /data/graphite/whisper
Puesto que estamos iniciando más de un servicio, debemos usar un script de punto de entrada personalizado. Seguimos avanzando y escribimos esto.
#!/bin/sh
gunicorn -b 0.0.0.0:8000 -w 2 graphite_api.app:app &
sleep 2
/go-carbon -config /data/graphite/go-carbon.conf
Después de desplazarnos a debian:stretch e instalar nuestros paquetes y configuraciones, nuestro Dockerfile en nuestro directorio go-carbon debería verse ahora de la siguiente forma:
FROM debian:stretch
RUN mkdir -p /data/graphite/whisper/
RUN apt update && apt upgrade -y && apt dist-upgrade -y && apt autoremove -y
RUN apt install -y gunicorn graphite-api
ADD go-carbon /
ADD entrypoint.sh /
ADD conf-examples/* /data/graphite/
RUN chmod +x /entrypoint.sh
RUN rm /etc/graphite-api.y* ; ln -s /data/graphite/graphite-api.yaml /etc/graphite-api.yaml
CMD ["/entrypoint.sh"]
EXPOSE 2003 2004 7002 7007 2003/udp 8000
VOLUME /data/graphite/
Avancemos y recompilemos, luego impulsemos nuestra nueva imagen:
$ docker build -t go-carbon . && \
$ docker tag go-carbon swarm:5000/carbon-cache-arm && \
$ docker push swarm:5000/carbon-cache-arm
Después eliminaremos nuestro antiguo servicio y lo volveremos a crear. Soy consciente de los procesos de actualización para ejecutar los servicios, aunque sentía que podía escribir un buen tocho sobre este tema, así que lo dejaría como está.
$ docker service rm carbon-cach
$ docker service create --name=carbon-cache --publish=2003:2003/tcp --publish=2003:2003/udp --publish=8000:8000/tcp swarm:5000/go-carbon-arm

Configuración de Graphite

Llegados a este punto, estamos listos para la última parte del proyecto, que es otra imagen que necesitaremos recompilar. Sin embargo, gracias a los “fat manifests” o listas de manifiesto de Docker, al hacer referencia a “debian” obtendrás la imagen adecuada para tu arquitectura. Casi todas las compilaciones oficiales se hacen de esta forma, así que ya no es necesario buscar hasta dar con una imagen para la arquitectura ARM

Con suerte, en mi próximo artículo, exploraremos la configuración de tus propios “fat manifests” en tu registro privado. Esto es muy útil si tienes, como yo, arquitecturas mixtas como amd64 en tu swarm y quieres que cualquiera de tus servicios pueda implementarse en cualquiera de tus nodos. Así que empecemos por la imagen Grafanas. Elegí la imagen en  https://goo.gl/pfpVef, ya que tiene todos los plugins que quería ya cargados, y eso ahorra un montón de trabajo para todo el mundo. Por supuesto, puedes hacerte con la imagen oficial y seguir el mismo proceso:

$ git clone https://github.com/monitoringartist/grafana-xxl.git
$ cd grafana-xxl
$ cp Dockerfile Dockerfile.arm
Necesitamos cambiar la línea 17 de:
$ curl https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${GRAFANA_VERSION}_amd64.deb > /tmp/grafana.deb && \
Por los siguiente:
$ curl https://github.com/fg2it/grafana-on-raspberry/releases/download/v${GRAFANA_VERSION}/grafana_${GRAFANA_VERSION}_armhf.deb > /tmp/grafana.deb && \
Despues, la línea 20 debe cambiar de:
$ curl -L https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 > /usr/sbin/gosu && \
A esto:
$ curl -L https://github.com/tianon/gosu/releases/download/1.10/gosu-armhf > /usr/sbin/gosu && \
Una vez hecho esto, estamos listos para recompilar, mover e implementar nuestro servicio. Usaremos nuevamente esos comandos cada vez más útiles y familiares:
$ docker build -t grafana-xxl-arm -f Dockerfile.arm .
$ docker tag grafana-xxl-arm swarm:5000/grafana-xxl-arm
$ docker push swarm:5000/grafana-xxl-arm
$ docker service create --name=grafana --publish=3000:3000/tcp swarm:5000/grafana-xxl-arm
El último paso es iniciar sesión en tu instancia grafana en http://swarm:3000/ con el nombre de usuario y la contraseña por defecto “admin” y “admin”. Una vez que hayas iniciado sesión, simplemente agrega http://swarm:8000/ como fuente de datos grafana predeterminada y estarás listo para usar Docker.

Be the first to comment

Leave a Reply