Архив рубрики: Разное

Prometheus. Сбор метрик php-fpm.

Подготовка к сборке метрик php-fpm делится на несколько этапов:
— редактирование конфиг пула;
— пробросить доступ к статусам PHP-FPM;
— запуск экспортера.

Настройка пула.
Настройки пула хранятся в файле www.conf. Хочу обратить ваше внимание, что файл может располагаться в разных места, например:
— /etc/php-fpm.d/www.conf
— /etc/php/7.3/fpm/pool.d/www.conf

Первым делом открываем к статистике, для этого нужно задать параметр pm.status_path. Раскомментируем строку с этим параметром:

# vim www.conf
...
pm.status_path = /status
...
ping.path = /ping
...

Задавать параметр ping.path необязательно.

Важно проверить проверить адрес, по которому принимаются запросы FastCGI, за это отвечает параметр listen:

# cat /etc/php-fpm.d/www.conf |grep -e 'listen =' 

listen = 127.0.0.1:9000

Адрес может быть в формате ip.address:port, либо ссылка на php-socket:

# cat /etc/php/7.3/fpm/pool.d/www.conf |grep -e 'listen ='
listen = /run/php/php7.3-fpm.sock

От значения параметра listen будет зависеть следующий пункт настройки.

Настройка Nginx.
Опустим основную настройку Nginx, в данном случаем нам нужно лишь пробросить страницу со статусами для экспортера.

для этого достаточно добавить в конфиг следующие строки:

location ~ ^/(status|ping)$ {
allow all;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
include fastcgi_params;
}

Если пул был настрое на сокет, то параметр fastcgi_pass будет иметь значение: fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
Важно отметить, если вы используете это на проде, то заменить параметр allow all; на необходимые адреса или подсети, а остальным запретить доступ параметром deny all;

В целом примерный конфиг будет выглядеть так:

server {
    server_name localhost;
    listen   9000; 

    location ~ ^/(status|ping)$ {
        allow 172.0.0.0/32;
        allow 127.0.0.1/32;
        deny all;
        fastcgi_pass 127.0.0.1:9000;
        #fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 16k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;
        include fastcgi_params;
    }

}

Убедимся что все работает, открываем станицу или кидаем curl для проверки промежуточного результата:

Вывод curl на соответствующий адрес:

# curl localhost:9000/status
...
pool:                 www
process manager:      dynamic
start time:           12/Dec/2019:13:43:47 +0300
start since:          78
accepted conn:        4
listen queue:         0
max listen queue:     0
listen queue len:     128
idle processes:       4
active processes:     1
total processes:      5
max active processes: 1
max children reached: 0
slow requests:        0

Все работает, остался финальный этап.

Запуск экспортера.

Официальном сайт Prometheus предлагает php-fpm-exporter за авторством bakins, его и будем использовать.

Рассмотрим параметры запуска php-fpm-exporter:

# php-fpm-exporter --help

usage: php-fpm-exporter [<flags>]

Flags:
  -h, --help                   Show context-sensitive help (also try --help-long and --help-man).
      --addr="127.0.0.1:8080"  listen address for metrics handler
      --endpoint="http://127.0.0.1:9000/status"  
                               url for php-fpm status
      --fastcgi=FASTCGI        fastcgi url. If this is set, fastcgi will be used instead of HTTP
      --web.telemetry-path="/metrics"  
                               Path under which to expose metrics. Cannot be /

Нужно определиться как запускать эксопртер:
— в контейнере;
— локально запустить как процесс.

Для запуска в докер контейнере рекомендую пример от Флант.
При запуске контейнера пробрасываем порты с 8080 на нужный:

docker run -d -p 9000:8080 --name php-fpm-exporter php-fpm-exporter

Запуск как процесс более хлопотный.
Можно скачать уже готовый экспортер с репозитория bakins. Мы же пройдем весь путь сначала.

Первым делом клонируем репозиторий и собираем экспортер:
Для сборки потребуется пакет golang

# git clone https://github.com/bakins/php-fpm-exporter.git
# cd php-fpm-exporter
# ./script/build
...
+ NAME=php-fpm-exporter
+ ARCH=amd64
+ export GOFLAGS=-mod=vendor
+ GOFLAGS=-mod=vendor
+ export GO111MODULE=on
+ GO111MODULE=on
+ for OS in darwin linux
+ FILE=php-fpm-exporter.darwin.amd64
+ CGO_ENABLED=0
+ GOOS=darwin
+ GOARCH=amd64
+ go build -o php-fpm-exporter.darwin.amd64 ./cmd/php-fpm-exporter
++ openssl sha256 php-fpm-exporter.darwin.amd64
++ awk '{print $2}'
+ SHA=b9b5203821aa158221002abed322572a9d0a95df58d26cb35d74b7dc60d6d907
+ echo 'b9b5203821aa158221002abed322572a9d0a95df58d26cb35d74b7dc60d6d907 php-fpm-exporter.darwin.amd64'
+ for OS in darwin linux
+ FILE=php-fpm-exporter.linux.amd64
+ CGO_ENABLED=0
+ GOOS=linux
+ GOARCH=amd64
+ go build -o php-fpm-exporter.linux.amd64 ./cmd/php-fpm-exporter
++ openssl sha256 php-fpm-exporter.linux.amd64
++ awk '{print $2}'
+ SHA=e53c1392bb5ef2297b1b8487a75fa87c9c1f06c9f76d1da7b35523d94922a6d8
+ echo 'e53c1392bb5ef2297b1b8487a75fa87c9c1f06c9f76d1da7b35523d94922a6d8 php-fpm-exporter.linux.amd64'
...

