<!--
  canonical-url: https://www.avonture.be/blog/docker-compose-viz
  published:     2024-06-08
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# How to generate a graph from compose.yaml

> Instantly visualize your Docker Compose architecture. Use `compose-viz` to generate a clear graph of services, dependencies, and exposed ports from your `compose.yaml` file.

---
![How to generate a graph from compose.yaml](/img/v2/docker_tips.webp)

**TL;DR**

This article shows how to visualize a `compose.yaml` file as a dependency graph using the `compose-viz` Docker image, producing an image (PNG, SVG, and other formats via `--format`) that shows services, their dependencies, and exposed ports at a glance — useful for understanding large multi-service Docker architectures. It also mentions `docker compose config` to resolve and merge multiple `.yml` files/variables before visualizing.

Imagine you have a very big `compose.yaml` file with a lot of services and dependencies.

You also have multiple exposed ports.

You'd like to have an at-a-glance view of services, dependencies and open ports. Is this possible? Yes! <https://github.com/compose-viz/compose-viz> does the magic for us.

Here's what `compose-viz` generates from a Joomla `compose.yaml`:

![Joomla compose-viz](./images/joomla.webp)

> **How to interpret the image?:**
>
> We can see that the port `8080` is exposed to the computer. That port is, in fact, port `80` of the `joomla` container. And, too, we see that `joomla` has a dependency with the `joomladb` container. Easy no?

## Reproduce it yourself

For the demo, please start a Linux shell and run `mkdir -p /tmp/compose-viz && cd $_` to create a folder called `compose-viz` in your Linux temporary folder and jump in it.

Please create a new file called `compose.yaml` with this **simplified** content:

**compose.yaml**

```yaml
services:
  joomla:
    image: joomla
    ports:
      - 8080:80
    depends_on:
      - joomladb

  joomladb:
    image: postgres:16.0-alpine
```

Let the magic happen and run `docker run --rm -it -u $(id -u):$(id -g) -v $(pwd):/in wst24365888/compose-viz compose.yaml` — you'll get the image shown above.

> **See the --format flag:**
>
> By adding `--format svg`, you'll get an SVG instead of a PNG. The list of supported output formats is huge: `png|dot|jpeg|json|svg|bmp|canon|cmap|cmapx|cmapx_np|dot_json|emf|emfplus|eps|fig|gif|gv|imap|imap_np|ismap|jpe|jpg|json0|metafile|mp|pdf|pic|plain|plain-ext|pov|ps|ps2|tif|tiff|tk|vml|xdot|xdot1.2|xdot1.4|xdot_json`.

## A more complex example

Replace the content of the `compose.yaml` with this one:

**compose.yaml**

```yaml
services:

  redis:
    image: redis:alpine
    ports:
      - "6379"
    networks:
      - frontend
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  db:
    image: postgres:9.4
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend
    deploy:
      placement:
        constraints: [ node.role == manager ]
  vote:
    image: dockersamples/examplevotingapp_vote:before
    ports:
      - 5000:80
    networks:
      - frontend
    depends_on:
      - redis
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
      restart_policy:
        condition: on-failure
  result:
    image: dockersamples/examplevotingapp_result:before
    ports:
      - 5001:80
    networks:
      - backend
    depends_on:
      - db
    deploy:
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 1
      labels: [ APP=VOTING ]
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 3
        window: 120s
      placement:
        constraints: [ node.role == manager ]

  visualizer:
    image: dockersamples/visualizer
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      placement:
        constraints: [ node.role == manager ]

networks:
  frontend:
  backend:

volumes:
  db-data:
```

And the image here below will be generated by the tool:

![More complex example](./images/more_complex.webp)

Here, we can see:

* We've four exposed ports: `5001`, `5000`, `6379` and `8080`.
* Port `8080` is linked to a `visualizer` web service; that service is using a volume pointing to `/var/run/docker.sock`
* Ports `5000` and `5001` are referring to services called `vote` and `result`. Since the internal port is port `80`, we know that these ports are web interfaces.
* The `vote` service (port `5000`) is using a `redis` service; accessible using port `6379`.
* The `result` service (port `5001`) is linked to a Postgres service called `db` and having persistent data (since we have a Docker volume called `db-data`).
* And so on.

Such a visualization tool greatly simplifies the understanding of a Docker architecture.

*`compose-viz` gives you one fixed rendering. If you want to control exactly what the diagram shows, [Documentation as Code - Transform Your Infrastructure into Beautiful Diagrams with Python and Mermaid](/blog/docker-python-mermaid) parses the same `compose.yaml` with a Python script you own, and [Docker - Diagrams as code](/blog/docker-diagram-as-code) lists a dozen other diagram-as-code tools.*

## Docker config

If like me you're using a lot of `.yml` files by running Docker and/or using environment variables in it; just run `docker compose config` to ask Docker to *render* (on the screen only) what it calls *Parse, resolve and render compose file in canonical format* i.e. it will merge all your `.yml` in one string and resolve variables.

Copy/paste the screen output in a temporary file and use this tool on that file.
