ELK:n käytännön sovellus. Asetetaan logstash

Esittely

Toisen järjestelmän käyttöönoton yhteydessä jouduimme käsittelemään suuren määrän erilaisia ​​lokeja. Soittimeksi valittiin ELK. Tässä artikkelissa kerrotaan kokemuksistamme tämän pinon luomisesta.

Emme aseta tavoitteeksi kuvailla sen kaikkia ominaisuuksia, vaan haluamme keskittyä käytännön ongelmien ratkaisemiseen. Tämä johtuu siitä, että riittävän suurella dokumentaatiomäärällä ja valmiilla kuvilla on paljon sudenkuoppia, ainakin me löysimme ne.

Otimme pinon käyttöön docker-composen kautta. Lisäksi meillä oli hyvin kirjoitettu docker-compose.yml, jonka avulla pystyimme nostamaan pinoa lähes ilman ongelmia. Ja meistä näytti siltä, ​​että voitto oli jo lähellä, nyt väännetään sitä hieman tarpeidemme mukaan ja siinä se.

Valitettavasti yritys virittää järjestelmä vastaanottamaan ja käsittelemään lokeja sovelluksestamme ei onnistunut heti. Siksi päätimme, että jokaista komponenttia kannattaa tutkia erikseen ja palata sitten niiden yhteyksiin.

Joten aloitetaan logstashista.

Ympäristö, käyttöönotto, Logstashin käyttö kontissa

Käyttöönottoa varten käytämme docker-composea, tässä kuvatut kokeet suoritettiin MacOS- ja Ubuntu 18.0.4 -käyttöjärjestelmillä.

Alkuperäisessä docker-compose.yml-tiedostossamme oleva logstash-kuva on docker.elastic.co/logstash/logstash:6.3.2

Käytämme sitä kokeiluihin.

Logstashin suorittamiseksi kirjoitimme erillisen docker-compose.yml-tiedoston. Tietysti kuva oli mahdollista käynnistää komentoriviltä, ​​mutta loppujen lopuksi ratkaisimme tietyn tehtävän, jossa kaikki docker-composesta käynnistetään puolestamme.

Lyhyesti asetustiedostoista

Kuten kuvauksesta seuraa, logstash voidaan ajaa yhdelle kanavalle, tässä tapauksessa sen täytyy siirtää *.conf-tiedosto tai useille kanaville, jolloin sen on siirrettävä pipelines.yml-tiedosto, joka puolestaan , viittaa kunkin kanavan tiedostoihin .conf.
Valitsimme toisen tien. Se vaikutti meistä monipuolisemmalta ja skaalautuvammalta. Siksi loimme pipelines.yml:n ja teimme pipelines-hakemiston, johon laitamme .conf-tiedostot jokaiselle kanavalle.

Säilön sisällä on toinen asetustiedosto - logstash.yml. Emme koske siihen, käytämme sitä sellaisenaan.

Joten hakemistorakennemme on:

ELK:n käytännön sovellus. Asetetaan logstash

Toistaiseksi oletetaan, että tämä on tcp portissa 5046 tulotietojen vastaanottamiseksi, ja käytämme stdout-lähtöä.

Tässä on niin yksinkertainen kokoonpano ensimmäistä kertaa. Koska ensimmäinen tehtävä on käynnistää.

Joten meillä on tämä docker-compose.yml

version: '3'

networks:
  elk:

volumes:
  elasticsearch:
    driver: local

services:

  logstash:
    container_name: logstash_one_channel
    image: docker.elastic.co/logstash/logstash:6.3.2
    networks:
      	- elk
    ports:
      	- 5046:5046
    volumes:
      	- ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
	- ./config/pipelines:/usr/share/logstash/config/pipelines:ro

Mitä me täällä näemme?

  1. Verkot ja volyymit on otettu alkuperäisestä docker-compose.yml-tiedostosta (se, jossa koko pino käynnistetään) eivätkä ne mielestäni vaikuta paljoakaan kokonaiskuvaan tässä.
  2. Luomme yhden palvelun (palvelut) logstash-kuvasta docker.elastic.co/logstash/logstash:6.3.2 ja annamme sille nimen logstash_one_channel.
  3. Välitämme portin 5046 kontin sisällä samaan sisäiseen porttiin.
  4. Yhdistämme ./config/pipelines.yml putken määritystiedostomme säilön sisällä olevaan /usr/share/logstash/config/pipelines.yml-tiedostoon, josta logstash poimii sen ja tekee siitä vain luku -muotoisen varmuuden vuoksi.
  5. Yhdistämme ./config/pipelines-hakemiston, jossa meillä on putken asetustiedostot, hakemistoon /usr/share/logstash/config/pipelines ja teemme siitä myös vain luku -muotoisen.

