Postřehy o mém prvním edge zařízení

Dva roky zpět jsem si koupil Raspberry pi desku a osadil jí SSD modulem. Od té doby jsem s ní neudělal vůbec nic. Neměl jsem čas, byl jsem líný. Desku jsem odstěhoval do kanceláře, kde asi rok netknutě ležela. Jenže někdy po vánocích jsem se trochu nalil a rozhodl se, že jí odvezu domu a zkusím na ní něco rozjet. A tak začala víkendová hra na zprovoznění krabičky na mém stole.

Vzdálená správa

Kdybych měl IPv6, tak bych v téhle části jen napsal o správném nastavení ACL / Firewallu. To má Radek úplnou pravdu a já mu děkuji, že šíří osvětu. Takovou věc ale u svého ISP nemám (bydlím na vesnici, úplně si nemůžu vybírat), takže se podíváme na způsob, kterým jsem si zajistil připojení z celého světa: Teleport.

Teleport je nástroj na zjednodušení vzdáleného přístupu do uzlů pomocí SSH. Říkám tomu SSH na steroidech, umožňuje to single sign on, vynucuje druhý faktor a pomocí reverzního tunelu lze připojit i zařízení za NAT. To je přesně můj případ. Takže v AWS jsem si rozjel Teleport cluster (proxy a auth. server) a pak jsem do něj zapojil Raspberry pi.

teleport:
  auth_token: "redacted"
  ca_pin: "redacted"
  auth_servers:
    - "redacted:3080"
ssh_service:
    enabled: true
    labels:
        env: dev

proxy_service:
    enabled: false

Výsledkem je, že se mi Teleport ve webovém rozhraní ukazuje moje domácí Raspberry pi se šipkou, která označuje právě ten reverzní tunel.

Teď se můžu kdekoliv přihlásit ke své Teleport proxy a pak skočit přímo do Raspberry pi.

➜ tsh ssh root@raspberrypi
root@raspberrypi:~# 

Základní monitoring

Teď mi tady vznikly dva uzly, které bych měl ideálně nějak monitorovat. Můžu si všude nainstalovat Prometheus s Alertmanager a nebo můžu využít volného plánu od nějakého SaaS poskytovatele. No a vzhledem k tomu, že jsem v posledním měsíci dost zkoušel Grafana Cloud, tak jsem se rozhodl právě pro něj, protože má velmi štědrý free tier a zároveň se k tomu můžu chovat, jako bych měl vlastní Prometheus.

Na monitoring základních technických metrik stačí node_exporter, u kterého je potřeba zapnout systemd collector pro exportování metrik o důležitých systemd službách. Zde doporučuji omezit počet exportovaných služeb pomocí přepínače --collector.systemd.unit-whitelist, nepotřebujeme sledovat úplně vše a free tier Grafana Cloudu má omezení právě v počtu uložených metrik.

--collector.systemd.unit-whitelist="teleport.service"

Metriky pak sbírám relativně novým Grafana Agentem, který se v tomhle případě chová jako takový odlehčený Prometheus. Koukněte do scrape_configs a hned pochopíte, co tím myslím. 

server:
  http_listen_port: 12345
prometheus:
  wal_directory: /tmp/grafana-agent-wal
  global:
    scrape_interval: 15s
  configs:
    - name: integrations
      scrape_configs:
        - job_name: node_exporter
          metric_relabel_configs:
            - source_labels: [__name__]
              regex: 'node_systemd_unit_state|node_memory_MemAvailable_bytes|node_memory_MemTotal_bytes|node_cpu_seconds_total'
              action: keep
          static_configs:
            - targets:
                - localhost:9100
          relabel_configs:
            - source_labels: [__address__]
              target_label: instance
              replacement: "redacted"
      remote_write:
        - url: https://prometheus-us-central1.grafana.net/api/prom/push
          basic_auth:
            username: "redacted"
            password: "redacted"

V konfiguračním souboru Grafana Agent si prosím všimněte, že sbírám jen některé metriky. Má to několik důvodů. V první řadě, jak jsem již řekl, v Grafana Cloud platíme za objem. Takže když si tady explicitně vyberu, tak v podstatě nehrozí, že se nevejdu do free tieru. 

A za druhé, nejsem fanda sbírání haldy metrik jen proto, že bych je možná mohl potřebovat. Zkrátka a dobře sbírám jen to, na čem mám pověšené dashboardy nebo alerty. A když mi při řešení problému něco chybí, tak to přidám. 

Tenhle princip se mimochodem hodí při provozu vlastního Prometheus. Když začnete sbírat vše dostupné, tak se velmi brzy začnete divit, co všechno Prometheus sežere.

Routing trafficu do Raspberry pi

