golang生成和处理Docker容器连接关系图的插件库decompose的使用

Golang生成和处理Docker容器连接关系图的插件库decompose的使用

decompose是一个用于Docker环境的逆向工程工具,可以获取Docker容器的所有网络连接并将其导出为多种格式。

功能特性

  • 跨平台支持,使用不同策略获取容器连接:
    • 在Linux上以root用户运行最快,使用nsenter支持所有容器类型
    • 非root用户或非Linux系统会尝试在容器内运行netstat
  • 单二进制静态编译的CLI工具
  • 生成带端口号的详细连接关系图
  • 支持多种输出格式:
    • Graphviz dot格式
    • Structurizr DSL
    • Compose YAML
    • PlantUML
    • 伪图形树
    • JSON流
    • 统计信息(节点数、连接数和监听端口数)
    • CSV格式(包含name、listen和outbounds列)
  • 快速扫描,约470个容器4000个连接只需5秒
  • 基于图拓扑的自动聚类
  • 深度检查模式,显示容器内进程间的连接
  • Unix套接字连接支持
  • 测试覆盖率超过95%

安装方式

  • 下载预编译的二进制文件(支持Linux、FreeBSD、macOS和Windows)
  • 使用Docker镜像

使用示例

基本使用

decompose [flags]

可用参数:

-cluster string
    json文件包含聚类规则,或auto:<similarity>自动聚类,similarity是(0.0,1.0]范围内的浮点数
-compress
    压缩图
-deep
    基于进程的内省
-follow string
    仅跟踪指定名称的容器,逗号分隔或从@文件读取
-format string
    输出格式:csv, dot, json, puml, sdsl, stat, tree, yaml (默认"json")
-help
    显示帮助
-load value
    加载json流,可多次使用
-local
    跳过外部主机
-meta string
    json文件包含用于丰富的元数据
-no-loops
    从输出中移除自循环连接
-no-orphans
    从输出中移除孤立的(未连接的)节点
-out string
    输出:文件名或"-"表示stdout(默认"-")
-proto string
    要扫描的协议:tcp,udp,unix或all(默认"all")
-silent
    禁止在stderr中显示进度消息
-skip-env string
    要从输出中跳过的环境变量名,不区分大小写,逗号分隔
-version
    显示版本

环境变量

DOCKER_HOST - 连接URI
DOCKER_CERT_PATH - 包含key.pem、cert.pm和ca.pem的目录路径
DOCKER_TLS_VERIFY - 启用客户端TLS验证
IN_DOCKER_PROC_ROOT - 用于Docker内场景 - 主机挂载的/proc的根目录

示例代码

  1. 保存完整的json流:
sudo decompose > nodes-1.json
  1. 获取dot格式文件:
decompose -format dot > connections.dot
  1. 获取TCP和UDP连接的dot格式:
decompose -proto tcp,udp -format dot > tcp.dot
  1. 合并来自json流的图,按协议过滤,跳过远程主机并保存为dot格式:
decompose -local -proto tcp -load "nodes-*.json" -format dot > graph-merged.dot
  1. 加载json流,丰富内容并保存为structurizr dsl格式:
decompose -load nodes-1.json -meta metadata.json -format sdsl > workspace.dsl
  1. 保存自动聚类的图,相似度因子为0.6,格式为structurizr dsl:
decompose -cluster auto:0.6 -format sdsl > workspace.dsl

JSON流格式

type Item struct {
    Name       string              `json:"name"` // 容器名称
    IsExternal bool                `json:"is_external"` // 此主机是否为外部主机
    Image      *string             `json:"image,omitempty"` // Docker镜像(如果有)
    Container  struct{
        Cmd    []string          `json:"cmd"`
        Env    []string          `json:"env"`
        Labels map[string]string `json:"labels"`
    } `json:"container"` // 容器信息
    Listen     map[string][]{
        Kind   string            `json:"kind"`  // tcp / udp / unix
        Value  string            `json:"value"`
        Local  bool              `json:"local"` // 是否绑定到回环
    } `json:"listen"` // 带有进程名称的端口
    Networks   []string            `json:"networks"` // 网络名称
    Tags       []string            `json:"tags"` // 标签,如果存在元数据
    Volumes    []*struct{
        Type string `json:"type"`
        Src  string `json:"src"`
        Dst  string `json:"dst"`
    } `json:"volumes"`           // 卷信息,仅在'-full'时
    Connected  map[string][]string `json:"connected"` // 名称 -> 端口切片
}

