Compare commits

...

10 commits

Author SHA1 Message Date
MuratovAS
84387e105d
Update docker-network-graph.py 2024-01-14 03:28:30 +05:00
MuratovAS
e13dcacb0a
add example 2024-01-14 03:19:45 +05:00
MuratovAS
2492ba0646
visualization of ports 2024-01-14 03:18:42 +05:00
MuratovAS
212a082af3
line type = network type 2024-01-14 01:29:41 +05:00
Aleksej Muratov
e8c090b3be
Update README.md 2024-01-13 17:15:22 +00:00
MuratovAS
a93f185969
update ci 2024-01-13 21:37:07 +05:00
MuratovAS
b503fb7bb9
Update README.md 2024-01-13 21:32:28 +05:00
MuratovAS
739a7a1527
update 2024-01-13 21:31:01 +05:00
Will
bb23b21806 ignore dot output 2023-06-16 21:46:59 -04:00
Will
a9dd1728c9 update docker, clamp 3.6 <= python < 4 2023-06-16 21:46:17 -04:00
15 changed files with 395 additions and 156 deletions

View file

@ -1,3 +1,4 @@
.*
test/
example.png
docker-compose.yml

View file

@ -1,12 +0,0 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch"]
- dependency-name: "*"
update-types: ["version-update:semver-minor"]

53
.github/workflows/docker-build-push.yml vendored Normal file
View file

@ -0,0 +1,53 @@
name: Docker (Build and Push)
# Controls when the workflow will run
on:
push:
tags:
- 'v*.*.*'
# permissions are needed if pushing to ghcr.io
permissions:
packages: write
jobs:
build_push:
name: Build and Push
runs-on: ubuntu-latest
steps:
# Get the repository's code
- uses: actions/checkout@v4
# https://github.com/docker/setup-qemu-action
- uses: docker/setup-qemu-action@v3
# https://github.com/docker/setup-buildx-action
- uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
# list of Docker images to use as base name for tags
images: |
ghcr.io/muratovas/docker-network-graph
# Docker tags based on the following events/attributes
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Build and Push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View file

@ -1,60 +0,0 @@
name: Publish Docker image
on:
push:
branches:
- '**'
tags:
- 'v*'
jobs:
push_to_registry:
name: Build and push docker image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v4
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/docker-network-graph,ghcr.io/${{ github.repository_owner }}/docker-network-graph
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
if: github.event_name != 'pull_request'
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/386,linux/arm/v6,linux/arm/v7,linux/arm64
push: True
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache

3
.gitignore vendored
View file

@ -1,5 +1,4 @@
*.gv
*.pdf
*.png
*.svg
.idea
/output

View file

@ -1,5 +1,6 @@
Copyright (c) 2018 Eugene Agafonov
Copyright (c) 2023 e-dant (github.com/e-dant)
Copyright (c) 2024 MuratovAS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -4,10 +4,10 @@ verify_ssl = true
name = "pypi"
[packages]
docker = "~=3.7"
graphviz = "*"
docker = "==6.*"
[dev-packages]
[requires]
python_version = "3"
python_version = ">=3.6,<4"

33
Pipfile.lock generated
View file