Теперь запустим экспортер

# chmod +x php-fpm-exporter.linux.amd64
# cp php-fpm-exporter.linux.amd64 /usr/share/php-fpm-exporter
# php-fpm-exporter

Если во втором пункте при настройки страницы со статусом вы указали нестандартный порт(порт по умолчанию 9000), то при запуске экспортера задаем ключ —endpoint. Если вы хотите отрыть доступ к станице с метриками по нестандартному порту запускаем экспортер с ключем —addr:

# php-fpm-exporter --addr=192.168.122.10:10202 --endpoint http://localhost:10101/status > /dev/null &

После всех действий проверяем доступность метрик, заходим на страницу http://192.168.122.10:10202/metrics:

Вывод curl страницы с метриками:

# curl 192.168.122.10:10202/metrics
...
# HELP phpfpm_accepted_connections_total Total number of accepted connections
# TYPE phpfpm_accepted_connections_total counter
phpfpm_accepted_connections_total 12
# HELP phpfpm_active_max_processes Maximum active process count
# TYPE phpfpm_active_max_processes counter
phpfpm_active_max_processes 1
# HELP phpfpm_listen_queue_connections Number of connections that have been initiated but not yet accepted
# TYPE phpfpm_listen_queue_connections gauge
phpfpm_listen_queue_connections 0
# HELP phpfpm_listen_queue_length_connections The length of the socket queue, dictating maximum number of pending connections
# TYPE phpfpm_listen_queue_length_connections gauge
phpfpm_listen_queue_length_connections 0
# HELP phpfpm_listen_queue_max_connections Max number of connections the listen queue has reached since FPM start
# TYPE phpfpm_listen_queue_max_connections counter
phpfpm_listen_queue_max_connections 0
# HELP phpfpm_max_children_reached_total Number of times the process limit has been reached
# TYPE phpfpm_max_children_reached_total counter
phpfpm_max_children_reached_total 0
# HELP phpfpm_processes_total process count
# TYPE phpfpm_processes_total gauge
phpfpm_processes_total{state="active"} 1
phpfpm_processes_total{state="idle"} 1
# HELP phpfpm_scrape_failures_total Number of errors while scraping php_fpm
# TYPE phpfpm_scrape_failures_total counter
phpfpm_scrape_failures_total 0
# HELP phpfpm_slow_requests_total Number of requests that exceed request_slowlog_timeout
# TYPE phpfpm_slow_requests_total counter
phpfpm_slow_requests_total 0
# HELP phpfpm_up able to contact php-fpm
# TYPE phpfpm_up gauge
phpfpm_up 1

Возможные ошибки.

Если страница метрик отдает следующее содержание:

#curl 192.168.122.22:10202/metrics 
...
# HELP phpfpm_scrape_failures_total Number of errors while scraping php_fpm
# TYPE phpfpm_scrape_failures_total counter
phpfpm_scrape_failures_total 2
# HELP phpfpm_up able to contact php-fpm
# TYPE phpfpm_up gauge
phpfpm_up 0

Из вывода видно, что мы получили phpfpm_up 0, это значит, что экспортер не может получить статистику php-fpm со страницы, которую мы настраивали в Nginx.

Проверяем работу php-fpm, открывается ли localhost:9000/status. Если страница /status не на 9000, смотрим как запустить экспортер ссылкой на нужный адрес.

Полезные ссылки:
flant/php-fpm-exporter
bakins/php-fpm-exporter
Список рекомендуемых экспортеров

0

сurl. Кинуть запрос на определенный адрес.

Иногда возникают ситуации, когда нам надо кинуть запрос на адрес, но с условием, чтобы имя резолвилось на определенный адрес.
Это можно сделать с помощью утилиты curl с ключом —resolve:

~ curl --help
...
--resolve <host:port:address[,address]...> Resolve the host+port to this address
...

 ~ ping google.com
PING google.com (74.125.205.101) 56(84) bytes of data.

 ~ ping google.com
PING google.com (74.125.205.102) 56(84) bytes of data.

~ curl --resolve google.com:443:74.125.205.102 -k  'https://google.com/' 

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>

Используя ключ —resolve , curl может сделать запросы, используя заданный адрес и предотвращая перезапись нормально разрешенных адресов. Это некоторая альтернатива /etc/hosts в командной строке. Порт должен позволять работать с необходимым протоколом.

Допустим у Вас есть сервис https://myAPP.srv.local/ за балансировщиком и резолвится по нескольким адресам:
192.168.1.20
192.168.1.21

У сервиса есть healthcheck, который отдает информацию о состоянии. Однако же при попадании на https://health.myAPP.srv.local/ иногда мы получаем ошибку, например, «ERR_SSL_UNRECOGNIZED_NAME_ALERT».

