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/ test/
example.png 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 *.gv
*.pdf *.pdf
*.png
*.svg
.idea .idea
/output

View file

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

View file

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

33
Pipfile.lock generated
View file

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

View file

@ -3,34 +3,50 @@
Visualize the relationship between Docker networks and containers Visualize the relationship between Docker networks and containers
as a neat graphviz graph. 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
![example graph](https://raw.githubusercontent.com/e-dant/docker-network-graph/release/example.png) ![example graph](./example.svg)
## Usage ## Usage
usage: docker-network-graph.py [-h] [-v] [-o OUT] ```bash
usage: docker-network-graph.py [-h] [-v] [-o OUT] [-u]
Visualize docker networks. Visualize docker networks.
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help Show this help message and exit
-v, --verbose Verbose output -v, --verbose Verbose output
-o OUT, --out OUT Write output to file -o OUT, --out OUT Write output to file [not supported by container]
-u, --url Generate link for GraphvizOnline
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.
## Running inside docker ## Running inside docker
If you want to generate a graph for a remote system you can also easily If you want to generate a graph for a remote system you can also easily
run this script inside a pre-built docker container: 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]. This will just generate and output the graph in the [DOT Language][dot].
You can then paste that code into [GraphvizOnline][gvonline] 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 paste the previous output there, press enter and finally CTRL+C to
generate the file. 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 ## Development
If you'd like to contribute to this project, there is a sample docker-compose file If you'd like to contribute to this project, there is a sample docker-compose file
using dummy containers in `test`. 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_b
- network_c - network_c
- no_gateway - 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: host_service:
container_name: host_service container_name: host_service
image: leoverto/dummy-image image: leoverto/dummy-image
@ -33,6 +41,9 @@ services:
network_mode: none network_mode: none
networks: networks:
internet:
driver_opts:
com.docker.network.bridge.enable_icc: "false"
network_a: network_a:
network_b: network_b:
network_c: network_c:

View file

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