Métricas con el Odroid-N2

Ubuntu minimal instalado en un disco de 60Gb solo para testing 😁 no lo recomiendo.

elodroidn2

El Odroid

El odroid n2 es una placa bastante buena, aunque descontinuada ya, por su jefe el odroid n2+ aún asi era una placa que en su momento superaba con creces a la rasberry-py, y claramente por eso la tenemos aquí

odroidn2 odroidn2+

ON/OFF

  • Para apagarlo se puede hacer desde la interface del Sistema.

  • Via infrarojo.

  • Customizarle un botón para ON/OFF.

  • O un esp( pero es muy exagerado 😅)

Cpu benchmark

El Odroid tiene buen rendimiento, Pobre raspi, igualmente esto no es de mi autoria pero no tiene pinta que sea falso o alterado para ofrecer ventaja.

benchmark cpu

Cable para conexión SDD

En un inicio las estabilidad del SO era poca, pero se debía a que el disco ssd sufria algún tipo de desconexión, lentidud etc…​ lo cual producia que la pantalla se quedara congelada.

Este adaptador es muy estable, sin que se frizee el S0 en este caso Ubuntu Mate.

cable estable odroid ssd

odroid@odroid:/$ lsusb (1)
Bus 002 Device 003: ID 174c:1153 ASMedia Technology Inc. ASM1153 SATA 3Gb/s bridge (2)
Bus 002 Device 005: ID 174c:1153 ASMedia Technology Inc. ASM1153 SATA 3Gb/s bridge
Bus 002 Device 002: ID 05e3:0620 Genesys Logic, Inc. USB3.1 Hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 05e3:0610 Genesys Logic, Inc. 4-port hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
1 Ejecutamos lsusb
2 Tenemos el chipset ASM1153 correcto y estable, permitiendo una velocidad mayor IO de disco.
Info de usuarios que recomienda su uso.

Instalando Ubuntu 22.04 LTS

Instalación de docker y fixeo de arranque

Este script da todo masticado ya, no tenemos que hacer practicamente nada.

Sí, al querer hacer un hello world con docker tenemos este error

Odroid n2 OCI runtime create failed: runc create failed: unable to start container process: error during container init: error setting cgroup config for procHooks process: bpf_prog_query(BPF_CGROUP_DEVICE) failed: invalid argument: unknown

Editaremos el /media/boot/boot.ini

Es porque nos falta añadir la línea siguiente:

# Boot Args
setenv bootargs "root=UUID=e139ce78-9841-40fe-8823-96a304a09859 rootwait rw ${condev} ${amlogic} no_console_suspend fsck.repair=yes net.ifnames=0>
setenv bootargs "${bootargs} systemd.unified_cgroup_hierarchy=0" (1)
1 Justo esta, en el fichero /media/boot/boot.ini, y reiniciamos.

Deberíamos poder ver la línea esa en:

root@odroid:~# cat /proc/cmdline
root=/dev/sda2 rootwait rw console=ttyS0,115200n8  no_console_suspend fsck.repair=yes net.ifnames=0 elevator=noop hdmimode=custombuilt cvbsmode=576cvbs max_freq_a53=1896 max_freq_a73=1800 maxcpus=6 voutmode=hdmi modeline=2560,1080,185580,66659,60,2560,2624,2688,2784,1080,1083,1093,1111,0,0,1 disablehpd=false cvbscable=0 overscan=100  monitor_onoff=false logo=osd0,loaded hdmitx=cec3f sdrmode=auto consoleblank=0 enable_wol=0
(1)
cgroup_hierarchy=1 systemd.unified_cgroup_hierarchy=0
1 Listo, ya podriamos hacer un hello-world con docker.

Docker compose en el Odroid

Necesitamos docker compose, entonces buscamos la última release y es ésta v2.24.0-birthday.10

sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0-birthday.10/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Lo ejecutamos con:

docker-compose -f docker-compose.yml up -d (1)
1 En el mismo directorio.

Grafana

logo horizontal dark

Grafana permite vizualizar métricas en tiempo real, y además es muy customizable, es necesario que use un datasource, en este caso usaremos prometheus que bajo fondo usa PromQL siendo compatible con más de 100 apis.

En el odroid por alguna razón tuve ciertos problemas de permisos simplemente, faltaba el id del usuario correcto con el comando:
id -u

Y el mío era el 1000 🔥 este debemos usarlo en el docker-compose.yml

networks:
  monitoring:
    driver: bridge
volumes:
  prometheus_data: {}
