Table of Contents
CloudFormationのSDKを使うにあたって
AWSのSDKを使うときによくS3やEC2とか、メジャーなサービスを使ったサンプルや記事なんかはあるんですが、CloudFormationに関して全然ありませんでした。 あとは用語とライブラリ内の構造体がたくさんありどれがどれだかよくわからないのと関数がたくさんあるので、正直どれを使えばいいのか手探りでした。。。ここは地味に辛かったです、、
ライブラリ
ここら辺が必要
github.com/aws/aws-sdk-go/aws
github.com/aws/aws-sdk-go/aws/session
github.com/aws/aws-sdk-go/aws/credentials
github.com/aws/aws-sdk-go/service/cloudformation
パッケージ管理は今回はめんどくさいそこまで大きなアプリではないっていうのと、とりあえず動かすのが目的なんでそのままgo get
でインストール。さくさくっとやって行きましょう。
クライアントの準備
ではでは、さくさくっとクライアントを用意しましょう。 ここは他のAWSのSDKと同様、アクセスキーとシークレットキー、リージョンを指定します。
cli := cloudformation.New(session.New(), &aws.Config{
Credentials: credentials.NewStaticCredentials(os.Getenv("ACCESS_KEY"), os.Getenv("SECRET_KEY"), ""),
Region: aws.String(region),
})
テンプレート
次にCloudFormationで使うテンプレートを読み込みます。
data, err := ioutil.ReadFile(`cloudformation/tempalte.yml`)
if err != nil {
return nil, err
}
body := string(data)
stack := &cloudformation.CreateStackInput{
StackName: aws.String(c.StackName),
TemplateBody: aws.String(body),
}
ファイルにテンプレートを記載しているのでファイルの中を読み込みます。これは通常のCloudFormationで使うテンプレートファイルと同様のものになります。
そしてファイル内をcloudformation.CreateStackInput
構造体のTemplateBody
に入れます。
ここはTemplateURL
かTemplateBody
どちらかを指定する必要があり、TemplateURL
の場合は
S3のバケットのURLを指定します。
そして、StackName
を指定します。これが最小構成のCreateStackInput
になりますかね。
パラメータを指定
次にパラメータを指定していきます。構成管理ツールでよくあるのが変数みたいにパラメータを持つことができます。CloudFormationでもできるのでパラメータを指定して行きます。
res := []*cloudformation.Parameter{}
for _, v := range params {
param := &cloudformation.Parameter{}
param = param.SetParameterKey(v.Key)
param = param.SetParameterValue(v.Value)
res = append(res, param)
}
stack.SetParameters(res)
stack.SetParameters
が実際にパラメータをセットしてる関数になります。
stack
は上記のCreateStackInput
構造体になります。SetParameters
関数でCreateStackInput
構造体にパラメータを追加します。
ちなみにパラメータはcloudformation.Parameter
の配列で構造は以下のようなものになります。
type Parameter struct {
ParameterKey *string `type:"string"`
ParameterValue *string `type:"string"`
ResolvedValue *string `type:"string"`
UsePreviousValue *bool `type:"boolean"`
}
基本的にParameterKey
とParameterValue
に値を入れて入れば問題ないです。
これでテンプレートのパラメータに値を指定することができました。
Stackを構築
では今まで作ったCreateStackInput
構造体を基にStackを作って行きましょう。
output, err := cli.CreateStack(stack)
はい、出来上がり!(あっさり)これでStackが作られ始めます。CreateStack
の返り値でoutput
には今回作るStackのStackIdが入った構造体が返ってきます。
これで終わりではない、、
はい、これで完成、、、っというわけにはいかないですね。
先ほどのCreateStack
関数は作成されたStackIdを返します。ただこれはStack内のリソースが全て正常に起動されたらレスポンスをするのではなくStackができた瞬間にレスポンスを返します。つまりStack内のリソースが正常に起動できてるかはこの段階では判断できません。
なので、定期的にStackのステータスがCREATE_COMPLETE
になったかどうか確認する必要があります。
最後にここのチェック処理を実装していきます。
describe := &cloudformation.DescribeStacksInput{
StackName: aws.String(StackName),
}
timer := 10
timeout := 600
resFlg := true
for resFlg {
if timeout <= 0 {
return false
}
out, err := cli.DescribeStacks(describe)
if err != nil {
return nil, err
}
if out == nil {
resFlg = false
break
}
for _, v := range out.Stacks {
if "CREATE_COMPLETE" == *v.StackStatus {
resFlg = false
}
}
if resFlg == false {
break
}
time.Sleep(time.Duration(timer) * time.Second)
timeout = timeout - time
}
DescribeStacks
関数でStackの詳細情報を取得します。
ループの中でDescribeStacks
関数を実行しステータスがCREATE_COMPLETE
じゃなかった場合は10秒停止し、再度実行します。600秒の間にStackで完成しなかった場合はチェックするのをやめています(とりあえず無限ループに入らないため)。
これでステースがCREATE_COMPLETE
になるまで待機し、全ての作成が完了したらループを抜け、その次の処理を行ってきます。
ここの処理はCREATE_COMPLETE
のみしかチェックしてないため他のステータスも考慮する必要があるが、、
とりあえずこれで動くことを確認!!
無事にCloudFormationをGoから扱い、Stackの構築までできました(めでたしめでたし)
まとめ
Terraformとか他の構成管理ツールも検討しましたがGolangから実行したいっていうのと、作成されたリソースに対して次の処理を挟み込みたいのでCloudFormationにしました。
他のAWSリソースのSDKと同じような使い方なのでそこまで詰まることはなく、テンプレートさえできてさえいればさくさくっとできてしまいます。
今後の課題として、Stackのステータスの監視の実装がまだ不十分なのと更新処理等がまだできてないのでそこらへんの実装を進めて行きます。
kobaru
インフラ好きっ子