Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show container / node stats #27

Merged
merged 28 commits into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e752945
refactor: cleaning elm client directory structure
mohsenasm Oct 18, 2023
4beeb70
vagrant test cluster
mohsenasm Oct 18, 2023
6a8f20c
test-cluster: forwarded dashboard port
mohsenasm Oct 18, 2023
39256bc
add parse-prometheus-text-format
mohsenasm Oct 18, 2023
87707ac
server: add debug logs
mohsenasm Oct 18, 2023
ef0d9f8
server: extract running node-exporter ips from docker data
mohsenasm Oct 18, 2023
fc49a16
server: add diskFullness to node data
mohsenasm Oct 18, 2023
610feca
server: format diskFullness as percent
mohsenasm Oct 18, 2023
0c7c216
add diskFullness to frontend
mohsenasm Oct 18, 2023
369df24
server: support regex for node-exporter name
mohsenasm Oct 20, 2023
a187da6
client: add network name as a tooltip
mohsenasm Oct 20, 2023
4fb9747
test-cluster: fix env name in compose-all.yml
mohsenasm Oct 20, 2023
33f67d7
test-cluster: use a better vagrant box for docker
mohsenasm Oct 20, 2023
4df3f20
server: make fetchNodeMetrics and fetchDockerData independent
mohsenasm Oct 20, 2023
c38caba
server: add node cpu metric
mohsenasm Oct 20, 2023
8ff7082
server: add node memory metric
mohsenasm Oct 20, 2023
b378373
server: comment /debug-metrics
mohsenasm Oct 20, 2023
b71ca9b
server: add /debug-log
mohsenasm Oct 20, 2023
fb1e4ef
server: support multiple node-exporters
mohsenasm Oct 20, 2023
c9896aa
server: support custom mountpoint for node-exporter metrics
mohsenasm Oct 20, 2023
04caef7
server: fetch container info from cadvisor
mohsenasm Oct 21, 2023
9e1752d
client: add containers' memory and cpu info
mohsenasm Oct 21, 2023
e337ca1
server: fix node cpu metric
mohsenasm Oct 21, 2023
e24b3de
server: use env for update intervals
mohsenasm Oct 21, 2023
d3bde78
Update readme: add list of environment variables
mohsenasm Oct 21, 2023
5e707d2
Update readme: add link to lego DNS providers
mohsenasm Oct 21, 2023
2202706
Update readme: fix link of lego DNS providers
mohsenasm Oct 21, 2023
eb59fad
Update readme: add more examples for environment variables
mohsenasm Oct 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
push:
branches:
- 'master'
- 'dev_security'
- 'dev_stats'
tags:
- 'v*'

Expand Down
9 changes: 5 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ RUN yarn install --production

# elm doesn't work under alpine 6 or 8
FROM node:10.16.0-buster-slim AS elm-build
WORKDIR /home/node/app
RUN npm install --unsafe-perm -g [email protected] --silent
RUN apt-get update; apt-get install -y netbase
COPY elm-package.json ./
WORKDIR /home/node/app/elm-client
COPY ./elm-client/elm-package.json .
RUN elm package install -y
COPY . .
COPY ./elm-client/ /home/node/app/elm-client/
RUN elm make Main.elm --output=client/index.js

FROM base AS release
Expand All @@ -28,11 +28,12 @@ RUN wget -O lego_v4.14.2_linux_amd64.tar.gz https://github.com/go-acme/lego/rele
ENV LEGO_PATH=/lego-files

COPY --from=dependencies /home/node/app/node_modules node_modules
COPY --from=elm-build /home/node/app/client/ client
COPY --from=elm-build /home/node/app/elm-client/client/ client
COPY server server
COPY server.sh server.sh
COPY crontab /var/spool/cron/crontabs/root

# ENV PORT=8080
# HEALTHCHECK --interval=5s --timeout=3s \
# CMD curl --fail http://localhost:$PORT/_health || exit 1
# HEALTHCHECK --interval=5s --timeout=3s \
Expand Down
108 changes: 69 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,95 @@ A simple monitoring dashboard for Docker in Swarm Mode.

![Example Dashboard](./swarm.gif)