services:
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - 9100:9100
    networks:
      - monitoring
  prom-pushgateway:
    image: prom/pushgateway
    ports:
      - 9091:9091
    networks:
      - monitoring
  prometheus:
    image: prom/prometheus:latest
    user: "1000" (1)
    environment:
      - PUID=1000 (2)
      - PGID=1000 (3)
    container_name: prometheus
    restart: unless-stopped
    volumes:
      - /home/odroid/Documents/metricas/prometheus.yml:/etc/prometheus/prometheus.yml
      - /home/odroid/Documents/metricas:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'
    ports:
      - 9090:9090
    networks:
      - monitoring
  grafana:
    image: grafana/grafana:latest
    user: "1000" (4)
    container_name: grafana
    ports:
      - 3000:3000
    restart: unless-stopped
    volumes:
      - /home/odroid/Documents/metricas/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
      - /home/odroid/Documents/metricas/grafana:/var/lib/grafana
    networks:
      - monitoring
  #artillery:
  #  image: artilleryio/artillery:latest
  #  container_name: artillery
  #  networks:
  #    - monitoring
1 El user id se debe ajustar
2 Igual en este punto
3 Igual
4 Igual

Reset de password

Sí, típica historia, pasara que en el algún momento perdamos el acceso al grafana, pero podemos resolverlo con:

docker exec -ti e3e338f0bfae \ (1)
grafana cli admin reset-admin-password \
newPassw0rd (2)
1 Le pasamos el id del container de grafana.
2 Esta será la nueva password
root@odroid:/media/share-nas/dockerfiles++# docker exec -ti e3e338f0bfae grafana cli admin reset-admin-password odroidPassw00rd
INFO [01-05|23:01:35] Starting Grafana                         logger=settings version= commit= branch= compiled=1970-01-01T00:00:00Z
INFO [01-05|23:01:35] Config loaded from                       logger=settings file=/usr/share/grafana/conf/defaults.ini
INFO [01-05|23:01:35] Config overridden from Environment variable logger=settings var="GF_PATHS_DATA=/var/lib/grafana"
INFO [01-05|23:01:35] Config overridden from Environment variable logger=settings var="GF_PATHS_LOGS=/var/log/grafana"
INFO [01-05|23:01:35] Config overridden from Environment variable logger=settings var="GF_PATHS_PLUGINS=/var/lib/grafana/plugins"
INFO [01-05|23:01:35] Config overridden from Environment variable logger=settings var="GF_PATHS_PROVISIONING=/etc/grafana/provisioning"
INFO [01-05|23:01:35] Target                                   logger=settings target=[all]
INFO [01-05|23:01:35] Path Home                                logger=settings path=/usr/share/grafana
INFO [01-05|23:01:35] Path Data                                logger=settings path=/var/lib/grafana
INFO [01-05|23:01:35] Path Logs                                logger=settings path=/var/log/grafana
INFO [01-05|23:01:35] Path Plugins                             logger=settings path=/var/lib/grafana/plugins
INFO [01-05|23:01:35] Path Provisioning                        logger=settings path=/etc/grafana/provisioning
INFO [01-05|23:01:35] App mode production                      logger=settings
INFO [01-05|23:01:35] Connecting to DB                         logger=sqlstore dbtype=sqlite3
INFO [01-05|23:01:35] Starting DB migrations                   logger=migrator
INFO [01-05|23:01:35] migrations completed                     logger=migrator performed=0 skipped=523 duration=1.624073ms
INFO [01-05|23:01:35] Envelope encryption state                logger=secrets enabled=true current provider=secretKey.v1

Admin password changed successfully ✔

El fichero prometheus.yml

Este fichero lo necesita prometheus si o si, para el intervalo de scraping, además las url’s de pushgateway ( que no la usare de momento aquí), pero si la de node-exporter.

En caso de que el arranque del contenedor de prometheus falle, este fichero debemos también editarle.

Además borrar y crear el contenedor de prometheus nuevamente.

docker-compose stop (1)
docker rm id_contenedor_prometheus (2)
docker-compose -f docker-compose.yml up -d (3)
1 Parando contenedores, grafana, prometheus, node, pushgateway, sin recrear ninguno.
2 Removiendo container, a través de su id.
3 Recreando container de prometheus, los demás contenedores se reutilizaran.
global:
  scrape_interval: 1m

scrape_configs:
  - job_name: 'prometheus'
    scrape_interval: 1m
    static_configs:
      - targets: ['localhost:9090'] (1)

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100'] (2)

  - job_name: dev-push-gateway
    metrics_path: /metrics
    scheme: http
    static_configs:
      - targets: ['prom-pushgateway:9091'] (3)
        labels:
          service: 'prom-pushgateway'
1 Url de prometheus
2 Url del node-exporter
3 Url del push-gateway

Añadiendo el datasource

Como lo indica el input sera la url del servidor de prometheus más su puerto.

grafana datasource

Por último confirmamos el datasource de prometheus, esta notificación es la que debemos tener.

Save and test
datasource añadido correctamente

Pushgateway

