მონიტორინგი და ლოგირება

ისწავლეთ Docker-ის კონტეინერების მონიტორინგი და ეფექტური ლოგირების სტრატეგიების დანერგვა

Docker-ის მონიტორინგი და ლოგირება

ეფექტური მონიტორინგი და ლოგირება აუცილებელია საიმედო Docker გარემოს შესანარჩუნებლად. ისინი გვეხმარება პრობლემების მოგვარებაში, წარმადობის ოპტიმიზაციასა და აპლიკაციის ჯანმრთელობის უზრუნველყოფაში. ყოვლისმომცველი მონიტორინგისა და ლოგირების სტრატეგია უზრუნველყოფს კონტეინერის ქცევის ხილვადობას, იძლევა პრობლემების პროაქტიული გამოვლენის საშუალებას და გვეხმარება მომსახურების დონის მიზნების შენარჩუნებაში.

Docker-ის კონტეინერები წარმოადგენენ უნიკალურ მონიტორინგის გამოწვევებს მათი ეფემერული ბუნების, იზოლაციის მახასიათებლებისა და დინამიური გარემოს გამო, რომელშიც ისინი ხშირად მუშაობენ. ეფექტური კონტეინერის დაკვირვებადობის სტრატეგიამ უნდა გაითვალისწინოს ეს მახასიათებლები და ამავდროულად უზრუნველყოს მნიშვნელოვანი ინფორმაცია კონტეინერის მთელი სასიცოცხლო ციკლის განმავლობაში.

კონტეინერის მონიტორინგი

ჩაშენებული მონიტორინგი

Docker-ი უზრუნველყოფს ძირითად მონიტორინგის შესაძლებლობებს, რომლებიც არ საჭიროებს დამატებით ინსტრუმენტებს ან დაყენებას:

# ყველა კონტეინერის რესურსების რეალურ დროში გამოყენების ნახვა
docker stats
# გამომავალი მონაცემების ნიმუში:
# CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
# 1a2b3c4d5e6f   web       0.25%     15.23MiB / 1.952GiB   0.76%     648B / 648B       0B / 0B           2
# 2a3b4c5d6e7f   redis     0.05%     2.746MiB / 1.952GiB   0.14%     1.45kB / 1.05kB   0B / 0B           5

# კონტეინერის დეტალური სტატისტიკის ნახვა JSON ფორმატში (სასარგებლოა სკრიპტინგისთვის)
docker stats --no-stream --format "{{json .}}" container_name | jq '.'
# JSON გამომავალი მონაცემების ლამაზად დაბეჭდვა jq-ს საშუალებით უკეთესი წაკითხვადობისთვის

# სტატისტიკის გაფილტვრა მხოლოდ კონკრეტული კონტეინერების საჩვენებლად
docker stats $(docker ps --format {{.Names}} | grep "api-")

# მხოლოდ კონკრეტული სვეტების ჩვენება
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"

# კონტეინერის კონფიგურაციის დეტალების შემოწმება
docker inspect container_name

# კონკრეტული კონფიგურაციის ინფორმაციის ამოღება
docker inspect --format '{{.HostConfig.Memory}}' container_name
docker inspect --format '{{.State.Health.Status}}' container_name
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name

# კონტეინერის მოვლენების რეალურ დროში ნახვა
docker events --filter 'type=container'

ჩაშენებულ მონიტორინგის ინსტრუმენტებს აქვთ კარგი საწყისი წერტილი, მაგრამ აქვთ შეზღუდვები:

  • ისტორიული მონაცემების შენახვის გარეშე
  • შეზღუდული მეტრიკების დეტალიზაცია
  • შეტყობინებების შესაძლებლობების გარეშე
  • მინიმალური ვიზუალიზაციის ოფციები
  • კონტეინერ-ცენტრული და არა აპლიკაცია-ცენტრული ხედვა

cAdvisor

Google-ის კონტეინერების მრჩეველი (cAdvisor) უზრუნველყოფს უფრო დეტალურ კონტეინერის მეტრიკებს ვებ ინტერფეისით და აჩენს Prometheus-თან თავსებად ენდფოინთებს:

# cAdvisor კონტეინერის გაშვება ყველა საჭირო volume mount-ით
docker run -d \
  --name=cadvisor \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --volume=/dev/disk/:/dev/disk:ro \
  --publish=8080:8080 \
  --privileged \
  --device=/dev/kmsg \
  --restart=always \
  gcr.io/cadvisor/cadvisor:v0.47.0

cAdvisor-ი უზრუნველყოფს:

  • რესურსების გამოყენების დეტალური სტატისტიკას (CPU, მეხსიერება, ქსელი, ფაილური სისტემა)
  • კონტეინერის სასიცოცხლო ციკლის მოვლენებს
  • ისტორიულ წარმადობის მონაცემებს (მოკლევადიანი, მეხსიერებაში შენახვა)
  • კონტეინერის იერარქიის ვიზუალიზაციას
  • Prometheus მეტრიკების ენდფოინთს /metrics-ზე
  • აპარატურა-სპეციფიკურ მონიტორინგს (NVML NVIDIA GPU-ებისთვის)
  • კონტეინერების ავტომატურ აღმოჩენას

cAdvisor-ის მიერ გამოვლენილი ძირითადი მეტრიკები:

  • CPU-ს გამოყენების დაშლა (მომხმარებელი, სისტემა, შეზღუდვა)
  • მეხსიერების დეტალები (RSS, ქეში, swap, სამუშაო ნაკრები)
  • ქსელის სტატისტიკა (RX/TX ბაიტები, შეცდომები, დაკარგული პაკეტები)
  • ფაილური სისტემის გამოყენებისა და I/O სტატისტიკა
  • პროცესების სტატისტიკა კონტეინერების შიგნით

ინტერფეისზე წვდომა:

  • ვებ ინტერფეისი http://localhost:8080-ზე
  • API ენდფოინთები პროგრამული წვდომისთვის:
    • /api/v1.3/containers - ყველა კონტეინერის სტატისტიკა
    • /api/v1.3/docker/[container_name] - კონკრეტული კონტეინერის სტატისტიკა
    • /metrics - Prometheus-ის ფორმატის მეტრიკები

Prometheus + Grafana

მძლავრი კომბინაცია მეტრიკების შეგროვების, შენახვის, გამოთხოვისა და ვიზუალიზაციისთვის, რომელიც ფართოდ ითვლება ინდუსტრიის სტანდარტად კონტეინერების მონიტორინგისთვის:

version: '3.8'
services:
  prometheus:
    image: prom/prometheus:v2.44.0
    container_name: prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"
    restart: unless-stopped
    
  node-exporter:
    image: prom/node-exporter:v1.5.0
    container_name: node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"
    restart: unless-stopped
    
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.47.0
    container_name: cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    ports:
      - "8080:8080"
    restart: unless-stopped
    
  grafana:
    image: grafana/grafana:9.5.1
    container_name: grafana
    user: "472"
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin_password
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SERVER_DOMAIN=localhost
    restart: unless-stopped

volumes:
  prometheus_data: {}
  grafana_data: {}

prometheus.yml კონფიგურაციის მაგალითი:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']
    
  - job_name: 'docker'
    metrics_path: /metrics
    static_configs:
      - targets: ['172.17.0.1:9323']  # Docker daemon-ის მეტრიკები (მოითხოვს daemon-ის კონფიგურაციას)

  # კონტეინერების ავტომატური აღმოჩენა და სკრეიპინგი prometheus.io ანოტაციებით
  - job_name: 'docker-containers'
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        filters:
          - name: label
            values: ['prometheus.io.scrape=true']
    relabel_configs:
      - source_labels: ['__meta_docker_container_label_prometheus_io_port']
        target_label: __metrics_path__
        replacement: /metrics
      - source_labels: ['__meta_docker_container_name']
        target_label: container_name
      - source_labels: ['__meta_docker_container_label_prometheus_io_job']
        target_label: job

ეს დაყენება უზრუნველყოფს:

  • Prometheus: დროის სერიების მონაცემთა ბაზა მძლავრი საძიებო ენით (PromQL)
  • Node Exporter: ჰოსტის დონის მეტრიკები (CPU, მეხსიერება, დისკი, ქსელი)
  • cAdvisor: კონტეინერ-სპეციფიური მეტრიკები
  • Grafana: ვიზუალიზაციის დაფები და შეტყობინებები

შეგიძლიათ ჩართოთ Docker daemon-ის მეტრიკები /etc/docker/daemon.json-ში დამატებით:

{
  "metrics-addr": "0.0.0.0:9323",
  "experimental": true
}

კონტეინერებისთვის გავრცელებული Prometheus მეტრიკები:

  • container_cpu_usage_seconds_total - მოხმარებული CPU-ს კუმულაციური დრო
  • container_memory_usage_bytes - მიმდინარე მეხსიერების გამოყენება, ქეშის ჩათვლით
  • container_memory_rss - Resident Set Size (ფაქტობრივი მეხსიერების გამოყენება)
  • container_network_receive_bytes_total - მიღებული ქსელის ბაიტები
  • container_network_transmit_bytes_total - გაგზავნილი ქსელის ბაიტები
  • container_fs_reads_bytes_total - დისკიდან წაკითხული ბაიტები
  • container_fs_writes_bytes_total - დისკზე ჩაწერილი ბაიტები

PromQL მოთხოვნების მაგალითები:

# CPU-ს გამოყენების პროცენტი კონტეინერის მიხედვით
sum(rate(container_cpu_usage_seconds_total{name=~".+"}[1m])) by (name) * 100

# მეხსიერების გამოყენება MB-ში კონტეინერის მიხედვით
sum(container_memory_usage_bytes{name=~".+"}) by (name) / 1024 / 1024

# ქსელის მიღების გამტარუნარიანობა
rate(container_network_receive_bytes_total{name=~".+"}[5m])

ლოგირების სტრატეგიები

ლოგირების დრაივერების კონფიგურაცია

ლოგირების დრაივერები შეიძლება დაკონფიგურირდეს daemon-ის დონეზე (ყველა კონტეინერისთვის) ან თითოეული კონტეინერისთვის:

# ლოგირების დრაივერის დაყენება კონკრეტული კონტეინერისთვის
docker run --log-driver=syslog \
  --log-opt syslog-address=udp://logs.example.com:514 \
  --log-opt syslog-facility=daemon \
  --log-opt tag="{{.Name}}/{{.ID}}" \
  nginx

# JSON ფაილის დრაივერის გამოყენება ზომაზე დაფუძნებული როტაციით
docker run --log-driver=json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  --log-opt compress=true \
  nginx

