Praktika aplikado de ELK. Agordante logstash

Enkonduko

Dum deplojado de alia sistemo, ni alfrontis la bezonon prilabori grandan nombron da diversaj protokoloj. ELK estis elektita kiel la instrumento. Ĉi tiu artikolo parolos pri nia sperto pri agordo de ĉi tiu stako.

Ni ne metas celon priskribi ĉiujn ĝiajn kapablojn, sed ni volas koncentriĝi pri solvado de praktikaj problemoj. Ĉi tio estas pro tio, ke kun sufiĉe granda kvanto da dokumentado kaj pretaj bildoj, estas multaj faŭltoj, almenaŭ ni trovis ilin.

Ni deplojis la stakon per docker-compose. Plie, ni havis bone verkitan docker-compose.yml, kiu permesis al ni levi la stakon preskaŭ sen problemoj. Kaj ŝajnis al ni, ke venko jam estis proksima, nun ni iomete tordos ĝin por konveni niajn bezonojn kaj jen.

Bedaŭrinde, provo agordi la sistemon por ricevi kaj prilabori protokolojn de nia aplikaĵo tuj ne sukcesis. Tial ni decidis, ke indas studi ĉiun komponanton aparte, kaj poste reveni al iliaj rilatoj.

Do ni komencu per logstash.

Medio, deplojo, kurante Logstash en ujo

Por deplojo, ni uzas docker-compose, la eksperimentoj priskribitaj ĉi tie estis faritaj sur MacOS kaj Ubuntu 18.0.4.

La logstash-bildo, kiun ni havis en nia originala docker-compose.yml, estas docker.elastic.co/logstash/logstash:6.3.2

Ni uzos ĝin por eksperimentoj.

Por ruli logstash, ni skribis apartan docker-compose.yml. Kompreneble, eblis lanĉi la bildon de la komandlinio, sed finfine ni solvis specifan taskon, kie ĉio de docker-compose estas lanĉita por ni.

Mallonge pri agordaj dosieroj

Kiel sekvas el la priskribo, logstash povas ruliĝi kiel por unu kanalo, en ĉi tiu kazo, ĝi bezonas translokigi la dosieron *.conf aŭ por pluraj kanaloj, en kiu kazo ĝi bezonas translokigi la pipelines.yml-dosieron, kiu siavice. , raportos al dosieroj .conf por ĉiu kanalo.
Ni prenis la duan vojon. Ĝi ŝajnis al ni pli diverstalenta kaj skalebla. Tial ni kreis pipelines.yml, kaj faris pipelines-dosierujon en kiu ni metos .conf dosierojn por ĉiu kanalo.

Ene de la ujo estas alia agorda dosiero - logstash.yml. Ni ne tuŝas ĝin, ni uzas ĝin tia.

Do nia dosierujo-strukturo estas:

Praktika aplikado de ELK. Agordante logstash

Por la momento, ni supozas, ke ĉi tio estas tcp sur la haveno 5046 por ricevi enigajn datumojn, kaj ni uzos stdout por eligo.

Jen tia simpla agordo por la unua kuro. Ĉar la komenca tasko estas lanĉi.

Do ni havas ĉi tiun 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

Kion ni vidas ĉi tie?

  1. Retoj kaj volumoj estis prenitaj de la originala docker-compose.yml (tiu kie la tuta stako estas lanĉita) kaj mi pensas, ke ili ne multe influas la ĝeneralan bildon ĉi tie.
  2. Ni kreas unu servon (servoj) logstash, el la bildo docker.elastic.co/logstash/logstash:6.3.2 kaj donas al ĝi la nomon logstash_one_channel.
  3. Ni plusendas la havenon 5046 ene de la ujo, al la sama interna haveno.
  4. Ni mapas nian agordan dosieron ./config/pipelines.yml al la /usr/share/logstash/config/pipelines.yml-dosiero ene de la ujo, kie logstash prenos ĝin kaj faros ĝin nurlegebla, ĉiaokaze.
  5. Ni mapas la dosierujon ./config/pipelines, kie ni havas la pipajn agordajn dosierojn, al la dosierujo /usr/share/logstash/config/pipelines kaj ankaŭ faras ĝin nurlegebla.

Praktika aplikado de ELK. Agordante logstash

piping.yml dosiero

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

