ここに terraform graph があるじゃろ?これをこうして…こうじゃ。
GitHub のマークダウンファイルにおいて、Mermaid.js が使えるようになったので、練習のために terraform graph
の出力を、わかりやすく Mermaid 構文に変換して、README.md ファイル等に埋め込む GitHub Action を作成しました。
サンプルとして、以下のような Terraform AWS provider の使用例 の出力で説明します。
初手、出力された GraphViz の DOT フォーマットを、単純に Mermaid 構文に置き換えます。
flowchart LR n0["aws_elb.web"] n1["aws_instance.web"] n2["aws_internet_gateway.default"] n3["aws_key_pair.auth"] n4["aws_route.internet_access"] n5["aws_security_group.default"] n6["aws_security_group.elb"] n7["aws_subnet.default"] n8["aws_vpc.default"] n9(["output.address"]) na[/"provider<br/>["registry.terraform.io/hashicorp/aws"]"\] nb(["var.aws_amis"]) nc(["var.aws_region"]) nd(["var.key_name"]) ne(["var.public_key_path"]) n0-->n1 n0-->n6 n1-->n3 n1-->n5 n1-->n7 n1-->nb n2-->n8 n3-->na n3-->nd n3-->ne n4-->n2 n5-->n8 n6-->n8 n7-->n8 n8-->na n9-->n0 na-->n0 na-->n4 na-->nc
各リソースと値を、種類ごとに subgraph
にまとめ、スタイルを適用して、リソースを強調します。
%%tfmermaid %%{init:{"theme":"default","themeVariables":{"lineColor":"#6f7682","textColor":"#6f7682"}}}%% flowchart LR classDef r fill:#5c4ee5,stroke:#444,color:#fff classDef v fill:#eeedfc,stroke:#eeedfc,color:#5c4ee5 classDef ms fill:none,stroke:#dce0e6,stroke-width:2px classDef vs fill:none,stroke:#dce0e6,stroke-width:4px,stroke-dasharray:10 classDef ps fill:none,stroke:none classDef cs fill:#f7f8fa,stroke:#dce0e6,stroke-width:2px subgraph "n0"["ELB Classic"] n1["aws_elb.web"]:::r end class n0 cs subgraph "n2"["EC2 (Elastic Compute Cloud)"] n3["aws_instance.web"]:::r n4["aws_key_pair.auth"]:::r end class n2 cs subgraph "n5"["VPC (Virtual Private Cloud)"] n6["aws_internet_gateway.default"]:::r n7["aws_route.internet_access"]:::r n8["aws_security_group.default"]:::r n9["aws_security_group.elb"]:::r na["aws_subnet.default"]:::r nb["aws_vpc.default"]:::r end class n5 cs subgraph "nc"["Output Values"] nd(["output.address"]):::v end class nc vs ne[/"provider<br/>["registry.terraform.io/hashicorp/aws"]"\] subgraph "nf"["Input Variables"] ng(["var.aws_amis"]):::v nh(["var.aws_region"]):::v ni(["var.key_name"]):::v nj(["var.public_key_path"]):::v end class nf vs n1-->n3 n1-->n9 n3-->n4 n3-->n8 n3-->na n3--->ng n6-->nb n4-->ne n4--->ni n4--->nj n7-->n6 n8-->nb n9-->nb na-->nb nb-->ne nd--->n1 ne-->n1 ne-->n7 ne--->nh
provider は 1 個しかなく、役割は自明なので省略します。
%%tfmermaid %%{init:{"theme":"default","themeVariables":{"lineColor":"#6f7682","textColor":"#6f7682"}}}%% flowchart LR classDef r fill:#5c4ee5,stroke:#444,color:#fff classDef v fill:#eeedfc,stroke:#eeedfc,color:#5c4ee5 classDef ms fill:none,stroke:#dce0e6,stroke-width:2px classDef vs fill:none,stroke:#dce0e6,stroke-width:4px,stroke-dasharray:10 classDef ps fill:none,stroke:none classDef cs fill:#f7f8fa,stroke:#dce0e6,stroke-width:2px subgraph "n0"["ELB Classic"] n1["aws_elb.web"]:::r end class n0 cs subgraph "n2"["EC2 (Elastic Compute Cloud)"] n3["aws_instance.web"]:::r n4["aws_key_pair.auth"]:::r end class n2 cs subgraph "n5"["VPC (Virtual Private Cloud)"] n6["aws_internet_gateway.default"]:::r n7["aws_route.internet_access"]:::r n8["aws_security_group.default"]:::r n9["aws_security_group.elb"]:::r na["aws_subnet.default"]:::r nb["aws_vpc.default"]:::r end class n5 cs subgraph "nc"["Output Values"] nd(["output.address"]):::v end class nc vs subgraph "ne"["Input Variables"] nf(["var.aws_amis"]):::v ng(["var.aws_region"]):::v nh(["var.key_name"]):::v ni(["var.public_key_path"]):::v end class ne vs n1-->n3 n1-->n9 n3-->n4 n3-->n8 n3-->na n3--->nf n6-->nb n4--->nh n4--->ni n7-->n6 n8-->nb n9-->nb na-->nb nd--->n1
矢印は、依存元から依存先を指しているのですが、値の代入元から代入先を向くほうが直感的なので、逆にします。
%%tfmermaid %%{init:{"theme":"default","themeVariables":{"lineColor":"#6f7682","textColor":"#6f7682"}}}%% flowchart LR classDef r fill:#5c4ee5,stroke:#444,color:#fff classDef v fill:#eeedfc,stroke:#eeedfc,color:#5c4ee5 classDef ms fill:none,stroke:#dce0e6,stroke-width:2px classDef vs fill:none,stroke:#dce0e6,stroke-width:4px,stroke-dasharray:10 classDef ps fill:none,stroke:none classDef cs fill:#f7f8fa,stroke:#dce0e6,stroke-width:2px subgraph "n0"["ELB Classic"] n1["aws_elb.web"]:::r end class n0 cs subgraph "n2"["EC2 (Elastic Compute Cloud)"] n3["aws_instance.web"]:::r n4["aws_key_pair.auth"]:::r end class n2 cs subgraph "n5"["VPC (Virtual Private Cloud)"] n6["aws_internet_gateway.default"]:::r n7["aws_route.internet_access"]:::r n8["aws_security_group.default"]:::r n9["aws_security_group.elb"]:::r na["aws_subnet.default"]:::r nb["aws_vpc.default"]:::r end class n5 cs subgraph "nc"["Output Values"] nd(["output.address"]):::v end class nc vs subgraph "ne"["Input Variables"] nf(["var.aws_amis"]):::v ng(["var.aws_region"]):::v nh(["var.key_name"]):::v ni(["var.public_key_path"]):::v end class ne vs n3-->n1 n9-->n1 n4-->n3 n8-->n3 na-->n3 nf--->n3 nb-->n6 nh--->n4 ni--->n4 n6-->n7 nb-->n8 nb-->n9 nb-->na n1--->nd
左から、リソースが作成されていく流れが俯瞰しやすくなったように思います。Terraform 設定ファイルを含む Github リポジトリにおいて、次のとおりに Github Action を使用することで、このようなグラフが自動的に README.md ファイルに埋め込まれます。
- 下記の内容の .github/workflows/tfmermaid.yml ファイルを作成する
name: tfmermaid on: push: jobs: generate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: asannou/tfmermaid-action@v1 with: file: README.md - name: commit run: | git add README.md if ! git diff --cached --quiet --exit-code then git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git commit -m "generated" git push fi
- README.md ファイルの埋め込む場所に
%%tfmermaid
とコメントされた mermaid コードブロックを配置する
```mermaid %%tfmermaid ```
状況に合わせて、provider
を表示したり、var
等を省略したり、矢印を順方向にしたり、グラフ全体の向き を変更する等のオプションも用意しています。
- uses: asannou/tfmermaid-action@v1 with: file: README.md include: provider exclude: var,local,output,data arrow-direction: forward orientation: RL
その他の例は https://github.com/asannou/tfmermaid-action/blob/v1/README.md#examples で確認してください。
Docker のベースイメージを GitHub で自動的に更新する
かつて Docker Hub にベースイメージが更新されたタイミングで自動的にビルドする機能があったと記憶しているのですが、Autobuilds が free plan で使えなくなったため、GitHub Actions と Dependabot を利用して更新する方法を検討しました。
テスト環境として nginx:stable をベースイメージとする Dockerfile とビルドして Docker Hub にプッシュするワークフローを用意します。そのまま、このワークフローの定期実行をスケジュールすることで、最新のベースイメージが反映されたイメージを維持できますが、 更新がない時の不要なビルドによるコストと、下記の自動的な無効化を回避するために、Dependabot を採用します。
パブリックリポジトリでは、60日間にリポジトリにアクティビティがなかった場合、スケジュールされたワークフローは自動的に無効化されます。
使用制限、支払い、管理 - GitHub Docs
最初に、Dockerfile を監視する dependabot.yml を用意します。nginx:stable は、現在の stable バージョンである nginx:1.20.2 と同じイメージを示しており、バージョンアップに合わせて、新しいイメージに変更されていきます。nginx 自体はバージョン番号が同じであれば内容も同一ですが、Docker イメージの場合、ベースイメージの debian や、パッケージ等の nginx 以外の更新によっても、イメージが更新される点に注意してください。Dependabot には、その時点で指しているイメージを教える必要があるため、次のようにダイジェスト値を追加します。
ダイジェスト値の取得は CLI です。
$ docker inspect --format='{{index .RepoDigests 0}}' nginx:stable
nginx@sha256:cba27ee29d62dfd6034994162e71c399b08a84b50ab25783eabce64b1907f774
また、nginx:1.20 のようにバージョンを指定する場合も同様にダイジェスト値を追加できます。
以上で、Dependabot がベースイメージのバージョンアップを検知した際に、自動的にプルリクエストを作成するようになります。
しかしながら、この状態だとプルリクエストができる度に人間がマージをする必要があります。
仮に、ベースイメージとして nginx:1.20 を指定した場合、1.20.x の最新のバージョンが使用されますが、nginx はセマンティックバージョニングに従っていると思われるので、後方互換性を伴うバグ修正によるパッチバージョンの変更は、自動的にマージすることにします。
自動マージのワークフロー例を参考にして、以下のファイルを作成します。steps.dependabot-metadata.outputs.update-type は定義されないようなので、条件から外しています。
結果、Dependabot によるプルリクエストと同時に、ワークフローが実行され、自動マージされました。
検証が不十分なのですが、自動マージの場合、ビルドをするワークフローが push や pull_request イベントではトリガーされなかったため、workflow_run イベントを追加しています。
ベースイメージの自動的な更新は完了しましたが、Dockerfile で apt や yum 等の Dependabot で監視できないパッケージをインストールしている場合は、それらのバージョンアップに気づくことができません。
そのようなイメージを確実に更新し続けるためには、前述のとおりビルドのワークフローを定期実行し、何らかの方法でスケジュールの無効化を回避する必要があると考えます。
56562
ニコニコ実況の BS 民は解放された感じ - 知らないけどきっとそう。 の設定をしていて、チャンネルの勢いの数値が 56562 になった場合は、次のとおりに変更してください。
- hosts ファイルを修正している環境
59.106.13.23 jk.nicovideo.jp
- NicoJK.ini ファイルを修正している環境(dev-201218 リリース)
customJKHostName=jk.from.tv
- NicoJK.ini ファイルを修正している環境(dev-201229 リリース以降)
channelsUri=http://jk.from.tv/api/v2_app/getchannels
- 上記以外で 3.113.121.119 を参照している環境は jk.from.tv に変更