Praktyske tapassing fan ELK. It ynstellen fan logstash

Ynlieding

By it ynsetten fan in oar systeem, waarden wy konfrontearre mei de needsaak om in grut oantal ferskillende logs te ferwurkjen. ELK waard keazen as it ark. Dit artikel sil ús ûnderfining besprekke by it ynstellen fan dizze stapel.

Wy sette gjin doel om al syn mooglikheden te beskriuwen, mar wy wolle ús spesifyk konsintrearje op it oplossen fan praktyske problemen. Dit komt troch it feit dat ek al is der in frij grutte hoemannichte dokumintaasje en klearmakke bylden, der binne nochal in soad falkûlen, teminsten wy fûnen se.

Wy hawwe de stapel ynset fia docker-compose. Boppedat hienen wy in goed skreaune docker-compose.yml, wêrtroch't wy de steapel hast sûnder problemen koenen ferheegje. En it like ús ta dat de oerwinning al ticht wie, no sille wy it in bytsje oanpasse oan ús behoeften en dat is it.

Spitigernôch wie it besykjen om it systeem te konfigurearjen om logs fan ús applikaasje te ûntfangen en te ferwurkjen net daliks suksesfol. Dêrom hawwe wy besletten dat it de muoite wurdich wie om elke komponint apart te studearjen, en dan werom te gean nei har ferbiningen.

Dus, wy begûnen mei logstash.

Miljeu, ynset, it útfieren fan Logstash yn in kontener

Foar ynset brûke wy docker-compose de hjir beskreaune eksperiminten waarden útfierd op MacOS en Ubuntu 18.0.4.

De logstash-ôfbylding dy't waard registrearre yn ús oarspronklike docker-compose.yml is docker.elastic.co/logstash/logstash:6.3.2

Wy sille it brûke foar eksperiminten.

Wy hawwe in aparte docker-compose.yml skreaun om logstash út te fieren. Fansels wie it mooglik om de ôfbylding fan 'e kommandorigel te starten, mar wy hawwe in spesifyk probleem oplost, wêr't wy alles útfiere fan docker-compose.

Koart oer konfiguraasjebestannen

As folget út 'e beskriuwing kin logstash wurde útfierd foar ien kanaal, yn dat gefal moat it it *.conf-bestân trochjaan, of foar ferskate kanalen, yn dat gefal moat it de pipelines.yml-bestân trochjaan, dy't op syn beurt , sil keppelje nei de triemmen .conf foar elk kanaal.
Wy namen it twadde paad. It like ús mear universeel en skalberber. Dêrom, wy makke pipelines.yml, en makke in pipelines triemtafel dêr't wy sille sette .conf triemmen foar elk kanaal.

Binnen de kontener is der in oare konfiguraasjetriem - logstash.yml. Wy reitsje it net oan, wy brûke it sa't it is.

Dat, ús mapstruktuer:

Praktyske tapassing fan ELK. It ynstellen fan logstash

Om ynfiergegevens te ûntfangen, geane wy ​​der no fan út dat dit tcp is op poarte 5046, en foar útfier sille wy stdout brûke.

Hjir is in ienfâldige konfiguraasje foar de earste lansearring. Om't de earste taak is om te lansearjen.

Dat, wy hawwe dizze 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

Wat sjogge wy hjir?

  1. Netwurken en folumes waarden nommen fan 'e orizjinele docker-compose.yml (dejinge wêr't de heule stapel wurdt lansearre) en ik tink dat se hjir net in protte ynfloed hawwe op it totale byld.
  2. Wy meitsje ien logstash tsjinst(en) út de docker.elastic.co/logstash/logstash:6.3.2 ôfbylding en neame it logstash_one_channel.
  3. Wy foarút poarte 5046 binnen de kontener, nei deselde ynterne haven.
  4. Wy map ús pipe konfiguraasje triem ./config/pipelines.yml oan de triem /usr/share/logstash/config/pipelines.yml binnen de kontener, dêr't logstash sil ophelje en meitsje it allinnich-lês, foar it gefal.
  5. Wy mapje de map ./config/pipelines, wêr't wy bestannen hawwe mei kanaalynstellingen, yn 'e map /usr/share/logstash/config/pipelines en meitsje it ek allinich lêzen.