# AWS CloudWatch ლოგირების კონფიგურაცია
docker run --log-driver=awslogs \
  --log-opt awslogs-region=us-west-2 \
  --log-opt awslogs-group=my-container-logs \
  --log-opt awslogs-stream=web-app \
  my-web-app

# ლოგების გაგზავნა Fluentd-ში მორგებული ლეიბლებით
docker run --log-driver=fluentd \
  --log-opt fluentd-address=localhost:24224 \
  --log-opt tag="docker.{{.Name}}" \
  --log-opt fluentd-async=true \
  --log-opt labels=environment,service_name \
  --label environment=production \
  --label service_name=api \
  my-api-service

ნაგულისხმევი ლოგირების დრაივერის კონფიგურაცია ყველა კონტეინერისთვის /etc/docker/daemon.json-ში:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true",
    "labels": "environment,project",
    "env": "HOSTNAME,ENVIRONMENT"
  }
}

daemon.json-ის შეცვლის შემდეგ, გადატვირთეთ Docker daemon-ი:

sudo systemctl restart docker

შეგიძლიათ შეამოწმოთ მიმდინარე ლოგირების დრაივერის კონფიგურაცია:

docker info --format '{{.LoggingDriver}}'

კონტეინერ-სპეციფიკური ლოგირების კონფიგურაციისთვის:

docker inspect --format '{{.HostConfig.LogConfig}}' container_name

გავრცელებული ლოგირების ოფციები დრაივერებში:

  • mode - ბლოკირებადი (ნაგულისხმევი) ან არაბლოკირებადი
  • max-buffer-size - ბუფერის ზომა არაბლოკირებადი რეჟიმისთვის
  • env - კონკრეტული გარემოს ცვლადების ჩართვა ლოგებში
  • labels - კონტეინერის ლეიბლების ჩართვა ლოგებში
  • tag - ლოგის შეტყობინების თეგის ფორმატის მორგება

კონტეინერის ლოგების ნახვა

ძირითადი ლოგის ბრძანებები

# კონტეინერის ლოგების ნახვა (აჩვენებს ყველა ლოგს)
docker logs container_name

# კონტეინერის ლოგების რეალურ დროში თვალყურის დევნა (tail -f-ის მსგავსად)
docker logs -f container_name

# დროის ნიშნულების ჩვენება ლოგებთან (სასარგებლოა დებაგინგისთვის)
docker logs -t container_name

# ბოლო n ხაზის ჩვენება (მთელი ლოგის ისტორიის ნაცვლად)
docker logs --tail=100 container_name

# ოფციების კომბინირება რეალურ დროში მონიტორინგისთვის დროის ნიშნულებით
docker logs -f -t --tail=50 container_name

# ლოგების გაფილტვრა დროის მიხედვით (ლოგების ჩვენება კონკრეტული დროის ნიშნულიდან)
docker logs --since 2023-07-01T00:00:00 container_name

# ლოგების ჩვენება კონკრეტულ დროის ნიშნულამდე
docker logs --until 2023-07-02T00:00:00 container_name

# ლოგების ჩვენება შედარებითი დროიდან (მაგ., ბოლო საათი)
docker logs --since=1h container_name

# ლოგებში კონკრეტული ნიმუშების ძებნა grep-ით
docker logs container_name | grep ERROR

# ლოგების გამოტანა სხვადასხვა ფორმატში (სასარგებლოა პარსინგისთვის)
docker logs --details container_name

# კონკრეტული ლოგის ნიმუშების რაოდენობის დათვლა
docker logs container_name | grep -c "Connection refused"

# ლოგის დროის ნიშნულების ამოღება და ფორმატირება დროის ანალიზისთვის
docker logs -t container_name | awk '{print $1, $2}' | sort

# მრავალი კონტეინერის ერთდროულად მონიტორინგი
docker logs $(docker ps -q) 2>&1 | grep ERROR

# კონტეინერის ლოგების ჩვენება ფერადი გამოსახულებით სხვადასხვა ლოგის დონისთვის
docker logs container_name | grep --color -E "ERROR|WARN|INFO|DEBUG|$"

გაითვალისწინეთ, რომ docker logs მუშაობს მხოლოდ json-file, local, ან journald ლოგირების დრაივერების მქონე კონტეინერებთან. სხვა ლოგირების დრაივერებისთვის (როგორიცაა syslog, fluentd და ა.შ.), ლოგებზე წვდომა დაგჭირდებათ მათი შესაბამისი სისტემების საშუალებით.

ლოგების მიღების წარმადობის მოსაზრებები

  • დიდი მოცულობის ლოგებისთვის, გამოიყენეთ --tail გამომავალი მონაცემების შესაზღუდად
  • მოერიდეთ docker logs-ის ხშირ გამოძახებას დატვირთულ production სისტემებზე
  • განიხილეთ --since დროშის გამოყენება დროის დიაპაზონის შესაზღუდად
  • მაღალი ტრაფიკის მქონე კონტეინერებისთვის, გამოიყენეთ გამოყოფილი ლოგირების გადაწყვეტა docker logs-ის ნაცვლად
  • docker logs ბრძანება კითხულობს მთელ ლოგ ფაილს ფილტრების გამოყენებამდე, რაც შეიძლება რესურს-ინტენსიური იყოს

ლოგების როტაცია

ლოგების როტაცია აუცილებელია დისკის სივრცის გამოფიტვის თავიდან ასაცილებლად. დააკონფიგურირეთ ის Docker daemon-ის პარამეტრებში:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",      // თითოეული ლოგ ფაილის მაქსიმალური ზომა როტაციამდე
    "max-file": "3",        // შესანახი ლოგ ფაილების რაოდენობა
    "compress": "true"      // როტირებული ლოგ ფაილების შეკუმშვა
  }
}

კონტეინერ-სპეციფიკური ლოგების როტაცია შეიძლება დაკონფიგურირდეს runtime-ში:

# ლოგების როტაციის კონფიგურაცია კონკრეტული კონტეინერისთვის
docker run -d \
  --log-opt max-size=5m \
  --log-opt max-file=5 \
  --log-opt compress=true \
  --name web nginx

არსებული deployment-ებისთვის, რომლებსაც არ აქვთ მართული ლოგ ფაილები, შეგიძლიათ გამოიყენოთ გარე ლოგების როტაცია:

# logrotate კონფიგურაციის მაგალითი (/etc/logrotate.d/docker-containers)
/var/lib/docker/containers/*/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

შეგიძლიათ ხელით გამოიწვიოთ ლოგების როტაცია კონტეინერის ან Docker daemon-ის გადატვირთვით.

გავრცელებული ლოგების როტაციის პრობლემები:

  • Docker daemon-ის გადატვირთვაა საჭირო daemon.json-ის ცვლილებების ძალაში შესასვლელად
  • კონტეინერებს, რომლებიც შექმნილია ლოგების როტაციის კონფიგურაციამდე, არ ექნებათ ის გამოყენებული
  • ძალიან მაღალი მოცულობის ლოგების მქონე კონტეინერებს შეიძლება კვლავ ჰქონდეთ პრობლემები როტაციის მიუხედავად
  • copytruncate logrotate-ში შეიძლება გამოტოვოს ლოგები როტაციის ფანჯრის დროს
  • ჩადგმული JSON ლოგები შეიძლება რთული იყოს პარსინგისთვის როტაციის შემდეგ

მრავალკონტეინერიანი ლოგების აგრეგაცია

ინსტრუმენტებს, როგორიცაა Fluentd, Logstash, ან Filebeat, შეუძლიათ შეაგროვონ ლოგები მრავალი კონტეინერიდან და გადააგზავნონ ისინი ცენტრალიზებულ ლოგირების სისტემებში:

version: '3.8'
services:
  app:
    image: my-app
    logging:
      driver: fluentd
      options:
        fluentd-address: fluentd:24224
        tag: app.{{.Name}}
        fluentd-async: "true"
        fluentd-async-connect: "true"
        labels: "environment,service_name,version"
        env: "NODE_ENV,SERVICE_VERSION"
    labels:
      environment: production
      service_name: api
      version: "1.0.0"
    environment:
      NODE_ENV: production
      SERVICE_VERSION: "1.0.0"
  
  web:
    image: nginx
    logging:
      driver: fluentd
      options:
        fluentd-address: fluentd:24224
        tag: web.{{.Name}}
        fluentd-async: "true"
    depends_on:
      - app
  
  db:
    image: postgres
    logging:
      driver: fluentd
      options:
        fluentd-address: fluentd:24224
        tag: db.{{.Name}}
        fluentd-async: "true"
  
  fluentd:
    image: fluentd/fluentd:v1.16-1
    volumes:
      - ./fluentd/conf:/fluentd/etc
      - fluentd-data:/fluentd/log
    ports:
      - "24224:24224"
      - "24224:24224/udp"
    environment:
      - FLUENTD_CONF=fluent.conf
    restart: always

volumes:
  fluentd-data:

Fluentd კონფიგურაციის მაგალითი (fluent.conf):

<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

# Docker ლოგების პარსინგი
<filter **>
  @type parser
  key_name log
  reserve_data true
  remove_key_name_field true
  <parse>
    @type json
    json_parser json
  </parse>
</filter>

# Kubernetes მეტამონაცემების დამატება, თუ K8s-ში მუშაობს
<filter kubernetes.**>
  @type kubernetes_metadata
</filter>

# გამოტანა Elasticsearch-ში
<match **>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
  logstash_prefix fluentd
  <buffer>
    @type file
    path /fluentd/log/buffer
    flush_thread_count 2
    flush_interval 5s
    chunk_limit_size 2M
    queue_limit_length 32
    retry_max_interval 30
    retry_forever true
  </buffer>
</match>

# ლოგების ლოკალური ასლის შენახვა დებაგინგისთვის
<match **>
  @type copy
  <store>
    @type file
    path /fluentd/log/${tag}/%Y/%m/%d.%H.%M
    append true
    <format>
      @type json
    </format>
    <buffer tag,time>
      @type file
      timekey 1h
      timekey_use_utc true
      timekey_wait 10m
    </buffer>
  </store>
</match>

ალტერნატიული ლოგების აგრეგაციის გადაწყვეტილებები:

  • Filebeat: მსუბუქი ლოგების გამგზავნი Elastic Stack-იდან
    filebeat:
      image: docker.elastic.co/beats/filebeat:8.8.0
      volumes:
        - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
        - /var/lib/docker/containers:/var/lib/docker/containers:ro
        - /var/run/docker.sock:/var/run/docker.sock:ro
      user: root
      restart: always
    
  • Logstash: უფრო მძლავრი ლოგების დამუშავების მილსადენი
    logstash:
      image: docker.elastic.co/logstash/logstash:8.8.0
      volumes:
        - ./logstash/pipeline:/usr/share/logstash/pipeline:ro
        - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
      ports:
        - "5000:5000/tcp"
        - "5000:5000/udp"
        - "9600:9600"
      environment:
        LS_JAVA_OPTS: "-Xmx512m -Xms512m"
      restart: always
    
  • Vector: მაღალი წარმადობის დაკვირვებადობის მონაცემთა მილსადენი
    vector:
      image: timberio/vector:0.29.1-alpine
      volumes:
        - ./vector.toml:/etc/vector/vector.toml:ro
        - /var/lib/docker/containers:/var/lib/docker/containers:ro
        - /var/run/docker.sock:/var/run/docker.sock:ro
      ports:
        - "8686:8686"
      restart: always
    

ცენტრალიზებული ლოგირება

ELK სტეკის მაგალითი

Production-ისთვის მზა ELK სტეკის deployment-ი სათანადო კონფიგურაციითა და რესურსების პარამეტრებით:

version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.1
    container_name: elasticsearch
    environment:
      - node.name=elasticsearch
      - cluster.name=docker-cluster
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - xpack.security.enabled=true
      - ELASTIC_PASSWORD=changeme
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    cap_add:
      - IPC_LOCK
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    networks:
      - elk
    healthcheck:
      test: ["CMD-SHELL", "curl -s http://localhost:9200 | grep -q 'You Know, for Search'"]
      interval: 10s
      timeout: 10s
      retries: 120
  
  logstash:
    image: docker.elastic.co/logstash/logstash:8.8.1
    container_name: logstash
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
    ports:
      - "5044:5044"
      - "5000:5000/tcp"
      - "5000:5000/udp"
      - "9600:9600"
    environment:
      LS_JAVA_OPTS: "-Xmx256m -Xms256m"
    networks:
      - elk
    depends_on:
      - elasticsearch
  
  kibana:
    image: docker.elastic.co/kibana/kibana:8.8.1
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_URL=http://elasticsearch:9200
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=changeme
    networks:
      - elk
    depends_on:
      - elasticsearch
    healthcheck:
      test: ["CMD-SHELL", "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'"]
      interval: 10s
      timeout: 10s
      retries: 120
      
  filebeat:
    image: docker.elastic.co/beats/filebeat:8.8.1
    container_name: filebeat
    command: filebeat -e -strict.perms=false
    volumes:
      - ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    user: root
    networks:
      - elk
    depends_on:
      - elasticsearch
      - logstash

networks:
  elk:
    driver: bridge

volumes:
  es_data:
    driver: local

## აპლიკაციის ლოგირების საუკეთესო პრაქტიკები

::steps
### ლოგირება STDOUT/STDERR-ში
- **დაწერეთ ლოგები სტანდარტულ გამომავალ და შეცდომების ნაკადებში**
  - Docker-ი იჭერს ყველაფერს, რაც იწერება stdout/stderr-ში
  - არ არის საჭირო ლოგ ფაილების მართვა კონტეინერებში
  - ამცირებს სირთულესა და დისკის სივრცის პრობლემებს
  - იძლევა კონტეინერის გადატვირთვის საშუალებას ლოგების დაკარგვის გარეშე
  - ხდის ლოგებს ხელმისაწვდომს `docker logs` ბრძანებით

- **მიეცით Docker-ს ლოგების შეგროვების საშუალება**
  - Docker daemon-ი მართავს ლოგების შენახვასა და როტაციას
  - თანმიმდევრული ლოგირების მექანიზმი ყველა კონტეინერისთვის
  - იძლევა ცენტრალიზებული ლოგების კონფიგურაციის საშუალებას
  - ამარტივებს ლოგირების არქიტექტურას
  - იძლევა ლოგირების დრაივერების შეცვლის საშუალებას აპლიკაციის ცვლილებების გარეშე

- **იცავს 12-ფაქტორიანი აპლიკაციის მეთოდოლოგიას**
  - პრინციპი IV: მოეპყარით ლოგებს, როგორც მოვლენების ნაკადებს
  - აპლიკაცია არ ზრუნავს შენახვაზე/მარშრუტიზაციაზე
  - გამოყოფს ლოგების გენერაციას ლოგების დამუშავებისგან
  - იძლევა უფრო მარტივი ჰორიზონტალური მასშტაბირების საშუალებას
  - ხელს უწყობს პასუხისმგებლობების გამიჯვნას

- **ლოგირების პრაქტიკის მაგალითები:**
  ```javascript
  // Node.js მაგალითი - კარგი პრაქტიკა
  console.log(JSON.stringify({
    level: 'info',
    message: 'მომხმარებელი შევიდა სისტემაში',
    timestamp: new Date().toISOString(),
    userId: user.id
  }));
  
  // ცუდი პრაქტიკა - ფაილებში წერა
  // fs.appendFileSync('/var/log/app.log', 'მომხმარებელი შევიდა სისტემაში\n');

სტრუქტურირებული ლოგირება

  • გამოიყენეთ JSON ან სხვა სტრუქტურირებული ფორმატები
    • იძლევა მანქანურად წაკითხვადი ლოგების დამუშავების საშუალებას
    • ინარჩუნებს კავშირებს მონაცემთა ველებს შორის
    • ამარტივებს პარსინგსა და გამოთხოვას
    • ინარჩუნებს მონაცემთა ტიპებსა და იერარქიებს
    • ხელს უწყობს ავტომატიზებულ ანალიზს
  • ჩართეთ აუცილებელი მეტამონაცემების ველები
    • timestamp: ISO 8601 ფორმატი დროის სარტყლით (მაგ., 2023-07-01T12:34:56.789Z)
    • level: სიმძიმის დონე (მაგ., debug, info, warn, error)
    • service: სერვისის ან კომპონენტის სახელი
    • message: ადამიანისთვის წაკითხვადი აღწერა
    • traceId: განაწილებული კვალის იდენტიფიკატორი
  • დაამატეთ კორელაციის ID-ები მოთხოვნების თვალყურის დევნებისთვის
    • იძლევა მოთხოვნების თვალყურის დევნების საშუალებას მრავალ სერვისში
    • ეხმარება განაწილებული სისტემის დებაგინგში
    • ამარტივებს რთული სამუშაო პროცესების ანალიზს
    • აუცილებელია მიკროსერვისული არქიტექტურებისთვის
    • ველების მაგალითი: requestId, correlationId, traceId, spanId
  • ჩართეთ კონტექსტური ინფორმაცია
    • მომხმარებლის იდენტიფიკატორები (ანონიმიზირებული საჭიროების შემთხვევაში)
    • რესურსის იდენტიფიკატორები (მაგ., orderId, productId)
    • შესრულებული ოპერაცია
    • წყაროს ინფორმაცია (მაგ., IP მისამართი, user agent)
    • წარმადობის მეტრიკები (მაგ., ხანგრძლივობა, რესურსების გამოყენება)
  • სტრუქტურირებული ლოგის ფორმატის მაგალითი:
    {
      "timestamp": "2023-07-01T12:34:56.789Z",
      "level": "error",
      "service": "payment-service",
      "message": "გადახდის დამუშავება ვერ მოხერხდა",
      "traceId": "abc123def456",
      "userId": "user-789",
      "orderId": "order-456",
      "error": {
        "code": "INSUFFICIENT_FUNDS",
        "message": "ანგარიშზე არასაკმარისი თანხაა"
      },
      "paymentMethod": "credit_card",
      "amount": 99.95,
      "duration_ms": 236
    }
    

ლოგების დონეები

  • დანერგეთ სათანადო ლოგების დონეები
    • DEBUG: დეტალური ინფორმაცია development/დებაგინგისთვის
    • INFO: დადასტურება, რომ ყველაფერი მოსალოდნელად მუშაობს
    • WARN: რაღაც მოულოდნელი, მაგრამ არა აუცილებლად შეცდომა
    • ERROR: რაღაც ვერ მოხერხდა, რაც გამოსაძიებელია
    • FATAL/CRITICAL: სისტემა გამოუსადეგარია, საჭიროა დაუყოვნებლივი ყურადღება
  • დააკონფიგურირეთ შესაბამისი დონე თითოეული გარემოსთვის
    • Development: DEBUG ან INFO მაქსიმალური ხილვადობისთვის
    • Testing/QA: INFO ან WARN ხმაურის შესამცირებლად
    • Production: WARN ან ERROR წარმადობაზე ზემოქმედების მინიმიზაციისთვის
    • გამოიყენეთ გარემოს ცვლადები ლოგების დონეების გასაკონტროლებლად
    • მაგალითი:
      # ლოგის დონის დაყენება გარემოს ცვლადით
      docker run -e LOG_LEVEL=INFO my-app
      
  • უსაფრთხოების მოსაზრებები
    • არასდროს დალოგოთ რწმუნებათა სიგელები, ტოკენები, ან API გასაღებები
    • მოახდინეთ მგრძნობიარე პერსონალური ინფორმაციის ჰეშირება ან მასკირება
    • დაიცავით შესაბამისი რეგულაციები (GDPR, CCPA, HIPAA)
    • იყავით ფრთხილად stack trace-ებთან production-ში
    • დანერგეთ ლოგის ველების რედაქტირება მგრძნობიარე მონაცემებისთვის
    • მაგალითი:
      // ლოგირება რედაქტირებით
      logger.info({
        user: { id: user.id, email: redactEmail(user.email) },
        action: "profile_update",
        changes: redactSensitiveFields(changes)
      });
      
  • ჩართეთ ქმედითი ინფორმაცია შეცდომების ლოგებში
    • შეცდომის ტიპი და შეტყობინება
    • Stack trace (development/testing-ში)
    • კონტექსტი, რომელმაც გამოიწვია შეცდომა
    • მოთხოვნის პარამეტრები (გასუფთავებული)
    • კორელაციის ID-ები კვალის დასადგენად
    • შემოთავაზებული გადაწყვეტის ნაბიჯები, სადაც შესაძლებელია
  • წარმადობის მოსაზრებები
    • ლოგების მოცულობა გავლენას ახდენს სისტემის წარმადობაზე
    • გამოიყენეთ ნიმუშების აღება მაღალი მოცულობის debug ლოგებისთვის
    • განიხილეთ ასინქრონული ლოგირება წარმადობა-კრიტიკული გზებისთვის
    • დანერგეთ circuit breaker-ები ლოგირების წარუმატებლობისთვის
    • დააკვირდეთ და შეატყობინეთ ლოგების არანორმალურ მოცულობაზე ::

ჯანმრთელობის შემოწმება და მონიტორინგი

ჯანმრთელობის შემოწმება უზრუნველყოფს კონტეინერის ჯანმრთელობის სტატუსის ავტომატურ მონიტორინგს, რაც Docker-ს საშუალებას აძლევს აღმოაჩინოს და აღადგინოს აპლიკაციის გაუმართაობები.

# ჯანმრთელობის შემოწმების დამატება Dockerfile-ში
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
  CMD curl -f http://localhost/ || exit 1

ჯანმრთელობის შემოწმების პარამეტრები:

  • interval: დრო შემოწმებებს შორის (ნაგულისხმევი: 30წმ)
  • timeout: მაქსიმალური დრო შემოწმების დასასრულებლად (ნაგულისხმევი: 30წმ)
  • start-period: საწყისი საშეღავათო პერიოდი (ნაგულისხმევი: 0წმ)
  • retries: ზედიზედ წარუმატებლობების რაოდენობა არაჯანსაღად ჩათვლამდე (ნაგულისხმევი: 3)
version: '3.8'
services:
  web:
    image: nginx
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
  
  api:
    image: my-api:latest
    healthcheck:
      test: ["CMD", "wget", "-O", "/dev/null", "-q", "http://localhost:8080/health"]
      interval: 15s
      timeout: 5s
      retries: 5
      start_period: 30s
  
  redis:
    image: redis:alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3
  
  postgres:
    image: postgres:13
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s

ჯანმრთელობის შემოწმების საუკეთესო პრაქტიკები:

  • შექმენით შემოწმებები, რომლებიც ამოწმებენ ძირითად ფუნქციონალობას და არა მხოლოდ იმას, რომ პროცესი მუშაობს
  • შეინარჩუნეთ შემოწმებები მსუბუქი, რათა თავიდან აიცილოთ რესურსების მოხმარება
  • ჩართეთ სათანადო тайმაუტები, რათა თავიდან აიცილოთ ჩამოკიდებული შემოწმებები
  • დააყენეთ შესაბამისი start period-ები ნელა გაშვებადი აპლიკაციებისთვის
  • დანერგეთ health ენდფოინთები, რომლებიც ამოწმებენ დამოკიდებულებებს
  • გამოიყენეთ გასვლის კოდები სწორად (0 = ჯანსაღი, 1 = არაჯანსაღი)
  • მოერიდეთ რთულ სკრიპტებს, რომლებიც შეიძლება წარუმატებელი იყოს აპლიკაციის ჯანმრთელობასთან დაუკავშირებელი მიზეზების გამო

ჯანმრთელობის შემოწმების მდგომარეობები:

  • starting: start period-ის დროს, ჯერ არ ითვლება არაჯანსაღად
  • healthy: შემოწმება გადის
  • unhealthy: შემოწმება ვერ ხერხდება

შეგიძლიათ შეამოწმოთ კონტეინერის ჯანმრთელობის სტატუსი:

docker inspect --format='{{.State.Health.Status}}' container_name

მონიტორინგის მეტრიკები

Prometheus-ის კონფიგურაცია

prometheus.yml-ის მაგალითი Docker-ის ყოვლისმომცველი მონიტორინგისთვის:

global:
  scrape_interval: 15s
  evaluation_interval: 15s
  scrape_timeout: 10s

  # ლეიბლების დამატება ყველა დროის სერიასა და შეტყობინებაზე
  external_labels:
    environment: production
    region: us-west-1

# წესების ფაილები შეიცავს ჩაწერის წესებსა და შეტყობინების წესებს
rule_files:
  - "/etc/prometheus/rules/*.yml"

scrape_configs:
  # Docker daemon-ის მეტრიკები
  - job_name: 'docker'
    static_configs:
      - targets: ['docker-host:9323']
    metrics_path: '/metrics'
    scheme: 'http'
  
  # კონტეინერის მეტრიკები cAdvisor-იდან
  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']
    metrics_path: '/metrics'
    scheme: 'http'
    scrape_interval: 10s
  
  # ჰოსტის მეტრიკები node-exporter-იდან
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']
    metrics_path: '/metrics'
    scheme: 'http'
  
  # Prometheus-ის თვით-მონიტორინგი
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  
  # აპლიკაციის მეტრიკები
  - job_name: 'application'
    static_configs:
      - targets: ['app:8080']
    metrics_path: '/actuator/prometheus'
    scheme: 'http'
  
  # კონტეინერების ავტომატური აღმოჩენა Prometheus-ის ანოტაციებით
  - job_name: 'docker-containers'
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        filters:
          - name: label
            values: ['prometheus.io.scrape=true']
    relabel_configs:
      # კონტეინერის სახელის გამოყენება instance ლეიბლად
      - source_labels: ['__meta_docker_container_name']
        regex: '/(.*)'
        target_label: 'instance'
        replacement: '$1'
      # მეტრიკების გზის ამოღება კონტეინერის ლეიბლიდან
      - source_labels: ['__meta_docker_container_label_prometheus_io_metrics_path']
        regex: '(.+)'
        target_label: '__metrics_path__'
        replacement: '$1'
      # პორტის ამოღება კონტეინერის ლეიბლიდან
      - source_labels: ['__meta_docker_container_label_prometheus_io_port']
        regex: '(.+)'
        target_label: '__address__'
        replacement: '${1}:${__meta_docker_container_label_prometheus_io_port}'
      # კონტეინერის ლეიბლების დამატება Prometheus-ის ლეიბლებად
      - action: labelmap
        regex: __meta_docker_container_label_(.+)

შეტყობინებებისთვის, დაამატეთ AlertManager-ის კონფიგურაცია:

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

# შეტყობინების წესების ფაილის მაგალითი (/etc/prometheus/rules/container_alerts.yml)
groups:
- name: container_alerts
  rules:
  - alert: ContainerCpuUsage
    expr: (sum by(name) (rate(container_cpu_usage_seconds_total{name!=""}[1m])) / scalar(count(node_cpu_seconds_total{mode="idle"}))) * 100 > 80
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "კონტეინერის CPU-ს გამოყენება (instance {{ $labels.instance }})"
      description: "კონტეინერის CPU-ს გამოყენება 80%-ზე მეტია\n  VALUE = {{ $value }}%\n  LABELS = {{ $labels }}"
  
  - alert: ContainerMemoryUsage
    expr: (container_memory_usage_bytes{name!=""} / container_spec_memory_limit_bytes{name!=""} * 100) > 80
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "კონტეინერის მეხსიერების გამოყენება (instance {{ $labels.instance }})"
      description: "კონტეინერის მეხსიერების გამოყენება 80%-ზე მეტია\n  VALUE = {{ $value }}%\n  LABELS = {{ $labels }}"

Grafana-ს დაფის დაყენება

ძირითადი დაყენება

  1. Grafana-ზე წვდომა (ნაგულისხმევი: http://localhost:3000)
    • დარწმუნდით, რომ Grafana სერვისი გაშვებულია და პორტი ხელმისაწვდომია
    • შეამოწმეთ ნებისმიერი პროქსი ან ქსელის შეზღუდვა
  2. შესვლა ნაგულისხმევი რწმუნებათა სიგელებით (admin/admin)
    • პირველი შესვლისას მოგეთხოვებათ პაროლის შეცვლა
    • დააყენეთ ძლიერი პაროლი და შეინახეთ უსაფრთხოდ
    • განიხილეთ დამატებითი მომხმარებლების დაყენება შესაბამისი უფლებებით
  3. Prometheus მონაცემთა წყაროს დამატება
    • გადადით Configuration > Data Sources
    • დააჭირეთ "Add data source" და აირჩიეთ "Prometheus"
    • დააყენეთ URL http://prometheus:9090-ზე (ან შესაბამის მისამართზე)
    • დააყენეთ scrape interval Prometheus-ის კონფიგურაციის შესაბამისად
    • შეამოწმეთ კავშირი, რათა დარწმუნდეთ, რომ მუშაობს
    • გაფართოებული პარამეტრები:
      HTTP Method: GET
      Type: Server (ნაგულისხმევი)
      Access: Server (ნაგულისხმევი)
      Disable metrics lookup: No
      Custom query parameters: None
      
  4. Docker-ის მონიტორინგის დაფების იმპორტი
    • გადადით Dashboards > Import
    • შეიყვანეთ დაფის ID ან ატვირთეთ JSON ფაილი
    • რეკომენდებული დაფის ID-ები:
      • 893: Docker-ისა და სისტემის მონიტორინგი (1 სერვერი)
      • 10619: Docker-ის მონიტორინგი Prometheus-ით
      • 11467: კონტეინერის მეტრიკების დაფა
      • 1860: Node Exporter Full
    • დაარეგულირეთ ცვლადები თქვენი გარემოს შესაბამისად
    • შეინახეთ დაფა შესაბამისი სახელითა და საქაღალდით
  5. შეტყობინებების კონფიგურაცია
    • გადადით Alerting > Alert Rules
    • შექმენით შეტყობინების წესები კრიტიკულ მეტრიკებზე დაყრდნობით
    • დააყენეთ შესაბამისი ზღვრები და შეფასების ინტერვალები
    • დააკონფიგურირეთ შეტყობინების არხები (email, Slack, PagerDuty და ა.შ.)
    • შეამოწმეთ შეტყობინებები სათანადო მიწოდების უზრუნველსაყოფად
    • შეტყობინების წესის მაგალითი:
      Rule name: High Container CPU Usage
      Data source: Prometheus
      Expression: max by(container_name) (rate(container_cpu_usage_seconds_total{container_name!=""}[1m]) * 100) > 80
      Evaluation interval: 1m
      Pending period: 5m
      

დაფის რეკომენდაციები

  • Docker Host-ის მეტრიკების დაფა
    • სისტემის დატვირთვა, CPU, მეხსიერება, დისკი და ქსელი
    • ჰოსტის მუშაობის დრო და სტაბილურობის მეტრიკები
    • Docker daemon-ის მეტრიკები
    • გაშვებული კონტეინერების რაოდენობა
    • რესურსების გამოყენების ტრენდები
    • პანელების მაგალითი:
      • CPU-ს გამოყენება კონტეინერის მიხედვით (დაწყობილი გრაფიკი)
      • მეხსიერების გამოყენება კონტეინერის მიხედვით (დაწყობილი გრაფიკი)
      • კონტეინერის სტატუსების რაოდენობა (stat პანელი)
      • სისტემის დატვირთვა (gauge)
      • დისკის სივრცის გამოყენება (წრიული დიაგრამა)
  • კონტეინერის რესურსების გამოყენების დაფა
    • თითოეული კონტეინერის CPU, მეხსიერებისა და I/O მეტრიკები
    • კონტეინერის გადატვირთვების რაოდენობა
    • ჯანმრთელობის შემოწმების სტატუსი
    • ქსელის ტრაფიკი კონტეინერის მიხედვით
    • ძირითადი ვიზუალიზაციები:
      • კონტეინერის რესურსების გამოყენების heatmap
      • დროის სერიების გრაფიკები თითოეული რესურსის ტიპისთვის
      • Top N რესურსების მომხმარებლები (ცხრილი)
      • კონტეინერის სასიცოცხლო ციკლის მოვლენები (ანოტაციები)
      • რესურსების ლიმიტის შედარება ფაქტობრივ გამოყენებასთან
  • აპლიკაცია-სპეციფიური მეტრიკების დაფები
    • თქვენი აპლიკაციისთვის რელევანტური ბიზნეს KPI-ები
    • მოთხოვნის სიხშირე, შეცდომების სიხშირე და შეყოვნება
    • მონაცემთა ბაზის კავშირების pool-ის სტატუსი
    • ქეშის დარტყმის კოეფიციენტები
    • მორგებული ინსტრუმენტაციის მეტრიკები
    • მომხმარებლის გამოცდილების მეტრიკები
    • მაგალითი: ელექტრონული კომერციის დაფა:
      • შეკვეთები წუთში
      • კალათის მიტოვების კოეფიციენტი
      • გადახდის დამუშავების დრო
      • პროდუქტის ძებნის შეყოვნება
      • აქტიური მომხმარებლის სესიები
  • შეტყობინების ზღვრების ვიზუალიზაცია
    • გააერთიანეთ მეტრიკები შეტყობინების ზღვრებთან
    • ვიზუალური ინდიკატორები ზღვრებთან მიახლოებისთვის
    • შეტყობინებების ისტორია და სიხშირე
    • გადაწყვეტის საშუალო დროის თვალყურის დევნა
    • შეტყობინებების კორელაცია სისტემის მოვლენებთან
    • პანელის მაგალითი: გრაფიკი ფერადი ზღვრების ზოლებით
  • ლოგების კორელაციის ხედები
    • გაერთიანებული მეტრიკებისა და ლოგების პანელები
    • შეცდომების სიხშირის კორელაცია ლოგების მოცულობასთან
    • მოვლენების მარკერები დროის სერიების გრაფიკებზე
    • ლოგების კონტექსტი ანომალიებისთვის
    • მეტრიკებიდან ლოგებზე გადასვლა
    • მაგალითი: მოთხოვნის შეყოვნების გრაფიკი შეცდომების ლოგების ჩანაწერებით, როგორც ანოტაციები

შეტყობინების კონფიგურაცია

# Alertmanager-ის ყოვლისმომცველი კონფიგურაციის მაგალითი
global:
  # smarthost და SMTP გამგზავნი, რომლებიც გამოიყენება ელ.ფოსტის შეტყობინებებისთვის
  smtp_smarthost: 'smtp.example.org:587'
  smtp_from: '[email protected]'
  smtp_auth_username: 'alertmanager'
  smtp_auth_password: 'password'
  
  # Slack-ის auth ტოკენი
  slack_api_url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXX'
  
  # PagerDuty ინტეგრაცია
  pagerduty_url: 'https://events.pagerduty.com/v2/enqueue'
  
  # ნაგულისხმევი შეტყობინების პარამეტრები
  resolve_timeout: 5m

# შეტყობინებების შაბლონები
templates:
  - '/etc/alertmanager/template/*.tmpl'

# ძირეული მარშრუტი, რომელზეც ყველა შეტყობინება შედის
route:
  # ნაგულისხმევი მიმღები
  receiver: 'team-emails'
  
  # ჯგუფური შეტყობინებები კატეგორიისა და გარემოს მიხედვით
  group_by: ['alertname', 'environment', 'service']
  
  # დაელოდეთ 30ს ერთი და იგივე ჯგუფის შეტყობინებების აგრეგაციისთვის
  group_wait: 30s
  
  # გაგზავნეთ განახლებული შეტყობინება, თუ ჯგუფს ახალი შეტყობინებები დაემატა
  group_interval: 5m
  
  # რამდენ ხანს უნდა დაელოდოთ შეტყობინების ხელახლა გაგზავნამდე
  repeat_interval: 4h
  
  # შვილობილი მარშრუტები
  routes:
  - receiver: 'critical-pages'
    matchers:
      - severity="critical"
    # არ დაელოდოთ კრიტიკული შეტყობინებების გაგზავნას
    group_wait: 0s
    # დაბალი ინტერვალი კრიტიკული შეტყობინებებისთვის
    repeat_interval: 1h
    # გააგრძელეთ სხვა შვილობილ მარშრუტებზე გადაგზავნა
    continue: true
    
  - receiver: 'slack-notifications'
    matchers:
      - severity=~"warning|info"
    # გააგრძელეთ სხვა შვილობილი მარშრუტების დამუშავება
    continue: true
    
  - receiver: 'database-team'
    matchers:
      - service=~"database|postgres|mysql"
    
  - receiver: 'frontend-team'
    matchers:
      - service=~"frontend|ui|web"

# დათრგუნვის წესები ხელს უშლის დაბალი სიმძიმის შეტყობინებების გაგზავნას, თუ უფრო მაღალი სიმძიმის
# შეტყობინება უკვე აქტიურია იმავე პრობლემაზე
inhibit_rules:
- source_matchers:
    - severity="critical"
  target_matchers:
    - severity="warning"
  # დათრგუნეთ მხოლოდ იმ შემთხვევაში, თუ alertname იგივეა
  equal: ['alertname', 'instance']

receivers:
  - name: 'team-emails'
    email_configs:
      - to: '[email protected]'
        send_resolved: true
        html: '{{ template "email.default.html" . }}'
        headers:
          Subject: '{{ template "email.subject" . }}'
  
  - name: 'critical-pages'
    pagerduty_configs:
      - service_key: 'your-pagerduty-service-key'
        send_resolved: true
        description: '{{ template "pagerduty.default.description" . }}'
        severity: 'critical'
        client: 'Alertmanager'
        client_url: 'https://alertmanager.example.com'
  
  - name: 'slack-notifications'
    slack_configs:
      - channel: '#monitoring'
        send_resolved: true
        icon_url: 'https://avatars3.githubusercontent.com/u/3380462'
        title: '{{ template "slack.default.title" . }}'
        title_link: 'https://alertmanager.example.com/#/alerts'
        text: '{{ template "slack.default.text" . }}'
        footer: 'Prometheus Alertmanager'
        actions:
          - type: 'button'
            text: 'Runbook 📚'
            url: '{{ (index .Alerts 0).Annotations.runbook_url }}'
  
  - name: 'database-team'
    slack_configs:
      - channel: '#db-alerts'
        send_resolved: true
        title: '{{ template "slack.default.title" . }}'
        text: '{{ template "slack.default.text" . }}'
  
  - name: 'frontend-team'
    slack_configs:
      - channel: '#frontend-alerts'
        send_resolved: true
        title: '{{ template "slack.default.title" . }}'
        text: '{{ template "slack.default.text" . }}'

დებაგინგი ლოგებით

ლოგების ეფექტური ანალიზი კრიტიკულია კონტეინერის პრობლემების მოსაგვარებლად. აქ მოცემულია პრაქტიკული ტექნიკა კონტეინერის ლოგებიდან ღირებული ინფორმაციის ამოსაღებად:

# კონტეინერის პრობლემების დებაგინგი შეცდომების ფილტრაციით
docker logs --tail=100 -t container_name | grep ERROR

# ლოგების თვალყურის დევნა კონკრეტული ნიმუშის დამთხვევით (გაფართოებული regex-ის გამოყენებით)
docker logs -f container_name | grep -E "error|exception|fail|fatal|panic"

# ლოგების ამოღება კონტექსტით (3 ხაზი თითოეული დამთხვევის წინ და შემდეგ)
docker logs container_name | grep -A 3 -B 3 "Exception"

# კონკრეტული შეცდომის ტიპების ყველა შემთხვევის პოვნა და დათვლა
docker logs container_name | grep -o "OutOfMemoryError" | wc -l

# ლოგების ძებნა კონკრეტულ დროის ფანჯარაში
docker logs --since 2023-07-01T10:00:00 --until 2023-07-01T11:00:00 container_name

# ლოგების შენახვა ფაილში ოფლაინ ანალიზისთვის
docker logs container_name > container.log

# ლოგების შედარება დროის პერიოდებში
docker logs --since 2h container_name > recent.log
docker logs --since 4h --until 2h container_name > older.log
diff recent.log older.log | less

# JSON ლოგების პარსინგი უკეთესი წაკითხვადობისთვის
docker logs container_name | grep -v '^$' | jq '.'

# კონკრეტული ველების ამოღება JSON ლოგებიდან
docker logs container_name | grep -v '^$' | jq 'select(.level=="error") | {timestamp, message, error}'

# ლოგების თვალყურის დევნა და სხვადასხვა ლოგის დონის ფერებით გამოყოფა
docker logs -f container_name | GREP_COLOR="01;31" grep -E --color=always 'ERROR|$' | GREP_COLOR="01;33" grep -E --color=always 'WARN|$'

# ლოგების ამოღება კონკრეტული მოთხოვნის ID-სთვის
docker logs container_name | grep "request-123456"

# ნელი ოპერაციების პოვნა (მაგ., 1 წამზე მეტი ხნის მოთხოვნები)
docker logs container_name | grep -E "took [1-9][0-9]{3,}ms"

# stack trace-ების ამოღება
docker logs container_name | grep -A 20 "Exception" | grep -v "^$"

# ლოგების მოცულობის ანალიზი დროის მიხედვით (ლოგები წუთში)
docker logs -t container_name | cut -d' ' -f1 | cut -d'T' -f2 | cut -c1-8 | sort | uniq -c

გაფართოებული დებაგინგის ტექნიკა:

  • ლოგების კორელაცია სისტემის მოვლენებთან (deployment-ები, მასშტაბირება და ა.შ.)
  • ლოგების შედარება მრავალ კონტეინერზე განაწილებული პრობლემებისთვის
  • დროის ნიშნულების გამოყენება მოვლენების თანმიმდევრობის შესაქმნელად
  • კონტეინერის გარემოს ცვლადების შემოწმება კონფიგურაციის პრობლემებისთვის
  • კონტეინერის გაშვების ლოგების ცალკე ანალიზი runtime ლოგებისგან
  • აპლიკაციისა და ინფრასტრუქტურის ლოგების ერთდროულად მონიტორინგი
  • regex ნიმუშების გამოყენება სტრუქტურირებული მონაცემების ამოსაღებად არასტრუქტურირებული ლოგებიდან

მონიტორინგის გაფართოებული თემები

განაწილებული კვალი

  • დანერგეთ OpenTelemetry ან Jaeger
    • თვალყური ადევნეთ მოთხოვნებს, როდესაც ისინი გადიან განაწილებულ სისტემებში
    • შექმენით კვალის ID-ები ლოგების კორელაციისთვის სერვისებში
    • ინსტრუმენტირება გაუკეთეთ კოდს OpenTelemetry SDK-ით
    • განათავსეთ Jaeger ან Zipkin კოლექტორები
    • Jaeger deployment-ის მაგალითი:
      version: '3.8'
      services:
        jaeger:
          image: jaegertracing/all-in-one:1.37
          ports:
            - "6831:6831/udp"  # Jaeger აგენტი - იღებს span-ებს Thrift ფორმატში
            - "16686:16686"    # Jaeger UI
          environment:
            - COLLECTOR_ZIPKIN_HOST_PORT=:9411
      
  • მოთხოვნების კვალი მრავალ კონტეინერში
    • გაავრცელეთ კვალის კონტექსტი სერვისებს შორის
    • დააფიქსირეთ მოთხოვნის გზა მიკროსერვისებში
    • ჩაწერეთ მშობელი-შვილის ურთიერთობები span-ებს შორის
    • შეინახეთ baggage ელემენტები მოთხოვნის კონტექსტისთვის
    • კლიენტის ინსტრუმენტაციის მაგალითი (Node.js):
      const tracer = opentelemetry.trace.getTracer('my-service');
      const span = tracer.startSpan('process-order');
      try {
        // ატრიბუტების დამატება span-ზე
        span.setAttribute('order.id', orderId);
        span.setAttribute('customer.id', customerId);
        
        // შვილობილი span-ის შექმნა
        const dbSpan = tracer.startSpan('database-query', {
          parent: span,
        });
        // მონაცემთა ბაზის ოპერაციების დამუშავება
        dbSpan.end();
        
        // კონტექსტის გავრცელება HTTP მოთხოვნებზე
        const headers = {};
        opentelemetry.propagation.inject(opentelemetry.context.active(), headers);
        await axios.post('http://inventory-service/check', data, { headers });
      } catch (error) {
        span.recordException(error);
        span.setStatus({ code: SpanStatusCode.ERROR });
      } finally {
        span.end();
      }
      
  • სერვისის შეყოვნების გაზომვა
    • გამოთვალეთ თითოეულ სერვისში დახარჯული დრო
    • დაშალეთ დამუშავების დრო ოპერაციების მიხედვით
    • იდენტიფიცირეთ ნელი კომპონენტები ან დამოკიდებულებები
    • შეადარეთ შეყოვნება სხვადასხვა გარემოში
    • კორელაცია მოახდინეთ შეყოვნებასა და რესურსების გამოყენებას შორის
    • span ატრიბუტების მაგალითი შეყოვნების ანალიზისთვის:
      database.query.duration_ms: 45.2
      http.request.duration_ms: 120.7
      cache.lookup_time_ms: 2.1
      business_logic.processing_time_ms: 15.8
      
  • ბოთლის ყელების იდენტიფიცირება
    • გააანალიზეთ კრიტიკული გზა მოთხოვნის დამუშავებაში
    • იპოვეთ ოპერაციები უმაღლესი შეყოვნების წვლილით
    • გამოავლინეთ კონკურენციის წერტილები და რესურსების შეზღუდვები
    • რაოდენობრივად შეაფასეთ გარე დამოკიდებულებების გავლენა
    • კვალზე დაფუძნებული ცხელი წერტილების ანალიზის ტექნიკა
    • ცხელი წერტილების დაფის მაგალითი, რომელიც აჩვენებს სერვისის შეყოვნების დაშლას
  • სერვისის დამოკიდებულებების ვიზუალიზაცია
    • შექმენით სერვისის დამოკიდებულების გრაფიკები
    • გააანალიზეთ ტრაფიკის ნიმუშები სერვისებს შორის
    • გამოთვალეთ შეცდომების სიხშირე სერვისების წყვილებს შორის
    • იდენტიფიცირეთ ზედმეტი ან არასაჭირო გამოძახებები
    • გამოავლინეთ წრიული დამოკიდებულებები
    • ვიზუალიზაციის ინსტრუმენტების მაგალითი:
      • Jaeger UI სერვისის გრაფიკი
      • Grafana სერვისის გრაფიკის პანელი
      • Kiali service mesh-ის ვიზუალიზაციისთვის
      • მორგებული D3.js ვიზუალიზაცია

მორგებული მეტრიკები

  • აპლიკაცია-სპეციფიური მეტრიკების გამოვლენა
    • იდენტიფიცირეთ ძირითადი ბიზნეს და ტექნიკური მეტრიკები
    • ინსტრუმენტირება გაუკეთეთ აპლიკაციის კოდს მეტრიკებით
    • გამოავლინეთ მეტრიკების ენდფოინთები (/metrics)
    • შექმენით მნიშვნელოვანი მეტრიკების სახელები და ლეიბლები
    • დააბალანსეთ კარდინალობა და სარგებლიანობა
    • მორგებული მეტრიკების მაგალითი:
      # მრიცხველი ბიზნეს მოვლენებისთვის
      order_total{status="completed",payment_method="credit_card"} 1550.75
      
      # საზომი აქტიური რესურსების გამოყენებისთვის
      active_user_sessions{region="us-west"} 1250
      
      # ჰისტოგრამა შეყოვნების განაწილებისთვის
      api_request_duration_seconds_bucket{endpoint="/api/v1/products",le="0.1"} 1500
      api_request_duration_seconds_bucket{endpoint="/api/v1/products",le="0.5"} 1950
      api_request_duration_seconds_bucket{endpoint="/api/v1/products",le="1.0"} 1990
      api_request_duration_seconds_bucket{endpoint="/api/v1/products",le="+Inf"} 2000
      
  • Prometheus კლიენტის ბიბლიოთეკების დანერგვა
    • გამოიყენეთ ოფიციალური კლიენტის ბიბლიოთეკები ენაზე-სპეციფიური ინსტრუმენტაციისთვის
    • შექმენით მრიცხველები, საზომები, ჰისტოგრამები და შეჯამებები
    • დაარეგისტრირეთ მეტრიკები registry-ში
    • დააყენეთ middleware სტანდარტული მეტრიკებისთვის
    • დაამატეთ მორგებული ლეიბლები ფილტრაციისა და აგრეგაციისთვის
    • იმპლემენტაციის მაგალითი (Python):
      from prometheus_client import Counter, Gauge, Histogram, Summary, start_http_server
      
      # მეტრიკების შექმნა
      REQUEST_COUNT = Counter('app_request_count', 'აპლიკაციის მოთხოვნების რაოდენობა', ['method', 'endpoint', 'status'])
      REQUEST_LATENCY = Histogram('app_request_latency_seconds', 'აპლიკაციის მოთხოვნის შეყოვნება', ['method', 'endpoint'])
      ACTIVE_SESSIONS = Gauge('app_active_sessions', 'აქტიური სესიები', ['region'])
      
      # მეტრიკების ენდფოინთის გაშვება
      start_http_server(8000)
      
      # მეტრიკების განახლება კოდში
      def process_request(request):
          ACTIVE_SESSIONS.labels(region='us-west').inc()
          
          with REQUEST_LATENCY.labels(method='POST', endpoint='/api/v1/order').time():
              # მოთხოვნის დამუშავება
              result = handle_request(request)
          
          REQUEST_COUNT.labels(method='POST', endpoint='/api/v1/order', status=result.status_code).inc()
          ACTIVE_SESSIONS.labels(region='us-west').dec()
          
          return result
      
  • მორგებული დაფების შექმნა
    • შექმენით დანიშნულება-სპეციფიური ვიზუალიზაციის პანელები
    • გააერთიანეთ ტექნიკური და ბიზნეს მეტრიკები
    • შექმენით drill-down შესაძლებლობები
    • გამოიყენეთ შესაბამისი ვიზუალიზაციის ტიპები
    • დანერგეთ დინამიური ცვლადები ფილტრაციისთვის
    • Grafana-ს დაფის JSON სტრუქტურის მაგალითი:
      {
        "title": "ელექტრონული კომერციის პლატფორმის დაფა",
        "panels": [
          {
            "title": "შეკვეთების მოცულობა გადახდის მეთოდის მიხედვით",
            "type": "barchart",
            "datasource": "Prometheus",
            "targets": [
              {
                "expr": "sum by(payment_method) (order_total)",
                "legendFormat": "{{payment_method}}"
              }
            ]
          },
          {
            "title": "API შეყოვნება (95-ე პროცენტილი)",
            "type": "timeseries",
            "datasource": "Prometheus",
            "targets": [
              {
                "expr": "histogram_quantile(0.95, sum(rate(api_request_duration_seconds_bucket[5m])) by (le, endpoint))",
                "legendFormat": "{{endpoint}}"
              }
            ]
          }
        ]
      }
      
  • რელევანტური ზღვრების დაყენება
    • განსაზღვრეთ SLI-ები (მომსახურების დონის ინდიკატორები) და SLO-ები (მომსახურების დონის მიზნები)
    • შექმენით შეტყობინების ზღვრები ბიზნეს გავლენაზე დაყრდნობით
    • დანერგეთ მრავალდონიანი ზღვრები (გაფრთხილება, კრიტიკული)
    • გამოიყენეთ ისტორიული მონაცემები საბაზისო ხაზების დასადგენად
    • გაითვალისწინეთ ტრაფიკის ნიმუშები და სეზონურობა
    • შეტყობინების ზღვრების მაგალითი:
      - alert: APIHighLatency
        expr: histogram_quantile(0.95, sum(rate(api_request_duration_seconds_bucket[5m])) by (le, endpoint)) > 0.5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "მაღალი API შეყოვნება {{ $labels.endpoint }}-ზე"
          description: "95-ე პროცენტილის შეყოვნება არის {{ $value }}წმ, რაც აჭარბებს SLO-ს 0.5წმ-ს"
      
  • კორელაცია ბიზნეს მეტრიკებთან
    • დააკავშირეთ ტექნიკური მეტრიკები ბიზნეს შედეგებთან
    • გაზომეთ კონვერსიის გავლენა წარმადობის პრობლემებზე
    • თვალყური ადევნეთ რესურსების გამოყენებასთან დაკავშირებულ ხარჯებს
    • შექმენით კომპოზიტური KPI დაფები
    • დანერგეთ ბიზნეს გავლენის შეფასება
    • კორელაციის მოთხოვნების მაგალითი:
      # კონვერსიის კოეფიციენტი vs. გვერდის ჩატვირთვის დრო
      sum(rate(purchase_completed_total[1h])) / sum(rate(product_page_view_total[1h]))
      
      # შემოსავლის გავლენა შეცდომებზე
      sum(rate(order_total{status="error"}[1h]))
      
      # მომხმარებლის კმაყოფილების კორელაცია
      rate(support_ticket_created{category="performance"}[1d]) / rate(active_user_sessions[1d])
      

ავტომატიზებული პასუხები

  • დანერგეთ ავტომასშტაბირება მეტრიკებზე დაყრდნობით
    • დააკონფიგურირეთ ჰორიზონტალური pod-ების ავტომასშტაბირება
    • გამოიყენეთ მორგებული მეტრიკები მასშტაბირების გადაწყვეტილებებისთვის
    • დააყენეთ შესაბამისი cooldown პერიოდები
    • დანერგეთ პროგნოზირებადი მასშტაბირება ცნობილი ნიმუშებისთვის
    • შეამოწმეთ მასშტაბირების ქცევა სხვადასხვა პირობებში
    • Docker Swarm სერვისის მასშტაბირების მაგალითი:
      # ავტომასშტაბირება docker service update-ით
      while true; do
        # მიმდინარე მეტრიკების მიღება
        REQUESTS=$(curl -s http://prometheus:9090/api/v1/query?query=sum\(rate\(http_requests_total\[1m\]\)\) | jq -r '.data.result[0].value[1]')
        
        # სასურველი რეპლიკების გამოთვლა (1 რეპლიკა 100 მოთხოვნაზე/წამში)
        DESIRED=$(echo "$REQUESTS / 100" | bc)
        if [ $DESIRED -lt 2 ]; then DESIRED=2; fi
        if [ $DESIRED -gt 10 ]; then DESIRED=10; fi
        
        # მიმდინარე რეპლიკების მიღება
        CURRENT=$(docker service ls --filter name=myapp --format "{{.Replicas}}" | cut -d '/' -f1)
        
        # მასშტაბირება საჭიროების შემთხვევაში
        if [ $DESIRED -ne $CURRENT ]; then
          echo "მასშტაბირება $CURRENT-დან $DESIRED რეპლიკამდე"
          docker service update --replicas $DESIRED myapp
        fi
        
        sleep 30
      done
      
  • დააკონფიგურირეთ ავტომატური აღდგენა წარუმატებელი კონტეინერებისთვის
    • დააყენეთ შესაბამისი გადატვირთვის პოლიტიკები
    • დანერგეთ ჯანმრთელობის შემოწმებები ზუსტი წარუმატებლობის გამოვლენისთვის
    • დააკონფიგურირეთ liveness და readiness probe-ები
    • დააფიქსირეთ დიაგნოსტიკური ინფორმაცია გადატვირთვამდე
    • დანერგეთ circuit breaker-ები დამოკიდებული სერვისებისთვის
    • Docker Compose კონფიგურაციის მაგალითი:
      services:
        app:
          image: myapp:latest
          restart: unless-stopped
          healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
            interval: 10s
            timeout: 5s
            retries: 3
            start_period: 40s
          deploy:
            restart_policy:
              condition: on-failure
              max_attempts: 3
              window: 120s
          logging:
            driver: "json-file"
            options:
              max-size: "10m"
              max-file: "3"
      
  • შექმენით runbook-ები გავრცელებული პრობლემებისთვის
    • დაადოკუმენტირეთ სტანდარტული პრობლემების მოგვარების პროცედურები
    • ჩართეთ დიაგნოსტიკური ბრძანებები და მოსალოდნელი გამომავალი მონაცემები
    • დაუკავშირეთ შეტყობინებები კონკრეტულ runbook-ის სექციებს
    • უზრუნველყავით ესკალაციის გზები გადაუჭრელი პრობლემებისთვის
    • შეინარჩუნეთ runbook-ების ვერსიების კონტროლი
    • runbook-ის სტრუქტურის მაგალითი:
      # API სერვისის მაღალი შეყოვნების Runbook
      
      ## სიმპტომები
      - API პასუხის დრო > 500ms (95-ე პროცენტილი)
      - გაზრდილი შეცდომების სიხშირე ქვედა დონის სერვისებში
      - შეტყობინება: APIHighLatency აქტიურია
      
      ## დიაგნოსტიკური ნაბიჯები
      1. შეამოწმეთ კონტეინერის რესურსების გამოყენება:
      
      docker stats api-service
      
      2. შეამოწმეთ მონაცემთა ბაზის კავშირების pool-ი:
      
      curl http://api-service:8080/actuator/metrics/hikaricp.connections.usage
      
      3. შეამოწმეთ ნელი მოთხოვნები:
      
      docker logs api-service | grep "slow query"
      
      ## გადაწყვეტის ნაბიჯები
      1. თუ კავშირების pool-ის გამოყენება > 80%:
      - გაზარდეთ pool-ის ზომა კონფიგურაციაში
      - გადატვირთეთ სერვისი `docker restart api-service`-ით
      
      2. თუ ნელი მოთხოვნები გამოვლინდა:
      - შეამოწმეთ მონაცემთა ბაზის ინდექსები
      - მოახდინეთ იდენტიფიცირებული მოთხოვნების ოპტიმიზაცია
      
      3. თუ CPU/მეხსიერების გამოყენება მაღალია:
      - მოახდინეთ სერვისის მასშტაბირება: `docker service scale api-service=3`
      
      ## ესკალაცია
      თუ პრობლემა 15 წუთის შემდეგ არ მოგვარდა:
      - დაუკავშირდით: [email protected]
      - Slack: #database-support
      
  • შეიმუშავეთ ავტომატიზებული გამოსწორება
    • დანერგეთ სკრიპტირებული პასუხები გავრცელებულ პრობლემებზე
    • შექმენით თვით-აღდგენის შესაძლებლობები
    • დაამატეთ circuit breaker-ები დეგრადირებული დამოკიდებულებებისთვის
    • დანერგეთ კორექტული დეგრადაციის რეჟიმები
    • დააბალანსეთ ავტომატიზაცია და ადამიანური ზედამხედველობა
    • ავტომატიზებული გამოსწორების სკრიპტის მაგალითი:
      #!/bin/bash
      # მონაცემთა ბაზის კავშირის ავტომატური გადატვირთვა
      
      # შეამოწმეთ კავშირის შეცდომები
      ERROR_COUNT=$(docker logs --since 5m db-service | grep "connection reset" | wc -l)
      
      if [ $ERROR_COUNT -gt 10 ]; then
        echo "მონაცემთა ბაზის კავშირის პრობლემები გამოვლინდა, გამოსწორების შესრულება"
        
        # დიაგნოსტიკის დაფიქსირება გამოსწორებამდე
        docker logs --since 15m db-service > /var/log/remediation/db-$(date +%s).log
        
        # გამოსწორების შესრულება
        docker exec db-service /scripts/connection-reset.sh
        
        # შესწორების ვერიფიკაცია
        sleep 5
        NEW_ERRORS=$(docker logs --since 1m db-service | grep "connection reset" | wc -l)
        
        # შეტყობინება შედეგზე
        if [ $NEW_ERRORS -eq 0 ]; then
          echo "გამოსწორება წარმატებულია" | slack-notify "#monitoring"
        else
          echo "გამოსწორება ვერ მოხერხდა, ესკალაცია" | slack-notify "#monitoring" --urgent
          # PagerDuty ინციდენტის გამოწვევა
          pagerduty-trigger "მონაცემთა ბაზის კავშირის პრობლემები გრძელდება გამოსწორების შემდეგ"
        fi
      fi
      
  • დააყენეთ ესკალაციის პოლიტიკები
    • განსაზღვრეთ მკაფიო ესკალაციის ზღვრები
    • შექმენით იარუსიანი რეაგირების გუნდები
    • დანერგეთ მორიგეობის როტაციის გრაფიკები
    • თვალყური ადევნეთ აღიარებისა და გადაწყვეტის საშუალო დროს
    • დაადოკუმენტირეთ კომუნიკაციის პროტოკოლები
    • ესკალაციის პოლიტიკის მაგალითი:
      # PagerDuty ესკალაციის პოლიტიკა
      escalation_policies:
        - name: "API სერვისის ესკალაცია"
          description: "ესკალაციის პოლიტიკა API სერვისის ინციდენტებისთვის"
          num_loops: 2
          escalation_rules:
            - escalation_delay_in_minutes: 15
              targets:
                - id: "PXXXXXX"  # პირველადი მორიგე ინჟინერი
                  type: "user_reference"
            - escalation_delay_in_minutes: 15
              targets:
                - id: "PXXXXXX"  # მეორადი მორიგე ინჟინერი
                  type: "user_reference"
            - escalation_delay_in_minutes: 30
              targets:
                - id: "PXXXXXX"  # ინჟინერიის მენეჯერი
                  type: "user_reference"
      

წარმადობის მონიტორინგი

საუკეთესო პრაქტიკების ჩამონათვალი

ლოგირების საუკეთესო პრაქტიკები

  • ლოგირება STDOUT/STDERR-ში
    • დაიცავით კონტეინერის საუკეთესო პრაქტიკები
    • ჩართეთ ცენტრალიზებული შეგროვება
    • მოერიდეთ ლოგ ფაილების მართვას კონტეინერებში
    • მიეცით Docker-ის ლოგირების დრაივერებს ტრანსპორტის დამუშავების საშუალება
    • მაგალითი: დააკონფიგურირეთ აპლიკაციები, რომ პირდაპირ დაწერონ stdout/stderr-ში და არა ლოგ ფაილებში
  • გამოიყენეთ სტრუქტურირებული ლოგირების ფორმატი
    • დანერგეთ JSON-ფორმატირებული ლოგები
    • ჩართეთ თანმიმდევრული მეტამონაცემების ველები
    • გამოიყენეთ სათანადო მონაცემთა ტიპები JSON-ში
    • დაამატეთ კორელაციის ID-ები მოთხოვნების თვალყურის დევნებისთვის
    • შეინარჩუნეთ სქემის თანმიმდევრულობა
    • სტრუქტურირებული ლოგის მაგალითი:
      {
        "timestamp": "2023-07-10T15:23:45.123Z",
        "level": "error",
        "service": "order-service",
        "message": "გადახდის დამუშავება ვერ მოხერხდა",
        "traceId": "abc123def456",
        "orderId": "order-789",
        "errorCode": "PAYMENT_DECLINED",
        "duration_ms": 345
      }
      
  • დანერგეთ ლოგების როტაცია
    • დააკონფიგურირეთ ზომასა და დროზე დაფუძნებული როტაცია
    • დააყენეთ შესაბამისი შენახვის პერიოდები
    • შეკუმშეთ როტირებული ლოგები
    • დააკვირდეთ დისკის გამოყენებას
    • მოახდინეთ როტაციის კორექტული დამუშავება
    • Docker-ის ლოგირების კონფიგურაციის მაგალითი:
      {
        "log-driver": "json-file",
        "log-opts": {
          "max-size": "20m",
          "max-file": "5",
          "compress": "true"
        }
      }
      
  • დააყენეთ შესაბამისი ლოგების დონეები
    • გამოიყენეთ DEBUG development გარემოსთვის
    • გამოიყენეთ INFO ან WARN production-ისთვის
    • დაარეზერვეთ ERROR ქმედითი პრობლემებისთვის
    • გახადეთ ლოგების დონეები კონფიგურირებადი runtime-ში
    • გამოიყენეთ თანმიმდევრული დონის განსაზღვრებები სერვისებში
    • ლოგის დონის კონფიგურაციის მაგალითი:
      logging:
        level:
          root: WARN
          com.example.api: INFO
          com.example.database: WARN
          com.example.payment: INFO
      
  • დააკონფიგურირეთ ცენტრალიზებული ლოგირება
    • მოახდინეთ ლოგების აგრეგაცია ყველა კონტეინერიდან
    • დანერგეთ სათანადო ინდექსირება და ძებნა
    • დააყენეთ ლოგების პარსინგი და ნორმალიზაცია
    • დააკონფიგურირეთ წვდომის კონტროლი ლოგებისთვის
    • დაადგინეთ შენახვისა და არქივირების პოლიტიკები
    • EFK სტეკის დაყენების მაგალითი:
      • Filebeat ან Fluentd ლოგების შესაგროვებლად
      • Elasticsearch შენახვისა და ინდექსირებისთვის
      • Kibana ვიზუალიზაციისა და ძებნისთვის
      • Curator ინდექსის სასიცოცხლო ციკლის მართვისთვის
  • მოერიდეთ მგრძნობიარე მონაცემებს ლოგებში
    • დანერგეთ მონაცემთა მასკირება PII-სთვის
    • არასდროს დალოგოთ რწმუნებათა სიგელები ან საიდუმლოებები
    • შეამოკლეთ პოტენციურად დიდი payload-ები
    • წაშალეთ მგრძნობიარე ჰედერები
    • მოახდინეთ პერსონალური იდენტიფიკატორების ანონიმიზაცია
    • მასკირების იმპლემენტაციის მაგალითი:
      function logRequest(req) {
        const sanitized = {
          method: req.method,
          path: req.path,
          query: sanitizeObject(req.query),
          headers: sanitizeHeaders(req.headers),
          body: sanitizeObject(req.body)
        };
        logger.info({ request: sanitized }, "შემომავალი მოთხოვნა");
      }
      
      function sanitizeObject(obj) {
        const masked = {...obj};
        const sensitiveFields = ['password', 'token', 'ssn', 'credit_card'];
        
        for (const field of sensitiveFields) {
          if (masked[field]) masked[field] = '***REDACTED***';
        }
        return masked;
      }
      

მონიტორინგის საუკეთესო პრაქტიკები

  • მონიტორინგი გაუწიეთ როგორც ჰოსტს, ასევე კონტეინერებს
    • თვალყური ადევნეთ ჰოსტის დონის რესურსებს (CPU, მეხსიერება, დისკი, ქსელი)
    • დააკვირდეთ კონტეინერ-სპეციფიკურ მეტრიკებს
    • კორელაცია მოახდინეთ კონტეინერის წარმადობასა და ჰოსტის შეზღუდვებს შორის
    • დააკვირდეთ "ხმაურიანი მეზობლის" პრობლემებს
    • თვალყური ადევნეთ Docker daemon-ის ჯანმრთელობას
    • მონიტორინგის სტეკის მაგალითი:
      • Node Exporter ჰოსტის მეტრიკებისთვის
      • cAdvisor კონტეინერის მეტრიკებისთვის
      • Docker daemon-ის მეტრიკების ენდფოინთი
      • პროცეს-სპეციფიური მეტრიკები აპლიკაციებიდან
  • დანერგეთ შეტყობინებები შესაბამისი ზღვრებით
    • შექმენით მრავალდონიანი შეტყობინებები (გაფრთხილება/კრიტიკული)
    • მოერიდეთ შეტყობინებების დაღლილობას სათანადო ზღვრებით
    • ჩართეთ runbook-ის ბმულები შეტყობინებებში
    • დააჯგუფეთ დაკავშირებული შეტყობინებები ხმაურის შესამცირებლად
    • დანერგეთ შეტყობინებების დედუპლიკაცია
    • შეტყობინებების კონფიგურაციის მაგალითი:
      - alert: ContainerHighCpuUsage
        expr: rate(container_cpu_usage_seconds_total{name!=""}[1m]) * 100 > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "კონტეინერის CPU-ს მაღალი გამოყენება ({{ $labels.name }})"
          description: "კონტეინერის CPU-ს გამოყენება 80%-ზე მეტია 5 წუთის განმავლობაში"
          runbook_url: "https://wiki.example.com/runbooks/container-cpu"
      
  • გამოიყენეთ ვიზუალიზაციის დაფები
    • შექმენით როლ-სპეციფიური დაფები
    • ჩართეთ როგორც მიმოხილვის, ასევე დეტალური ხედები
    • გამოიყენეთ შესაბამისი ვიზუალიზაციის ტიპები
    • დანერგეთ შაბლონის ცვლადები ფილტრაციისთვის
    • დააბალანსეთ ინფორმაციის სიმჭიდროვე და წაკითხვადობა
    • დაფის ორგანიზაციის მაგალითი:
      • აღმასრულებელი მიმოხილვა: მაღალი დონის ჯანმრთელობა და KPI-ები
      • ოპერაციების დაფა: სისტემის ჯანმრთელობა და რესურსების გამოყენება
      • დეველოპერის დაფა: აპლიკაციის წარმადობა და შეცდომები
      • სერვის-სპეციფიური დაფები: დეტალური მეტრიკები თითოეული სერვისისთვის
      • მორიგეობის დაფა: მიმდინარე შეტყობინებები და ბოლო ინციდენტები
  • თვალყური ადევნეთ ბიზნეს-რელევანტურ მეტრიკებს
    • დააკვირდეთ ძირითად წარმადობის ინდიკატორებს (KPI)
    • შექმენით ბიზნეს-ტექნიკური კორელაციის ხედები
    • გაზომეთ მომხმარებლის გამოცდილების მეტრიკები
    • თვალყური ადევნეთ კონვერსიისა და ჩართულობის მეტრიკებს
    • დააკვირდეთ ტრანზაქციის ღირებულებასა და მოცულობას
    • ბიზნეს მეტრიკების მაგალითი:
      # ბიზნეს მეტრიკები Prometheus ფორმატში
      # HELP order_value_total შეკვეთების ჯამური ღირებულება ვალუტაში
      # TYPE order_value_total counter
      order_value_total{currency="USD",status="completed"} 15234.50
      
      # HELP checkout_started დაწყებული checkout პროცესების ჯამური რაოდენობა
      # TYPE checkout_started counter
      checkout_started 5423
      
      # HELP checkout_completed დასრულებული checkout პროცესების ჯამური რაოდენობა
      # TYPE checkout_completed counter
      checkout_completed 4231
      
  • დანერგეთ ჯანმრთელობის შემოწმებები
    • შექმენით მნიშვნელოვანი აპლიკაციის health ენდფოინთები
    • შეამოწმეთ დამოკიდებულებები health probe-ებში
    • დანერგეთ readiness vs. liveness გამიჯვნა
    • გახადეთ health check-ები მსუბუქი
    • ჩართეთ ვერსიისა და დამოკიდებულების ინფორმაცია
    • ჯანმრთელობის შემოწმების ენდფოინთის მაგალითი:
      app.get('/health', async (req, res) => {
        try {
          // შეამოწმეთ მონაცემთა ბაზის კავშირი
          const dbStatus = await checkDatabase();
          
          // შეამოწმეთ ქეშის სერვისი
          const cacheStatus = await checkRedis();
          
          // შეამოწმეთ გარე API დამოკიდებულება
          const apiStatus = await checkExternalApi();
          
          const allHealthy = dbStatus && cacheStatus && apiStatus;
          
          res.status(allHealthy ? 200 : 503).json({
            status: allHealthy ? 'healthy' : 'unhealthy',
            version: '1.2.3',
            timestamp: new Date().toISOString(),
            components: {
              database: dbStatus ? 'up' : 'down',
              cache: cacheStatus ? 'up' : 'down',
              api: apiStatus ? 'up' : 'down'
            }
          });
        } catch (error) {
          res.status(500).json({ status: 'error', error: error.message });
        }
      });
      
  • დაგეგმეთ მონიტორინგის მასშტაბირებადობა
    • დააპროექტეთ კონტეინერების რაოდენობის ზრდისთვის
    • დანერგეთ მეტრიკების აგრეგაცია მაღალი კარდინალობის მონაცემებისთვის
    • გამოიყენეთ შესაბამისი შენახვის პოლიტიკები
    • განიხილეთ რესურსების მოთხოვნები მონიტორინგის ინსტრუმენტებისთვის
    • დანერგეთ ფედერაცია ფართომასშტაბიანი deployment-ებისთვის
    • მასშტაბირებადობის ტექნიკის მაგალითი:
      • Prometheus-ის იერარქიული ფედერაცია
      • სერვისების აღმოჩენა დინამიური გარემოსთვის
      • მეტრიკების აგრეგაცია და downsampling
      • მეტრიკების sharding სერვისის ან namespace-ის მიხედვით
      • მორგებული ჩაწერის წესები გავრცელებული მოთხოვნებისთვის
      # ჩაწერის წესები ეფექტური გამოთხოვისთვის
      groups:
      - name: container_aggregation
        interval: 1m
        rules:
        - record: job:container_cpu:usage_rate5m
          expr: sum(rate(container_cpu_usage_seconds_total[5m])) by (job)
        - record: job:container_memory:usage_bytes
          expr: sum(container_memory_usage_bytes) by (job)