Pushgateway de momento es opcional, pero si quiero tenerle de una vez, para un futuro usarle con artillery, JMeter, quizás hasta gatling.

Util para métricas que se hacen difíciles de scrapear para prometheus, entonces pushgateway suele trabajar en conjunto para ese tipo de métricas.

Un caso de uso será de loading-testing por ejemplo con Artillery

Prometheus

prometheus logo
interface targets prometheus

Panel de node-exporter

Node exporter, nos permite exponer métricas del sistema operativo, por lo cual prometheus puede scrapear para que grafana las grafique, lo interesante es que existen ya varios paneles que podemos reutilizar.

Importando panel node-exporter

Añadimos un nuevo dashboard

new dashboard
importando panel node exporter
grafana

Los contenedores

odroid@odroid:/$ docker ps -a
CONTAINER ID   IMAGE                           COMMAND                  CREATED         STATUS                   PORTS                                                                                            NAMES
461e1411b79c   prom/prometheus:latest          "/bin/prometheus --c…"   7 hours ago     Up 7 hours               0.0.0.0:9090->9090/tcp, :::9090->9090/tcp                                                        prometheus
0c06aa9ce69c   prom/pushgateway                "/bin/pushgateway"       8 hours ago     Up 8 hours               0.0.0.0:9091->9091/tcp, :::9091->9091/tcp                                                        metricas-prom-pushgateway-1
f890a1909c4b   grafana/grafana:latest          "/run.sh"                8 hours ago     Up 8 hours               0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                                        grafana
5f500f92425e   prom/node-exporter:latest       "/bin/node_exporter …"   8 hours ago     Up 8 hours               0.0.0.0:9100->9100/tcp, :::9100->9100/tcp                                                        node-exporter
7c658c9f7a8b   portainer/portainer-ce:latest   "/portainer"             8 hours ago     Up 8 hours               0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp, 9000/tcp   portainer
b9f106d61216   mariadb/columnstore             "/usr/bin/tini -- do…"   24 hours ago    Up 9 hours               0.0.0.0:3306->3306/tcp, :::3306->3306/tcp                                                        mariadb_columnstore
86f32f6a33f7   oracle/database:19.3.0-ee       "/bin/bash -c 'exec …"   4 days ago      Exited (1) 4 days ago                                                                                                     debug
72247c856602   oracle/database:19.3.0-ee       "/bin/bash -c 'exec …"   4 days ago      Exited (1) 4 hours ago                                                                                                    oracle
acdc26e3ac5a   hello-world                     "/hello"                 11 months ago   Exited (0) 5 days ago

Poco espacio en disco

Mirando métricas

Llega un momento que el disco del Odroid se quedo corto, pero con un USB adicional podemos añadir otro disco más grande

En el panel de node exporter se mostrará el disco nuevo.

newdisk2TB

Usando NFS del NAS

Otra opción interesate es usar el NFS que hemos activado en el NAS, este protocolo tiene un buen rendimiento y no es muy difícil de usar, nos permitirá tener un directorio en nuestro host que apunta a otra dirección en la red.

Lo presentado aquí, en local es inseguro, dado que no tengo seteada la seguridad como debería, pero para un testeo rápido viene bien.

Entonces instalamos:

sudo apt update && sudo apt install nfs-common (1)
sudo mount -t nfs 192.168.1.250:/mnt/pool/ /media/share-nas (2)
Created symlink /run/systemd/system/remote-fs.target.wants/rpc-statd.service → /lib/systemd/system/rpc-statd.service.
1 Actualizamos e instalamos el nfs-common
2 Montamos la unidad externa en nuestro host
nfs disco unidad mas espacio
Las rutas anteriores son de esto:

/media/usb0 ruta del Odroid con menos de 50Gb.
/media/share-nas ruta del NFS del NAS con mucho mas espacio para simple testeo.

Montado automático

sudo nano /etc/fstab
# UNCONFIGURED FSTAB FOR BASE SYSTEM
LABEL=BOOT /media/boot vfat umask=0077 0 1
UUID=e139ce78-9841-40fe-8823-96a304a09859 / ext4 errors=remount-ro 0 1
192.168.1.250:/mnt/pool/mariadb /media/share-nas nfs defaults 0 0 (1)
1 La ruta NFS nueva.
Si el fichero fstab es editado mal, no podremos arrancar el Ubuntu del Odroid.

En caso de que no tengamos acceso a la ruta nfs y tengamos este tipo de error

Error con ruta nfs

d????????    ??   ??   /media/share-nas (1)
1 Este directorio estaba montado, pero con alguna update del servidor externo, ya no tenemos acceso.

Entonces la solución de momento fue editar el fstab con una nueva ruta y vulgarmente reiniciar el odroid, pero esta solución parece mejor

mount -o remount /share/