Отлавливаем curl’ом эту ошибку:

 ~ curl -k -X GET 'https://health.myAPP.srv.local/' 
...
OK
...

 ~ curl -k -X GET 'https://health.myAPP.srv.local/'
curl: (35) error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name

Мы знаем на какие адреса резолвится имя, проверяем конкретно по адресам:

 ~ curl --resolve health.myAPP.srv.local:443:192.168.1.20 -k -X GET 'https://health.myAPP.srv.local/' 
...
OK
...

 ~ curl --resolve health.myAPP.srv.local:443:192.168.1.21 -k -X GET 'https://health.myAPP.srv.local/'
curl: (35) error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name

Таким образом мы выявили на каком именно узле у нас проблема, правим сертификат на хосте 192.168.1.21 и можно считать траблшутинг успешным.

0

Kubernetes. Taints and Tolerations. Запуск подов на мастере.

При первых опытах с Kubernetes возникает проблема, когда Вы разворачиваете одну или несколько нод-мастеров в кластере, служебные поды запускаются и работают, но при попытки развернуть pod с каким-либо сервисом, он зависает в статусе Pending и мы получаем ошибку: «0/1 nodes are available: 1 node(s) had taints that the pod didn’t tolerate.»

И так, что мы имеем?

Есть кластер, с одной нодой:

# kubectl get nodes
NAME           STATUS   ROLES    AGE   VERSION
k8s-master-1   Ready    master   16h   v1.16.3

Служебные поды работают:

# kubectl get po -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
coredns-5644d7b6d9-bqsfm               1/1     Running   0          16h
coredns-5644d7b6d9-h5rr5               1/1     Running   0          16h
etcd-k8s-master-1                      1/1     Running   0          16h
kube-apiserver-k8s-master-1            1/1     Running   0          16h
kube-controller-manager-k8s-master-1   1/1     Running   0          16h
kube-flannel-ds-amd64-nmszk            1/1     Running   0          16h
kube-proxy-sw84w                       1/1     Running   0          16h
kube-scheduler-k8s-master-1            1/1     Running   0          16h

Однако же поды которые вы создаете сами остаются в статусе Pending:

# kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubia-b2cgm   0/1     Pending   0          15h

Смотрим состояние пода:

# kubectl describe po kubia-b2cgm 
...
Type     Reason            Age                From               Message
----     ------            ----               ----               -------
Warning  FailedScheduling  51s (x15 over 3m)  default-scheduler  0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.

В чем же дело?

Ответ на этот вопрос изложен в официальной документации в статье «Taints and Tolerations».

Вкратце, в Kubernetes реализована политика разграничение ролей узлов кластера, ограничивающая установку тех или иных подов на «зараженные» поды.

Как быть, что делать?

Первый делом проверяем свойство ноды на предмет наличия установленной политики:

# kubectl describe nodes k8s-master-1 |grep Taints
...
Taints:             node-role.kubernetes.io/master:NoSchedule
...

Согласно вышеупомянутой документации, мы можем сделать вывод, что нода k8s-master-1 в статусе master:NoSchedule

Это означает, что ни один под не сможет планировать развертывание на узел k8s-master-1, если у него нет соответствующего допуска.

И тут у нас есть два варианта развития событий:
— Предоставить соответствующий допуск самому поду.
— Отключить эту политику для данного узла.

Вариант 1. Выдать допуск поду.

В манифесте указываем допуск:

tolerations:
- key: node-role.kubernetes.io/master
  operator: "Exists"
  effect: NoSchedule 

Пример создание Replication Controller для подов с допуском:

apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    app: kubia
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia
        ports:
        - containerPort: 8080
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: "Exists"
        effect: NoSchedule 

Этот способ подходи только в том случае, если Вы выносите самописные поды. При установки подов с помощью Helm нужно указывать tolerations отдельным ключом.

Вариант 2. Отключить политику в Taints.

Отключаем политику на ноде k8s-master-1:

# kubectl taint nodes k8s-master-1 node-role.kubernetes.io/master- 

Проверяем состояние ноды:

# kubectl describe nodes k8s-master-1 |grep Taints
...
Taints:             <none>
...

Данный способ более универсальный и не привязывает нас к модификациям манифестов.

Первоисточник:
— статья «Taints and Tolerations».
— Книга «Kubernetes в действии» автор Лукша Марко.

0

Gitlab. Mirroring repositories.

При необходимости переноса проекта из стороннего репозиторияв в Ваш локальный, Gitlab предлагает инструмент Mirroring repositories.

Зеркалирование в Gitlab поддерживает два режима:
Push: зеркалирование проекта из локального Gilbab в удаленный репозиторий.
Pull: зеркалирование проекта из удаленного репозитория в локальный Gilbab.

Рассмотрим функциональность инструмента Mirroring repositories на примере зеркалирования проекта из удаленного Atlassian Bitbucket в локальный Gitlab.

Создаем новый проект, далее переходим в настройки этого проекта и добавляем уделенный репозиторий:

Projects > Setting > Repository > Mirroring repositories