ELK:n käytännön sovellus. Asetetaan logstash

piping.yml-tiedosto

- pipeline.id: HABR
  pipeline.workers: 1
  pipeline.batch.size: 1
  path.config: "./config/pipelines/habr_pipeline.conf"

Se kuvaa yhtä kanavaa HABR-tunnisteella ja polun sen asetustiedostoon.

Ja lopuksi tiedosto "./config/pipelines/habr_pipeline.conf"

input {
  tcp {
    port => "5046"
   }
  }
filter {
  mutate {
    add_field => [ "habra_field", "Hello Habr" ]
    }
  }
output {
  stdout {
      
    }
  }

Emme mene sen kuvaukseen toistaiseksi, yritämme ajaa:

docker-compose up

Mitä me näemme?

Kontti on käynnistynyt. Voimme tarkistaa sen toiminnan:

echo '13123123123123123123123213123213' | nc localhost 5046

Ja näemme vastauksen säilökonsolissa:

ELK:n käytännön sovellus. Asetetaan logstash

Mutta samalla näemme myös:

logstash_one_channel | [2019-04-29T11:28:59,790][VIRHE][logstash.licensechecker.licensereader] Lisenssitietoja ei voi noutaa lisenssipalvelimelta {:message=>"Elasticsearch ei tavoitettavissa: [http://elasticsearch:9200/][Manticore" ::ResolutionFailure]elasticsearch", ...