元数据格式

为了丰富输出内容,你可以提供额外的json文件,例如:

{
    "foo": {
        "info": "info for foo",
        "docs": "https://acme.corp/docs/foo",
        "repo": "https://git.acme.corp/foo",
        "tags": ["some"]
    },
    "bar": {
        "info": "info for bar",
        "tags": ["other", "not-foo"]
    }
}

聚类

使用规则聚类

你可以通过灵活的规则将服务聚类到"clusters"中,支持dot、structurizr和stat输出格式。

示例json(顺序很重要):

[
    {
        "name": "cluster-name",
        "weight": 1,
        "if": "<expression>"
    },
    ...
]

自动聚类

decompose提供自动聚类选项,使用-cluster auto:<similarity>尝试,similarity是(0.0,1.0]范围内的浮点数,表示节点必须有多少相似端口才能放在同一集群中(1.0 - 必须所有端口都相同)。

示例结果

从redis-cluster获取的方案:

Redis Cluster Diagram

重现步骤:

git clone https://github.com/s0rg/redis-cluster-compose.git
cd redis-cluster-compose
docker compose up -d

然后:

decompose -format dot | dot -Tsvg > redis-cluster.svg

许可证

MIT License


更多关于golang生成和处理Docker容器连接关系图的插件库decompose的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang生成和处理Docker容器连接关系图的插件库decompose的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用decompose库生成和处理Docker容器连接关系图

decompose是一个用于分析和可视化Docker容器连接关系的Go库,它可以帮助开发者理解复杂的容器间依赖关系。下面我将详细介绍如何使用这个库。

安装decompose库

首先,你需要安装decompose库:

go get github.com/google/decompose

基本使用方法

1. 获取Docker容器连接信息

package main

import (
	"fmt"
	"log"

	"github.com/google/decompose/docker"
)

func main() {
	// 创建Docker连接器
	connector, err := docker.NewConnector()
	if err != nil {
		log.Fatalf("Failed to create Docker connector: %v", err)
	}

	// 获取所有容器及其连接关系
	containers, err := connector.GetContainers()
	if err != nil {
		log.Fatalf("Failed to get containers: %v", err)
	}

	// 打印容器信息
	for _, container := range containers {
		fmt.Printf("Container ID: %s\n", container.ID)
		fmt.Printf("Name: %s\n", container.Name)
		fmt.Printf("Image: %s\n", container.Image)
		fmt.Printf("Ports: %v\n", container.Ports)
		fmt.Printf("Links: %v\n", container.Links)
		fmt.Println("------------------------")
	}
}

2. 生成DOT格式的关系图

decompose可以生成DOT格式的输出,便于使用Graphviz等工具可视化:

package main

import (
	"fmt"
	"log"

	"github.com/google/decompose/docker"
	"github.com/google/decompose/graph"
)

func main() {
	// 创建Docker连接器
	connector, err := docker.NewConnector()
	if err != nil {
		log.Fatalf("Failed to create Docker connector: %v", err)
	}

	// 获取容器数据
	containers, err := connector.GetContainers()
	if err != nil {
		log.Fatalf("Failed to get containers: %v", err)
	}

	// 创建图生成器
	g := graph.NewGraph()

	// 添加容器到图中
	for _, container := range containers {
		g.AddContainer(container)
	}

	// 生成DOT格式输出
	dotOutput := g.DOT()
	fmt.Println(dotOutput)
}

3. 将关系图保存为图片

要生成可视化的图片,你需要安装Graphviz工具:

package main

import (
	"log"
	"os"
	"os/exec"

	"github.com/google/decompose/docker"
	"github.com/google/decompose/graph"
)

