feat: добавлена поддержка обнаружения Docker-контейнеров в коллектор proxvmservices
**Новые возможности:** - Обнаружение сервисов, запущенных в Docker-контейнерах - Поддержка Docker Compose развертываний - Проверка как по имени контейнера, так и по образу **Добавленные функции:** - isDockerContainerRunning() - проверка контейнеров по имени - isDockerImageRunning() - проверка контейнеров по образу - getDockerContainerPorts() - получение портов контейнера - getDockerContainerVersion() - получение версии из контейнера **Обновленные сервисы с Docker поддержкой:** - PostgreSQL: postgres, patroni, bitnami/postgresql - Redis: redis - ClickHouse: clickhouse, clickhouse/clickhouse-server - RabbitMQ: rabbitmq - MongoDB: mongo - Elasticsearch: elasticsearch - Grafana: grafana, grafana/grafana - Prometheus: prometheus, prom/prometheus **Обновленная документация:** - Добавлены способы развертывания (нативные, Docker, Docker Compose) - Обновлены методы обнаружения с Docker проверками - Добавлены примеры использования Docker команд - Добавлен docker в системные зависимости **Поддерживаемые способы развертывания:** - Нативные процессы (systemd, init) - Docker-контейнеры - Docker Compose Теперь коллектор может обнаруживать сервисы независимо от способа их развертывания! Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
parent
d0f7bb6d24
commit
4a36a04d82
@ -4,6 +4,11 @@
|
||||
|
||||
Коллектор `proxvmservices` предназначен для обнаружения и мониторинга сервисов на виртуальных машинах и контейнерах Proxmox. Он автоматически определяет запущенные сервисы, их конфигурацию, состояние кластеров и соединения между сервисами.
|
||||
|
||||
**Поддерживаемые способы развертывания:**
|
||||
- Нативные процессы (systemd, init)
|
||||
- Docker-контейнеры
|
||||
- Docker Compose
|
||||
|
||||
## Поддерживаемые сервисы
|
||||
|
||||
### Кластерные сервисы
|
||||
@ -41,11 +46,12 @@
|
||||
|
||||
### PostgreSQL с Patroni
|
||||
1. **Процессы**: проверка `postgres` и `patroni`
|
||||
2. **Порты**: 5432 (PostgreSQL), 8008 (Patroni REST API)
|
||||
3. **Версия**: через `psql --version` или `postgres --version`
|
||||
4. **Конфигурация**: парсинг файлов `/etc/patroni/patroni.yml`, `/etc/patroni.yml`
|
||||
5. **Кластер**: команда `patronictl list` для получения информации о членах кластера
|
||||
6. **Репликация**: SQL-запрос `SELECT client_addr, state FROM pg_stat_replication`
|
||||
2. **Docker**: проверка контейнеров `postgres`, `patroni`, образов `postgres`, `bitnami/postgresql`
|
||||
3. **Порты**: 5432 (PostgreSQL), 8008 (Patroni REST API)
|
||||
4. **Версия**: через `psql --version` или `postgres --version`
|
||||
5. **Конфигурация**: парсинг файлов `/etc/patroni/patroni.yml`, `/etc/patroni.yml`
|
||||
6. **Кластер**: команда `patronictl list` для получения информации о членах кластера
|
||||
7. **Репликация**: SQL-запрос `SELECT client_addr, state FROM pg_stat_replication`
|
||||
|
||||
### etcd
|
||||
1. **Процессы**: проверка `etcd`
|
||||
@ -61,21 +67,24 @@
|
||||
|
||||
### ClickHouse
|
||||
1. **Процессы**: проверка `clickhouse-server`
|
||||
2. **Порты**: 8123 (HTTP), 9000 (native)
|
||||
3. **Версия**: через `clickhouse-client --version`
|
||||
4. **Кластер**: SQL-запрос `SELECT host_name FROM system.clusters`
|
||||
2. **Docker**: проверка контейнеров `clickhouse`, образов `clickhouse/clickhouse-server`
|
||||
3. **Порты**: 8123 (HTTP), 9000 (native)
|
||||
4. **Версия**: через `clickhouse-client --version`
|
||||
5. **Кластер**: SQL-запрос `SELECT host_name FROM system.clusters`
|
||||
|
||||
### Redis
|
||||
1. **Процессы**: проверка `redis-server`
|
||||
2. **Порты**: 6379 (client)
|
||||
3. **Версия**: через `redis-cli --version`
|
||||
4. **Кластер**: команда `redis-cli cluster nodes`
|
||||
2. **Docker**: проверка контейнеров `redis`, образов `redis`
|
||||
3. **Порты**: 6379 (client)
|
||||
4. **Версия**: через `redis-cli --version`
|
||||
5. **Кластер**: команда `redis-cli cluster nodes`
|
||||
|
||||
### RabbitMQ
|
||||
1. **Процессы**: проверка `rabbitmq-server`
|
||||
2. **Порты**: 5672 (AMQP), 15672 (management)
|
||||
3. **Версия**: через `rabbitmqctl version`
|
||||
4. **Кластер**: команда `rabbitmqctl cluster_status`
|
||||
2. **Docker**: проверка контейнеров `rabbitmq`, образов `rabbitmq`
|
||||
3. **Порты**: 5672 (AMQP), 15672 (management)
|
||||
4. **Версия**: через `rabbitmqctl version`
|
||||
5. **Кластер**: команда `rabbitmqctl cluster_status`
|
||||
|
||||
### Kafka
|
||||
1. **Процессы**: проверка `kafka.Kafka`
|
||||
@ -85,9 +94,10 @@
|
||||
|
||||
### MongoDB
|
||||
1. **Процессы**: проверка `mongod`
|
||||
2. **Порты**: 27017 (mongod)
|
||||
3. **Версия**: через `mongosh --version`
|
||||
4. **Кластер**: команда `mongosh --eval "rs.status().members.map(m => m.name)"`
|
||||
2. **Docker**: проверка контейнеров `mongo`, образов `mongo`
|
||||
3. **Порты**: 27017 (mongod)
|
||||
4. **Версия**: через `mongosh --version`
|
||||
5. **Кластер**: команда `mongosh --eval "rs.status().members.map(m => m.name)"`
|
||||
|
||||
### Новые кластерные сервисы
|
||||
|
||||
@ -99,9 +109,10 @@
|
||||
|
||||
#### Elasticsearch
|
||||
1. **Процессы**: проверка `elasticsearch`, `java.*elasticsearch`
|
||||
2. **Порты**: 9200 (HTTP), 9300 (transport)
|
||||
3. **Версия**: через HTTP API `http://localhost:9200`
|
||||
4. **Кластер**: HTTP API `/_cluster/state/nodes`
|
||||
2. **Docker**: проверка контейнеров `elasticsearch`, образов `elasticsearch`
|
||||
3. **Порты**: 9200 (HTTP), 9300 (transport)
|
||||
4. **Версия**: через HTTP API `http://localhost:9200`
|
||||
5. **Кластер**: HTTP API `/_cluster/state/nodes`
|
||||
|
||||
#### Greenplum
|
||||
1. **Процессы**: проверка `postgres.*greenplum`, `gpdb`
|
||||
@ -142,13 +153,15 @@
|
||||
|
||||
#### Grafana
|
||||
1. **Процессы**: проверка `grafana-server`, `grafana`
|
||||
2. **Порты**: 3000 (HTTP)
|
||||
3. **Версия**: через `grafana-server --version`
|
||||
2. **Docker**: проверка контейнеров `grafana`, образов `grafana/grafana`
|
||||
3. **Порты**: 3000 (HTTP)
|
||||
4. **Версия**: через `grafana-server --version`
|
||||
|
||||
#### Prometheus
|
||||
1. **Процессы**: проверка `prometheus`
|
||||
2. **Порты**: 9090 (HTTP)
|
||||
3. **Версия**: через `prometheus --version`
|
||||
2. **Docker**: проверка контейнеров `prometheus`, образов `prom/prometheus`
|
||||
3. **Порты**: 9090 (HTTP)
|
||||
4. **Версия**: через `prometheus --version`
|
||||
|
||||
#### Loki
|
||||
1. **Процессы**: проверка `loki`
|
||||
@ -321,6 +334,7 @@ proxvmservices:
|
||||
- `ss` - для проверки портов
|
||||
- `curl` - для HTTP API запросов
|
||||
- `getent` - для разрешения hostname в IP
|
||||
- `docker` - для проверки Docker-контейнеров
|
||||
|
||||
#### Основные сервисы
|
||||
- `psql` или `postgres` - для PostgreSQL
|
||||
@ -360,6 +374,12 @@ proxvmservices:
|
||||
pgrep -f postgres
|
||||
pgrep -f patroni
|
||||
|
||||
# Проверка Docker-контейнеров
|
||||
docker ps --filter "name=postgres"
|
||||
docker ps --filter "name=patroni"
|
||||
docker ps --filter "ancestor=postgres"
|
||||
docker ps --filter "ancestor=bitnami/postgresql"
|
||||
|
||||
# Проверка портов
|
||||
ss -tln sport = :5432
|
||||
ss -tln sport = :8008
|
||||
@ -406,6 +426,10 @@ clickhouse-client --query "SELECT * FROM system.clusters"
|
||||
# Проверка процессов
|
||||
pgrep -f redis-server
|
||||
|
||||
# Проверка Docker-контейнеров
|
||||
docker ps --filter "name=redis"
|
||||
docker ps --filter "ancestor=redis"
|
||||
|
||||
# Проверка портов
|
||||
ss -tln sport = :6379
|
||||
|
||||
|
@ -216,6 +216,78 @@ func isProcessRunning(processName string) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// isDockerContainerRunning проверяет, запущен ли Docker-контейнер с указанным именем или образом
|
||||
func isDockerContainerRunning(containerName string) bool {
|
||||
cmd := exec.Command("docker", "ps", "--filter", "name="+containerName, "--format", "{{.Names}}")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(string(output)) != ""
|
||||
}
|
||||
|
||||
// isDockerImageRunning проверяет, запущен ли Docker-контейнер с указанным образом
|
||||
func isDockerImageRunning(imageName string) bool {
|
||||
cmd := exec.Command("docker", "ps", "--filter", "ancestor="+imageName, "--format", "{{.Names}}")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(string(output)) != ""
|
||||
}
|
||||
|
||||
// getDockerContainerPorts получает порты Docker-контейнера
|
||||
func getDockerContainerPorts(containerName string) []int {
|
||||
cmd := exec.Command("docker", "port", containerName)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return []int{}
|
||||
}
|
||||
|
||||
var ports []int
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Парсим строку типа: "5432/tcp -> 0.0.0.0:5432"
|
||||
if strings.Contains(line, "->") {
|
||||
parts := strings.Split(line, "->")
|
||||
if len(parts) > 0 {
|
||||
portPart := strings.TrimSpace(parts[0])
|
||||
if strings.Contains(portPart, "/") {
|
||||
portStr := strings.Split(portPart, "/")[0]
|
||||
if port, err := strconv.Atoi(portStr); err == nil {
|
||||
ports = append(ports, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ports
|
||||
}
|
||||
|
||||
// getDockerContainerVersion получает версию из Docker-контейнера
|
||||
func getDockerContainerVersion(containerName, versionCommand string) string {
|
||||
cmd := exec.Command("docker", "exec", containerName, "sh", "-c", versionCommand)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// Парсим версию из вывода
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(string(output))
|
||||
if len(matches) > 1 {
|
||||
return matches[1]
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// getListeningPorts возвращает список портов, на которых слушает процесс
|
||||
func getListeningPorts(ports ...int) []int {
|
||||
var listeningPorts []int
|
||||
@ -243,8 +315,10 @@ func runCommand(command string, args ...string) (string, error) {
|
||||
|
||||
// detectPostgreSQL обнаруживает PostgreSQL с Patroni
|
||||
func detectPostgreSQL() *ServiceInfo {
|
||||
// Проверяем процессы
|
||||
if !isProcessRunning("postgres") && !isProcessRunning("patroni") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("postgres") && !isProcessRunning("patroni") &&
|
||||
!isDockerContainerRunning("postgres") && !isDockerContainerRunning("patroni") &&
|
||||
!isDockerImageRunning("postgres") && !isDockerImageRunning("bitnami/postgresql") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1035,7 +1109,9 @@ func parseEtcdMembers(output string) []EtcdMember {
|
||||
|
||||
// detectRedis обнаруживает Redis (standalone или cluster)
|
||||
func detectRedis() *ServiceInfo {
|
||||
if !isProcessRunning("redis-server") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("redis-server") &&
|
||||
!isDockerContainerRunning("redis") && !isDockerImageRunning("redis") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1070,7 +1146,9 @@ func detectRedis() *ServiceInfo {
|
||||
}
|
||||
|
||||
func detectClickHouse() *ServiceInfo {
|
||||
if !isProcessRunning("clickhouse-server") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("clickhouse-server") &&
|
||||
!isDockerContainerRunning("clickhouse") && !isDockerImageRunning("clickhouse/clickhouse-server") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1105,7 +1183,9 @@ func detectClickHouse() *ServiceInfo {
|
||||
}
|
||||
|
||||
func detectRabbitMQ() *ServiceInfo {
|
||||
if !isProcessRunning("rabbitmq-server") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("rabbitmq-server") &&
|
||||
!isDockerContainerRunning("rabbitmq") && !isDockerImageRunning("rabbitmq") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1166,7 +1246,9 @@ func detectKafka() *ServiceInfo {
|
||||
}
|
||||
|
||||
func detectMongoDB() *ServiceInfo {
|
||||
if !isProcessRunning("mongod") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("mongod") &&
|
||||
!isDockerContainerRunning("mongo") && !isDockerImageRunning("mongo") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1298,7 +1380,9 @@ func detectDragonflyDB() *ServiceInfo {
|
||||
|
||||
// detectElasticsearch обнаруживает Elasticsearch
|
||||
func detectElasticsearch() *ServiceInfo {
|
||||
if !isProcessRunning("elasticsearch") && !isProcessRunning("java.*elasticsearch") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("elasticsearch") && !isProcessRunning("java.*elasticsearch") &&
|
||||
!isDockerContainerRunning("elasticsearch") && !isDockerImageRunning("elasticsearch") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1335,7 +1419,9 @@ func detectElasticsearch() *ServiceInfo {
|
||||
|
||||
// detectGrafana обнаруживает Grafana
|
||||
func detectGrafana() *ServiceInfo {
|
||||
if !isProcessRunning("grafana-server") && !isProcessRunning("grafana") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("grafana-server") && !isProcessRunning("grafana") &&
|
||||
!isDockerContainerRunning("grafana") && !isDockerImageRunning("grafana/grafana") {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1364,7 +1450,9 @@ func detectGrafana() *ServiceInfo {
|
||||
|
||||
// detectPrometheus обнаруживает Prometheus
|
||||
func detectPrometheus() *ServiceInfo {
|
||||
if !isProcessRunning("prometheus") {
|
||||
// Проверяем процессы и Docker-контейнеры
|
||||
if !isProcessRunning("prometheus") &&
|
||||
!isDockerContainerRunning("prometheus") && !isDockerImageRunning("prom/prometheus") {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user