Zde mám stejný problém, jako se vzdálenou správou: NAT. Na tuhle věc existuje několik řešení. Dříve jsem používal Wireguard, ale tentokrát jsem se rozhodl, že se pustím do něčeho o trochu méně časově náročného. Na Twitteru už nějakou dobu sleduji Alexe, který tenhle problém vyřešil napsáním Inlets tunelu. A tak jsem si od něj koupil osobní licenci (zejména abych ho podpořil ❤️) a routing HTTP požadavků vyřešil kombinací tohoto tunelu a Traefik proxy, která umí automaticky konfigurovat TLS. Nějaké detaily níže.

Inlets-pro je fakt specializovaná věc, co řeší jen jeden problém. Proto je rozjetí extrémně jednoduché. Na straně serveru (AWS) stačí pustit

/usr/local/bin/inlets-pro server --token=redacted --common-name=redacted --listen-data 127.0.0.1:

a na straně klienta (Raspberry pi)

/usr/local/bin/inlets-pro client --url=wss://redacted:8123/connect --ports=8080 --token=redacted --upstream localhost --license-file=/etc/inlets-pro/license

Takhle rozjetý tunel otevře v AWS port 8080 na localhost a pokud tam pošleme nějaký HTTP request tak dojde k jeho předání aplikaci, která běží na portu 8080 u mě na stole.

Automatické TLS a vystavení služby do Internetu

A teď už nám zbývá vyřešit předávání požadavků z internetu pomocí Traefik proxy s automatickým TLS. Traefik je jedna binárka, kterou si jednoduše můžete stáhnout z GitHubu, napsat pro ní krátký konfigurační soubor ve formátu TOML nebo YAML a pak to stačí jen spustit ručně a nebo pomocí systemd. Konfigurace zajišťující základní routing a automatické TLS vypadá nějak takhle.

log:
  level: ERROR

accessLog: {}

entryPoints:
  web:
   address: ":80"
   http:
     redirections:
       entryPoint:
         to: websecure
         scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  myresolver:
    acme:
      email: stepan@vrany.dev
      storage: acme.json
      httpChallenge:
        entryPoint: web

providers:
  file:
    directory: "/etc/traefik/conf"

A tohle je pak konfigurace samotné HTTP části, kde Traefiku říkáme, kudy co a jak. 

http:
  routers:
    router0:
      tls:
        certResolver: myresolver
      entryPoints:
      - web
      - websecure
      service: raspberrypi01-8080
      rule: Host(`redacted`) && Path(`/`)

  services:
    raspberrypi01-8080:
      loadBalancer:
        servers:
        - url: http://localhost:8080/
        passHostHeader: false

Nejzajímavější částí konfigurace jsou services, kde můžete vidět směřování na Inlets tunel naslouchající na 127.0.0.1:8080

Když teď pošlu HTTP požadavek na HTTPS port svého serveru, tak vidím, že celý řetězec funguje tak, jak má.

➜ curl http://redacted -L -I
HTTP/1.1 308 Permanent Redirect
Location: https://redacted/
Date: Sun, 31 Jan 2021 14:17:02 GMT
Content-Length: 18
Content-Type: text/plain; charset=utf-8

HTTP/2 200 
content-type: text/plain; charset=utf-8
date: Sun, 31 Jan 2021 14:17:02 GMT
content-length: 8

➜ curl https://redacted
Hello, !root


Traefik umí celou řadu dalších věcí, na každý router lze pověsit middleware, který může třeba řešit basic auth nebo forward auth společně s nějakým OIDC poskytovatelem. Kompletní seznam konfigurace je v dokumentaci, která je vskutku obsáhlá. 

Osobně považuji Traefik dokumentaci za jednu z nejlepších, co lze mezi OpenSource nástroji najít.

Další samozřejmosti

V tomhle článku jsem zcela záměrně nepopisoval všechny výzvy takové konfigurace, které jsem během víkendu řešil. Pro bezstarostný běh je potřeba vyřešit například:

  • nastavení Security Groups v AWS VPC
  • nastavení systémového firewallu na obou uzlech
  • nastavení loggingu, zde se nabízí Loki, když jsme se rozhodli používat Grafana Cloud
  • nastavení tracing collectorů, tady můžeme rovněž sáhnout po Grafana Cloudu a sledovat HTTP requesty už od Traefik proxy, která má podporu pro tracing
  • vystavení metrik v aplikaci
  • nastavení alertingu v Grafana
  • a spoustu dalších věcí 😊

Závěr

Víte, co je největší sranda? No především to, že nevím co na tom Raspberry pi spustit za aplikaci 😁Evidentně jsem lepší v plánováni infrastruktury, než ve vymýšlení super cool IoT věcí. Ale já na něco přijdu!