この記事は、NTTテクノクロス Advent Calendar 2023の1日目の記事になります。
メリークリスマス!NTTテクノクロスの堀江です。普段はAWSやAzure上でのシステム設計、構築や実装、調査検証系の案件を幅広く担当しています。
はじめに
本記事では、今年自分が開発・公開したOSSツールである、cfn-docgen(及び、そのVSCode拡張機能版である、cfn-docgen-vsc-extension)について紹介していきます。
cfn-docgenとは
cfn-docgenとは、YAML/JSON形式で記述されたAWS CloudFormation(以降、cfnと呼称)テンプレートファイルから、マークダウン形式のドキュメントファイルを自動生成することが出来るツールです。
cfn-docgenが実現することは主に以下の2点です。
- リソースの構成図や設計思想といった情報をcfnテンプレートファイル内に完結して記述出来るため、cfnテンプレートファイルと詳細設計書(aka.パラメータシート)の二重管理の手間を省く
- YAML/JSONファイルから、より人間が読みやすい形式のドキュメントを生成することで、顧客や非AWS技術者に対する情報伝達を円滑にする
以下のように、AWSリソースとユーザ独自のDescription(詳細は後述)を定義した左のcfnテンプレートファイルから、右のようなマークダウン形式のドキュメントを自動生成する出来ます。
基本的にはCLIツール(Python3.10以上が必要)ですが、後述の通り、様々な形式で使用が可能です。
$ cfn-docgen docgen \
--format markdown \
--source docs/sample-template.yaml \
--dest ./docs/
[INFO] successfully generate document [./docs/sample-template.md] from template [docs/sample-template.yaml]
使用方法
cfn-docgenにはdocgen機能とskeleton機能という2種類のサブ機能があります。
docgen機能
cfnテンプレートファイルからドキュメントを自動生成するための機能
ドキュメント生成パターン
cfn-docgenでは、ローカルファイルだけでなく、S3バケット上に格納されたファイルもドキュメント生成対象やドキュメントのアップロード先に直接指定することが可能です。また、ディレクトリ(S3パス)配下の複数のcfnテンプレートファイルから、複数のドキュメントを一括で自動生成することも可能です。
$ cfn-docgen docgen \
--format markdown \
--source docs/sample-template.yaml \
--dest ./docs/
[INFO] successfully generate document [./docs/sample-template.md] from template [docs/sample-template.yaml]
$ cfn-docgen docgen \
--source s3://bucket/prefix/sample-template.yaml \
--dest s3://bucket/prefix/sample-template.md
[INFO] successfully generate document [s3://bucket/prefix/sample-template.md] from template [s3://bucket/prefix/sample-template.yaml]
$ tree ./templates/
./templates/
├── sample-template-1.yaml
└── subfolder
└── sample-template-2.yaml
1 directory, 2 files
# 指定したディレクトリ配下のcfnテンプレートファイルからドキュメントを一括生成
$ cfn-docgen docgen \
--source ./templates/ \
--dest s3://bucket/documents/
[INFO] successfully generate document [s3://bucket/documents/sample-template-1.md] from template [./templates/sample-template-1.yaml]
[INFO] successfully generate document [s3://bucket/documents/subfolder/sample-template-2.md] from template [./templates/subfolder/sample-template-2.yaml
Descriptionの埋め込み
そのcfnテンプレートや各リソース、各リソースのプロパティに関して明記が必要な情報を、cfnテンプレートファイル内のMetadata
セクションにDescriptionとして記述する(埋め込む)ことで、それらの情報も含めて綺麗にドキュメントが生成されます。
AWSTemplateFormatVersion: 2010-09-09
Description: This template creates 1 VPC and 2 public subnets in it.
Metadata:
CfnDocgen:
Description: |
このテンプレートファイル東京リージョン上で以下のリソースを作成します
- VPC
- パブリックサブネット(2AZに1つずつ)
![Archtecture](./images/sample-template.drawio.png)
**注意点**
- このテンプレートファイルは**東京リージョン**上でのみの使用に制限しています
- このテンプレートファイルを使用する前に、[東京リージョン上に作成可能なVPCの最大数の設定](https://ap-northeast-1.console.aws.amazon.com/servicequotas/home/services/vpc/quotas/L-F678F1CE)を確認することを推奨します(デフォルトは5VPC)**
AWSTemplateFormatVersion: 2010-09-09
Metadata:
CfnDocgen:
Mappings:
CidrBlockMap: CidrBlocks for each environment
Conditions:
EnvCondition: Check if the value of parameter `EnvType` is `prod`
Rules:
RegionRule: This template is available only in ap-northeast-1
AWSTemplateFormatVersion: 2010-09-09
Resources:
VPC:
Metadata:
CfnDocgen:
Description: アプリケーションサーバを稼働させるために使用するVPC
Properties:
EnableDnsHostnames: アプリケーションサーバのホスト名でパブリックIPを名前解決できるように有効化する
Type: AWS::EC2::VPC
Properties:
EnableDnsHostnames: true
CidrBlock: ...
AWS CDKコードに対しても、Descriptionの埋め込み及びドキュメントの自動生成が可能です。
from aws_cdk import (
Stack,
aws_ec2 as ec2,
)
from constructs import Construct
from typing import Any
from cfn_docgen.domain.model.cfn_template import (
CfnTemplateMetadataCfnDocgenDefinition as Metadata,
CfnTemplateResourceMetadataDefinition as ResourceMetadata,
CfnTemplateResourceMetadataCfnDocgenDefinition as CfnDocgen
)
class CfnDocgenSampleCdkStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs:Any) -> None:
super().__init__(scope, construct_id, **kwargs)
# テンプレート全体に対するDescriptionの埋め込み
self.add_metadata(
"CfnDocgen", Metadata(
Description="テンプレート全体に対するDescriptionの埋め込み"
).model_dump(),
)
self.vpc_construct = ec2.Vpc(self, "VpcConstruct", max_azs=1)
# リソースに対するDescriptionの埋め込み
self.vpc_construct.node.default_child.cfn_options.metadata = ResourceMetadata(
CfnDocgen=CfnDocgen(Description="リソースに対するDescriptionの埋め込み")
).model_dump()
カスタムリソース仕様の使用
独自のリソース仕様を定義したファイルを読み込ませることで、デフォルトでは非対応のサードパーティーのリソースタイプやCustom::SomeCustomResource
のようなカスタムリソースタイプに関してもドキュメント生成することが出来ます。
※カスタムリソース仕様ファイルの例はこちらを参照
$ cfn-docgen docgen \
-s docs/sample-template.yaml \
-s docs/sample-template.md \
-c docs/custom-specification.json
skeleton機能
(こちらの機能は副産物のようなものですが、)以下のように、任意のリソースタイプのcfnテンプレート定義のスケルトンを出力することが出来ます。
後述するようにVSCode拡張機能として使用することで、cfnテンプレートファイル執筆を効率化させることを目的としています。
$ cfn-docgen skeleton --type AWS::EC2::VPC --format yaml
Type: AWS::EC2::VPC
Metadata:
Documentation: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html
CfnDocgen:
Description: ''
Properties: {}
Properties:
CidrBlock: String
EnableDnsHostnames: Boolean
EnableDnsSupport: Boolean
InstanceTenancy: String
Ipv4IpamPoolId: String
Ipv4NetmaskLength: Integer
Tags:
- Key: String
Value: String
配布形式
CLI
使用にはPython3.10以上が必要になります。
※OSはLinux、Windows共に対応
$ pip install cfn-docgen
VSCode拡張機能
前述したdocgen機能とskeleton機能をVSCode拡張機能としても使用可能です。
※別途CLIのインストールは必須
Dockerイメージ
# pull image from DockerHub
$ docker pull horietakehiro/cfn-docgen:latest
# local directory(before)
$ tree /tmp/sample/
/tmp/sample/
└── sample-template.json
0 directories, 1 files
# run as command
$ docker run \
-v /tmp/sample/:/tmp/ \
horietakehiro/cfn-docgen:latest docgen \
--source /tmp/sample-template.json \
--dest /tmp/
[INFO] successfully generate document [/tmp/sample-template.md] from template [/tmp/sample-template.json]
# local directory(after)
$ tree /tmp/sample/
/tmp/sample/
├── sample-template.json
└── sample-template.md
0 directories, 2 files
Pythonモジュール
from cfn_docgen import (
CfnDocgenService, CfnDocgenServiceCommandInput,
CfnTemplateSource, CfnDocumentDestination
)
service = CfnDocgenService.with_default()
service.main(
command_input=CfnDocgenServiceCommandInput(
template_source=CfnTemplateSource("s3://bucket/template.yaml", service.context),
document_dest=CfnDocumentDestination("s3://bucket/document.md", service.context),
fmt="markdown",
)
)
サーバレスアプリケーション
AWS上のサーバレスアプリケーションとしても使用可能です。
リポジトリからリソースをデプロイするとcfn-docgen-${AWS::AccountId}-${AWS::Region}
という名前のS3バケットが作成されます。そのバケットのtemplates/
パス配下にcfnテンプレートファイルをアップロードすることで、documents/
パス配下にドキュメントが自動生成されます。
cfn-docgenの開発理由
最後に、このツールを開発した理由について書こうと思います。
AWSを扱うようになってはや4年、cfnテンプレートでAWS上のシステムを定義・構築するインフラ周りの仕事で、同時にシステムやリソースの詳細設計書(aka. パラメータシート)の執筆も求められる、という状況に度々遭遇しました。
システムの構成やリソース同士の相互関係を表現した図表や、リソース設定の具体値を決めた経緯や特記事項の文章を、綺麗な形でドキュメントに残すこと自体は重要です。システムの全体像や設計の意図を、顧客や経験の浅いメンバ(≒非AWS技術者)にも分かり易く伝えることが出来るためです。
しかしそのドキュメントをExcelやWordとして執筆していくとなると、途端に様々な手間や危険が増えます。
- 作業コストが単純増加
- 詳細設計書やパラメータシートで記述する内容と、cfnテンプレートファイルで定義する内容は(表現は違っていても)情報としてはほぼ等価であることが殆どです(リソースの定義内容をYAML/JSON形式で書くか、表形式で書くかの違い)。同じ内容のドキュメントを2種類作成・保守することになります。
- 設計内容と実装内容の乖離リスク
- 設計(詳細設計書)と実装(cfnテンプレートファイル)のドキュメントが分かれていると、片方の内容の変更をもう片方に反映し忘れる(或いは不適切な内容で反映する)という、変更管理のリスクが常に付き纏います。また、詳細設計書がExcelやWordの場合、バージョンごとの差分の確認が面倒です。
- 等々。
cfn-docgenは、そういった問題を解消することを目的に開発しました。
- システムの構成図や設計の意図といった情報も全てcfnテンプレートファイルに完結して記述することで、ドキュメント執筆・保守の手間を省く一方で、ドキュメントの長期的な品質を維持し易いようにする。
- cfnテンプレート(YAML/JSON形式)から、より人間が読みやすいマークダウン形式のドキュメントを生成することで、その内容を顧客や非AWS技術者でも容易に理解出来るようにする。
このツールが、皆さんのAWSシステム開発・保守のお力になれば幸いです。
明日のNTTテクノクロス Advent Calendar 2023は、 @etctaro さんによる、Compose Multiplatform関する記事です。お楽しみに!