rancid の.cloginrc をvault 管理にする
rancid というツールがある.ネットワーク運用するにあたって,もはや手放せなくなっている.rancid のなにが便利かについては別エントリで書こうと思うが,本来の目的よりも付随する xlogin スクリプト (clogin, jlogin, …) を気に入って使っている.
xlogin について簡単に言えば
ようなやつで,1. のための認証情報を~/.cloginrc
に書いておく必要がある.パスワード入力が不要になるので「10 台のルーターでshow interfaces descriptions
とshow bgp summary
とshow ospf neighbor
を打ってgrep に渡す」とか「100 台のルーターでsyslog の設定を変える」みたいなことが簡単にできる.
問題意識
ネットワークデバイスにログインするために 共有のジャンプサーバーを用意することが多く,xlogin をつかうには そこに~/.cloginrc
を置く必要がある.
「共有サーバーに ファイルとして認証情報(id + password) を置く」というのがイマイチだなあと思っていた.*1 というのは,
そこでvault を手元のローカルホストで動かしておいて,.cloginrc
の情報をそこに格納しておくと ずいぶんマシになった.
- super-user に読まれてしまうのは変わらない
- 認証情報の実体がローカルホストにあり,暗号化される.ssh セッションを切れば認証情報にアクセスできなくなる
- 認証情報へのアクセスログが残るので,不正アクセスに気づける
vault の設定
セットアップ (ローカルホスト)
プラットフォームにあったvault をダウンロード し,PATH のどこかに置く.
設定ファイルを書く.
# ~/.vault backend "file" { path = "/Users/codeout/.vault.d" } listener "tcp" { address = "localhost:8200" tls_disable = 1 # ssh tunnel を通すのでTLS 不要 }
vault server を起動し,初期化する.
$ vault server -config ~/.vault >&/dev/null & $ export VAULT_ADDR=http://localhost:8200 $ vault init -key-threshold 1 -key-shares 1 vault $ vault init -key-threshold 1 -key-shares 1 Key 1: ced979c0b1c0ff62b2ac2aa08e54b8258bd4d88170ed67627b4c0fc3dd87133c Initial Root Token: b5aae184-0fcf-3f7d-09db-9928d82eca56 Vault initialized with 1 keys and a key threshold of 1. Please securely distribute the above keys. When the Vault is re-sealed, restarted, or stopped, you must provide at least 1 of these keys to unseal it again. Vault does not store the master key. Without at least 1 keys, your Vault will remain permanently sealed.
ローカルホストでの利用なので master key は1つにした.
デフォルト設定ファイルの評価タイミングが雑っぽくて,今日時点では-config ~/.vault
やexport VAULT_ADDR=http://localhost:8200
を省略することができない.そのうち~/.vault
がきちんと評価されるようになって,省略可能になる気がする.
起動直後はsealed なので unseal しておく.
$ vault unseal ced979c0b1c0ff62b2ac2aa08e54b8258bd4d88170ed67627b4c0fc3dd87133c Sealed: false Key Shares: 1 Key Threshold: 1 Unseal Progress: 0
ログの設定.
$ mkdir ~/.vault.d/log vault $ vault audit-enable file path=/Users/codeout/.vault.d/log/vault_audit.log Successfully enabled audit backend 'file'!
.cloginrc
をvault に格納する.組織ごとに異なる.cloginrc
を1つのvault に入れる必要があるので,key を分ける.ついでにpolicy も分けておいて 必要最小限のデータにのみアクセスを許可する.
チームA の.cloginrc
をsecret/team-a
に格納する例:
$ vault auth b5aae184-0fcf-3f7d-09db-9928d82eca56
Successfully authenticated!
token: b5aae184-0fcf-3f7d-09db-9928d82eca56
token_duration: 0
token_policies: [root]
# ./team-a.hcl path "sys/*" { policy = "deny" } path "secret/*" { policy = "deny" } path "secret/team-a" { policy = "write" } path "auth/token/lookup-self" { policy = "read" }
$ vault policy-write team-a team-a.hcl Policy 'team-a' written. $ vault write secret/team-a cloginrc=@/Users/codeout/.cloginrc Success! Data written to: secret/team-a
最後に,ポートフォワードと環境変数を転送するよう~/.ssh/config
を設定しておく.
# ~/.ssh/config Host jump-server Hostname 192.168.3.102 RemoteForward 8200 localhost:8200 SendEnv VAULT_TOKEN
確認
5分で失効するトークンを発行して ローカルホストから値が取れることを確認する.
$ vault token-create -lease=5m -policy=team-a Key Value token ccc70554-da81-4d2f-08be-d0d38232395c token_duration 300 token_renewable true token_policies [team-a] $ VAULT_TOKEN=ccc70554-da81-4d2f-08be-d0d38232395c vault read secret/team-a Key Value lease_duration 2592000 cloginrc ### default add method * {ssh} {telnet} add user * codeout add password * {some!secret} {some!secret} add method 192.168.0.79 {telnet} add password 192.168.0.79 {another!secret} {another!secret}
ログが残ることも確認.
{"time":"2015-11-28T15:29:11Z","type":"request","auth":{"display_name":"token","policies":["team-a"],"metadata":null},"request":{"operation":"read","path":"secret/team-a","data":null,"remote_address":"127.0.0.1"},"error":""} {"time":"2015-11-28T15:29:11Z","type":"response","error":"","auth":{"display_name":"","policies":["team-a"],"metadata":null},"request":{"operation":"read","path":"secret/team-a","data":null,"remote_address":"127.0.0.1"},"response":{"secret":{"lease_id":""},"data":{"cloginrc":"hmac-sha256:46ac8a23ac9efff3c42e5b9e31a7854e50f4a4e713810388003dbfcb1c9a607b"},"redirect":""}}
5分後には値が取れなくなっているはず.
セットアップ (ジャンプサーバー)
こちらも プラットフォームにあったvault をダウンロードし,PATH のどこかに置く.
.zshrc
などにvault のURL を設定する.外部からジャンプサーバーにssh するときに張るssh tunnel を指定しておく.
# ~/.zshrc export VAULT_ADDR=http://localhost:8200
rancid がインストールされているものとして,.cloginrc
を書き換える.
.cloginrc
はtcl スクリプトとして読まれるため,必要に応じてvault から認証情報を取得する動作になる.
# ~/.cloginrc if [ catch {eval [eval exec "vault read -field=cloginrc secret/team-a"]} reason ] { send_user "\nError: $reason\n" exit 1 }
可能であれば,ssh クライアントから環境変数VAULT_TOKEN
を受け付けるよう sshd を設定する.
# /etc/ssh/sshd_config AcceptEnv LANG LC_* VAULT_TOKEN
つかいかた
ローカルホストでvault を起動し,トークンを発行する.-lease
を指定しなければ30日有効なトークンが発行されるが,期間は適宜.
$ vault server -config ~/.vault >&/dev/null& $ vault unseal ced979c0b1c0ff62b2ac2aa08e54b8258bd4d88170ed67627b4c0fc3dd87133c $ vault auth b5aae184-0fcf-3f7d-09db-9928d82eca56 # 普段は上記の状態で動かしっぱなし $ vault token-create -lease=24h -policy=team-a Key Value token d78015ad-e903-2122-dea9-6b1bcb970391 token_duration 86400 token_renewable true token_policies [team-a]
$ VAULT_TOKEN=d78015ad-e903-2122-dea9-6b1bcb970391 ssh jump-server
これでxlogin できるようになっているはず.
$ jlogin 192.168.3.103 192.168.3.103 spawn ssh -c 3des -x -l codeout 192.168.3.103 Password: --- JUNOS 12.1X46-D10 built 2013-12-05 15:04:51 UTC codeout@vsrx>
ローカルホストでvault がunsealed で動いており,ssh tunnel 経由でジャンプサーバーからvault にアクセスでき,トークンがある場合のみ認証情報にアクセスできるようになった.
ローカルホストの~/.vault.d/log/vault_audit.log
には認証情報へのアクセスがすべて記録されるので,不正アクセスの調査ができる.
別のチームB のジャンプサーバーにssh する場合は,vault に格納するkey, policy 名を切り替えればよい.
ジャンプサーバーのsshd を設定変更できない場合は クライアントから環境変数を渡せないので,ログイン後にexport VAULT_TOKEN=d78015ad-e903-2122-dea9-6b1bcb970391
する.
このとき,一応コマンドヒストリーに残らないよう気をつける.たとえばzsh でhist_ignore_space
が設定されている場合は,export
の先頭に半角スペースを入れておけばヒストリーに残らない.
どうせsuper-user には/proc/<pid>/environ
やps e
などで環境変数を読まれてしまうが,いちおう余計なところに残さないほうがいい.
まとめ
.cloginrc
をまるまるvault 管理にすることで,より安全にxlogin を使えるようになった.やはりsuper-user は認証情報にアクセスできてしまうため 完全ではないが
構成を実現できた.
環境変数をsuper-user から隠す方法 もしくはうまく暗号化する方法があれば完璧なので,知見をお持ちのかたはぜひ教えてください.
El Capitan でSCR3310-NTTCom をつかう
Hubot にlongest match 機能をつける
ネットワーク運用をしていると,ホストアドレスから経路をルックアップしたいことが結構ある.
たとえばDDoS を受けたとき.いろいろな対処が考えられるが,網内のルーターでパケットフィルターする際に「src address → src prefix の変換をしてからガバッと止めたい」とか.
そんな面倒くさいことはBot にやってもらいたい.
実装のアイデア
ルーターにログインして変換してもいいし,ルーティングテーブルを別に持って検索してもいい.
ルーターにログインしてshow route
するのはIO バウンドな処理なのでnode との相性はよさそうだが,「src address が100コ」みたいな場合では遅いと思われる.よくあるルーターだと「まとめて引数を渡して,まとめて結果を受け取る」みたいなことができないため「1コ引数を渡して,1コ結果を受け取る」を100回やらないといけない.
一方,ルーティングテーブルを別に持つのってどう実装しよう?とか自前でpatricia tree つくんの?という面倒くささがある.
MRT TABLE DUMP + patricia tree でやってみる
実は,後者の面倒くさいところを解決してくれるbgpdump2 というツールがある.「node バインディング書けばいいのでは」と思ってやってみたら,結構うまく動くっぽかった.(まだ最小限の実装しかできてないです)
これを使うとlongest match の結果を返してくれる.
var BGPDump = require('node-bgpdump2'); var bgpdump = new BGPDump('path_to_rib.bz2'); console.log(bgpdump.lookup('8.8.8.8')); // => // { prefix: '8.8.8.0/24', // nexthop: '202.249.2.169', // origin_as: 15169, // as_path: '2497 15169' }
Hubot から使うのもカンタンで,
npm install node-bgpdump2 --save npm install https://github.com/codeout/node-mrt.git --save
たとえばshow route
モドキを返すやつ.
# scripts/route.coffee BGPDump = require('node-bgpdump2') MRT = require('node-mrt') mrt = new MRT('wide') module.exports = (robot) -> robot.respond /route (.*)/, (msg) -> mrt.get (text)-> msg.send text , (path)-> bgpdump = new BGPDump(path) msg.send JSON.stringify(bgpdump.lookup(msg.match[1]))
ちなみに node-mrt はarchive.routeviews.org からMRT アーカイブをダウンロードしてキャッシュしてくれるライブラリです.
もうちょい複雑なことを: DDoS 対策手順を作ってもらう
一例だけれど,たとえばDDoS を検知後に
- src address → src prefix に変換
- src prefix ベースで帯域制限する手順をつくり,GitHub Issue としてオープン
というところまでHubot にお願いしたい.
(今回は例としてsrc prefix だけの条件)
hubot-github-templated-issues というの流用すれば結構ラクにできて,8.8.8.8, 8.8.4.4, 64.6.64.6, 64.6.65.6 からのDDoS を検知したときに
hubot anti ddos packet_filter/ratelimit_2g DDoS対策 src: [ 8.8.8.8, 8.8.8.8, 64.6.64.6, 64.6.65.6 ]
とHubot にお願いすると,
手順書をIssue 化してくれる.
(↑ ではMRT アーカイブをダウンロードしているが,キャッシュがあればそれをつかう)
https://github.com/codeout/sandbox/issues/108
この手順書はテンプレート にパラメーターを埋めて作ったもので,hubot-github-templated-issues がよしなにやってくれます.
今回つかったスクリプト: scripts/anti_ddos.coffee
まとめ
node-bgpdump2 を使うと,Hubot にlongest match 機能をつけられてけっこう便利だと思う.
bgpdump2 自体,少しコンセプト実装っぽい側面があって完全にライブラリ化されていないため,できたら作者の方に今後のロードマップについて聞きたいところです.
iOS9 のMail.app で使えるcipher,使えないcipher
iOS9 に上げたiphone でimaps できなくなったため,Client Hello が送るcipher suite を調べた.
iOS8.4.1 | iOS9.0 | |
---|---|---|
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 | × | ○ |
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 | × | ○ |
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 | ○ | ○ |
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | ○ | ○ |
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA | ○ | ○ |
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA | ○ | ○ |
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA | ○ | ○ |
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | × | ○ |
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | × | ○ |
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 | ○ | ○ |
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | ○ | ○ |
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA | ○ | ○ |
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA | ○ | ○ |
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA | ○ | ○ |
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 | ○ | × |
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 | ○ | × |
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA | ○ | × |
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA | ○ | × |
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA | ○ | × |
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 | ○ | × |
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 | ○ | × |
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA | ○ | × |
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA | ○ | × |
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA | ○ | × |
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 | × | ○ |
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 | × | ○ |
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 | ○ | ○ |
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 | ○ | ○ |
TLS_DHE_RSA_WITH_AES_256_CBC_SHA | ○ | ○ |
TLS_DHE_RSA_WITH_AES_128_CBC_SHA | ○ | ○ |
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA | ○ | ○ |
TLS_RSA_WITH_AES_256_GCM_SHA384 | × | ○ |
TLS_RSA_WITH_AES_128_GCM_SHA256 | × | ○ |
TLS_RSA_WITH_AES_256_CBC_SHA256 | ○ | ○ |
TLS_RSA_WITH_AES_128_CBC_SHA256 | ○ | ○ |
TLS_RSA_WITH_AES_256_CBC_SHA | ○ | ○ |
TLS_RSA_WITH_AES_128_CBC_SHA | ○ | ○ |
TLS_RSA_WITH_3DES_EDE_CBC_SHA | ○ | ○ |
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA | ○ | ○ |
TLS_ECDHE_RSA_WITH_RC4_128_SHA | ○ | ○ |
TLS_ECDH_ECDSA_WITH_RC4_128_SHA | ○ | × |
TLS_ECDH_RSA_WITH_RC4_128_SHA | ○ | × |
TLS_RSA_WITH_RC4_128_SHA | ○ | ○ |
TLS_RSA_WITH_RC4_128_MD5 | ○ | ○ |
ちなみにOSX Yosemite (10.10.5) はiOS8.4.1 と同じcipher を送る.
openssl ciphers -tls1 HIGH と比べる
iOS8 & iOS9 & OSX Yosemite で使えるものは以下のcipher (openssl 形式) しかない.
- ECDHE-ECDSA-AES256-SHA (0xC00A)
- ECDHE-ECDSA-AES128-SHA (0xC009)
- ECDHE-ECDSA-DES-CBC3-SHA (0xC008)
- ECDHE-RSA-AES256-SHA (0xC014)
- ECDHE-RSA-AES128-SHA (0xC013)
- ECDHE-RSA-DES-CBC3-SHA (0xC012)
- DHE-RSA-AES256-SHA (0x0039)
- DHE-RSA-AES128-SHA (0x0033)
- EDH-RSA-DES-CBC3-SHA (0x0016)
- AES256-SHA (0x0035)
- AES128-SHA (0x002F)
- DES-CBC3-SHA (0x000A)
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:変更のために作ったブランチ
Gitlab + Gitlab CI をためす
Gitlab + Jenkins があまりグッとこなかったので,Gitlab + Gitlab CI をためしてみた.結論から言えば,Gitlab + Jenkins より良いと思う.
Docker 上に準備
やることは
- Gitlab コンテナを動かす
- Gitlab CI コンテナを動かす
- Gitlab Runner コンテナを動かす
OSX 環境でためしたので,
$ docker-machine ip default 192.168.99.100
文中の192.168.99.100 とポートは適宜読み替えてください.
1. Gitlab コンテナを動かす
$ curl https://raw.githubusercontent.com/sameersbn/docker-gitlab/master/docker-compose.yml > gitlab.yml
$ docker-compose -f gitlab.yml up
http://192.168.99.100:10080 にアクセスできるようになるので,
- root ログインして必要なユーザーをつくる
- 鍵を登録する
- 適当なプロジェクトをつくる
- System OAuth applications に,あとで必要になる “http://192.168.99.100:10081/user_sessions/callback” を登録しておく
- Application Id: b3c0249b80e96cc35c4952bd288d8ba27fdfdbb93cfac6939d1438ffbdb9aa63
- Secret: a791b4b8e7a6515b457cf94a5246b74c1a72377ada25c009413fe0932f152753
参考: https://hub.docker.com/r/sameersbn/gitlab/
2. Gitlab CI コンテナを動かす
$ curl https://raw.githubusercontent.com/sameersbn/docker-gitlab-ci/master/docker-compose.yml > gitlab-ci.yml
$ vi gitlab-ci.yml
適宜編集
-postgresql: +ci-postgresql: image: sameersbn/postgresql:9.4-3 environment: - DB_USER=gitlab_ci @@ -6,24 +6,24 @@ - DB_NAME=gitlab_ci_production volumes: - /srv/docker/gitlab-ci/postgresql:/var/lib/postgresql -redis: +ci-redis: image: sameersbn/redis:latest volumes: - /srv/docker/gitlab-ci/redis:/var/lib/redis ci: image: sameersbn/gitlab-ci:7.13.5 links: - - redis:redisio - - postgresql:postgresql + - ci-redis:redisio + - ci-postgresql:postgresql ports: - "10081:80" environment: - TZ=Asia/Kolkata - - GITLAB_URL=http://localhost:10080 - - GITLAB_APP_ID= - - GITLAB_APP_SECRET= - - GITLAB_CI_SECRETS_SESSION_KEY_BASE= - - GITLAB_CI_SECRETS_DB_KEY_BASE= + - GITLAB_URL=http://192.168.99.100:10080 + - GITLAB_APP_ID=b3c0249b80e96cc35c4952bd288d8ba27fdfdbb93cfac6939d1438ffbdb9aa63 # Application Id + - GITLAB_APP_SECRET= a791b4b8e7a6515b457cf94a5246b74c1a72377ada25c009413fe0932f152753 # Secret + - GITLAB_CI_SECRETS_SESSION_KEY_BASE=v5W2GBFZP9TxTd29tkxSmpdFm66BD8S9fTrVMrJkmGQ2KddgSqRdCL4t4Npk2vWh # pwgen -Bsv1 64 などで作成 + - GITLAB_CI_SECRETS_DB_KEY_BASE=94fzWmKLLfWKkWlklQ9C4GXN8svTmnS2wMC7Xm9pw6hwdpLXgCcDl3R9Txxv8nLR # pwgen -Bsv1 64 などで作成 - GITLAB_CI_HOST=localhost - GITLAB_CI_PORT=10081 - GITLAB_CI_EMAIL=ci@example.com
$ docker-compose -f gitlab-ci.yml up
http://192.168.99.100:10081 にアクセスできるようになるので,
- OAuth ログイン
- プロジェクト一覧が取れる → 必要なプロジェクトを “Add project to CI”
- Runners page でトークンを調べる
- 9967476047fe03df0f230dca181cf4
参考: https://hub.docker.com/r/sameersbn/gitlab-ci/
3. Gitlab Runner コンテナを動かす
$ docker run -d --name gitlab-runner --restart always \ -v /srv/gitlab-runner/config:/etc/gitlab-runner \ gitlab/gitlab-runner:latest docker exec -it gitlab-runner gitlab-runner register Please enter the gitlab-ci coordinator URL (e.g. http://gitlab-ci.org:3000/): http://192.168.99.100:10081/ Please enter the gitlab-ci token for this runner: 9967476047fe03df0f230dca181cf4 Please enter the gitlab-ci description for this runner: [8370d5d6805a]: INFO[0129] 99674760 Registering runner... succeeded Please enter the executor: docker-ssh, ssh, shell, parallels, docker: [shell]: INFO[0133] Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Runners page をリロードすると,Runner が登録されている.
Runner に必要なビルド環境をつくる.(たとえば) ruby をインストール.
$ docker exec -it gitlab-runner bash $ apt-get update $ apt-get install -y wget curl gcc libxml2-dev libxslt-dev libcurl4-openssl-dev libreadline6-dev libc6-dev libssl-dev make build-essential zlib1g-dev openssh-server git-core libyaml-dev postfix libpq-dev libicu-dev $ su gitlab-runner $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build $ rbenv install 2.2.3 $ rbenv global 2.2.3
参考: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/docker.md
Gitlab CI ができること
- branch 作成時にCI を回す
- Merge Request 作成時にCI を回す
- Gitlab 上に結果表示
- Status Badge
- 結果をSlack / HipChat に通知
- Gitlab と連携
- OAuth
- プロジェクト取得
おおよそ十分な機能をもっている.Jenkins がJava なのに対し,go + ruby + rails.
Gitlab と一緒に使うならJenkins より直観的だし,プロジェクトごとにrunner を分けられて安心だなと思った.
フルルート入れるのにgobgp を使ってみる
「どの程度お手軽にフルルートを注入できるか?」の続編です.
2015/08/12 追記 : gobgp の不具合,修正されました
今回 gobgp のコミッターさんから「mrt 実装しましたー,もしお時間あったら試してみてください!」と連絡もらったので 試しました.
MRT TABLE_DUMP からフルルートを注入してみます.
gobgp ?
BGP Daemon のGo 実装です. 速そうだしガンガン機能が足されていて 注目のbgpd.
- Go なので,マルチコアをうまく使ってくれそう
- gobgpd (サーバー) とgobgp (CLI) で構成されている
- サーバー <-> CLI 間はgrpc
- MRT から経路生成できるし,MRT Dump もできる
- 経路フィルター書けたり,VRF つくれたり,RPKI できたり,route server できたり,EVPN できたりしそう (未確認)
- ドキュメント
特にサーバーはgrpc を話すので,「手軽にクライアント作れるかもしれないな」とも思ってます.
bgpsimple vs. gobgp
フルルート注入スピードについて,bgpsimple *1と比べてみると
bgpsimple | gobgpd | |
---|---|---|
ピアが上がるまで | 0'00" | 0'07" |
フルルート広告し終わるまで | 2'42" | 1'43" |
clear bgp 後,フルルート広告し終わるまで | 3'12" | 1'24" |
gobgp めっちゃ速い!!!
bgpsimple がシングルスレッドなのに対し,gobgpd はマルチスレッドで CPU バウンドな処理と相性よさそう.実際にマルチコアをうまく使ってくれます.
環境
- MacBook Pro (Retina, Mid 2012) + VMWare
- Guest
- bgpsimple 0.12 + perl 5.14.2
- gobgp 2015/08/10 + go1.4.2
経路受信側は別Hypervisor のvSRX.ボトルネックにならないよう,経路はすべてreject する設定.
gobgp の長所
- 速い!!!
- CLI から多少コントロールできる
- MRT を読んで一旦RIB に格納しているため,経路広告前にbest path selection が走っている
- 経路の整合性が取れていて,受信側の負荷が下がる
- MRT を直接入力できる (bgpdump 不要)
gobgp の短所
不具合ありそうeBGP UPDATE メッセージにLP 属性が入っているeBGP UPDATE メッセージのAS_PATH 属性に,自分のAS が入っていない
見つけた不具合はすぐ修正してもらえました.ありがとうございます
サポートOS が少ないかも?
個人的にはデバッグのためOSX で動くとうれしいが,Linux も手に入りやすい部類だと思う.上記の不具合が解決したら 積極的に使っていきたい.
*1:bgpsimple はMRT から経路生成するならお手軽で便利なので,イチオシだったbgpd