Praktyske tapassing fan ELK. It ynstellen fan logstash

Pipelines.yml triem

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

Ien kanaal mei de HABR-identifikaasje en it paad nei syn konfiguraasjetriem wurde hjir beskreaun.

En as lêste it bestân "./config/pipelines/habr_pipeline.conf"

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

Litte wy no net yngean op syn beskriuwing, litte wy besykje it út te fieren:

docker-compose up

Wat sjogge wy?

De kontener is begûn. Wy kinne har wurking kontrolearje:

echo '13123123123123123123123213123213' | nc localhost 5046

En wy sjogge it antwurd yn 'e kontenerkonsole:

Praktyske tapassing fan ELK. It ynstellen fan logstash

Mar tagelyk sjogge wy ek:

logstash_one_channel | [2019-04-29T11:28:59,790][ERROR][logstash.licensechecker.licensereader] Kin lisinsje-ynformaasje net ophelje fan lisinsjetsjinner {:message=>“Elasticsearch net te berikken: [http://elasticsearch:9200/][Manticore ::ResolutionFailure] elasticsearch", ...

logstash_one_channel | [2019-04-29T11:28:59,894][INFO ][logstash.pipeline ] Pipeline is mei súkses begûn {:pipeline_id=>".monitoring-logstash", :thread=>"# "}

logstash_one_channel | [2019-04-29T11:28:59,988][INFO ][logstash.agent ] Pipelines rinnen {:count=>2, :running_pipelines=>[:HABR, :".monitoring-logstash"], :non_running_pipelines=>[ ]}
logstash_one_channel | [2019-04-29T11:29:00,015][ERROR][logstash.inputs.metrics] X-Pack is ynstalleare op Logstash mar net op Elasticsearch. Ynstallearje asjebleaft X-Pack op Elasticsearch om de tafersjochfunksje te brûken. Oare funksjes kinne beskikber wêze.
logstash_one_channel | [2019-04-29T11:29:00,526][INFO ][logstash.agent ] Logstash API einpunt {:port=>9600} mei súkses begûn
logstash_one_channel | [2019-04-29T11:29:04,478][INFO ][logstash.outputs.elasticsearch] Sûnenskontrôle útfiere om te sjen oft in Elasticsearch-ferbining wurket {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_one_channel | [2019-04-29T11:29:04,487][WARN ][logstash.outputs.elasticsearch] Besocht de ferbining mei deade ES-eksimplaar opnij te meitsjen, mar krige in flater. {:url=>“elastyk sykje:9200/", :error_type=>LogStash::Outputs::ElasticSearch::HttpClient::Pool::HostUnreachableError, :error=>"Elasticsearch Unreachable: [http://elasticsearch:9200/][Manticore::ResolutionFailure] elasticsearch"}
logstash_one_channel | [2019-04-29T11:29:04,704][INFO ][logstash.licensechecker.licensereader] Sûnenskontrôle útfiere om te sjen oft in Elasticsearch-ferbining wurket {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_one_channel | [2019-04-29T11:29:04,710][WARN ][logstash.licensechecker.licensereader] Besocht de ferbining mei deade ES-eksimplaar opnij te meitsjen, mar krige in flater. {:url=>“elastyk sykje:9200/", :error_type=>LogStash::Outputs::ElasticSearch::HttpClient::Pool::HostUnreachableError, :error=>"Elasticsearch Unreachable: [http://elasticsearch:9200/][Manticore::ResolutionFailure] elasticsearch"}

En ús log krûpt de hiele tiid omheech.

Hjir haw ik it berjocht yn grien markearre dat de pipeline mei súkses lansearre is, yn read it flaterberjocht en yn giel it berjocht oer in besykjen om kontakt te meitsjen elastyk sykje: 9200.
Dit bart om't logstash.conf, opnommen yn 'e ôfbylding, in kontrôle befettet foar beskikberens fan elasticsearch. Ommers, logstash giet derfan út dat it wurket as ûnderdiel fan de Elk stack, mar wy skieden it.

It is mooglik om te wurkjen, mar it is net handich.

De oplossing is om dizze kontrôle út te skeakeljen fia de omjouwingsfariabele XPACK_MONITORING_ENABLED.

Litte wy in feroaring meitsje yn docker-compose.yml en it opnij útfiere:

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

No, alles is goed. De kontener is klear foar eksperiminten.

Wy kinne opnij ynfiere yn 'e folgjende konsole:

echo '13123123123123123123123213123213' | nc localhost 5046

En sjoch:

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 | }

Wurkje binnen ien kanaal

Sa hawwe wy lansearre. No kinne jo eins de tiid nimme om logstash sels te konfigurearjen. Litte wy it pipelines.yml-bestân foar no net oanreitsje, lit ús sjen wat wy kinne krije troch te wurkjen mei ien kanaal.

Ik moat sizze dat it algemiene prinsipe fan wurkjen mei it kanaalkonfiguraasjetriem goed beskreaun is yn 'e offisjele hantlieding, hjir hjir
As jo ​​​​yn it Russysk wolle lêze, hawwe wy dizze brûkt lidwurd(mar de query syntaksis dêr is âld, wy moatte nimme dit rekken).

Litte wy sequentially gean fan 'e Ynput seksje. Wy hawwe al wurk sjoen op tcp. Wat oars kin wêze nijsgjirrich hjir?

Test berjochten mei help fan hertslach

D'r is sa'n nijsgjirrige kâns om automatyske testberjochten te generearjen.
Om dit te dwaan, moatte jo it heartbean-plugin ynskeakelje yn 'e ynfier seksje.

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

Skeakelje it oan, begjin ien kear yn 'e minút te ûntfangen

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 | }

As wy faker wolle ûntfange, moatte wy de yntervalparameter tafoegje.
Dit is hoe't wy elke 10 sekonden in berjocht krije.

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

It opheljen fan gegevens út in triem

Wy hawwe ek besletten om te sjen nei de triemmodus. As it goed wurket mei it bestân, dan is miskien gjin agent nedich, teminsten foar lokaal gebrûk.

Neffens de beskriuwing moat de bestjoeringsmodus fergelykber wêze mei sturt -f, d.w.s. lêst nije rigels of, as opsje, lêst it hiele bestân.

Dus wat wy wolle krije:

  1. Wy wolle ûntfange rigels dy't wurde taheakke oan ien log triem.
  2. Wy wolle ûntfange gegevens dy't wurdt skreaun nei ferskate log triemmen, wylst kinne skieden wat wurdt ûntfongen fan wêr.
  3. Wy wolle der wis fan wêze dat as logstash opnij starte, it dizze gegevens net wer ûntfangt.
  4. Wy wolle kontrolearje dat as logstash útskeakele is, en gegevens wurde skreaun nei bestannen, dan as wy it útfiere, sille wy dizze gegevens ûntfange.

Om it eksperimint út te fieren, litte wy in oare rigel tafoegje oan docker-compose.yml, iepenje de map wêryn wy de bestannen pleatse.

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

En feroarje de ynfier seksje yn habr_pipeline.conf

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

Litte wy begjinne:

docker-compose up

Om logbestannen te meitsjen en te skriuwen sille wy it kommando brûke:


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 | }

Ja, it wurket!

Tagelyk sjogge wy dat wy it paadfjild automatysk tafoege hawwe. Dit betsjut dat wy yn 'e takomst records dêrop kinne filterje.

Noch in kear besykje:

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 | }

En no nei in oar bestân:

 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 | }

Grut! De triem is ophelle, it paad is korrekt oantsjutte, alles is goed.

Stopje logstash en begjin opnij. Litte we wachtsje. Stilte. Dy. Wy krije dizze records net wer.

En no it meast dryste eksperimint.

Ynstallearje logstash en útfiere:

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

Run logstash wer en sjoch:

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 | }

Hoera! Alles waard oppakt.

Mar wy moatte jo warskôgje oer it folgjende. As de logstash-kontener is wiske (docker stop logstash_one_channel && docker rm logstash_one_channel), dan sil neat wurde ophelle. De posysje fan it bestân dêr't it waard lêzen waard opslein yn 'e kontener. As jo ​​rinne it út scratch, it sil allinne akseptearje nije rigels.

It lêzen fan besteande triemmen

Litte wy sizze dat wy logstash foar it earst lansearje, mar wy hawwe al logs en wy wolle se ferwurkje.
As wy logstash útfiere mei de ynfierseksje dy't wy hjirboppe brûkten, sille wy neat krije. Allinich nije rigels sille wurde ferwurke troch logstash.

Om rigels út besteande bestannen op te heljen, moatte jo in ekstra rigel tafoegje oan 'e ynfierseksje:

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

Boppedat is der in nuânse: dit hat allinich ynfloed op nije bestannen dy't logstash noch net sjoen hat. Foar deselde bestannen dy't al yn it sichtfjild fan logstash wiene, hat it har grutte al ûnthâlden en sil no allinich nije yngongen yn nimme.

Litte wy hjir stopje en de ynputseksje bestudearje. Der binne noch in protte opsjes, mar dat is genôch foar ús foar fierdere eksperiminten foar no.

Routing en gegevenstransformaasje

Litte wy besykje it folgjende probleem op te lossen, lit ús sizze dat wy berjochten hawwe fan ien kanaal, guon fan harren binne ynformatyf, en guon binne flaterberjochten. Se ferskille per tag. Guon binne INFO, oaren binne ERROR.

Wy moatte se skiede by de útgong. Dy. Wy skriuwe ynformaasje berjochten yn ien kanaal, en flater berjochten yn in oar.

Om dit te dwaan, ferpleatse fan 'e ynfier seksje nei filter en útfier.

Mei it brûken fan de filterseksje sille wy it ynkommende berjocht parse, en derfan krije in hash (kaai-wearde-pearen), dêr't wy al mei wurkje kinne, d.w.s. disassemble neffens betingsten. En yn 'e útfier seksje sille wy berjochten selektearje en elk nei syn eigen kanaal stjoere.

Parsing in berjocht mei grok

Om tekststrings te parsearjen en in set fjilden fan har te krijen, is d'r in spesjale plugin yn 'e filterseksje - grok.

Sûnder mysels it doel te stellen om hjir in detaillearre beskriuwing fan te jaan (hierfoar ferwize ik offisjele dokumintaasje), Ik jou myn ienfâldige foarbyld.

Om dit te dwaan, moatte jo beslute oer it formaat fan 'e ynfierstrings. Ik haw se sa:

1 INFO berjocht1
2 FOUT berjocht 2

Dy. De identifier komt earst, dan INFO/ERROR, dan wat wurd sûnder spaasjes.
It is net dreech, mar it is genôch om it prinsipe fan wurking te begripen.

Dat, yn 'e filterseksje fan' e grok-plugin, moatte wy in patroan definiearje foar it parsearjen fan ús snaren.

It sil der sa útsjen:

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

Yn essinsje is it in reguliere útdrukking. Der wurde klear makke patroanen brûkt, lykas INT, LOGLEVEL, WORD. Har beskriuwing, lykas oare patroanen, kinne jo hjir fine hjir

No, troch dit filter troch te gean, sil ús tekenrige feroarje yn in hash fan trije fjilden: message_id, message_type, message_text.

Se sille wurde werjûn yn de útfier seksje.

Routing fan berjochten nei de útfierseksje mei it kommando if

Yn 'e útfierseksje soene wy, sa't wy ús ûnthâlde, de berjochten splitse yn twa streamen. Guon - dy't iNFO binne, sille wurde útfierd nei de konsole, en mei flaters sille wy útfiere nei in bestân.

Hoe skiede wy dizze berjochten? De betingst fan it probleem suggerearret al in oplossing - ommers, wy hawwe al in tawijd message_type fjild, dat kin allinnich nimme twa wearden: INFO en ERROR. It is op dizze basis dat wy in kar meitsje mei de if-statement.

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

In beskriuwing fan wurkjen mei fjilden en operators is te finen yn dizze seksje offisjele hânlieding.

No, oer de eigentlike konklúzje sels.

Konsolútfier, alles is hjir dúdlik - stdout {}

Mar de útfier nei in bestân - tink derom dat wy dit alles útfiere fan in kontener en om it bestân wêryn wy it resultaat skriuwe fan bûten tagonklik te meitsjen, moatte wy dizze map iepenje yn docker-compose.yml.

Totaal:

De útfierseksje fan ús bestân sjocht der sa út:


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

Yn docker-compose.yml foegje wy in oar folume ta foar útfier:

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

Wy lansearje it, besykje it, en sjogge in ferdieling yn twa streamen.

Boarne: www.habr.com

Add a comment