golang生成和处理Docker容器连接关系图的插件库decompose的使用
Golang生成和处理Docker容器连接关系图的插件库decompose的使用
decompose是一个用于Docker环境的逆向工程工具,可以获取Docker容器的所有网络连接并将其导出为多种格式。
功能特性
- 跨平台支持,使用不同策略获取容器连接:
- 在Linux上以root用户运行最快,使用
nsenter
支持所有容器类型 - 非root用户或非Linux系统会尝试在容器内运行
netstat
- 在Linux上以root用户运行最快,使用
- 单二进制静态编译的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的根目录
示例代码
- 保存完整的json流:
sudo decompose > nodes-1.json
- 获取dot格式文件:
decompose -format dot > connections.dot
- 获取TCP和UDP连接的dot格式:
decompose -proto tcp,udp -format dot > tcp.dot
- 合并来自json流的图,按协议过滤,跳过远程主机并保存为dot格式:
decompose -local -proto tcp -load "nodes-*.json" -format dot > graph-merged.dot
- 加载json流,丰富内容并保存为structurizr dsl格式:
decompose -load nodes-1.json -meta metadata.json -format sdsl > workspace.dsl
- 保存自动聚类的图,相似度因子为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获取的方案:
重现步骤:
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
更多关于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)
}
注意事项
- 使用decompose需要本地安装并运行Docker服务
- 生成可视化图表需要安装Graphviz工具
- 对于大型容器集群,生成的图表可能会很复杂,建议按网络或项目进行过滤
- 某些Docker配置可能需要管理员权限才能访问
通过decompose库,你可以方便地分析和可视化Docker容器间的复杂关系,这对于调试和优化容器化应用架构非常有帮助。