はじめに
デプロイツールとして、anisble-playbook
を利用して
slackからデプロイできるようにした話です。
背景
- stg/prd環境のEC2 provisioning -> middleware install -> deployを全て、
ansible-playbook
で実施している。 - 開発チームの方々にも
ansible-playbook
のコマンドを実行してもらっていた。 - 各種環境のデプロイはEC2上のサーバーから実施している。
- スプレッドシートにて、
ansible-playbook
の各種サーバー毎/task毎にコマンドを記載して、実行してもらっていた。 - 今までインフラとして、AWSやログ分析・監視基盤の構築をしていたので、自分自身が全くと言っていいレベルでプログラムのスキルがなかったので、勉強がてらgolangやりたかった。
課題・懸念
解決したい課題・懸念は、以下3点。
- 実行コマンドをコピペミスで、誤実行してしまうリスクがある。
- 「誰が」実行しているかわからない。
- サーバーにそもそも入らなければ、デプロイできない。
作ったもの
対象 | URL |
---|---|
go-slack-ansible | https://github.com/jkkitakita/go-slack-ansible |
前提
Mercariの @deeeet さんが書いた
GolangでSlack Interactive Messageを使ったBotを書く
の記事を参考にさせていただきながら、作成しました。
ディレクトリ構成
ansible
├ inventory
│ ├ stg
│ │ ├ group_vars
│ │ └ host
│ └ prd
│ ├ group_vars
│ └ host
go-slack-ansible
├ ansible
│ ├ config
│ │ └ config.go // ansible-playbookのconfig関連
│ ├ ansible_playbook.go // ansible-playbookで、provisioningとdeploy実行
│ ├ branch.go // デプロイするブランチを指定
│ ├ config.yaml // hostとrepoの対応一覧 & ansibleのtagの一覧
│ ├ const.go // 定数
│ ├ inventory_scanner.go // ansibleのinventoryを読み取って、対象ホストを取得
│ ├ tag.go // 指定するtagを取得する
│ └ terminate.go // ansible-playbookでサーバーのterminateを実行
├ cmd
│ └ bot
│ ├ handler.go //
│ ├ main.go // Slack Interactive Messages
│ └ slack.go //
├ config
│ └ config.go // logger等の設定
├ logger
│ └ logger.go // zapにて、logging
├ scripts
│ └ restart.sh // 再起動スクリプト
├ .env // slack BotID Channel,GitHub token etc...
├ go.mod
├ go.sum
└ Makefile
工夫したところ
前のメッセージの状況を残したい。
上記のgifを見てもらえればわかる通り
選択したhostやtagが選択後にメッセージに表示させています。
このように既存のメッセージの状態を上書きするためには
Slack Interactive Messageで、replace_original
をtrue
にする必要があリます。
Replacing the original message
https://api.slack.com/interactive-messages#building_workflows
これをしないと
このようになり、無駄に投稿されてしまう。
また、前の投稿を再度編集、選択できてしまいます。
nlopes/slack
を使った今回の場合は
originalMessage.ReplaceOriginal = true
https://github.com/jkkitakita/go-slack-ansible/blob/5a7f858e73/cmd/go-slack-ansible/handler.go#L109
として、replace_original
をtrue
に毎回上書きをすることで、できるようになりました。
zapのloggerにlogvel,caller,traceを追加する
botと全然関係ないけど(笑)
試しにloggerの勉強をしようと思って、zapを入れて見たものの
zapのドキュメントが少なく、loggerを仕込むにも一苦労したので、めも。
zap.New時に、↓のように渡してあげると、
return zap.New(
zapcore.NewCore(enc, w, zapConfig.Level),
zap.AddCaller(),
zap.AddStacktrace(zapcore.WarnLevel),
)
ex. INFO
{"severity":"INFO","timestamp":"2018-12-14T22:24:08.972+0900","caller":"go-slack-ansible/main.go:58","message":"[INFO] Start slack event listening"}
ex. WARN
{"severity":"WARN","timestamp":"2018-12-14T22:26:27.968+0900","caller":"go-slack-ansible/slack.go:71","message":"[WARN] Invalid bot: Jun Kitamura [10:22 PM]","trace":"main.(*SlackListener).handleMessageEvent\n\t/Users/jun.kitamura/go/src/go-slack-ansible/cmd/go-slack-ansible/slack.go:71\nmain.(*SlackListener).ListenAndResponse\n\t/Users/jun.kitamura/go/src/go-slack-ansible/cmd/go-slack-ansible/slack.go:37"}
今後の課題
- そもそもtest書いてない。。すいません。。
- methodを使って書きたかったが、全て普通の関数funcになってしまった。。
- 構造体、interfaceまだ勉強中です。。
さいごに
golang初挑戦でした。
色々な参考書や記事をツギハギでやりました。
コードも、記事の構成もツッコミどころ満載で、どこから突っ込んだらいいかわからないとは思いますが
「ここは違うだろ!」「ここはこうした方がいいよ!」
とかあれば、いつでも、コメントください。非常に喜びます。