Git repository URL: адрес удаленного репозитория
Mirror direction: в нашем случае это Pull
Authentication method: в нашем случае это аутентификация по паролю, но можно и по SSH-ключу.
Password: сам пароль.
Mirror user: пользователь от которого осуществляется настройка.
Так же стоит активировать функцию Overwrite diverged branches, она позволит перезаписывать проект, если версии веток разошлись между репозиториями.

После настройки первая синхронизация займет некоторое время.

Готово, теперь репозиторий будет обновляться каждые ~30 минут. Так же можно форсировать синхронизацию кнопкой «Update now»

Как это работает согласно официальной документации:

Как только функция Mirroring repositories включена для хранилища, хранилище добавляется в очередь.

Раз в минуту задание Sidekiq cron планирует обновления зеркал репозитория на основе:
— Доступности Sidekiq.
— Количество зеркал репозитория, уже находящихся в очереди, которые должны быть обновлены. Срок выполнения зависит от того, когда зеркало хранилища последний раз обновлялось, и сколько раз оно повторялось.

Зеркала репозитория обновляются, когда Sidekiq становится доступным для их обработки. Если процесс обновления зеркала репозитория:
— Успешно, обновление будет снова поставлено в очередь, по крайней мере, через 30 минут.
— Сбой (например, ветвь отклонена от восходящего направления), попытка будет предпринята позже. Зеркала могут выходить из строя до 14 раз, прежде чем они не будут поставлены в очередь для обновления снова (об этом моменте сы поговорим чуть позже).

Возможные ошибки.

При синхронизации проектов я столкнулся с проблемой наличия недопустимых имен веток в удаленном репозитории.

Репозитории синхронизировались, данные внутри обновлялись, но я получал ошибку «Branch name is invalid».

Как быть, что делать?
Смотрим ветки в нашем локальном репозитории, смотрим ветки в удаленном репозитории в Bitbucket. Оказалось у нас не хватает одной ветки с именем «-readmemd-1572439278772», которая не прошла проверку на доступность имени и не синхронизировалась в наш Gilbab

 ~ git branch -a
...
remotes/origin/------------/-readmemd-1572439278772
...

В нашем случае мы попросили удалить эту ветку, т.к. она была не актуальна.

Первоисточник: https://docs.gitlab.com/ee/user/project/repository/repository_mirroring.html
Тикет на ошибку «Branch name is invalid: https://gitlab.com/gitlab-org/gitlab/issues/35804

0

Elasticsearch. Настройка ILM

Статья является вольной интерпретацией оригинальной статьи из документации Elastic.

В Elasticsearch благодаря функционалу управления жизненным циклом индекса (index lifecycle management, сокращенно ILM) стало доступным управлять состоянием индекса, замораживать, сжимать или вовсе удалять его.

В этой статье будет показан простой пример удаления индекса спустя указанный промежуток времени в Elasticsearch v. 7.3.2.

Настроить правила жизненного цикла индекса и применить их к индексу можно двумя способами:
1. По средством Dev Tools в интерфейсе Kibana или curl из консоли терминала, если Kibana не используется в кластере.
2. Либо настроить политику использую интерфейс Kibana во вкладке Management > Index Lifecycle Policies.

Сперва рассмотрим первый вариант и создадим политику с помощью запроса во вкладке Dev Tools.

Настройка через консоль Dev Tools.

Проверяем список уже имеющихся политик:

GET _ilm/policy

По умолчанию будет присутствовать стандартная политика watch-history-ilm-policy:

{
  "watch-history-ilm-policy" : {
    "version" : 1,
    "modified_date" : "2019-07-02T07:58:10.186Z",
    "policy" : {
      "phases" : {
        "delete" : {
          "min_age" : "7d",
          "actions" : {
            "delete" : { }
          }        }      }    }  }}

Создадим собственное правило:

PUT _ilm/policy/filebeat-7.3.2  
{
  "policy": {                       
    "phases": {
      "warm": {                      
        "actions": {
          "rollover": {             
            "max_size": "1GB",
            "max_age": "1h"
          }
        }
      },
      "delete": {
        "min_age": "1h",           
        "actions": {
          "delete": {}              
        }
      }
    }
  }
}

Давайте подробнее рассмотрим наше действие и разберем основные параметры запроса.
PUT _ilm/policy/filebeat-7.3.2 — создаем политику и именем filebeat-7.3.2.
«phases»: «warm» — Определяем фазу в которой окажется индекс. Подробнее про фазы ILM.
«actions»: «rollover» — Определяем действие, которое произойдет с индексом в зависимости от параметров.
«max_size»: «1GB» — Определяем первый параметр для перехода индекса в другую стадию — максимальный размер индекса.
«max_age»: «1h» — Определяем второй параметр — возраст индекса.
«delete»: «min_age»: «1h» — по достижению одного из вышеперечисленных параметров спустя указанное время (1 час) индекс удлалиться.
«actions»: «delete» — Определяем действие для удаления индекса.

Получаем положительный ответ «acknowledged» : true.
Вновь проверяем список политик:

GET _ilm/policy

Видим новое правило filebeat-7.3.2, которое мы создали:

{
  "filebeat-7.3.2" : {
    "version" : 1,   //версия правила, будет расти после каждого изменения. Немного подробнее ниже.
    "modified_date" : "2019-09-23T13:40:33.031Z", //дата изменения
    "policy" : {
      "phases" : {
        "hot" : {
          "min_age" : "0ms",
          "actions" : {
            "rollover" : {
              "max_size" : "1gb",
              "max_age" : "1h"
            }
          }
        },
        "delete" : {
          "min_age" : "1h",
          "actions" : {
            "delete" : { }          }        }      }    }  },
  "watch-history-ilm-policy" : {
    "version" : 1,
    "modified_date" : "2019-07-02T07:58:10.186Z",
    "policy" : {
      "phases" : {
        "delete" : {
          "min_age" : "7d",
          "actions" : {
            "delete" : { }          }        }      }    }  }}

После создания правила, его необходимо применить непосредственно к индексам. Можно применить правила как для одного конкретного индекса (что в целом не имеет смысла), так и для темплейта в целом.

Создание темплейта для индексов :
Внимание, если template с именем filebeat-7.3.2 уже существует, следующее действие его перезапишет

PUT _template/filebeat-7.3.2
{
  "index_patterns": ["filebeat-7.3.2-*"],                 
  "settings": {
    "index.lifecycle.name": "filebeat-7.3.2" 
  }
}

В настройка шаблона мы указали какие индексы подпадают под шаблон «index_patterns»: [«filebeat-7.3.2-*»], т.е. все индексы которые начинаются с filebeat-7.3.2-, какую политику использовать индексам «index.lifecycle.name»: «filebeat-7.3.2».

Важно помнить, что если вы используете filebeat 7 версии, то он создает темплейт в Elasticsearch уже с указанием используемой политики:
Посмотрим стандартный шаблон который создаем сам filebeat

GET _template/filebeat-7.3.2

Мы видим, что он по умолчанию использует политику с именем filebeat-7.3.2, даже если она еще не создана.