func main() {
	// 获取Docker容器数据
	connector, err := docker.NewConnector()
	if err != nil {
		log.Fatal(err)
	}
	containers, err := connector.GetContainers()
	if err != nil {
		log.Fatal(err)
	}

	// 生成DOT文件
	g := graph.NewGraph()
	for _, container := range containers {
		g.AddContainer(container)
	}
	dotContent := g.DOT()

	// 将DOT内容写入临时文件
	tmpFile, err := os.CreateTemp("", "docker-graph-*.dot")
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.WriteString(dotContent); err != nil {
		log.Fatal(err)
	}
	tmpFile.Close()

	// 使用Graphviz生成图片
	outputFile := "docker-graph.png"
	cmd := exec.Command("dot", "-Tpng", tmpFile.Name(), "-o", outputFile)
	if err := cmd.Run(); err != nil {
		log.Fatalf("Failed to generate graph: %v", err)
	}

	log.Printf("Graph saved as %s", outputFile)
}

高级用法

1. 过滤容器

// 只显示运行中的容器
runningContainers := make([]docker.Container, 0)
for _, container := range containers {
    if container.State == "running" {
        runningContainers = append(runningContainers, container)
    }
}

2. 自定义图样式

// 创建自定义样式的图
g := graph.NewGraphWithOptions(&graph.Options{
    NodeShape:     "box",
    NodeStyle:     "filled",
    NodeFillColor: "lightblue",
    EdgeColor:     "gray",
})

for _, container := range containers {
    g.AddContainer(container)
}

3. 分析特定网络

// 获取特定网络的容器
networkName := "my-network"
networkContainers := make([]docker.Container, 0)
for _, container := range containers {
    for _, net := range container.Networks {
        if net == networkName {
            networkContainers = append(networkContainers, container)
            break
        }
    }
}

实际应用示例

下面是一个完整的示例,展示如何生成一个特定Docker网络的连接关系图:

package main

import (
	"log"
	"os"
	"os/exec"

	"github.com/google/decompose/docker"
	"github.com/google/decompose/graph"
)

func main() {
	// 1. 连接到Docker
	connector, err := docker.NewConnector()
	if err != nil {
		log.Fatal(err)
	}

	// 2. 获取所有容器
	containers, err := connector.GetContainers()
	if err != nil {
		log.Fatal(err)
	}

	// 3. 过滤出特定网络的容器
	targetNetwork := "my-app-network"
	var filteredContainers []docker.Container
	
	for _, c := range containers {
		for _, net := range c.Networks {
			if net == targetNetwork {
				filteredContainers = append(filteredContainers, c)
				break
			}
		}
	}

	// 4. 创建图并添加容器
	g := graph.NewGraphWithOptions(&graph.Options{
		NodeShape:     "ellipse",
		NodeStyle:     "filled",
		NodeFillColor: "lightgreen",
		EdgeColor:     "darkgreen",
		RankDir:       "LR", // 从左到右布局
	})

	for _, container := range filteredContainers {
		g.AddContainer(container)
	}

	// 5. 生成DOT文件
	dotContent := g.DOT()
	
	// 6. 保存为PNG
	tmpFile, err := os.CreateTemp("", "network-graph-*.dot")
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.WriteString(dotContent); err != nil {
		log.Fatal(err)
	}
	tmpFile.Close()

	outputFile := targetNetwork + "-graph.png"
	cmd := exec.Command("dot", "-Tpng", tmpFile.Name(), "-o", outputFile)
	if err := cmd.Run(); err != nil {
		log.Fatalf("Failed to generate graph: %v", err)
	}

	log.Printf("Network graph saved as %s", outputFile)
}

注意事项

  1. 使用decompose需要本地安装并运行Docker服务
  2. 生成可视化图表需要安装Graphviz工具
  3. 对于大型容器集群,生成的图表可能会很复杂,建议按网络或项目进行过滤
  4. 某些Docker配置可能需要管理员权限才能访问

通过decompose库,你可以方便地分析和可视化Docker容器间的复杂关系,这对于调试和优化容器化应用架构非常有帮助。

回到顶部