@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "7a973891b61a2778ab0989c6d5b6d0507ac7977cce469307bfd06903240b6449"
"sha256": "f30fb7db8567fcb899359e73c438a98a395302efa3ae741a9a181778bfaf8f39"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3"
"python_version": ">=3.6,<4"
},
"sources": [
{
@ -107,18 +107,11 @@
},
"docker": {
"hashes": [
"sha256:2434b396e616a5ef682fbf80e04839a59e8b81880ece5662c33dff34b8863519",
"sha256:a062a9f82dff025f79c2097c46f49f143f8898274db7e66041f78cafee66b962"
"sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20",
"sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9"
],
"index": "pypi",
"version": "==3.7.3"
},
"docker-pycreds": {
"hashes": [
"sha256:6ce3270bcaf404cc4c3e27e4b6c70d3521deae82fb508767870fdbf772d584d4",
"sha256:7266112468627868005106ec19cd0d722702d2b7d5912a28e19b826c3d37af49"
],
"version": "==0.4.0"
"version": "==6.1.3"
},
"graphviz": {
"hashes": [
@ -136,6 +129,14 @@
"markers": "python_version >= '3.5'",
"version": "==3.4"
},
"packaging": {
"hashes": [
"sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
],
"markers": "python_version >= '3.7'",
"version": "==23.1"
},
"requests": {
"hashes": [
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
@ -144,14 +145,6 @@
"markers": "python_version >= '3.7'",
"version": "==2.31.0"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"urllib3": {
"hashes": [
"sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1",

View file

@ -3,34 +3,50 @@
Visualize the relationship between Docker networks and containers
as a neat graphviz graph.
This repository fork [e-dant/docker-network-graph](https://github.com/e-dant/docker-network-graph)
Changes:
- Improved design
- Added the ability to generate url
- Added display of connections with the host
- Visualization of ports
- Github package
## Example
![example graph](https://raw.githubusercontent.com/e-dant/docker-network-graph/release/example.png)
![example graph](./example.svg)
## Usage
usage: docker-network-graph.py [-h] [-v] [-o OUT]
```bash
usage: docker-network-graph.py [-h] [-v] [-o OUT] [-u]
Visualize docker networks.
optional arguments:
-h, --help show this help message and exit
-h, --help Show this help message and exit
-v, --verbose Verbose output
-o OUT, --out OUT Write output to file
In most cases what you want to run are the following couple commands:
git clone https://github.com/e-dant/docker-network-graph.git
cd docker-network-graph
pipenv install
pipenv run python docker-network-graph.py -o output.svg
This will generate an .svg file containing the graph.
-o OUT, --out OUT Write output to file [not supported by container]
-u, --url Generate link for GraphvizOnline
```
## Running inside docker
If you want to generate a graph for a remote system you can also easily
run this script inside a pre-built docker container:
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock e-dant/docker-network-graph
```bash
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/muratovas/docker-network-graph:latest -u
```
For more advanced use cases you can append arguments to the `docker run`
command as if you were running it in a local shell.
## Running local
In most cases what you want to run are the following couple commands:
```bash
git clone https://github.com/muratovas/docker-network-graph.git
cd docker-network-graph
pipenv install
pipenv run python docker-network-graph.py -o output.svg
```
This will generate an .svg file containing the graph.
This will just generate and output the graph in the [DOT Language][dot].
You can then paste that code into [GraphvizOnline][gvonline]
@ -41,15 +57,17 @@ Alternatively, if you prefer to render locally, you can run
paste the previous output there, press enter and finally CTRL+C to
generate the file.
For more advanced use cases you can append arguments to the `docker run`
command as if you were running it in a local shell.
[dot]: https://www.graphviz.org/doc/info/lang.html
[gvonline]: https://dreampuf.github.io/GraphvizOnline/
## Development
If you'd like to contribute to this project, there is a sample docker-compose file
using dummy containers in `test`.
You can deploy it using `docker-compose -f test/docker-compose.yml up -d`.
You can deploy it using
```bash
docker-compose -f docker-compose.yml up -d
```
## Credit
[dot lang](https://www.graphviz.org/doc/info/lang.html)
[gvonline](https://dreampuf.github.io/GraphvizOnline/)

View file

@ -23,6 +23,14 @@ services:
- network_b
- network_c
- no_gateway
service_4:
container_name: service_4
image: leoverto/dummy-image
ports:
- "1234:1234"
- "0.0.0.0:5678:5678/udp"
networks:
- internet
host_service:
container_name: host_service
image: leoverto/dummy-image
@ -33,6 +41,9 @@ services:
network_mode: none
networks:
internet:
driver_opts:
com.docker.network.bridge.enable_icc: "false"
network_a:
network_b:
network_c:

View file

@ -5,6 +5,7 @@ import argparse
import random
import docker
import typing
import urllib.parse
from dataclasses import dataclass
from graphviz import Graph
from graphviz.parameters.formats import FORMATS
@ -22,7 +23,7 @@ COLORS = [
"#b2df8a",
"#fdbf6f",
"#cab2d6",
"#ffff99",
"#90f530",
"#0d8bad",
"#e98420",
"#0e9997",
@ -49,12 +50,16 @@ class Interface:
address: str
aliases: typing.List[str]
@dataclass
class Port:
port: str
@dataclass
class Container:
container_id: str
name: str
interfaces: typing.List[Interface]
ports: typing.List[Interface]
@dataclass
@ -124,11 +129,13 @@ def get_containers(
for container in client.containers.list():
interfaces: typing.List[Interface] = []
ports: typing.List[Port] = []
for port_name, port_info in container.attrs["NetworkSettings"]["Ports"].items():
ports.append(Port(port_name))
# Iterate over container interfaces
for net_name, net_info in container.attrs["NetworkSettings"][
"Networks"
].items():
for net_name, net_info in container.attrs["NetworkSettings"]["Networks"].items():
endpoint_id = net_info["EndpointID"]
aliases = []
@ -142,17 +149,16 @@ def get_containers(
links.append(Link(container.id, endpoint_id, net_name))
if verbose:
print(
f"Container: {container.name} {''.join([iface.address for iface in interfaces])}"
)
print(f"Container: {container.name} {ports} {''.join([iface.address for iface in interfaces])}")
containers.append(Container(container.id, container.name, interfaces))
containers.append(Container(container.id, container.name, interfaces, ports))
return containers, links
def draw_network(g: Graph, net: Network):
label = f"{{<gw_iface> {net.gateway} | {net.name}"
# <gw_iface> {net.gateway} |
label = f"{{{net.name}"
if net.internal:
label += " | Internal"
if net.isolated:
@ -163,13 +169,19 @@ def draw_network(g: Graph, net: Network):
f"network_{net.name}",
shape="record",
label=label,
fillcolor=net.color,
style="filled",
color=net.color + "60",
style="filled,rounded",
)
def draw_container(g: Graph, c: Container):
iface_labels = []
port_labels = []
for iport in c.ports:
port_label = "{"
port_label += f"{iport.port} }}"
port_labels.append(port_label)
for iface in c.interfaces:
iface_label = "{"
@ -179,27 +191,38 @@ def draw_container(g: Graph, c: Container):
iface_label += f"<{iface.endpoint_id}> {iface.address} }}"
iface_labels.append(iface_label)
label = f"{{ {c.name} | {{ {' | '.join(iface_labels)} }} }}"
label =f"{{ {c.name} "
if port_labels:
label = label + f"| {{ {' | '.join(port_labels)} }} "
label = label + f"| {{ {' | '.join(iface_labels)} }} }}"
g.node(
f"container_{c.container_id}",
shape="record",
label=label,
fillcolor="#ff9999",
fillcolor="#cdcdcd",
style="filled",
)
def draw_link(g: Graph, networks: typing.Dict[str, Network], link: Link):
if networks[link.network_name].isolated:
style="dashed"
elif networks[link.network_name].name == "host":
style="bold"
else:
style="solid"
g.edge(
f"container_{link.container_id}:{link.endpoint_id}",
f"network_{link.network_name}",
color=networks[link.network_name].color,
style=style,
)
def generate_graph(verbose: bool, file: str):
def generate_graph(verbose: bool, file: str, url: str):
docker_client = docker.from_env()
networks = get_networks(docker_client, verbose)
@ -230,10 +253,23 @@ def generate_graph(verbose: bool, file: str):
if link.network_name != "none":
draw_link(g, networks, link)
for _, network in networks.items():
if network.internal != True:
if network.name != "host":
g.edge(
f"network_{network.name}",
f"network_host",
color="#808080",
style="dotted",
)
if file:
g.render(base)
else:
print(g.source)
if url:
print("https://dreampuf.github.io/GraphvizOnline/#" + urllib.parse.quote(g.source))
else:
print(g.source)
def graphviz_output_file(filename: str):
@ -242,13 +278,12 @@ def graphviz_output_file(filename: str):
raise argparse.ArgumentTypeError("Must be valid graphviz output format")
return filename
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Visualize docker networks.")
parser.add_argument("-v", "--verbose", help="Verbose output", action="store_true")
parser.add_argument(
"-o", "--out", help="Write output to file", type=graphviz_output_file
)
parser.add_argument("-v", "--verbose", help="verbose output", action="store_true")
parser.add_argument("-o", "--out", help="write output to file", type=graphviz_output_file)
parser.add_argument("-u", "--url", help="generate link for GraphvizOnline", action="store_true")
args = parser.parse_args()
generate_graph(args.verbose, args.out)
generate_graph(args.verbose, args.out, args.url)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 85 KiB

212
example.svg Normal file
View file

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: %0 Pages: 1 -->
<svg width="1304pt" height="243pt" viewBox="0.00 0.00 1304.31 243.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 239)">
<title>%0</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-239 1300.3072,-239 1300.3072,4 -4,4"/>
<!-- network_bridge -->
<g id="node1" class="node">
<title>network_bridge</title>
<path fill="#1f78b4" fill-opacity="0.376471" stroke="#1f78b4" stroke-opacity="0.376471" d="M30.3198,-80.3C30.3198,-80.3 60.3198,-80.3 60.3198,-80.3 66.3198,-80.3 72.3198,-86.3 72.3198,-92.3 72.3198,-92.3 72.3198,-104.3 72.3198,-104.3 72.3198,-110.3 66.3198,-116.3 60.3198,-116.3 60.3198,-116.3 30.3198,-116.3 30.3198,-116.3 24.3198,-116.3 18.3198,-110.3 18.3198,-104.3 18.3198,-104.3 18.3198,-92.3 18.3198,-92.3 18.3198,-86.3 24.3198,-80.3 30.3198,-80.3"/>
<text text-anchor="middle" x="45.2027" y="-94.2" font-family="Times,serif" font-size="14.00" fill="#000000">bridge</text>
</g>
<!-- network_host -->
<g id="node7" class="node">
<title>network_host</title>
<path fill="#808080" fill-opacity="0.376471" stroke="#808080" stroke-opacity="0.376471" d="M613.3198,-.5C613.3198,-.5 643.3198,-.5 643.3198,-.5 649.3198,-.5 655.3198,-6.5 655.3198,-12.5 655.3198,-12.5 655.3198,-24.5 655.3198,-24.5 655.3198,-30.5 649.3198,-36.5 643.3198,-36.5 643.3198,-36.5 613.3198,-36.5 613.3198,-36.5 607.3198,-36.5 601.3198,-30.5 601.3198,-24.5 601.3198,-24.5 601.3198,-12.5 601.3198,-12.5 601.3198,-6.5 607.3198,-.5 613.3198,-.5"/>
<text text-anchor="middle" x="627.9874" y="-14.4" font-family="Times,serif" font-size="14.00" fill="#000000">host</text>
</g>
<!-- network_bridge&#45;&#45;network_host -->
<g id="edge12" class="edge">
<title>network_bridge--network_host</title>
<path fill="none" stroke="#808080" stroke-dasharray="1,5" d="M67.5657,-80.0812C71.9122,-77.2896 76.5941,-74.757 81.3198,-73 178.4884,-36.8744 504.6733,-22.8138 601.1943,-19.385"/>
</g>
<!-- network_docker&#45;network&#45;graph_internet -->
<g id="node2" class="node">
<title>network_docker-network-graph_internet</title>
<path fill="#33a02c" fill-opacity="0.376471" stroke="#33a02c" stroke-opacity="0.376471" d="M101.8597,-73.5C101.8597,-73.5 268.7799,-73.5 268.7799,-73.5 274.7799,-73.5 280.7799,-79.5 280.7799,-85.5 280.7799,-85.5 280.7799,-111.1 280.7799,-111.1 280.7799,-117.1 274.7799,-123.1 268.7799,-123.1 268.7799,-123.1 101.8597,-123.1 101.8597,-123.1 95.8597,-123.1 89.8597,-117.1 89.8597,-111.1 89.8597,-111.1 89.8597,-85.5 89.8597,-85.5 89.8597,-79.5 95.8597,-73.5 101.8597,-73.5"/>
<text text-anchor="middle" x="185.3198" y="-106.5" font-family="Times,serif" font-size="14.00" fill="#000000">docker-network-graph_internet</text>
<polyline fill="none" stroke="#33a02c" stroke-opacity="0.376471" points="89.8597,-98.3 280.7799,-98.3 "/>
<text text-anchor="middle" x="185.3198" y="-81.7" font-family="Times,serif" font-size="14.00" fill="#000000">Containers isolated</text>
</g>
<!-- network_docker&#45;network&#45;graph_internet&#45;&#45;network_host -->
<g id="edge13" class="edge">
<title>network_docker-network-graph_internet--network_host</title>
<path fill="none" stroke="#808080" stroke-dasharray="1,5" d="M281.026,-74.7156C283.8183,-74.1244 286.5875,-73.5511 289.3198,-73 404.4333,-49.7829 543.1284,-30.0247 600.9438,-22.1505"/>
</g>
<!-- network_docker&#45;network&#45;graph_network_a -->
<g id="node3" class="node">
<title>network_docker-network-graph_network_a</title>
<path fill="#e31a1c" fill-opacity="0.376471" stroke="#e31a1c" stroke-opacity="0.376471" d="M310.697,-80.3C310.697,-80.3 493.9426,-80.3 493.9426,-80.3 499.9426,-80.3 505.9426,-86.3 505.9426,-92.3 505.9426,-92.3 505.9426,-104.3 505.9426,-104.3 505.9426,-110.3 499.9426,-116.3 493.9426,-116.3 493.9426,-116.3 310.697,-116.3 310.697,-116.3 304.697,-116.3 298.697,-110.3 298.697,-104.3 298.697,-104.3 298.697,-92.3 298.697,-92.3 298.697,-86.3 304.697,-80.3 310.697,-80.3"/>
<text text-anchor="middle" x="402.3198" y="-94.2" font-family="Times,serif" font-size="14.00" fill="#000000">docker-network-graph_network_a</text>
</g>
<!-- network_docker&#45;network&#45;graph_network_a&#45;&#45;network_host -->
<g id="edge14" class="edge">
<title>network_docker-network-graph_network_a--network_host</title>
<path fill="none" stroke="#808080" stroke-dasharray="1,5" d="M453.3204,-80.2918C499.1467,-64.1107 564.6764,-40.9723 601.1572,-28.091"/>
</g>
<!-- network_docker&#45;network&#45;graph_network_b -->
<g id="node4" class="node">
<title>network_docker-network-graph_network_b</title>
<path fill="#ff7f00" fill-opacity="0.376471" stroke="#ff7f00" stroke-opacity="0.376471" d="M536.3043,-80.3C536.3043,-80.3 720.3353,-80.3 720.3353,-80.3 726.3353,-80.3 732.3353,-86.3 732.3353,-92.3 732.3353,-92.3 732.3353,-104.3 732.3353,-104.3 732.3353,-110.3 726.3353,-116.3 720.3353,-116.3 720.3353,-116.3 536.3043,-116.3 536.3043,-116.3 530.3043,-116.3 524.3043,-110.3 524.3043,-104.3 524.3043,-104.3 524.3043,-92.3 524.3043,-92.3 524.3043,-86.3 530.3043,-80.3 536.3043,-80.3"/>
<text text-anchor="middle" x="628.3198" y="-94.2" font-family="Times,serif" font-size="14.00" fill="#000000">docker-network-graph_network_b</text>
</g>
<!-- network_docker&#45;network&#45;graph_network_b&#45;&#45;network_host -->
<g id="edge15" class="edge">
<title>network_docker-network-graph_network_b--network_host</title>
<path fill="none" stroke="#808080" stroke-dasharray="1,5" d="M628.3198,-80.1921C628.3198,-67.1324 628.3198,-49.5795 628.3198,-36.5362"/>
</g>
<!-- network_docker&#45;network&#45;graph_network_c -->
<g id="node5" class="node">
<title>network_docker-network-graph_network_c</title>
<path fill="#6a3d9a" fill-opacity="0.376471" stroke="#6a3d9a" stroke-opacity="0.376471" d="M762.697,-80.3C762.697,-80.3 945.9426,-80.3 945.9426,-80.3 951.9426,-80.3 957.9426,-86.3 957.9426,-92.3 957.9426,-92.3 957.9426,-104.3 957.9426,-104.3 957.9426,-110.3 951.9426,-116.3 945.9426,-116.3 945.9426,-116.3 762.697,-116.3 762.697,-116.3 756.697,-116.3 750.697,-110.3 750.697,-104.3 750.697,-104.3 750.697,-92.3 750.697,-92.3 750.697,-86.3 756.697,-80.3 762.697,-80.3"/>
<text text-anchor="middle" x="854.3198" y="-94.2" font-family="Times,serif" font-size="14.00" fill="#000000">docker-network-graph_network_c</text>
</g>
<!-- network_docker&#45;network&#45;graph_network_c&#45;&#45;network_host -->
<g id="edge16" class="edge">
<title>network_docker-network-graph_network_c--network_host</title>
<path fill="none" stroke="#808080" stroke-dasharray="1,5" d="M803.3192,-80.2918C757.4929,-64.1107 691.9632,-40.9723 655.4824,-28.091"/>
</g>
<!-- network_docker&#45;network&#45;graph_no_gateway -->
<g id="node6" class="node">
<title>network_docker-network-graph_no_gateway</title>
<path fill="#b15928" fill-opacity="0.376471" stroke="#b15928" stroke-opacity="0.376471" d="M988.42,-80.3C988.42,-80.3 1180.2196,-80.3 1180.2196,-80.3 1186.2196,-80.3 1192.2196,-86.3 1192.2196,-92.3 1192.2196,-92.3 1192.2196,-104.3 1192.2196,-104.3 1192.2196,-110.3 1186.2196,-116.3 1180.2196,-116.3 1180.2196,-116.3 988.42,-116.3 988.42,-116.3 982.42,-116.3 976.42,-110.3 976.42,-104.3 976.42,-104.3 976.42,-92.3 976.42,-92.3 976.42,-86.3 982.42,-80.3 988.42,-80.3"/>
<text text-anchor="middle" x="1084.3198" y="-94.2" font-family="Times,serif" font-size="14.00" fill="#000000">docker-network-graph_no_gateway</text>
</g>
<!-- network_docker&#45;network&#45;graph_no_gateway&#45;&#45;network_host -->
<g id="edge17" class="edge">
<title>network_docker-network-graph_no_gateway--network_host</title>
<path fill="none" stroke="#808080" stroke-dasharray="1,5" d="M1003.557,-80.2455C991.4334,-77.7067 979.0629,-75.212 967.3198,-73 851.9177,-51.2625 713.3782,-30.7067 655.6498,-22.3863"/>
</g>
<!-- container_42e6eb67bb0da8991f3c4783d294ff2acc2e823906878904fb1fff3d2d8b3b3c -->
<g id="node8" class="node">
<title>container_42e6eb67bb0da8991f3c4783d294ff2acc2e823906878904fb1fff3d2d8b3b3c</title>
<polygon fill="#cdcdcd" stroke="#000000" points="0,-172.5 0,-222.1 90.6396,-222.1 90.6396,-172.5 0,-172.5"/>
<text text-anchor="middle" x="45.3198" y="-205.5" font-family="Times,serif" font-size="14.00" fill="#000000">lucid_banach</text>
<polyline fill="none" stroke="#000000" points="0,-197.3 90.6396,-197.3 "/>
<text text-anchor="middle" x="45.25" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.17.0.2</text>
</g>
<!-- container_42e6eb67bb0da8991f3c4783d294ff2acc2e823906878904fb1fff3d2d8b3b3c&#45;&#45;network_bridge -->
<g id="edge1" class="edge">
<title>container_42e6eb67bb0da8991f3c4783d294ff2acc2e823906878904fb1fff3d2d8b3b3c:8fdec3d891cec12f1fa9490dc3648a6546d49b39d6a4edb770bdd77b8ae2a144--network_bridge</title>
<path fill="none" stroke="#1f78b4" d="M45.3198,-172.3C45.3198,-153.2861 45.3198,-131.5241 45.3198,-116.5465"/>
</g>
<!-- container_7b5d4b5a8288ae9e728681845c115da2f3785c5dd758a1e519fc2d48cc9374a2 -->
<g id="node9" class="node">
<title>container_7b5d4b5a8288ae9e728681845c115da2f3785c5dd758a1e519fc2d48cc9374a2</title>
<polygon fill="#cdcdcd" stroke="#000000" points="118.3766,-160.1 118.3766,-234.5 252.263,-234.5 252.263,-160.1 118.3766,-160.1"/>
<text text-anchor="middle" x="185.3198" y="-217.9" font-family="Times,serif" font-size="14.00" fill="#000000">service_4</text>
<polyline fill="none" stroke="#000000" points="118.3766,-209.7 252.263,-209.7 "/>
<text text-anchor="middle" x="150.8745" y="-193.1" font-family="Times,serif" font-size="14.00" fill="#000000">1234/tcp</text>
<polyline fill="none" stroke="#000000" points="183.3724,-184.9 183.3724,-209.7 "/>
<text text-anchor="middle" x="217.8177" y="-193.1" font-family="Times,serif" font-size="14.00" fill="#000000">5678/udp</text>
<polyline fill="none" stroke="#000000" points="118.3766,-184.9 252.263,-184.9 "/>
<text text-anchor="middle" x="185.1266" y="-168.3" font-family="Times,serif" font-size="14.00" fill="#000000">172.20.0.2</text>
</g>
<!-- container_7b5d4b5a8288ae9e728681845c115da2f3785c5dd758a1e519fc2d48cc9374a2&#45;&#45;network_docker&#45;network&#45;graph_internet -->
<g id="edge2" class="edge">
<title>container_7b5d4b5a8288ae9e728681845c115da2f3785c5dd758a1e519fc2d48cc9374a2:539637b24463fc2f401b553afd44a420bbf73a9d48a19c7b3d7a7ea7b8756b81--network_docker-network-graph_internet</title>
<path fill="none" stroke="#33a02c" stroke-dasharray="5,2" d="M185.3198,-160.3C185.3198,-148.1368 185.3198,-134.6314 185.3198,-123.3385"/>
</g>
<!-- container_8685a8dab43025e96c9ef3e77b9cdbfbace7aafc7b9d91e1ea27c463c3c1c9f6 -->
<g id="node10" class="node">
<title>container_8685a8dab43025e96c9ef3e77b9cdbfbace7aafc7b9d91e1ea27c463c3c1c9f6</title>
<polygon fill="#cdcdcd" stroke="#000000" points="1210.3324,-73.5 1210.3324,-123.1 1296.3072,-123.1 1296.3072,-73.5 1210.3324,-73.5"/>
<text text-anchor="middle" x="1253.3198" y="-106.5" font-family="Times,serif" font-size="14.00" fill="#000000">host_service</text>
<polyline fill="none" stroke="#000000" points="1210.3324,-98.3 1296.3072,-98.3 "/>
<text text-anchor="middle" x="1253.0824" y="-81.7" font-family="Times,serif" font-size="14.00" fill="#000000"> </text>
</g>
<!-- container_8685a8dab43025e96c9ef3e77b9cdbfbace7aafc7b9d91e1ea27c463c3c1c9f6&#45;&#45;network_host -->
<g id="edge3" class="edge">
<title>container_8685a8dab43025e96c9ef3e77b9cdbfbace7aafc7b9d91e1ea27c463c3c1c9f6:166c04ea9a7e49c63a6b7739361510aa70f0014260e6b1b03b0ec9347d76ab54--network_host</title>
<path fill="none" stroke="#808080" stroke-width="2" d="M1210.3198,-86.3C1203.1825,-86.3 1207.4585,-76.6411 1201.3198,-73 1153.9416,-44.8983 763.079,-24.7734 655.5868,-19.7322"/>
</g>
<!-- container_3a39e0a8fdb79e342ecb663a52353c7d58b6cb63f0ec7d27d051f48ed5f8b61f -->
<g id="node11" class="node">
<title>container_3a39e0a8fdb79e342ecb663a52353c7d58b6cb63f0ec7d27d051f48ed5f8b61f</title>
<polygon fill="#cdcdcd" stroke="#000000" points="575.8198,-160.1 575.8198,-234.5 726.8198,-234.5 726.8198,-160.1 575.8198,-160.1"/>
<text text-anchor="middle" x="651.3198" y="-217.9" font-family="Times,serif" font-size="14.00" fill="#000000">service_2</text>
<polyline fill="none" stroke="#000000" points="575.8198,-209.7 726.8198,-209.7 "/>
<text text-anchor="middle" x="613.5698" y="-181.1" font-family="Times,serif" font-size="14.00" fill="#000000">172.18.0.3</text>
<polyline fill="none" stroke="#000000" points="651.3198,-160.1 651.3198,-209.7 "/>
<text text-anchor="middle" x="689.0698" y="-193.1" font-family="Times,serif" font-size="14.00" fill="#000000">s2.netc</text>
<polyline fill="none" stroke="#000000" points="651.3198,-184.9 726.8198,-184.9 "/>
<text text-anchor="middle" x="689.0698" y="-168.3" font-family="Times,serif" font-size="14.00" fill="#000000">172.19.0.2</text>
</g>
<!-- container_3a39e0a8fdb79e342ecb663a52353c7d58b6cb63f0ec7d27d051f48ed5f8b61f&#45;&#45;network_docker&#45;network&#45;graph_network_b -->
<g id="edge4" class="edge">
<title>container_3a39e0a8fdb79e342ecb663a52353c7d58b6cb63f0ec7d27d051f48ed5f8b61f:94b8eee245436859b87a0c20d17a1655878a8f7fc041cb66814c69e16d771a17--network_docker-network-graph_network_b</title>
<path fill="none" stroke="#ff7f00" d="M613.3198,-161.3C613.3198,-145.8968 617.6157,-128.9371 621.6095,-116.4982"/>
</g>
<!-- container_3a39e0a8fdb79e342ecb663a52353c7d58b6cb63f0ec7d27d051f48ed5f8b61f&#45;&#45;network_docker&#45;network&#45;graph_network_c -->
<g id="edge5" class="edge">
<title>container_3a39e0a8fdb79e342ecb663a52353c7d58b6cb63f0ec7d27d051f48ed5f8b61f:e46bd03cb25afb2c3447f32c6a0ea9ae1d32e94c5bc2c1c5de70641a0bdaf81d--network_docker-network-graph_network_c</title>
<path fill="none" stroke="#6a3d9a" d="M727.3198,-172.3C734.2379,-172.3 731.1037,-164.1445 736.3198,-159.6 757.2069,-141.4022 784.4401,-126.7956 807.4805,-116.4119"/>
</g>
<!-- container_09536a22736bb178d3013c3cdb91b361f71b128c9f768d9ce7c86398a280db1b -->
<g id="node12" class="node">
<title>container_09536a22736bb178d3013c3cdb91b361f71b128c9f768d9ce7c86398a280db1b</title>
<polygon fill="#cdcdcd" stroke="#000000" points="378.8198,-172.5 378.8198,-222.1 529.8198,-222.1 529.8198,-172.5 378.8198,-172.5"/>
<text text-anchor="middle" x="454.3198" y="-205.5" font-family="Times,serif" font-size="14.00" fill="#000000">service_1</text>
<polyline fill="none" stroke="#000000" points="378.8198,-197.3 529.8198,-197.3 "/>
<text text-anchor="middle" x="416.5698" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.21.0.3</text>
<polyline fill="none" stroke="#000000" points="454.3198,-172.5 454.3198,-197.3 "/>
<text text-anchor="middle" x="492.0698" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.18.0.2</text>
</g>
<!-- container_09536a22736bb178d3013c3cdb91b361f71b128c9f768d9ce7c86398a280db1b&#45;&#45;network_docker&#45;network&#45;graph_network_a -->
<g id="edge6" class="edge">
<title>container_09536a22736bb178d3013c3cdb91b361f71b128c9f768d9ce7c86398a280db1b:eadfb1979c37a6bbb31e06ddf4a3eaff6aa00fb6a4a0158361e727e20db355ad--network_docker-network-graph_network_a</title>
<path fill="none" stroke="#e31a1c" d="M416.3198,-172.3C416.3198,-152.9488 411.6406,-131.2395 407.6925,-116.3664"/>
</g>
<!-- container_09536a22736bb178d3013c3cdb91b361f71b128c9f768d9ce7c86398a280db1b&#45;&#45;network_docker&#45;network&#45;graph_network_b -->
<g id="edge7" class="edge">
<title>container_09536a22736bb178d3013c3cdb91b361f71b128c9f768d9ce7c86398a280db1b:5d78b06ddda5fdbb00cfcc6bc77e95fef1b73215643c4bec5403502357ec71e2--network_docker-network-graph_network_b</title>
<path fill="none" stroke="#ff7f00" d="M530.3198,-185.3C540.6146,-185.3 585.3415,-141.8093 610.665,-116.3265"/>
</g>
<!-- container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560 -->
<g id="node13" class="node">
<title>container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560</title>
<polygon fill="#cdcdcd" stroke="#000000" points="745.3198,-172.5 745.3198,-222.1 1047.3198,-222.1 1047.3198,-172.5 745.3198,-172.5"/>
<text text-anchor="middle" x="896.3198" y="-205.5" font-family="Times,serif" font-size="14.00" fill="#000000">service_3</text>
<polyline fill="none" stroke="#000000" points="745.3198,-197.3 1047.3198,-197.3 "/>
<text text-anchor="middle" x="783.0698" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.21.0.2</text>
<polyline fill="none" stroke="#000000" points="820.8198,-172.5 820.8198,-197.3 "/>
<text text-anchor="middle" x="858.5698" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.18.0.4</text>
<polyline fill="none" stroke="#000000" points="896.3198,-172.5 896.3198,-197.3 "/>
<text text-anchor="middle" x="934.0698" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.19.0.3</text>
<polyline fill="none" stroke="#000000" points="971.8198,-172.5 971.8198,-197.3 "/>
<text text-anchor="middle" x="1009.5698" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000">172.22.1.2</text>
</g>
<!-- container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560&#45;&#45;network_docker&#45;network&#45;graph_network_a -->
<g id="edge8" class="edge">
<title>container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560:f45658e99b5dde0e6cd56b73501cb2a090e01c39e3931f183eb4d51065518b72--network_docker-network-graph_network_a</title>
<path fill="none" stroke="#e31a1c" d="M745.3198,-185.3C733.0634,-185.3 744.8427,-167.3159 735.3198,-159.6 658.339,-97.2265 612.5919,-142.4315 515.3198,-123.6 503.8722,-121.3838 491.8114,-118.8731 480.0029,-116.3152"/>
</g>
<!-- container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560&#45;&#45;network_docker&#45;network&#45;graph_network_b -->
<g id="edge9" class="edge">
<title>container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560:a367aad35e5a35474486791b9d09671e4914d85fd9ae4c8eb3c90cab0a297296--network_docker-network-graph_network_b</title>
<path fill="none" stroke="#ff7f00" d="M858.3198,-172.3C858.3198,-156.0982 774.5466,-132.4994 708.1172,-116.3332"/>
</g>
<!-- container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560&#45;&#45;network_docker&#45;network&#45;graph_network_c -->
<g id="edge10" class="edge">
<title>container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560:691ab484a711d0310f08857c455bc7544b5cb57c709b97576ce4f8909a4f9671--network_docker-network-graph_network_c</title>
<path fill="none" stroke="#6a3d9a" d="M934.3198,-172.3C934.3198,-147.7045 913.6899,-129.0061 893.3824,-116.5582"/>
</g>
<!-- container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560&#45;&#45;network_docker&#45;network&#45;graph_no_gateway -->
<g id="edge11" class="edge">
<title>container_01b9dd47c89b732a8791369dd2df8bdbfa05e1267fedf01190e680bb449f8560:3d6f4f72c482ab4cac97ac9a30793ff81e073b496123c93a74f53c6354c02dfa--network_docker-network-graph_no_gateway</title>
<path fill="none" stroke="#b15928" d="M1047.3198,-185.3C1059.4222,-185.3 1051.8009,-170.8271 1056.3198,-159.6 1062.2612,-144.8388 1069.7922,-128.4609 1075.547,-116.35"/>
</g>
<!-- container_1f3ce68cf416e1aa17096362a691c217ae582713a2406c61cadf5c110e998587 -->
<g id="node14" class="node">
<title>container_1f3ce68cf416e1aa17096362a691c217ae582713a2406c61cadf5c110e998587</title>
<polygon fill="#cdcdcd" stroke="#000000" points="1065.2272,-172.5 1065.2272,-222.1 1171.4124,-222.1 1171.4124,-172.5 1065.2272,-172.5"/>
<text text-anchor="middle" x="1118.3198" y="-205.5" font-family="Times,serif" font-size="14.00" fill="#000000">isolated_service</text>
<polyline fill="none" stroke="#000000" points="1065.2272,-197.3 1171.4124,-197.3 "/>
<text text-anchor="middle" x="1117.9772" y="-180.7" font-family="Times,serif" font-size="14.00" fill="#000000"> </text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,6 +0,0 @@
#! /usr/bin/env bash
(
cd "$(dirname "$0")/.." \
&& pipenv install
)

View file

@ -1,6 +0,0 @@
#! /usr/bin/env bash
(
cd "$(dirname "$0")/.." \
&& pipenv run python docker-network-graph.py -o output.svg
)