Initial commit
This commit is contained in:
commit
b406214901
7 changed files with 134 additions and 0 deletions
11
.devcontainer/compose.yaml
Normal file
11
.devcontainer/compose.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
devcontainer:
|
||||||
|
image: mcr.microsoft.com/devcontainers/python:1-3.11-bookworm
|
||||||
|
volumes:
|
||||||
|
- ../..:/workspaces:cached
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
#network_mode: service:db
|
||||||
|
command: sleep infinity
|
||||||
|
ports:
|
||||||
|
- 9101:9101
|
35
.devcontainer/devcontainer.json
Normal file
35
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
||||||
|
{
|
||||||
|
"name": "Python 3",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
"dockerComposeFile":"compose.yaml",
|
||||||
|
"service": "devcontainer",
|
||||||
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||||
|
//"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bookworm",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers-contrib/features/act:1": {}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
// "features": {},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "pip install --user -r requirements.txt",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"ninoseki.vscode-pylens"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
// "customizations": {},
|
||||||
|
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
4
Dockerfile
Normal file
4
Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
FROM python:3.11-bookworm
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
COPY app.py /app.py
|
||||||
|
ENTRYPOINT python /app.py
|
4
Readme.md
Normal file
4
Readme.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
openshell-export-docker-status
|
||||||
|
==============================
|
||||||
|
|
||||||
|
A Prometheus exporter for docker network interface stats
|
65
app.py
Normal file
65
app.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import time
|
||||||
|
from typing import Dict
|
||||||
|
import docker
|
||||||
|
import prometheus_client
|
||||||
|
from prometheus_client.core import REGISTRY, CounterMetricFamily, InfoMetricFamily, StateSetMetricFamily
|
||||||
|
|
||||||
|
class ContainerCollector(object):
|
||||||
|
docker_client: docker.Client
|
||||||
|
|
||||||
|
def __init__(self, docker_client: docker.Client):
|
||||||
|
self.docker_client = docker_client
|
||||||
|
|
||||||
|
def collect(self):
|
||||||
|
nw_counters: Dict[str, CounterMetricFamily] = {}
|
||||||
|
for stat in ["bytes", "packets", "errors", "dropped"]:
|
||||||
|
for rt_short in ("rx", "tx"):
|
||||||
|
rt_long = "receive" if rt_short == "rx" else "transmit"
|
||||||
|
key = f"{rt_short}_{stat}"
|
||||||
|
nw_counters[key] = CounterMetricFamily(
|
||||||
|
f"node_network_{rt_long}_{stat}_total",
|
||||||
|
f"Docker container stats network.{key}",
|
||||||
|
labels=["container", "device"],
|
||||||
|
)
|
||||||
|
# "created", "running", "paused", "restarting", "removing", "exited", "dead"
|
||||||
|
# node_network_receive_packets_total
|
||||||
|
# node_network_speed_bytes
|
||||||
|
# node_network_transmit_bytes_total
|
||||||
|
# node_network_transmit_dropped_total
|
||||||
|
# node_network_transmit_errors_total
|
||||||
|
m_container_status = InfoMetricFamily("docker_container_info", "Container info.", labels=["container"])
|
||||||
|
|
||||||
|
for container in self.docker_client.containers(all=True):
|
||||||
|
container_name = container.get("Names", [""])[0].strip("/")
|
||||||
|
container_id = container.get("Id")
|
||||||
|
container_status = container.get('State','').lower()
|
||||||
|
|
||||||
|
m_container_status.add_metric([container_name], dict(status=container_status))
|
||||||
|
|
||||||
|
#print(container_name, container_id)
|
||||||
|
stats = self.docker_client.stats(container_id, stream=False)
|
||||||
|
# print(stats)
|
||||||
|
for interface, ifstats in stats.get("networks", {}).items():
|
||||||
|
#print(interface, ifstats)
|
||||||
|
|
||||||
|
for stat, value in ifstats.items():
|
||||||
|
if stat in nw_counters:
|
||||||
|
nw_counters[stat].add_metric(
|
||||||
|
[container_name, interface],
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
yield m_container_status
|
||||||
|
for metric in nw_counters.values():
|
||||||
|
yield metric
|
||||||
|
|
||||||
|
|
||||||
|
REGISTRY.register(ContainerCollector(docker.Client()))
|
||||||
|
prometheus_client.start_http_server(9101)
|
||||||
|
|
||||||
|
|
||||||
|
print("Started")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(10)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
12
compose.yaml
Normal file
12
compose.yaml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
version: '2.1'
|
||||||
|
services:
|
||||||
|
exporter-docker-stats:
|
||||||
|
image: local/openshell-export-docker-status
|
||||||
|
build: .
|
||||||
|
pull_policy: never
|
||||||
|
restart: always
|
||||||
|
container_name: exporter-docker-stats
|
||||||
|
ports:
|
||||||
|
- 9101:9101
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
docker-py == 1.10.6
|
||||||
|
prometheus-client == 0.17.1
|
||||||
|
urllib3 >= 1.26.0, < 2.0.0
|
Loading…
Reference in a new issue