Ĝi priskribas unu kanalon kun la HABR-identigilo kaj la vojon al ĝia agorda dosiero.

Kaj fine la dosiero "./config/pipelines/habr_pipeline.conf"

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

Ni ne eniros en ĝian priskribon nuntempe, ni provas ruli:

docker-compose up

Kion ni vidas?

La ujo komenciĝis. Ni povas kontroli ĝian laboron:

echo '13123123123123123123123213123213' | nc localhost 5046

Kaj ni vidas la respondon en la kontenera konzolo:

Praktika aplikado de ELK. Agordante logstash

Sed samtempe ni ankaŭ vidas:

logstash_unu_kanalo | [2019-04-29T11:28:59,790][ERARO][logstash.licensechecker.licensereader] Ne eblas preni informojn pri licenco de permesila servilo {:message=>"Elasticsearch Neatingebla: [http://elasticsearch:9200/][Manticore ::ResolutionFailure]elasticsearch", ...

logstash_unu_kanalo | [2019-04-29T11:28:59,894][INFO ][logstash.pipeline ] Dukto komenciĝis sukcese {:pipeline_id=>".monitoring-logstash", :thread =>"# »}

logstash_unu_kanalo | [2019-04-29T11:28:59,988][INFO ][logstash.agent ] Duktoj kurantaj {:count=>2, :running_pipelines=>[:HABR, :".monitoring-logstash"], :non_running_pipelines=>[ ]}
logstash_unu_kanalo | [2019-04-29T11:29:00,015][ERARO][logstash.inputs.metrics ] X-Pack estas instalita sur Logstash sed ne ĉe Elasticsearch. Bonvolu instali X-Pack sur Elasticsearch por uzi la monitoran funkcion. Aliaj funkcioj povas esti disponeblaj.
logstash_unu_kanalo | [2019-04-29T11:29:00,526][INFO ][logstash.agent ] Sukcese komencita Logstash API finpunkto {:port=>9600}
logstash_unu_kanalo | [2019-04-29T11:29:04,478][INFO ][logstash.outputs.elasticsearch] Rulanta sankontrolon por vidi ĉu Elasticsearch-konekto funkcias {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_unu_kanalo | [2019-04-29T11:29:04,487][WARN ][logstash.outputs.elasticsearch] Provis revivigi konekton al mortinta ES-instanco, sed ricevis eraron. {:url =>"elasta serĉado:9200/", :error_type=>LogStash::Outputs::ElasticSearch::HttpClient::Pool::HostUnreachableError, :error=>"Elasticsearch Neatingebla: [http://elasticsearch:9200/][Manticore::ResolutionFailure] elasta serĉo"}
logstash_unu_kanalo | [2019-04-29T11:29:04,704][INFO ][logstash.licensechecker.licensereader] Rulanta sankontrolon por vidi ĉu Elasticsearch-konekto funkcias {:healthcheck_url=>http://elasticsearch:9200/, :path=> "/"}
logstash_unu_kanalo | [2019-04-29T11:29:04,710][WARN ][logstash.licensechecker.licensereader] Provis revivigi konekton al mortinta ES-instanco, sed ricevis eraron. {:url =>"elasta serĉado:9200/", :error_type=>LogStash::Outputs::ElasticSearch::HttpClient::Pool::HostUnreachableError, :error=>"Elasticsearch Neatingebla: [http://elasticsearch:9200/][Manticore::ResolutionFailure] elasta serĉo"}

Kaj nia ŝtipo rampas supren la tutan tempon.

Ĉi tie mi reliefigis verde la mesaĝon, ke la dukto sukcese komenciĝis, ruĝe la erarmesaĝon kaj flava la mesaĝon pri provi kontakti. elasta serĉado: 9200.
Ĉi tio okazas pro la fakto, ke en la logstash.conf inkluzivita en la bildo, estas kontrolo pri la havebleco de elasta serĉo. Post ĉio, logstash supozas, ke ĝi funkcias kiel parto de la Elk-stako, kaj ni apartigis ĝin.

Vi povas labori, sed ĝi ne estas oportuna.

La solvo estas malŝalti ĉi tiun kontrolon per la mediovariablo XPACK_MONITORING_ENABLED.

Ni faru ŝanĝon al docker-compose.yml kaj rulu ĝin denove:

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

Nun, ĉio estas en ordo. La ujo estas preta por eksperimentoj.

Ni povas tajpi denove en la apuda konzolo:

echo '13123123123123123123123213123213' | nc localhost 5046

Kaj vidu:

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

Laboru ene de unu kanalo

Do ni komencis. Nun vi povas efektive preni la tempon por agordi logstash rekte. Ni ne tuŝu la pipelines.yml dosieron nuntempe, ni vidu, kion ni povas akiri laborante kun unu kanalo.

Mi devas diri, ke la ĝenerala principo labori kun la kanala agorda dosiero estas bone priskribita en la oficiala manlibro, ĉi tie tie
Se vi volas legi en la rusa, tiam ni uzis ĉi tiun artikolo(sed la demanda sintakso estas malnova tie, vi devas konsideri tion).

Ni iru sinsekve de la sekcio Enigo. Ni jam vidis la laboron pri tcp. Kio alia povas esti interesa ĉi tie?

Testu mesaĝojn uzante korbaton

Estas tia interesa ebleco generi aŭtomatajn testajn mesaĝojn.
Por fari tion, vi devas inkluzivi la aldonaĵon heartbean en la eniga sekcio.

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

Ni ŝaltas ĝin, ni komencas ricevi unufoje minuton

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

Ni volas ricevi pli ofte, ni devas aldoni la interval-parametron.
Jen kiel ni ricevos mesaĝon ĉiujn 10 sekundojn.

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

Akiro de datumoj de dosiero

Ni ankaŭ decidis rigardi la dosierreĝimon. Se ĝi funkcias bone kun la dosiero, tiam eblas, ke neniu agento estas bezonata, nu, almenaŭ por loka uzo.

Laŭ la priskribo, la operacimaniero devus esti simila al vosto -f, t.e. legas novliniojn aŭ, laŭvole, legas la tutan dosieron.

Do, kion ni volas ricevi:

  1. Ni volas ricevi liniojn, kiuj estas almetitaj al unu protokolo-dosiero.
  2. Ni volas ricevi datumojn, kiuj estas skribitaj al pluraj protokolaj dosieroj, samtempe povante apartigi tion, kio estis ricevita de kie.
  3. Ni volas certigi, ke kiam logstash estas rekomencita, ĝi ne ricevos ĉi tiujn datumojn denove.
  4. Ni volas kontroli, ke se logstash estas malŝaltita, kaj datumoj daŭre estas skribitaj al dosieroj, tiam kiam ni rulos ĝin, ni ricevos ĉi tiujn datumojn.

Por fari la eksperimenton, ni aldonu unu plian linion al docker-compose.yml, malfermante la dosierujon, kie ni metas la dosierojn.

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

Kaj ŝanĝu la enigsekcion en habr_pipeline.conf

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

Ni komencas:

docker-compose up

Por krei kaj skribi protokolojn, ni uzos la komandon:


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

Jes, ĝi funkcias!

Samtempe, ni vidas, ke ni aŭtomate aldonis la vojon kampon. Do en la estonteco, ni povos filtri rekordojn per ĝi.

Ni provu denove:

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

Kaj nun al alia dosiero:

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

Bonege! La dosiero estis prenita, la vojo estis ĝuste precizigita, ĉio estas en ordo.

Ĉesu logstash kaj rekomencu. Ni atendu. Silento. Tiuj. Ni ne ricevas ĉi tiujn rekordojn denove.

Kaj nun la plej aŭdaca eksperimento.

Ni metas logstash kaj ekzekutas:

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

Rulu logstash denove kaj vidu:

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

Hura! Ĉio reprenis.

Sed, necesas averti pri la sekvanta. Se la logstash-ujo estas forigita (docker stop logstash_one_channel && docker rm logstash_one_channel), nenio estos reprenita. La pozicio de la dosiero ĝis kiu ĝi estis legita estis konservita en la ujo. Se vi komencas de nulo, tiam ĝi akceptos nur novajn liniojn.

Legante ekzistantajn dosierojn

Ni diru, ke ni rulas logstash por la unua fojo, sed ni jam havas protokolojn kaj ni ŝatus prilabori ilin.
Se ni rulas logstash kun la eniga sekcio, kiun ni uzis supre, ni ricevos nenion. Nur novlinioj estos prilaboritaj de logstash.

Por tiri liniojn de ekzistantaj dosieroj, aldonu plian linion al la eniga sekcio:

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

Krome, estas nuanco, ĉi tio nur influas novajn dosierojn, kiujn logstash ankoraŭ ne vidis. Por la samaj dosieroj, kiuj jam estis en la vidkampo de logstash, ĝi jam memoris ilian grandecon kaj nun prenos nur novajn rekordojn en ili.

Ni ĉesu pri tio studante la enigsekcion. Estas multaj pli da ebloj, sed nuntempe ni havas sufiĉe por pliaj eksperimentoj.

Envojigo kaj transformo de datumoj

Ni provu solvi la sekvan problemon, ni diru, ke ni havas mesaĝojn de unu kanalo, kelkaj el ili estas informaj, kaj kelkaj estas erarmesaĝoj. Ili diferencas laŭ etikedo. Iuj estas INFO, aliaj estas ERARO.

Ni devas apartigi ilin ĉe la elirejo. Tiuj. Ni skribas informajn mesaĝojn en unu kanalo, kaj erarmesaĝojn en alia.

Por fari tion, iru de la eniga sekcio al filtrilo kaj eligo.

Uzante la filtrilan sekcion, ni analizos la envenantan mesaĝon, ricevante hash (ŝlosil-valoraj paroj) de ĝi, kun kiu ni jam povas labori, t.e. analizu laŭ la kondiĉoj. Kaj en la eligo sekcio, ni elektos mesaĝojn kaj sendos ĉiun al sia propra kanalo.

Analizante mesaĝon per grok

Por analizi tekstajn ĉenojn kaj akiri aron da kampoj de ili, estas speciala kromaĵo en la filtrila sekcio - grok.

Sen meti al mi la celon doni detalan priskribon de ĝi ĉi tie (por tio mi referencas al oficiala dokumentaro), mi donos mian simplan ekzemplon.

Por fari tion, vi devas decidi pri la formato de la eniglinioj. Mi havas ilin jene:

1 INFO-mesaĝo1
2 ERARA mesaĝo2

Tiuj. Unue identigilo, poste INFO/ERARO, poste iu vorto sen spacoj.
Ne malfacila, sed sufiĉa por kompreni la principon de funkciado.

Do, en la filtrila sekcio, en la grok kromaĵo, ni devas difini ŝablonon por analizi niajn ŝnurojn.

Ĝi aspektos tiel:

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

Esence, ĝi estas regula esprimo. Pretaj ŝablonoj estas uzataj, kiel INT, LOGLEVEL, WORD. Ilia priskribo, same kiel aliaj ŝablonoj, rigardeblas ĉi tie. tie

Nun, trapasante ĉi tiun filtrilon, nia ĉeno transformiĝos en hash de tri kampoj: message_id, message_type, message_text.

Ili estos montrataj en la eligo-sekcio.

Sendante mesaĝojn en la eligsekcio kun la komando if

En la eligo-sekcio, kiel ni memoras, ni dividos la mesaĝojn en du fluojn. Iuj - kiuj estas iNFO, ni eligos al la konzolo, kaj kun eraroj, ni eligos al dosiero.

Kiel ni povas dividi ĉi tiujn mesaĝojn? La kondiĉo de la problemo jam sugestas solvon - finfine ni jam havas dediĉitan mesaĝ-specan kampon, kiu povas preni nur du valorojn INFO kaj ERARO. Ĝuste sur ĝi ni faros elekton uzante la if deklaron.

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

Priskribo de laboro kun kampoj kaj funkciigistoj troveblas en ĉi tiu sekcio oficiala manlibro.

Nun, pri la konkludo mem.

Konzola eligo, ĉio estas klara ĉi tie - stdout {}

Sed la eligo al la dosiero - memoru, ke ni prizorgas ĉion ĉi el la ujo kaj por ke la dosiero en kiu ni skribas la rezulton estu alirebla de ekstere, ni devas malfermi ĉi tiun dosierujon en docker-compose.yml.

Sumo:

La eligsekcio de nia dosiero aspektas jene:


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

Aldonu unu plian volumon al docker-compose.yml por eligo:

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

Ni komencas, ni provas, ni vidas la dividon en du riveretojn.

fonto: www.habr.com

Aldoni komenton