最近 Twitter を見ていたら Diagrams という Python 書いたら良い感じのシステム構成図ができるサービスが流れてきた。
プライベートのインフラ構成図は今まで Cacoo で描いていたけど、今回 Diagrams に移行した。
なぜ Diagrams で書くのか
プライベートでは terraform だったり Kubernetes のマニフェストを1つのリポジトリで管理している。
AWS の構成や Kubernetes に変更を加える時はいつもそのリポジトリにコミットしてもろもろ終わった後に Cacoo の図を更新していた。
Cacoo は書きやすくて好きなのですが、自分としては図を更新する前の時点で達成感に満たされていつも終わっていました。
そしてどんどん実態と差分が広がり更新しなくなりました。
Diagrams を使うことで 1つにまとめているリポジトリに一緒にコミットすることができるので、図をアップデートし続けるのではないかと考え今回移行しました。
Diagrams の使い方
ドキュメントを見ると分かりますが簡単に始められそうです。
必要なものをインストールして
$ brew install graphviz $ pip install diagrams
それっぽいコードを書いて
# diagram.py from diagrams import Diagram from diagrams.aws.compute import EC2 from diagrams.aws.database import RDS from diagrams.aws.network import ELB with Diagram("Web Service", show=False): ELB("lb") >> EC2("web") >> RDS("userdb")
実行
$ python diagram.py
できあがり!!!
簡単!!
docker image を作る
今回、自分はgraphviz や diagrams を local mac にインストールせずに docker image を作って docker 上で実行するようにしました。
まずは Dockerfile を用意します。
FROM python:3.8 RUN apt-get update && \ apt-get install -y graphviz RUN pip install diagrams
https://hub.docker.com/r/hatappi/diagrams
あとは先ほどの python ファイルのあるディレクトリで下記のコマンドを実行すれば画像が生成されるはずです。
$ docker run \ -it \ --rm \ -w /tmp \ --entrypoint "python" \ -v ${PWD}:/tmp \ hatappi/diagrams:latest \ diagram.py
これで python のコードをメンテして画像を生成してコミットすれば良い世界になりました。
ただもう少し人がやる部分を減らしたい。
それは画像生成部分です。
Github Actions で画像を生成してコミットする
流れとしては diagrams のコードが commit されたら画像を生成して既にコミットされている画像と差分があった時に commit するようなものを作ります。
Github Actions の YAML を書く前にまずは先ほどの diagram.py を少し変更します。
from diagrams import Diagram from diagrams.aws.compute import EC2 from diagrams.aws.database import RDS from diagrams.aws.network import ELB from argparse import ArgumentParser def get_args(): argparser = ArgumentParser() argparser.add_argument('-n', '--name', type=str, default="diagram") return argparser.parse_args() args = get_args() with Diagram("Web Service", show=False, filename=args.name): ELB("lb") >> EC2("web") >> RDS("userdb")
実行時に生成するファイル名を指定できるようにしました。
次に Github Actions の YAML ファイルを作っていきますが、まずは完成したものをお見せします。
name: Generate And Push Diagram on: push: paths: - 'system_architecture/diagram.py' jobs: generate: name: Generate And Push Diagram runs-on: ubuntu-latest container: image: hatappi/diagrams:latest env: FILENAME: "diagram" steps: - uses: actions/checkout@v1 - name: set git config run: | git config --global user.email "test@example.com" git config --global user.name "test" git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY - name: generate diagram working-directory: ./system_architecture run: python diagram.py --name ${FILENAME} - name: confirm diagram change working-directory: ./system_architecture run: | CHANGED=$(git status -s | awk '{ print $2 }' | grep -E "^${FILENAME}.png$" | cat) if [ -n "${CHANGED}" ]; then echo "::set-env name=is_changed::true" fi - name: git push working-directory: ./system_architecture if: env.is_changed == 'true' run: | git add ${FILENAME}.png git commit -m "${FILENAME}.png" git push origin HEAD:${GITHUB_REF##*/} - name: upload diagram uses: actions/upload-artifact@v1 with: name: diagram path: ./system_architecture/${{ env.FILENAME }}.png
今回は system_architecture/diagram.py
に Diagrams のコードがあった場合にのみ JOB が実行されるように設定しました。
これにより画像をアップロードした時に job が走らないようにしています。
実際に動作させてみると画像に変更があった時は下記の画像のように git push が実行されます。
画像に変更がない時は下記の画像のように git push は実行されません。
あとは画像を README.md に貼れば作業としては完了です。
ここからは YAML ファイルの中身をいくつか紹介します。
任意のコンテナ上で step を実行する
container: image: hatappi/diagrams:latest
Github Actions は基本は Ubuntu や Windows のようなホストマシン上でステップを実行して必要なものがあれば step の中で install します。
今回は diagrams の Docker image があるので、上記のように指定して、コンテナ内で step を実行できるようにしています。
生成された画像に差分があるかを判定する
- name: confirm diagram change working-directory: ./system_architecture run: | CHANGED=$(git status -s | awk '{ print $2 }' | grep -E "^${FILENAME}.png$" | cat) if [ -n "${CHANGED}" ]; then echo "::set-env name=is_changed::true" fi
ここが一番重要な step です。
今回は初めて画像がコミットされる、画像に変更があるというパターンを想定して git status から grep して変更があるかを判定しました。
このあたりもっと良い感じの方法があったら教えてください。
変更があった時に echo コマンドを実行してますが、ここで echo した ::set-env name=is_changed::true
は Github Actions では特別な意味を持ちます。
Github Actions 上で ::set-env name={name}::{value}
と出力すると value な値の name を環境変数として設定してくれます。
help.github.com
今回は変更があったこと判定するために is_changed = true を設定しました。
変更があった時だけ push する
- name: git push working-directory: ./system_architecture if: env.is_changed == 'true' run: | git add ${FILENAME}.png git commit -m "${FILENAME}.png" git push origin HEAD:${GITHUB_REF##*/}
run の部分はファイルを add して commit して push しているだけです。
注目するのは if:
です。
名前から察することができるように条件式に一致した時のみ step を実行します。
ここで先ほど環境変数として設定した is_changed
を使って変更があった時のみを実行しています。
最後に
今回 Diagrams を使ってインフラ構成図を Python で書いて図を生成して、さらに図を生成してコミットする部分を Github Actions で自動化しました。
今回自動化して一番嬉しい点はスマホからコードを変更してコミットしても図は自動で生成されるので反映される点です。