logstash_one_channel | [2019-04-29T11:28:59,894][INFO ][logstash.pipeline ] Putkilinja käynnistyi onnistuneesti {:pipeline_id=>".monitoring-logstash", :thread=>"# »}

logstash_one_channel | [2019-04-29T11:28:59,988][INFO ][logstash.agent ] Liukulinjat käynnissä {:count=>2, :running_pipelines=>[:HABR, :".monitoring-logstash"], :non_running_pipelines=>[ ]}
logstash_one_channel | [2019-04-29T11:29:00,015][VIRHE][logstash.inputs.metrics ] X-Pack on asennettu Logstashiin, mutta ei Elasticsearchiin. Asenna X-Pack Elasticsearchiin käyttääksesi valvontaominaisuutta. Muita ominaisuuksia voi olla saatavilla.
logstash_one_channel | [2019-04-29T11:29:00,526][INFO ][logstash.agent ] Logstash API -päätepiste {:port=>9600} aloitettu onnistuneesti
logstash_one_channel | [2019-04-29T11:29:04,478][INFO ][logstash.outputs.elasticsearch] Suoritetaan kuntotarkastusta tarkistaaksesi, toimiiko Elasticsearch-yhteys {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_one_channel | [2019-04-29T11:29:04,487][VAROITUS ][logstash.outputs.elasticsearch] Yritettiin palauttaa yhteys kuolleeseen ES-instanssiin, mutta siinä tuli virhe. {:url=>"elasticsearch:9200/" elasticsearch"}
logstash_one_channel | [2019-04-29T11:29:04,704][INFO ][logstash.licensechecker.licensereader] Suoritetaan kuntotarkastusta tarkistaaksesi, toimiiko Elasticsearch-yhteys {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_one_channel | [2019-04-29T11:29:04,710][VAROITUS ][logstash.licensechecker.licensereader] Yritettiin palauttaa yhteys kuolleeseen ES-instanssiin, mutta siinä ilmeni virhe. {:url=>"elasticsearch:9200/" elasticsearch"}

Ja lokimme ryömii ylös koko ajan.

Tässä korostin vihreällä viestin, että liukuhihna käynnistyi onnistuneesti, punaisella virheilmoituksen ja keltaisella viestin yhteydenottoyrityksestä elasticsearch: 9200.
Tämä johtuu siitä, että kuvan sisältämässä logstash.conf-tiedostossa on tarkistus elasticsearchin saatavuudesta. Loppujen lopuksi logstash olettaa, että se toimii osana Elk-pinoa, ja erotimme sen.

Voit tehdä töitä, mutta se ei ole kätevää.

Ratkaisu on poistaa tämä tarkistus käytöstä ympäristömuuttujan XPACK_MONITORING_ENABLED kautta.

Tehdään muutos tiedostoon docker-compose.yml ja suoritetaan se uudelleen:

version: '3'

networks:
  elk:

volumes:
  elasticsearch:
    driver: local

services:

  logstash:
    container_name: logstash_one_channel
    image: docker.elastic.co/logstash/logstash:6.3.2
    networks:
      - elk
    environment:
      XPACK_MONITORING_ENABLED: "false"
    ports:
      - 5046:5046
   volumes:
      - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
      - ./config/pipelines:/usr/share/logstash/config/pipelines:ro

Nyt kaikki on hyvin. Säiliö on valmis kokeita varten.

Voimme kirjoittaa uudelleen viereiseen konsoliin:

echo '13123123123123123123123213123213' | nc localhost 5046

Ja nähdä:

logstash_one_channel | {
logstash_one_channel |         "message" => "13123123123123123123123213123213",
logstash_one_channel |      "@timestamp" => 2019-04-29T11:43:44.582Z,
logstash_one_channel |        "@version" => "1",
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |            "host" => "gateway",
logstash_one_channel |            "port" => 49418
logstash_one_channel | }

Työskentele yhden kanavan sisällä

Joten aloitimme. Nyt voit itse asiassa käyttää aikaa logstashin määrittämiseen suoraan. Älkäämme koskeko pipelines.yml-tiedostoon toistaiseksi, katsotaan mitä voimme saada työskentelemällä yhden kanavan kanssa.

Minun on sanottava, että kanavan määritystiedoston kanssa työskentelyn yleinen periaate on kuvattu hyvin täällä virallisessa ohjekirjassa täällä
Jos haluat lukea venäjäksi, käytimme tätä artikla(mutta kyselyn syntaksi on vanha, sinun on otettava tämä huomioon).

Siirrytään peräkkäin Input-osiosta. Olemme jo nähneet tcp:n työn. Mitä muuta mielenkiintoista tässä voi olla?

Testaa viestejä sydämenlyönnillä

On niin mielenkiintoinen mahdollisuus luoda automaattisia testiviestejä.
Tätä varten sinun on sisällytettävä heartbean-laajennus syöttöosioon.

input {
  heartbeat {
    message => "HeartBeat!"
   }
  } 

Laitamme sen päälle, alamme vastaanottaa kerran minuutissa

logstash_one_channel | {
logstash_one_channel |      "@timestamp" => 2019-04-29T13:52:04.567Z,
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |         "message" => "HeartBeat!",
logstash_one_channel |        "@version" => "1",
logstash_one_channel |            "host" => "a0667e5c57ec"
logstash_one_channel | }

Haluamme saada useammin, meidän on lisättävä intervalliparametri.
Näin saamme viestin 10 sekunnin välein.

input {
  heartbeat {
    message => "HeartBeat!"
    interval => 10
   }
  }

Tietojen hakeminen tiedostosta

Päätimme myös tarkastella tiedostotilaa. Jos se toimii hyvin tiedoston kanssa, on mahdollista, että agenttia ei tarvita, ainakin paikalliseen käyttöön.

Kuvauksen mukaan toimintatavan tulee olla samanlainen kuin tail -f, ts. lukee rivinvaihdot tai valinnaisesti koko tiedoston.

Joten mitä haluamme saada:

  1. Haluamme vastaanottaa rivit, jotka on liitetty yhteen lokitiedostoon.
  2. Haluamme vastaanottaa tietoja, jotka on kirjoitettu useisiin lokitiedostoihin, samalla kun pystymme erottamaan sen, mitä vastaanotettiin mistä.
  3. Haluamme varmistaa, että kun logstash käynnistetään uudelleen, se ei vastaanota näitä tietoja uudelleen.
  4. Haluamme tarkistaa, että jos logstash on poistettu käytöstä ja tietojen kirjoittaminen tiedostoihin jatkuu, saamme nämä tiedot, kun suoritamme sen.

Kokeilun suorittamiseksi lisätään vielä yksi rivi docker-compose.yml-tiedostoon ja avataan hakemisto, johon tiedostot asetetaan.

version: '3'

networks:
  elk:

volumes:
  elasticsearch:
    driver: local

services:

  logstash:
    container_name: logstash_one_channel
    image: docker.elastic.co/logstash/logstash:6.3.2
    networks:
      - elk
    environment:
      XPACK_MONITORING_ENABLED: "false"
    ports:
      - 5046:5046
   volumes:
      - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
      - ./config/pipelines:/usr/share/logstash/config/pipelines:ro
      - ./logs:/usr/share/logstash/input

Ja muuta habr_pipeline.conf-tiedoston syöttöosaa

input {
  file {
    path => "/usr/share/logstash/input/*.log"
   }
  }

Aloitamme:

docker-compose up

Lokitiedostojen luomiseen ja kirjoittamiseen käytämme komentoa:


echo '1' >> logs/number1.log

{
logstash_one_channel |            "host" => "ac2d4e3ef70f",
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |      "@timestamp" => 2019-04-29T14:28:53.876Z,
logstash_one_channel |        "@version" => "1",
logstash_one_channel |         "message" => "1",
logstash_one_channel |            "path" => "/usr/share/logstash/input/number1.log"
logstash_one_channel | }

Jep, se toimii!

Samalla näemme, että olemme lisänneet polkukentän automaattisesti. Joten tulevaisuudessa voimme suodattaa tietueita sen perusteella.

Yritetään uudestaan:

echo '2' >> logs/number1.log

{
logstash_one_channel |            "host" => "ac2d4e3ef70f",
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |      "@timestamp" => 2019-04-29T14:28:59.906Z,
logstash_one_channel |        "@version" => "1",
logstash_one_channel |         "message" => "2",
logstash_one_channel |            "path" => "/usr/share/logstash/input/number1.log"
logstash_one_channel | }

Ja nyt toiseen tiedostoon:

 echo '1' >> logs/number2.log

{
logstash_one_channel |            "host" => "ac2d4e3ef70f",
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |      "@timestamp" => 2019-04-29T14:29:26.061Z,
logstash_one_channel |        "@version" => "1",
logstash_one_channel |         "message" => "1",
logstash_one_channel |            "path" => "/usr/share/logstash/input/number2.log"
logstash_one_channel | }

Loistava! Tiedosto poimittiin, polku määritettiin oikein, kaikki on kunnossa.

Pysäytä logstash ja käynnistä uudelleen. Odotetaan. Hiljaisuus. Nuo. Emme saa näitä tietueita uudelleen.

Ja nyt rohkein kokeilu.

Laitamme logstash ja suoritamme:

echo '3' >> logs/number2.log
echo '4' >> logs/number1.log

Suorita logstash uudelleen ja katso:

logstash_one_channel | {
logstash_one_channel |            "host" => "ac2d4e3ef70f",
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |         "message" => "3",
logstash_one_channel |        "@version" => "1",
logstash_one_channel |            "path" => "/usr/share/logstash/input/number2.log",
logstash_one_channel |      "@timestamp" => 2019-04-29T14:48:50.589Z
logstash_one_channel | }
logstash_one_channel | {
logstash_one_channel |            "host" => "ac2d4e3ef70f",
logstash_one_channel |     "habra_field" => "Hello Habr",
logstash_one_channel |         "message" => "4",
logstash_one_channel |        "@version" => "1",
logstash_one_channel |            "path" => "/usr/share/logstash/input/number1.log",
logstash_one_channel |      "@timestamp" => 2019-04-29T14:48:50.856Z
logstash_one_channel | }

Hurraa! Kaikki nousi.

Mutta on tarpeen varoittaa seuraavista. Jos logstash-säilö poistetaan (docker stop logstash_one_channel && docker rm logstash_one_channel), mitään ei poimita. Tiedoston sijainti, johon asti se luettiin, tallennettiin säilön sisään. Jos aloitat tyhjästä, se hyväksyy vain uudet rivit.

Lukee olemassa olevia tiedostoja

Oletetaan, että käytämme logstashia ensimmäistä kertaa, mutta meillä on jo lokit ja haluaisimme käsitellä ne.
Jos suoritamme logstashin edellä käyttämämme syöttöosion kanssa, emme saa mitään. Logstash käsittelee vain rivinvaihdot.

Voit vetää rivejä olemassa olevista tiedostoista lisäämällä lisärivi syöttöosaan:

input {
  file {
    start_position => "beginning"
    path => "/usr/share/logstash/input/*.log"
   }
  }

Lisäksi on vivahde, tämä vaikuttaa vain uusiin tiedostoihin, joita logstash ei ole vielä nähnyt. Samojen tiedostojen osalta, jotka olivat jo logstash-näkymässä, se on jo muistanut niiden koon ja ottaa niistä nyt vain uudet tietueet.

Lopetetaan tämä tutkimalla syöttöosaa. Vaihtoehtoja on paljon, mutta toistaiseksi meillä on tarpeeksi lisäkokeita varten.

Reititys ja tiedon muuntaminen

Yritetään ratkaista seuraava ongelma, oletetaan, että meillä on viestejä yhdeltä kanavalta, joista osa on informatiivisia ja osa virheilmoituksia. Ne eroavat tunnisteittain. Jotkut ovat INFO, toiset ovat ERROR.

Meidän on erotettava ne uloskäynnissä. Nuo. Kirjoitamme tiedotusviestejä yhteen kanavaan ja virheilmoituksia toiseen.

Voit tehdä tämän siirtymällä tulo-osiosta suodattamaan ja tulostamaan.

Suodatinosion avulla jäsennämme saapuvan viestin ja saamme siitä hashin (avainarvoparit), jolla voimme jo työskennellä, ts. jäsentää ehtojen mukaan. Ja tulososiossa valitsemme viestit ja lähetämme kukin omalle kanavalleen.

Jäsentää viestiä grokin kanssa

Tekstimerkkijonojen jäsentämiseksi ja joukon kenttiä saamiseksi suodatinosassa on erityinen laajennus - grok.

Asettamatta itselleni tavoitteeksi antaa siitä yksityiskohtainen kuvaus täällä (tätä varten viittaan virallinen dokumentaatio), annan yksinkertaisen esimerkkini.

Tätä varten sinun on päätettävä syöttörivien muodosta. Minulla on ne tällaiset:

1 INFO-viesti1
2 VIRHEviesti2

Nuo. Ensin tunniste, sitten INFO/ERROR, sitten jokin sana ilman välilyöntejä.
Ei vaikeaa, mutta tarpeeksi ymmärtämään työn periaatteen.

Joten suodatinosiossa, grok-laajennuksessa, meidän on määritettävä malli merkkijonojemme jäsentämiseksi.

Se näyttää tältä:

filter {
  grok {
    match => { "message" => ["%{INT:message_id} %{LOGLEVEL:message_type} %{WORD:message_text}"] }
   }
  } 

Periaatteessa se on säännöllinen lauseke. Käytetään valmiita kuvioita, kuten INT, LOGLEVEL, WORD. Niiden kuvaus ja muut mallit ovat nähtävissä täällä. täällä

Nyt tämän suodattimen läpi kulkeva merkkijonomme muuttuu kolmen kentän tiivisteeksi: message_id, message_type, message_text.

Ne näkyvät tulosteosiossa.

Viestien reitittäminen tulososassa if-komennolla

Tulososiossa, kuten muistamme, aioimme jakaa viestit kahteen virtaan. Jotkut - jotka ovat iNFO, tuotamme konsoliin, ja virheiden yhteydessä tuotamme tiedostoon.

Kuinka voimme jakaa näitä viestejä? Ongelman tila ehdottaa jo ratkaisua - meillähän on jo oma message_type -kenttä, joka voi ottaa vain kaksi arvoa INFO ja ERROR. Sen perusteella teemme valinnan if-lauseen avulla.

if [message_type] == "ERROR" {
        # Здесь выводим в файл
       } else
     {
      # Здесь выводим в stdout
    }

Kuvaus työstä kenttien ja operaattoreiden kanssa löytyy tästä osiosta virallinen käsikirja.

Nyt itse johtopäätöksestä.

Konsolin lähtö, kaikki on selvää täällä - stdout {}

Mutta tulos tiedostoon - muista, että käytämme tätä kaikkea säilöstä ja jotta tiedosto, johon kirjoitamme tuloksen, on käytettävissä ulkopuolelta, meidän on avattava tämä hakemisto docker-compose.yml:ssä.

Yhteensä:

Tiedostomme tulososio näyttää tältä:


output {
  if [message_type] == "ERROR" {
    file {
          path => "/usr/share/logstash/output/test.log"
          codec => line { format => "custom format: %{message}"}
         }
    } else
     {stdout {
             }
     }
  }

Lisää yksi taltio docker-compose.yml-tiedostoon tulostusta varten:

version: '3'

networks:
  elk:

volumes:
  elasticsearch:
    driver: local

services:

  logstash:
    container_name: logstash_one_channel
    image: docker.elastic.co/logstash/logstash:6.3.2
    networks:
      - elk
    environment:
      XPACK_MONITORING_ENABLED: "false"
    ports:
      - 5046:5046
   volumes:
      - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
      - ./config/pipelines:/usr/share/logstash/config/pipelines:ro
      - ./logs:/usr/share/logstash/input
      - ./output:/usr/share/logstash/output

Aloitamme, yritämme, näemme jakautumisen kahteen virtaan.

Lähde: will.com

Lisää kommentti