{
  "filebeat-7.3.2" : {
    "order" : 1,
    "index_patterns" : [
      "filebeat-7.3.2-*"
    ],
    "settings" : {
      "index" : {
        "lifecycle" : {
          "name" : "filebeat-7.3.2",
          "rollover_alias" : "filebeat-7.3.2"
...

В идеале создать отдельный теплейт для с паттерном индексов filebeat-7.3.2-* параллельно стандартному темплейту filebeat.

Вернемся непосредственно к ILM.
После создания политики и применения ее индексам можем проверить состояние жизненного цикла индекса:
— для всех индексов:

GET filebeat-7.3.2-*/_ilm/explain

Получаем информацию о текущих стадиях всех индексов

{
  "indices" : {
    "filebeat-7.3.2-2019.09.23-000004" : {
      "index" : "filebeat-7.3.2-2019.09.23-000004",
      "managed" : true,
      "policy" : "filebeat-7.3.2",
      "lifecycle_date_millis" : 1569248425250,
      "phase" : "warm",
      "phase_time_millis" : 1569248426531,
      "action" : "complete",
      "action_time_millis" : 1569248485680,
      "step" : "complete",
      "step_time_millis" : 1569248485680,
      "phase_execution" : {
        "policy" : "filebeat-7.3.2",
        "phase_definition" : {
          "min_age" : "0ms",
          "actions" : {
            "shrink" : {
              "number_of_shards" : 1
            }          }        },
        "version" : 2,
        "modified_date_in_millis" : 1569237244490
      }    },
    "filebeat-7.3.2-2019.09.23-000005" : {
      "index" : "filebeat-7.3.2-2019.09.23-000005",
      "managed" : true,
      "policy" : "filebeat-7.3.2",
      "lifecycle_date_millis" : 1569248424138,
      "phase" : "hot",
      "phase_time_millis" : 1569248425501,
      "action" : "rollover",
      "action_time_millis" : 1569248485824,
      "step" : "check-rollover-ready",
      "step_time_millis" : 1569248485824,
      "phase_execution" : {
        "policy" : "filebeat-7.3.2",
        "phase_definition" : {
          "min_age" : "0ms",
          "actions" : {
            "rollover" : {
              "max_size" : "50mb",
              "max_age" : "1h"
            }
          }
        },
        "version" : 2,
        "modified_date_in_millis" : 1569237244490
      }    }  }}

— для конкретного индекса (вместо * указываем полное имя индекса):

GET filebeat-7.3.2-*/_ilm/explain

GET filebeat-7.3.2-2019.09.23-000004/_ilm/explain

Получаем информацию о текущей стадии на которой находится индекс:

{
  "indices" : {
    "filebeat-7.3.2-2019.09.23-000004" : {
      "index" : "filebeat-7.3.2-2019.09.23-000004",
      "managed" : true,
      "policy" : "filebeat-7.3.2",
      "lifecycle_date_millis" : 1569248425250,
      "phase" : "warm",
      "phase_time_millis" : 1569248426531,
      "action" : "complete",
      "action_time_millis" : 1569248485680,
      "step" : "complete",
      "step_time_millis" : 1569248485680,
      "phase_execution" : {
        "policy" : "filebeat-7.3.2",
        "phase_definition" : {
          "min_age" : "0ms",
          "actions" : {
            "shrink" : {
              "number_of_shards" : 1
            }
          }
        },
        "version" : 2,
        "modified_date_in_millis" : 1569237244490
      }    }  }}

Стоит обратить внимание, на параметры:
— «phase» : «hot»\»warm» — текущая стадия индекса
— «action» : «rollover»\»complete» — ожидаемое действие
— «step» : «check-rollover-ready»\»complete» — текущий шаг
— «version» : 2 — используемая версия правила.

Остановимся подробнее на параметре version. Важно помнить, что при изменении политики меняется и ее версия. Однако индексы автоматически не меняют используемую версию политики. Говоря простым языком, после изменения настрое политики, индексы не применят эти изменения и останутся на старой версии.

Создание правила через интерфейс Kibana

Настроить политику можно использую интерфейс Kibana, переходим во вкладку Management > Index Lifecycle Policies и нажимаем кнопку «Create policy«.

Настраиваем необходимые параметры, в нашем случае необходимо включить функцию Delete phase, заполняем остальные поля по примеру:

После заполнения нужных полей можно нажать кнопку «Show JSON«, чтобы увидеть как наш конфиг будет выглядеть в json. Его же можно использовать во вкладке Dev Tools.

Далее создаем template во вкладке Dev Tools, об этом описано выше, не буду повторяться. Да, к сожалению, через интерфейс Kibana нельзя управлять настройками темплейтов.

После настройки политики и шаблонов переходим во вкладку Management > Index Management выбираем нужный нам индекс, в графе Index lifecycle management будут подробности состояния кластера:

Итоги
Выполнив вышеописанные действия мы получим индексы которые каждый час переходят в состояние warm и доступны только для чтения, и еще через час вовсе удаляются. Время жизни в один час на каждую фазу выбрано для демонстрации процесса, реальные настройка подбирайте под свои нужды.

Отдельно хочу обратить на имена индексов. Мы используем Rollover Action в нашей политике, которая требует, чтобы имя нашего индекса заканчивалось цифрой. В нашем случае мы использовали 000001. Это важно, чтобы Rollover мог увеличивать это число при присвоении имени новому индексу, созданному при пролонгации.
Небольшой пример в картинках, как это работает:
Скормил filebeat несколько файлов с логами превышающих объем в 50 МБ, Elasticsearch создал два индекса.

Спустя несколько часов первые индексы были удалены, а новым были присвоены порядковые номера 000003 и 000004.

Полезная информация и первоисточник:
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-lifecycle-management.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-index-lifecycle-management.html

1+

Elasticsearch. Работа с curator_cli для фильтрации вывода индексов.

В прошлой статье о архивации индексов в Elasticsearch мы использовали инструмент Curator. Согласно официальной документации, Curator умеет фильтровать вывод индексов согласно заданным параметрам.

В этот рам мы рассмотрим несколько примеров фильтрации curator_cli.

Как говорилось ранее, мы использовали запрос выводящий список всех индексов старше N-дней. Рассмотрим подробнее, что делает этот запрос:

curator_cli --host localhost --port 9200 show_indices --filter_list "[{\"filtertype\":\"age\",\"source\":\"creation_date\",\"direction\":\"older\",\"unit\":\"days\",\"unit_count\":\"$DAYS\"},{\"filtertype\":\"kibana\",\"exclude\":\"True\"},{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"elastalert_status\",\"exclude\":\"True\"}]"

Мы запросили список всех индексов у Elasticsearch:

{\"filtertype\":\"age\",\"source\":\"creation_date\",\"direction\":\"older\",\"unit\":\"days\",\"unit_count\":\"$DAYS\"}

  • Параметр filtertype равный  age означает, что выборка индексов осуществляется на основе возраста(времени создания).
  • Параметр source равный creation_date — выбираем по дате создания.
  • Параметр direction равный older — этот параметр используется для определения того, являются ли индексы более старыми или младшими, чем контрольный момент времени, определяемый единицей, unit_count.
  • Параметр unit равный days — определяем параметр для unit_count. В нашем случаем мы ищем по дням (поиск возможен по другим временным единицам)
  • Параметр unit_count равный $DAYS — задаем множитель, старше какого дня ищем индексы.

Исключив из этого списка сервисный индекс .kibana в котором хранятся логи Kibana:

{\"filtertype\":\"kibana\",\"exclude\":\"True\"}

  • Параметр filtertype равный  kibana означает, что мы обращаемся к сервисному логу Kibana.
  • Параметр exclude равный True означает, что мы игнорируем данные индексы.

И исключив журнал запросов Elasticsearch:

{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"elastalert_status\",\"exclude\":\"True\"}

  • Параметр filtertype равный pattern означает, что данный тип фильтра будет перебирать список действий и сопоставлять индексы, соответствующие заданному шаблону.
  • Параметр kind равный regex — Этот параметр сообщает шаблону, что мы используем регулярное выражение.
  • Параметр value равный elastalert_status — значение kind, в нашем случаем мы обращаемся к журнал запросов Elasticsearch.
  • Параметр exclude равный True означает, что мы игнорируем данные индексы.

Немного о совмещении разных типов  filtertype

Если в Elasticsearch хранятся индексы с разным именем и назначением, то объединяя разные параметры поиска мы можем гибко фильтровать индексы.

На пример совместив filtertype pattern и age мы можем более точно выводить список индексов. Предположим в Elasticsearch два типа индексов с именами auditbeat-6.5.2-YYYY.MM.DD для хранения логов аудита и filebeat-6.2.3-YYYY.MM.DD для хранение логов сторонних сервисов.

#curator_cli --host localhost --port 9200 show_indices --filter_list "[{\"filtertype\":\"age\",\"source\":\"creation_date\",\"direction\":\"older\",\"unit\":\"days\",\"unit_count\":\"0\"},{\"filtertype\":\"kibana\",\"exclude\":\"True\"},{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"elastalert_status\",\"exclude\":\"True\"}]"

auditbeat-6.5.2-2019.02.18
auditbeat-6.5.2-2019.02.19
filebeat-6.2.3-2019.02.18
filebeat-6.2.3-2019.02.19

Объединив  filtertype pattern и age мы можем вывести отдельно список индексов auditbeat старше 1 (одного) дня:

#curator_cli --host localhost --port 9200 show_indices --filter_list "[{\"filtertype\":\"pattern\",\"kind\":\"prefix\",\"value\":\"auditbeat-\"},{\"filtertype\":\"age\",\"source\":\"creation_date\",\"direction\":\"older\",\"unit\":\"days\",\"unit_count\":\"1\"},{\"filtertype\":\"kibana\",\"exclude\":\"True\"},{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"elastalert_status\",\"exclude\":\"True\"}]"

auditbeat-6.5.2-2019.02.18

Как видим, для filtertype = pattern ми использовали регулярное выражение с шаблоном  value равному auditbeat-

Официальная документация: https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/filters.html

4+

Elasticsearch. Архивирование индексов в Elasticsearch

Возникает ситуация, когда необходимо архивировать индексы в Elasticsearch и складывать их на бекапный сервер. 
В таком случае мы прибегнем к elasticsearch-curator,  инструменту для управления вашими индексами и снимками Elasticsearch.

Подготовительный этап ОС.

Для начала нам необходимо установить соответствующее ПО для реализации данного сценария.

Подключим репозитирий Curator [5.5]:

для YUM Repository
https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/yum-repository.html

#vim /etc/yum.repos.d/elasticsearch-curator.repo
[curator-5]
name=CentOS/RHEL 7 repository for Elasticsearch Curator 5.x packages
baseurl=https://packages.elastic.co/curator/5/centos/7
gpgcheck=1
gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch
enabled=1

для APT repository
https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/apt-repository.html

#vim /etc/apt/sources.list.d/elasticsearch-curator.list
deb [arch=amd64] https://packages.elastic.co/curator/5/debian9 stable main

Ставим пакеты curator, NFS и jq:

для Centos 7 

#yum install -y elasticsearch-curator jq nfs

для Debian\Ubuntu

#sudo apt install -y  elasticsearch-curator jq nfs

Теперь создадим общую шару, куда будут иметь доступ наши машины с elasticsearch.
Советую создавать шару на стороннем сервере, можно поднять ее сразу на архивном, и примонтировать к elastic-машинам. 

Настройка NFS (на архивном сервере):

#mkdir -p /var/nfs_elk/snapshots/repository/
#mkdir -p /var/nfs_elk/snapshots/recovery/
#mkdir -p /var/nfs_elk/elasticsearch_backup
#chmod -R 755 /var/nfs_elk/*
#vim /etc/exports
/var/nfs_elk 192.168.1.0/24(rw,sync,no_root_squash)

Монтирование шары (на elastic-машинах):

#mkdir /var/nfs_elk/
#mount -t nfs 192.168.1.10:/var/nfs_elk/ /var/nfs_elk/

Подготовительный этап Elasticsearch.

После установки пакетов и настройки шар приступим к настройки elasticsearch.
Elasticsearch необходимо объявить общую шару и зарегистрировать ее.

В конфиг Elasticsearch.yml на всех машинах добавляем информацию об общей шаре и перезапустить сервис:

#vim /etc/elasticsearch/elasticsearch.yml
path.repo: /var/nfs-elk/snapshots

#systemctl restart elasticsearch

Объявить Elasticsearch на всех машинах о папке, куда будет бекапиться индекс:

curl -XPUT 'http://127.0.0.1:9200/_snapshot/repository' -H 'Content-Type: application/json' -d '{
"type": "fs",
"settings": {
"location": "repository",
"compress": true
}
}'

Объявить Elasticsearch на всех машинах о папке, куда будут складываться временные файлы при восстановлении индекса:

curl -XPUT 'http://127.0.0.1:9200/_snapshot/recovery' -H 'Content-Type: application/json' -d '{
"type": "fs",
"settings": {
"location": "recovery",
"compress": true
}
}'

Настройка архивирования индексов Elasticsearch

Процесс архивации протекает в несколько этапов:

  • Curator выводит список индексов из Elasticsearch согласно описанным правилам.
  • Создание снапшота индекса.
  • Переносим снапшота в ранее созданную директорию repository (/var/nfs_elk/snapshots/repository/).
  • Архивация в tar.gz и перенос архива в папку с бекапами.
  • Удаление индекса и снапшота.
  • Очистка папки repository.

Пример sh скрипта:

#vim backup.sh

#!/bin/bash

DAYS=21 #Количество дней, от текущей даты, старше которого индексы будут архивироваться
SNAPSHOT_DIRECTORY="/var/nfs_elk/snapshots" #Path to snapshot index из elasticsearch.yml
BACKUP_DIR="/var/nfs_elk/elasticsearch_backup" #Папка куда будут ложиться архивные логи
REPOSITORY="repository"
LOG="/var/log/elasticsearch/elasticsearch_backup.log" #Пишем процесс архивации в лог.
DATE=`date`

#Проверим существование папки для архивов и если нет, создадим её
if ! [ -d $BACKUP_DIR ]; then
mkdir -p $BACKUP_DIR
fi

#Получаем массив индексов, которые старше $DAYS
INDICES=`curator_cli --host localhost --port 9200 show_indices --filter_list "[{\"filtertype\":\"age\",\"source\":\"creation_date\",\"direction\":\"older\",\"unit\":\"days\",\"unit_count\":\"$DAYS\"},{\"filtertype\":\"kibana\",\"exclude\":\"True\"},{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"elastalert_status\",\"exclude\":\"True\"}]"`

#Проверим, не пустой ли список
TEST_INDICES=`echo $INDICES | grep -q -i "error" && echo 1 || echo 0`

if [ $TEST_INDICES == 1 ]
then
echo "$DATE Не найдено индексов для обработки" >> $LOG
exit
else
# Составляем цикл для каждого индекса в массиве $INDICES
for i in $INDICES
do
# Создаём снапшот для индекса $i
curator_cli --timeout 600 --host localhost --port 9200 snapshot --repository $REPOSITORY --filter_list "{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"$i\"}"

# Заносим в переменную имя снапшота для индекса $i
SNAPSHOT=`curator_cli --host localhost --port 9200 show_snapshots --repository $REPOSITORY`

# Архивируем папку репозитория и складываем архив в хранилище
cd $SNAPSHOT_DIRECTORY/$REPOSITORY && tar -zcvf $BACKUP_DIR"/"$i".tar.gz" ./*

# Удаляем snapshot
curator_cli --host localhost --port 9200 delete_snapshots --repository $REPOSITORY --filter_list "{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"$SNAPSHOT\"}"

# Удаляем индекс
curator_cli --host localhost --port 9200 delete_indices --filter_list "{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"$i\"}"

# Очищаем папку репозитория
rm -rf $SNAPSHOT_DIRECTORY/$REPOSITORY/*
done
fi

Подробнее о шаблонах фильтрации в этой статье

Ключ —host с параметром localhost возможно использовать только в том случае, если мы указали elasticsearch случать этот адрес. Если elasticsearch слушает порт 9200 только на одном адресе, то указать корректные данные.

После создания скрипта, добавим его выполнение в cron каждый день в час ночь (01:00 РМ):

#crontab -e
0 1 * * * /bin/bash /root/backup.sh >> /var/log/elasticsearch/elasticsearch_backup.log

Первоисточник: https://habr.com/ru/company/true_engineering/blog/349192/

3+

Список сетей сканеров для IPTABLES

-A INPUT -s 5.61.16.0/21 -j DROP
-A INPUT -s 5.61.232.0/21 -j DROP
-A INPUT -s 79.137.157.0/24 -j DROP
-A INPUT -s 79.137.174.0/23 -j DROP
-A INPUT -s 79.137.183.0/24 -j DROP
-A INPUT -s 94.100.176.0/20 -j DROP
-A INPUT -s 95.163.32.0/19 -j DROP
-A INPUT -s 95.163.212.0/22 -j DROP
-A INPUT -s 95.163.216.0/22 -j DROP
-A INPUT -s 95.163.248.0/21 -j DROP
-A INPUT -s 128.140.168.0/21 -j DROP
-A INPUT -s 178.22.88.0/21 -j DROP
-A INPUT -s 178.237.16.0/20 -j DROP
-A INPUT -s 178.237.29.0/24 -j DROP
-A INPUT -s 185.5.136.0/22 -j DROP
-A INPUT -s 185.16.148.0/22 -j DROP
-A INPUT -s 185.16.244.0/23 -j DROP
-A INPUT -s 185.16.246.0/24 -j DROP
-A INPUT -s 185.16.247.0/24 -j DROP
-A INPUT -s 188.93.56.0/21 -j DROP
-A INPUT -s 194.186.63.0/24 -j DROP
-A INPUT -s 195.211.20.0/22 -j DROP
-A INPUT -s 195.218.168.0/24 -j DROP
-A INPUT -s 217.20.144.0/20 -j DROP
-A INPUT -s 217.69.128.0/20 -j DROP

0

iSpy — уведомления в Telegram при обнаружении движения

Появилась необходимость получать уведомления при обнаружении движения от камеры видеонаблюдения. Камера была добавлена в iSpy.

При обнаружении движения iSpy умеет выполнять пользовательский скрипт, который отправляет уведомление в Telegram в определённый заранее канал или чат.

Для работы скрипта необходим curl под Windows, скачать можно тут. Батники я положил в одну директорию с curl.exe — нет необходимости в скрипте указывать путь до экзешника.

  Читать далее

2+