commit
0940ffa495
5 changed files with 189 additions and 35 deletions
46
README.md
46
README.md
|
@ -1,31 +1,41 @@
|
|||
# dockviz
|
||||
# dockviz: Visualizing Docker Data
|
||||
|
||||
Visualizing Docker Data
|
||||
This command takes Docker image and container information and presents in
|
||||
different ways, to help you understand what's going on inside the system.
|
||||
|
||||
This command takes the raw Docker JSON and visualizes it in various ways.
|
||||
# Quick Start
|
||||
|
||||
For image information, output can be formatted as
|
||||
[Graphviz](http://www.graphviz.org), as a tree in the terminal, or in a short summary.
|
||||
1. Download the [latest release](https://github.com/justone/dockviz/releases).
|
||||
2. Visualize images by running `dockviz images -t`, which has similar output to `docker images -t`.
|
||||
|
||||
For container information, only Graphviz output has been implemented.
|
||||
Image can be visualized as [Graphviz](http://www.graphviz.org), or as a tree or short summary in the terminal. Only Graphviz output has been implemented for containers.
|
||||
|
||||
# Examples
|
||||
# Output Examples
|
||||
|
||||
## Containers
|
||||
|
||||
Currently, containers are visualized with labeled lines for links. Containers that aren't running are greyed out.
|
||||
|
||||
```
|
||||
$ dockviz containers -d | dot -Tpng -o containers.png
|
||||
```
|
||||
|
||||
![](sample/containers.png "Container")
|
||||
|
||||
## Images
|
||||
|
||||
Image info is visualized with lines indicating parent images:
|
||||
|
||||
```
|
||||
$ dockviz images -d | dot -Tpng -o images.png
|
||||
```
|
||||
|
||||
![](sample/images.png "Image")
|
||||
|
||||
Or in short form:
|
||||
|
||||
```
|
||||
$ dockviz images -s
|
||||
nate/mongodb: latest
|
||||
redis: latest
|
||||
ubuntu: 12.04, precise, 12.10, quantal, 13.04, raring
|
||||
|
@ -34,6 +44,7 @@ ubuntu: 12.04, precise, 12.10, quantal, 13.04, raring
|
|||
Or as a tree in the terminal:
|
||||
|
||||
```
|
||||
$ dockviz images -t
|
||||
└─511136ea3c5a Virtual Size: 0.0 B
|
||||
|─f10ebce2c0e1 Virtual Size: 103.7 MB
|
||||
| └─82cdea7ab5b5 Virtual Size: 103.9 MB
|
||||
|
@ -67,29 +78,21 @@ Or as a tree in the terminal:
|
|||
|
||||
# Running
|
||||
|
||||
## TCP
|
||||
Dockviz supports connecting to the Docker daemon directly. It defaults to `unix:///var/run/docker.sock`, but respects the following as well:
|
||||
|
||||
When docker is listening on the TCP port:
|
||||
* The `DOCKER_HOST`, `DOCKER_CERT_PATH`, and `DOCKER_TLS_VERIFY` environment variables, as set up by [boot2docker](http://boot2docker.io/) or [docker-machine](https://docs.docker.com/machine/).
|
||||
* Command line arguments (e.g. `--tlscacert`), like those that Docker itself supports.
|
||||
|
||||
Dockviz also supports receiving Docker image or container json data on standard input.
|
||||
|
||||
```
|
||||
$ curl -s http://localhost:4243/images/json?all=1 | dockviz images --tree
|
||||
$ curl -s http://localhost:4243/containers/json?all=1 | dockviz containers --dot | dot -Tpng -o containers.png
|
||||
```
|
||||
|
||||
## Socket
|
||||
|
||||
When docker is listening on the socket:
|
||||
|
||||
```
|
||||
$ echo -e "GET /images/json?all=1 HTTP/1.0\r\n" | nc -U /var/run/docker.sock | tail -n +5 | dockviz images --tree
|
||||
$ echo -e "GET /containers/json?all=1 HTTP/1.0\r\n" | nc -U /var/run/docker.sock | tail -n +5 | dockviz containers --dot | dot -Tpng -o containers.png
|
||||
```
|
||||
|
||||
GNU netcat doesn't support `-U` (UNIX socket) flag, so OpenBSD variant can be used.
|
||||
|
||||
## Direct from Docker
|
||||
|
||||
Someday soon the Docker command line will allow dumping the image and container JSON directly.
|
||||
Note: GNU netcat doesn't support `-U` (UNIX socket) flag, so OpenBSD variant can be used.
|
||||
|
||||
# Binaries
|
||||
|
||||
|
@ -101,4 +104,3 @@ See the [releases](https://github.com/justone/dockviz/releases) area for binarie
|
|||
go get ./...
|
||||
go build
|
||||
```
|
||||
|
||||
|
|
14
cli.go
14
cli.go
|
@ -1,19 +1,31 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
)
|
||||
|
||||
type GlobalOptions struct {
|
||||
// no options yet
|
||||
TLSCaCert string `long:"tlscacert" value-name:"~/.docker/ca.pem" description:"Trust certs signed only by this CA"`
|
||||
TLSCert string `long:"tlscert" value-name:"~/.docker/cert.pem" description:"Path to TLS certificate file"`
|
||||
TLSKey string `long:"tlskey" value-name:"~/.docker/key.pem" description:"Path to TLS key file"`
|
||||
TLSVerify bool `long:"tlsverify" description:"Use TLS and verify the remote"`
|
||||
Host string `long:"host" short:"H" value-name:"unix:///var/run/docker.sock" description:"Docker host to connect to"`
|
||||
Version func() `long:"version" short:"v" description:"Display version information."`
|
||||
}
|
||||
|
||||
var globalOptions GlobalOptions
|
||||
var parser = flags.NewParser(&globalOptions, flags.Default)
|
||||
|
||||
var version = "v0.2"
|
||||
|
||||
func main() {
|
||||
globalOptions.Version = func() {
|
||||
fmt.Println("dockviz", version)
|
||||
os.Exit(0)
|
||||
}
|
||||
if _, err := parser.Parse(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
@ -28,15 +30,50 @@ var containersCommand ContainersCommand
|
|||
|
||||
func (x *ContainersCommand) Execute(args []string) error {
|
||||
|
||||
// read in stdin
|
||||
stdin, err := ioutil.ReadAll(os.Stdin)
|
||||
var containers *[]Container
|
||||
|
||||
stat, err := os.Stdin.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading all input", err)
|
||||
return fmt.Errorf("error reading stdin stat", err)
|
||||
}
|
||||
|
||||
containers, err := parseContainersJSON(stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
if (stat.Mode() & os.ModeCharDevice) == 0 {
|
||||
// read in stdin
|
||||
stdin, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading all input", err)
|
||||
}
|
||||
|
||||
containers, err = parseContainersJSON(stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
client, err := connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientContainers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var conts []Container
|
||||
for _, container := range clientContainers {
|
||||
conts = append(conts, Container{
|
||||
container.ID,
|
||||
container.Image,
|
||||
container.Names,
|
||||
apiPortToMap(container.Ports),
|
||||
container.Created,
|
||||
container.Status,
|
||||
container.Command,
|
||||
})
|
||||
}
|
||||
|
||||
containers = &conts
|
||||
}
|
||||
|
||||
if containersCommand.Dot {
|
||||
|
@ -48,6 +85,20 @@ func (x *ContainersCommand) Execute(args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func apiPortToMap(ports []docker.APIPort) []map[string]interface{} {
|
||||
result := make([]map[string]interface{}, 2)
|
||||
for _, port := range ports {
|
||||
intPort := map[string]interface{}{
|
||||
"IP": port.IP,
|
||||
"Type": port.Type,
|
||||
"PrivatePort": port.PrivatePort,
|
||||
"PublicPort": port.PublicPort,
|
||||
}
|
||||
result = append(result, intPort)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func parseContainersJSON(rawJSON []byte) (*[]Container, error) {
|
||||
|
||||
var containers []Container
|
||||
|
|
50
images.go
50
images.go
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
@ -29,15 +31,51 @@ var imagesCommand ImagesCommand
|
|||
|
||||
func (x *ImagesCommand) Execute(args []string) error {
|
||||
|
||||
// read in stdin
|
||||
stdin, err := ioutil.ReadAll(os.Stdin)
|
||||
var images *[]Image
|
||||
|
||||
stat, err := os.Stdin.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading all input", err)
|
||||
return fmt.Errorf("error reading stdin stat", err)
|
||||
}
|
||||
|
||||
images, err := parseImagesJSON(stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
if (stat.Mode() & os.ModeCharDevice) == 0 {
|
||||
// read in stdin
|
||||
stdin, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading all input", err)
|
||||
}
|
||||
|
||||
images, err = parseImagesJSON(stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
client, err := connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientImages, err := client.ListImages(docker.ListImagesOptions{All: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ims []Image
|
||||
for _, image := range clientImages {
|
||||
// fmt.Println(image)
|
||||
ims = append(ims, Image{
|
||||
image.ID,
|
||||
image.ParentID,
|
||||
image.RepoTags,
|
||||
image.VirtualSize,
|
||||
image.Size,
|
||||
image.Created,
|
||||
})
|
||||
}
|
||||
|
||||
images = &ims
|
||||
}
|
||||
|
||||
if imagesCommand.Dot {
|
||||
|
|
51
util.go
Normal file
51
util.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
func connect() (*docker.Client, error) {
|
||||
|
||||
// grab directly from docker daemon
|
||||
var endpoint string
|
||||
if env_endpoint := os.Getenv("DOCKER_HOST"); len(env_endpoint) > 0 {
|
||||
endpoint = env_endpoint
|
||||
} else if len(globalOptions.Host) > 0 {
|
||||
endpoint = globalOptions.Host
|
||||
} else {
|
||||
// assume local socket
|
||||
endpoint = "unix:///var/run/docker.sock"
|
||||
}
|
||||
|
||||
var client *docker.Client
|
||||
var err error
|
||||
dockerTlsVerifyEnv := os.Getenv("DOCKER_TLS_VERIFY")
|
||||
if dockerTlsVerifyEnv == "1" || globalOptions.TLSVerify {
|
||||
if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); len(dockerCertPath) > 0 {
|
||||
cert := path.Join(dockerCertPath, "cert.pem")
|
||||
key := path.Join(dockerCertPath, "key.pem")
|
||||
ca := path.Join(dockerCertPath, "ca.pem")
|
||||
client, err = docker.NewTLSClient(endpoint, cert, key, ca)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if len(globalOptions.TLSCert) > 0 && len(globalOptions.TLSKey) > 0 && len(globalOptions.TLSCaCert) > 0 {
|
||||
client, err = docker.NewTLSClient(endpoint, globalOptions.TLSCert, globalOptions.TLSKey, globalOptions.TLSCaCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("TLS Verification requested but certs not specified")
|
||||
}
|
||||
} else {
|
||||
client, err = docker.NewClient(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return client, nil
|
||||
}
|
Loading…
Reference in a new issue