## About
Swarm Dashboard shows you all the tasks running on a Docker Swarm organized
by service and node. It provides a space-efficient visualization
and works well at a glance. You can use it as a simple live dashboard of the state of your Swarm.

Swarm dashboard shows you all the tasks running on a Docker Swarm organized
by service and node. It provides a visualization that's space-efficient
and works well at a glance.
It also shows the CPU/Memory/Disk usage of your swarm node and containers.

You can use it as a simple live dashboard of the state of your Swarm.
## Usage

The Dashboard has a node.js server which streams swarm updates to an Elm client
over a WebSocket.

### Prior art

* Heavily inspired by [Docker Swarm Visualiser](https://github.com/dockersamples/docker-swarm-visualizer)

## Running

At the moment, the dashboard needs to be deployed on one of the swarm managers.
The dashboard needs to be deployed on one of the swarm managers.
You can configure it with the following Docker compose file:

```yml
# compose.yml
version: "3"

services:
dashboard:
image: mohsenasm/swarm-dashboard
swarm-dashboard:
image: mohsenasm/swarm-dashboard:dev_stats
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- lego-files:/lego-files
- /var/run/docker.sock:/var/run/docker.sock
ports:
- 8081:8081
- 8080:8080
environment:
PORT: 8081
PORT: 8080
ENABLE_AUTHENTICATION: "false"
# ENABLE_AUTHENTICATION: "true"
# AUTHENTICATION_REALM: "KuW2i9GdLIkql"
# USERNAME: "admin"
# PASSWORD: "supersecret"
ENABLE_HTTPS: "false"
# ENABLE_HTTPS: "true"
# HTTPS_HOSTNAME: "example.com"
# LEGO_NEW_COMMAND_ARGS: "--accept-tos [email protected] --domains=example.com --dns cloudflare run"
# LEGO_RENEW_COMMAND_ARGS: "--accept-tos [email protected] --domains=example.com --dns cloudflare renew"
# CLOUDFLARE_EMAIL: "[email protected]"
# CLOUDFLARE_API_KEY: "yourprivatecloudflareapikey"
NODE_EXPORTER_SERVICE_NAME_REGEX: "node-exporter"
CADVISOR_SERVICE_NAME_REGEX: "cadvisor"
deploy:
replicas: 1
placement:
constraints:
- node.role == manager

node-exporter:
image: quay.io/prometheus/node-exporter:v1.6.1
volumes:
- '/:/host:ro'
command:
- '--path.rootfs=/host'
deploy:
mode: global

volumes:
lego-files:
cadvisor:
image: gcr.io/cadvisor/cadvisor
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
deploy:
mode: global
```

and deploy with

```
$ docker stack deploy -c compose.yml svc
$ docker stack deploy -c compose.yml sd
```

Note that the usage of `node-exporter` and `cadvisor` are optional, to fetch node CPU/Memory/Disk usage and containers' CPU/Memory usage respectively. If you don't need this feature, make sure to remove `NODE_EXPORTER_SERVICE_NAME_REGEX` and `CADVISOR_SERVICE_NAME_REGEX` envs.

## Advance Usage

List of environment variables for more customization:

| Enviroment Varibles | Example | Considration |
|--------------------------------------|-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| PORT | 8080 | HTTP / HTTPS port |
| ENABLE_AUTHENTICATION | true | false by default |
| AUTHENTICATION_REALM | MyRealm | Use this env if ENABLE_AUTHENTICATION is `true`. |
| USERNAME | admin | Use this env if ENABLE_AUTHENTICATION is `true`. |
| PASSWORD | supersecret | Use this env if ENABLE_AUTHENTICATION is `true`. |
| ENABLE_HTTPS | true | false by default |
| LEGO_PATH | /lego-files | Use this env if ENABLE_HTTPS is `true`. Lego is used to create the SSL certificates. Create a named volume for this path to avoid the creation of a new certificate on each run. |
| HTTPS_HOSTNAME | swarm-dashboard.example.com | Use this env if ENABLE_HTTPS is `true`. |
| LEGO_NEW_COMMAND_ARGS | --accept-tos [email protected] --domains=swarm-dashboard.example.com --dns cloudflare run | Use this env if ENABLE_HTTPS is `true`. |
| LEGO_RENEW_COMMAND_ARGS | --accept-tos [email protected] --domains=swarm-dashboard.example.com --dns cloudflare renew | Use this env if ENABLE_HTTPS is `true`. |
| CLOUDFLARE_EMAIL | [email protected] | You can use any [DNS provider that Lego supports](https://go-acme.github.io/lego/dns/). |
| CLOUDFLARE_API_KEY | yourprivatecloudflareapikey | You can use any [DNS provider that Lego supports](https://go-acme.github.io/lego/dns/). |
| DOCKER_UPDATE_INTERVAL | 1000 | Refresh interval in ms. |
| METRICS_UPDATE_INTERVAL | 5000 | Refresh interval in ms. |
| NODE_EXPORTER_SERVICE_NAME_REGEX | node-exporter | Use this env to enable `node-exporter` integration. |
| NODE_EXPORTER_INTERESTED_MOUNT_POINT | /rootfs | You may need this config if you have not specified `--path.rootfs` for `node-exporter`. |
| NODE_EXPORTER_PORT | 9100 | |
| CADVISOR_SERVICE_NAME_REGEX | cadvisor | Use this env to enable `cadvisor` integration. |
| CADVISOR_PORT | 8080 | |


## Security

+ We redact docker event data before sending them to the client. The previous version was sending the whole docker event data, including environment variables (someone might have stored some passwords in them, by mistake!). So, please consider using the newer version.
Expand Down Expand Up @@ -93,12 +120,15 @@ There are two considerations for any serious deployment of the dashboard:

* Show more service details (published port, image name, and version)
* Node / Service / Task details panel
* Show node / task resources (CPU & Memory)
* Improve security for potential production use

Both feature requests and pull requests are welcome
Both feature requests and pull requests are welcome.

### Prior art

* Heavily inspired by [Docker Swarm Visualiser](https://github.com/dockersamples/docker-swarm-visualizer)

## Contributors

* Viktor Charypar (owner, BDFL) - code, docs
* Mohammad-Mohsen Aseman-Manzar (current maintainer) - code, docs
* Viktor Charypar (previous repo owner) - code, docs
* Clementine Brown - design
1 change: 1 addition & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ services:
# LEGO_RENEW_COMMAND_ARGS: "--accept-tos [email protected] --domains=example.com --dns cloudflare renew"
# CLOUDFLARE_EMAIL: "[email protected]"
# CLOUDFLARE_API_KEY: "yourprivatecloudflareapikey"
NODE_EXPORTER_SERVICE_NAME_REGEX: "node-exporter"
deploy:
replicas: 1
update_config:
Expand Down
64 changes: 53 additions & 11 deletions Components.elm → elm-client/Components.elm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ statusString state desiredState =


task : Service -> AssignedTask -> Html msg
task service { status, desiredState, containerSpec, slot } =
task service { status, desiredState, containerSpec, slot, info } =
let
classes =
[ ( status.state, True )
Expand All @@ -32,12 +32,39 @@ task service { status, desiredState, containerSpec, slot } =

Nothing ->
""

cpuInfo =
case info.cpu of
Just s ->
[
div [ class "tag left" ] [ text s ]
]

Nothing ->
[]

memoryInfo =
case info.memory of
Just s ->
[
div [ class "tag right" ] [ text s ]
]

Nothing ->
[]
in
li [ classList classes ]
[ text (service.name ++ slotLabel slot)
, br [] []
, text (statusString status.state desiredState)
]
(List.concat [
cpuInfo
, (List.concat [
memoryInfo
, [ text (service.name ++ slotLabel slot)
, br [] []
, text (statusString status.state desiredState)
]
])
])



serviceNode : Service -> TaskIndex -> Node -> Html msg
Expand Down Expand Up @@ -77,14 +104,29 @@ node node =

nodeRole =
String.join " " [ node.role, iff leader "(leader)" "" ]

info =
case node.info of
Just s ->
[
br [] []
, text (s)
]

Nothing ->
[]
in
th [ classList classes ]
[ strong [] [ text node.name ]
, br [] []
, text nodeRole
, br [] []
, text node.status.address
]
(List.concat [
[
strong [] [ text node.name ]
, br [] []
, text nodeRole
, br [] []
, text node.status.address
]
, info
])


swarmHeader : List Node -> List Network -> Html msg
Expand Down
Loading