JUNOS でCI する話
ネットワーク運用がどんどん便利になって「手軽にメトリック監視できる」「ネットワークリソース管理がほら簡単」みたいな話はけっこう聞く.ところが,本丸であるネットワーク本体への変更については「慎重に人手で」という運用をしているところが多いと思う.
それが悪いということではなくて,たぶん「頻度低いから手動がコストバランス良い」のような理由があるんだけど,じゃあ「それに合う形でワークフローを良くしたいよね」と思う.
たとえばCI を導入することで,ネットワークデバイスへの変更について議論しやすくなったり,レビューしやすくなるといいなあと.
ネットワークでのCI って難しい
ネットワークデバイスに変更を加える場合,ソフトウェア開発のように「あらかじめふるまいを確認する」のはけっこうなコストがかかる.しかし,変更はコマンドのリストとして表現できて,コマンド文法が既知だから「シンタックスが正しい」ことくらいは事前に確認できるはず.
コマンドが誤っていて手戻りが発生することも日常的にあるので,CI でシンタックスを確認するだけでもだいぶマシになるはず,と思って作ったのがこれ.
netconf 用xsd からPEG パーサーを自動生成するためのツール群と,生成されたPEG パーサーが含まれていて
- JUNOS のシンタックスチェック
show configuration
形式と| display set
形式の相互変換
ができる.詳しくは JANOG36 でのLT 資料 をご覧ください.
CI やってみると どんな感じか
無料でできる Gitlab + Gitlab-CI を使った例.eBGP neighbor を1つ加え,eBGP 全体を微調整するケースを考える.
サンプルレポジトリー: https://github.com/codeout/junos-ci/tree/gitlab
1. 変更案をGitlab にプッシュする
まず,これから加えたい変更について議論したり レビューしてもらうために,変更したい内容をGitlab に掲載する.
# gitlab プロジェクトをローカルにもってくる $ git clone ssh://git@192.168.99.100:10022/codeout/junos-ci.git $ cd junos-ci ... # いま master ブランチにいる junos-ci $ git branch * master # 変更用ブランチをつくる junos-ci $ git checkout -b add-neighbor ...
config/junos.conf
を修正して変更したい内容を記載する.
junos-ci $ git diff diff --git a/config/junos.conf b/config/junos.conf index 1331682..e860cc4 100644 --- a/config/junos.conf +++ b/config/junos.conf @@ -14,6 +14,8 @@ protocols { } local-address 198.51.100.1; } + neighbor 192.0.2.3; + invalid statement; # わざとエラーを混ぜる } } }
ここでテストを回してパスするのを確認 → git commit
→ Gitlab にプッシュするのが本筋だが,今回はテストが落ちることをみるためにテストせずコミット & プッシュ.
junos-ci $ git commit -am "xxxx 開通準備" junos-ci $ git push origin add-neighbor
2. Merge Request をつくる
Gitlab プロジェクトページに “Create Merge Request” ボタンが現れる.流れに沿ってMerge Request を作成する. こうすることで,他のメンバーに「こんな変更を加えたいので,議論 / レビューしてほしい」と伝えることができる.
作成が終わると勝手にCI が作動し Gitlab 上に “failed” と表示されるので,すぐシンタックスエラーがあることがわかる.(下図)
また,将来変更を適用した際 コンフリクトが発生しそうな場合も (下の例にはないが) warning が表示される.
さらにリンクをたどれば,どの行がおかしいかわかる.
(この場合 protocols bgp group ebgp-peers invalid statement
)
失敗したテストをパスさせるには,適宜修正してコミット & プッシュすればよい.再度CI が作動して “passed” に変化する.
- Gitlab にプッシュしてから “failed” に気づくと二度手間になるので,Merge Request オーナーがプッシュ前にテストするといい
- レビューする側はプッシュ前にテストされたかどうかわからないが,Gitlab のCI ステータスが “passed” であれば シンタックスは正しい = セマンティクスだけ議論 / レビューすればいい ことがわかる
3. Gitlab で議論 / レビュー
シンタックスチェックはCI 任せにできるので,変更内容だけを議論 / レビューすればいい.
手動でテストする
サンプルレポジトリー のRakefile
に,junoser を使ったテストのサンプルがある.
ディレクトリ構造やファイル拡張子がちがうと動かないかもしれないので,適宜修正ください.
junos-ci $ rake
skip ./config/cisco.conf
verifying ./config/junos.conf ... done
議論 / レビュー後のデプロイフロー
ネットワークデバイスのMerge Request にはひとつ問題がある.
- Merge Request をマージ
- デプロイ
show configuration
を行ったときの 1. と 3. の結果が必ずしも一致しない.セマンティクスは同じでも コマンド構造や順序がちがうかもしれない.今回のようにネットワークデバイスの設定を直接管理している場合,ネットワークデバイスが吐く設定をマスターにしたいということもあって,単に「Merge Request をマージして完了」にできない場合がある.
取りうる戦略がいくつかあって,
- 変更をmaster ブランチにマージ → 変更後の設定全体をデプロイ
- 変更をマージしない → 差分だけをデプロイ → トピックブランチ*1 を変更後の設定にrebase
それぞれ少しだけ説明します.
変更をmaster ブランチにマージ → 変更後の設定全体をデプロイ
シンプルなので,こちらがオススメ.
- Merge Request をmaster にマージ
- マージ結果を
load override
show configuration
をmaster にcommit
ほぼ コマンド投入漏れが発生しないし,変にコンフリクトしていてもshow | compare
などで気づくことができる.1. と3. のセマンティクスの整合は取れていると思われるので,そのままcommit する.
可能な限りこちらに寄せたほうが良いと思う.
変更をマージしない → 差分だけをJuniper にデプロイ → トピックブランチを変更後の設定にrebase
数ステップに分けて投入したい場合など.
junos-ci $ ./bin/patch master add-neighbor # config/junos.conf -> config/junos.conf set protocols bgp group ebgp-peers neighbor 192.0.2.3 set protocols bgp group ebgp-peers invalid statement
上のように差分をset
コマンドに変換して投入した場合,コンフリクトに気付けない可能性がある.
- Merge Request をmaster にマージせず,差分をデプロイ
- この時点の
show configuration
がトピックブランチと一致するかは保証されない - なので,トピックブランチをrebase して確認する
- Merge Request をマージ
rebase 時にコンフリクトした場合,設定順序含めてトピックブランチを整理するのがかなり面倒.ただし大きなMerge Request だと 途中で確認を挟まないといけないため,こちらの戦略を取らざるを得ない.
まとめ
- junoser を使えばJUNOS でCI できる
- シンタックスエラーに気づける
- コンフリクトに気づける
- Gitlab のようなツールを使えば,議論 / レビューが楽になる
- ネットワークへのデプロイ方法によってマージ方法が変わるが,なるべくマージ → 設定全体をデプロイしたほうがいい
ツールの具体的な設定方法を飛ばして「できた後はどんな感じか?」について書きましたが,ネットワークデバイスの設定をGitlab / Github 管理したらワークフローがどうなるか,CI し始めたらワークフローがどうなるか,イメージしてもらえるとうれしいです.
*1:変更のために作ったブランチ