Graphvizでサーバー構成図を作成


# 概要

DOT言語で記述したコードからグラフを生成できます。
グラフではなくコードを編集して生成する形をとることにより、
修正作業が容易になったり、差分が明確になったりといった恩恵を受けることができます。

以下、Macでの導入を記述していきます。

# 導入

`Homebrew` 経由で入ります。

```shell-session
brew install graphviz
```

# HelloWorld

dotファイルを作成します。

```hello.dot
digraph "hello world" {
  Hoge -> Huga;
}
```

`graphviz` の導入により、 `dot` コマンドが使用できるようになります。
このコマンドにより、作成したdotファイルから画像を生成します。

以下の例では `png` を指定しています。
サポートするフォーマットの一覧は[ドキュメント](http://www.graphviz.org/content/output-formats)から確認できます。

```shell-session
dot -T png hello.dot -o hello.png 
```


生成された画像を確認します。

```shell-session
open hello.png
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/e5b0b25e-0293-97a0-bd8f-386931828125.png "hello.png")

# 逆引き

## 形状の変更

`shape` を指定することで変更可能です。
形状の一覧は[ドキュメント](http://www.graphviz.org/doc/info/shapes.html)から確認できます。

```hello.dot
digraph "hello world" {
  node [shape = box];

  Hoge -> Huga;
  Foo -> Huga;
  Bar -> Huga;

  Bar [shape = box3d];
}
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/86c99ec0-78da-e611-5f8b-d31e7cceed36.png "hello.png")


## 矢印の変更

`arrowhead`、`arrowtail` を指定することで変更可能です。
形状の一覧は[ドキュメント](http://www.graphviz.org/content/arrow-shapes)から確認できます。

```hello.dot
digraph "hello world" {
  Hoge -> Huga;
  Foo -> Huga [arrowhead = vee];
  Bar01 -> Huga [dir = both];
  Bar02 -> Huga [dir = both, arrowhead = crow, arrowtail = dot];
}
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/338028d4-f5a7-a061-2bc4-ef24bb39cccc.png "hello.png")

## 色の変更

`color`、`fontcolor` を指定することで変更可能です。
色の一覧は[ドキュメント](http://www.graphviz.org/content/color-names)から確認できます。

```hello.dot
digraph "hello world" {
  Hoge -> Huga;
  Foo -> Huga;
  Bar -> Huga [color = red];

  Foo [color = green];
  Huga [style = filled, color = blue, fontcolor = white];
}
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/9c85dcf4-332c-3954-af77-df01e7276668.png "hello.png")


## グループ分け

`subgraph` を指定することでグループ分けが可能です。
prefix として `cluster` を付与する必要があります。

```
digraph "hello world" {
  {Hoge, Foo, Bar} -> Huga;
  Huga -> {Piyo01, Piyo02, Piyo03};

  subgraph cluster01 {
    {Hoge, Foo, Bar};

    style = filled;
    label = "hogehoge";
  }

  subgraph cluster02 {
    Huga;

    label = "hugahuga";
  }

  subgraph cluster_piyo {
    {Piyo01, Piyo02, Piyo03};
  }
}
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/304b2fe9-03d6-5afe-271a-9e5d1e1a6bc4.png "hello.png")


## 横方向に展開

`rank_dir` に `LR` を指定することで横方向に構造が進む形になります。

```
digraph "hello world" {
  rank_dir = LR;

  {Hoge, Foo, Bar} -> Huga;
  Huga -> {Piyo01, Piyo02, Piyo03};

  subgraph cluster01 {
    {Hoge, Foo, Bar};

    style = filled;
    label = "hogehoge";
  }

  subgraph cluster02 {
    Huga;

    label = "hugahuga";
  }

  subgraph cluster_piyo {
    {Piyo01, Piyo02, Piyo03};
  }
}
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/e205f86e-1ff9-0f29-d524-d29131705a38.png "hello.png")


## グループに対して矢印

`compound = true`、`lhead`、`ltail` を指定します。

```
digraph "hello world" {
  compound = true;

  {Hoge, Foo, Bar} -> Huga [lhead = cluster02];
  Huga -> {Piyo01, Piyo02, Piyo03} [lhead = cluster_piyo, ltail = cluster02];

  subgraph cluster01 {
    {Hoge, Foo, Bar};

    style = filled;
    label = "hogehoge";
  }

  subgraph cluster02 {
    Huga;

    label = "hugahuga";
  }

  subgraph cluster_piyo {
    {Piyo01, Piyo02, Piyo03};
  }
}
```

![hello.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/9aa08c60-5edd-3b86-33f0-26b4bf311bbc.png "hello.png")


# 作成例

サーバー構成図のサンプルを作ってみました。

```sample.dot
digraph "server" {
  compound = true;

  Internet -> FrontLoadBalancer;
  FrontLoadBalancer -> Front01 [lhead = cluster_front];
  Front01 -> DB_Master [lhead = cluster_db_master, ltail = cluster_front];
  Front01 -> DBLoadBalancer [lhead = cluster_db_slave, ltail = cluster_front];
  DBLoadBalancer -> {DB_Slave01, DB_Slave02, DB_Slave03};

  subgraph "cluster_front" {
    label = "Front Servers";

    {Front01, Front02, Front03};
  }

  subgraph "cluster_db" {
    subgraph "cluster_db_master" {
      label = "DB Master";

      DB_Master;
    }

    subgraph "cluster_db_slave" {
      label = "DB Slave";

      DBLoadBalancer;
      {DB_Slave01, DB_Slave02, DB_Slave03};
    }
  }
}
```

![sample.png](https://qiita-image-store.s3.amazonaws.com/2022/66245/03b85637-ffb5-94e3-e22d-0eaeef13959c.png "sample.png")


他にも、オフィシャルサイトに[Gallery](http://www.graphviz.org/Gallery.php)があり、
グラフとコードのサンプルが載っていますので、
作りたい図に近いものを探して参考にすると作成しやすくなります。

# 参考

* [オフィシャルサイト](http://www.graphviz.org/)
* [Graphviz を使って dot 言語で Server のインフラ構成を管理してみる](http://kakakikikeke.blogspot.jp/2015/04/graphviz-dot-server.html)
* [GraphViz - How to connect subgraphs?](http://stackoverflow.com/questions/2012036/graphviz-how-to-connect-subgraphs)