Minulla oli Varnish kaatunut. Itse en suuremmin omia sivujani käytä, koska ne ovat sisällöltään staattisia (rakenteeltaan toki dynaamisia) ja varsinkin koska olen ne pääosin itse kirjoittanut. Koska vietin aikaa sisältöni suhteen enemmänkin foorumillani, niin en tiennyt sivustojeni tipahtaneen linjoilta.
Puuttuvat työkalut ja laiskuus
Syy siihen, että korjaus venähti, johtui kahdesta syystä.
- Minulla ei ole käytössä minkäänlaista seurantaa, joka valvoisi järjestelmää
- Käyttäjät eivät koskaan kerro kun sivustot ovat alhaalla. Eivät edes sivustoon kytkeytyneessä Facebook-ryhmässä, eikä niihin kuuluvalla foorumilla
Laskin, että minulla on ollut viimeisen vuoden aikana ollut 41 major-tason kaatumista. Useimmiten Varnish on kaatunut, joskus WordPressit. Suurimman osan noista olen tiennyt, koska itse aiheutin ne. Mutta puolisen tusinaa on ollut sellaisia, että olen ollut täysin tietämätön ongelmista pidempään.
Major tarkoittaa minulla yli 15 minuutin kaatumista. Jos laskisin mukaan minorit, muut kuin päivityksistä johtuvat, niin määrä olisi olisi huimaavasti suurempi. Syy lyhyille kaatumisille on yleensä vanha tuttu — joku kirjoitusvirhe tai puuttuva puolipiste, jonka olisi huomannut, jos olisi vaivautunut tekemään syntaksitarkistuksen ennen restartia.
Aivan riippumatta siitä, että onko kyseessä 502 Bad Gateway
, joka on Varnishin kaatuminen, tai error 503
, joka tulee backendin kaatumisesta — sivustoja hostaava Apache2 — niin aito ongelma ei ole tekniikan pettäminen.
Kyllä, tekniikan pitäisi olla luotetavaa, mutta olen edelleenkin itseoppinut webmaster ja sysadmin, joka tekee hommia köyhyyttään, ja koska on kiva kokeilla kaikenlaista. Voin tehdä siis asioita, joita ammattisivustoilla ei voi tehdä. Mutta niillä sivustoilla on myös palkattu IT-osasto. Joten kaikenlaista tapahtuu ja suurin taloudellinen riski on muutama menetetty Adsense-euro.
Suurin ongelma on se, että en tiedä, jos jokin kaatuu ilman omaa toimintaa ja syytä
Valvontaohjelmat olisivat kivoja. Hyvät maksavat liikaa, ja halvat… no, ne ovat rajoittuneita. Monit toimii jossain tilanteessa ja osaa periaatteessa lähettää sähköpostia, mutta perustoiminnaltaan se tajuaa tehdä vain buutin. Ja jos se seuraa sivuston juuressa olevaa sisältöä, niin se aidosti seuraa vain Apachen toimintaa, eikä tiedä onko WordPress pystyssä.
Käytin sitä jonkun aikaakin 2020 paikkeilla, mutta luovuin siitä määttyjen ongelmien takia.
Käyttäjät olisivat tehokkain, jos he reagoisivat ja sellaisessa ympäristössä, että minäkin näen ilmoituksen. Osa saattaa mainita Facebookissa jossain sivulauseessa, mutta jättää mainitsematta minut. Jos en seuraa juuri sitä ketjua, niin en huomaa. Osa mainitsee ja näen, kun tulen Facebookiin. Mutta olen vähentänyt huomattavasti Metan palvelujen käyttöä (ja nyt kun he päättivät, että minun sisältöni on heidän, saatan vetää kaiken minimiin). Koska en salli push-ilmoituksia Facebookilta, niin maininnoissakin on ihan sattuman kauppaa huomaanko.
Sen sijaan olen foorumilla aktiivisesti. Siellä huomaisin. Foorumilla on myös lupa tehdä ilmoituksille push.
Kun tuosta yhdistää pisteet, niin tarvitsen järjestelmän, joka
- ei tarvitse käyttäjiltä tietoa
- reagoi (ainakin) 502/503 virheisiin — Nginx jää valvomatta, mutta kaikkea ei saa
- ilmoittaa foorumilla, kun tulee virhe
Mitä tein?
Nginx omalla tavallaan tekee valvonnan. Jos Varnish tai Apache2 eivät vastaa, niin virhe palautuu Nginxille. Siellä on määritelty oma reittinsä 502/503/504 virheille. Joten tietoa ei päästetäkään kävijälle, vaan se lähtee uudelle reitille.
Nginx lähettää tiedon Flaskille, joka on eräällä tavalla ultrakevyt web-vastaanotin (kylläkin wen- framework, mutta ei olla niin tarkkoja nyt). Sitä käyttävä python-scripti tekee logimerkinnän ja samalla tuuppaa tiedon virheestä foorumille. Foorumi on Discourse ja se tarjoaa kattavasti API-vaihtoehtoja, joten tottakai niitä piti hyödyntää.
Siinä ohessa myös kävijää informoidaan virheestä. Esitettävä ilmoitus ei tarjoa oikeaa http virhettä, koska kävijät eivät tarvitse sitä. Joku koputtelija voisikin haluta, mutta minua ei kiinnosta mitä joku aukkoja etsivä haluaa.
Koska tuo reitti aktivoituu aivan joka kerta kun joku pyytää urlia, niin riski olisi, että Discourse floodattaisiin täyteen tuhansia ilmoituksia. Tuo estetään yksinkertaisella rate limiterillä. Kun ensimmäinen virhe tulee, niin sille näytetään oma virheilmoituksensa, ja laskuri lähtee päälle.
Laskuri on aikapohjainen, ja neljä tuntia. Sinä aina seuraaville virheen saaville näytetään hieman erilainen virhe. Siinä kerrotaan mm. että adminia on jo informoitu.
Miksikö neljä tuntia? Se on täysin keinotekoinen raja ja perustuu vain omiin jossitteluihin. Yleensä pääsen tuossa ajassa koneelleni ja saan korjattua tilanteen. Tai sitten saan emergendy-ratkaisut päälle, jotka ohittavat virhepaikan. Ja jos en saa korjausta neljässä tunnissa, niin ajan täyttyessä tulee taas yksi foorumi-ilmoitus. Se on hallittavissa.
Ei tuo ehkä tyylikkäin ratkaisu ole, mutta tuota kummallisempaan en kyennyt.
Kun backend on alhaalla, eli tulee 503, niin reitti on sama, mutta Varnish välittää tiedon Nginxille. Jos Varnish on alhaalla, ollaan 502-virheessä, ja Nginx ottaa heti ohjat.
Ohjeet on tehty siinä järjestyksessä kuin mitä itse tein. En ole sen kummemmin kommentteja enempää selittänyt mitä tapahtuu ja miksi, mutta ne ovat aika itseään selittäviä.
Oletus on, että keulilla reverse proxyna ja terminoimassa SSL:n on Nginx. Kaikki samat saa tehtyä Apachella, mutta en osaa sitä. Sen jälkeen toisena reverse proxyna hoitamassa cachen (ja muita kikkoja) on Varnish. Backend on Apache2, joka hoitaa WordPress-sivustoja, mutta sehän ei ole tässä merkityksellistä. Ja foorumi on Discourse.
Jos kopioit tämän, niin toinen oletus on, että tiedät mitä teet. Kolmas oletus on, että itse kannat vastuun tekemisistäsi.
Varnish: vcl_backend_error ja vcl_synth
Lisää default.vcl
tai vastaavaan:
sub vcl_backend_error {
## Yritetään kerran uudelleen, jos tämä on ensimmäinen virhe
if (bereq.retries < 1) {
return(retry);
}
# Jos cachessä on grace-objekti käytettävissä, käytetään se
return(deliver);
# Mikään ei toimi, joten backend on alhaalla, 503
return(fail);
}
- ainoastaan
return(fail);
on oleellinen itse virheelle. Muut kohdat olivat jo entisestään. Mutta kun request ei osu kumpaankaan, niin se tarkoittaafail
ja se tulee vain backendin ollessa pois kuvioista ja Varnish antaa automaattisesti 503.
sub vcl_synth {
if (resp.status == 503) {
set resp.status = 503;
set resp.http.Content-Type = "text/html; charset=utf-8";
set resp.http.X-Varnish-XID = req.xid;
synthetic({""}); // Tyhjä, koska Nginx tekee sisällön
return (deliver);
}
}
Flaskin scripti Discourselle
Flask on erittäin kevyt serveri/palvelu, joka vahtii ja logittaa minulla sivustojen CSP-raportit. Joten yksinkertaisuuden nimissä käytin sitä.
Google kertoo miten saat Flaskin asennettua.
Scriptille tarvitaan hakemisto:
mkdir /opt/error_reporter
nano /opt/error_reporter/error_reporter.py
Kopioi tämä:
- muista laittaa Discoursen tiedot; huomaa API-käyttäjä, sen saa vaihtaa
chmod +x
tekee siitä suoritettavan- tee touchilla tarvittava log
error-reporter.service
Tehdään scriptistä systemd
.
nano /etc/systemd/system/error-reporter.service
Lisää tämä:
[Unit]
Description=Flask-based Error Reporter to Discourse
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/error_reporter
ExecStart=/usr/bin/python3 /opt/error_reporter/error_reporter.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
Ja sitten:
# Oletetaan että Flask on jo asennettu
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable --now error-reporter.service
Nginxin kutsu
Flask saa tiedon Nginxin virhesivujen kautta, jotka kerrotaan hostin conffissa. Lisää tämä server-lohkoon:
location @report_502 {
internal;
rewrite ^ /report/502 break;
proxy_pass http://127.0.0.1:5060;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header X-Error-Token "salainen-arvo-123";
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
location @report_503 {
internal;
rewrite ^ /report/504 break;
proxy_pass http://127.0.0.1:5060;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header X-Error-Token "salainen-arvo-123";
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
Tämä lisätään lohkoon location /
muiden proxy-määrittelyjen joukkoon:
proxy_intercept_errors on;
error_page 502 = @report_502;
error_page 503 = @report_503;
Sama rakenne täytyy toistaa kaikille halutuille erroreille. Tämä esimerkki on virheille 502 (Varnish on nurin) ja 503 (Apache2 ei vastaa).
- vaihda oikea token
- kävijälle ei näytettä
error_reporter.py
kautta minkäänlaista virhekoodia, jolloin hän ei näe mikä on aito virhetilanne. Onko tuolla merkitystä? Ei suuremmin, eikä vierailija edes tarvitse tietoa aidosta virheestä.
Testaus
Nopeimmin saat testattua sammuttamalla ensin backendin ja yrittämällä, joko curlilla tai suoraan selaimesta, sellaista urlia, joka ei ole cachessa. Jos sisältä haetaan cachesta, niin mikään ei anna virhettä 503 — eikä käyttäjän suhteen tarvitakaan, koska heillehän kaikki toimii. Admin jää tietysti ilman virhettä siihen asti, että joku hakee neitseellistä osoitetta. Joka, kiitos bottien, tapahtui aika nopeasti.
502-virheen testaamiseen riittää Varnishin pysäyttäminen. Ilmoituksen pitäisi tulla Discourseen melkoisen nopeasti.
Keskustele foorumilla Katiskan foorumi