Upload
airtoxin-ishii
View
451
Download
4
Embed Size (px)
Citation preview
2日間Fabricを触った俺が色々解説してみる
@airtoxin
Fabric?
About Fabric
Python(2.5-2.7)製のデプロイ・システムタスク実行ツール。
同様のツールにRuby製のCapistranoがある。
Install Fabric
Pythonとpipが入っているなら
$ (sudo) pip install Fabric
#!/usr/bin/env python # -‐*-‐ coding: utf-‐8 -‐*-‐
from fabric.api import env, local, run import difflib
env.hosts = [ ‘mydevelopment.jp' ] env.key_filename = [ '~/.ssh/mydevelopment.rsa' ] env.user = 'airtoxin' env.port = 9724
def get_date(): remote_date = run( 'date' ) local_date = local( 'date', capture=True ) for line in difflib.ndiff( [ remote_date ], [ local_date ] ): print line
Example of Fabricfabfile.py
サーバー実行コマンドタスク名
ローカル実行コマンド
Pythonで実行結果を処理
Run Fabric
fabfile.pyのあるディレクトリで
$ fab get_date(タスク名)
タスクリスト
定義タスクの一覧確認は
$ fab --list
コマンド• リモートでコマンドを実行 → run(‘command’)
• ローカルでコマンドを実行 → local(‘command’)
• sudoでコマンドを実行 → sudo(‘command’)
• ディレクトリの移動 → with cd(‘dirname’):
• ファイルアップロード → put(‘localpath’, ‘remotepath’)
• ファイルダウンロード → get(‘remotepath’, ‘localpath’)
コマンド
大体なんとかなる。
というか
local, run, sudoがあるので実質何でもできる。
それって…
Shellでいいじゃん!!
正しい
Shell vs Fabric
Shell動作環境周りで考えることがほぼ無し。
サーバー操作の共通言語として多くのエンジニアが扱えることが期待出来る。
実際には可読性が低く、メンテナンス性が悪い。シェル芸の乱立。
属人化したサーバー保守・デプロイのコード。いざ修正しようとしても手がつけられない。
Fabric可読性の高いと言われるPythonで程よくラップしたコードが書ける。メンテナンス性の向上。
文字列、配列操作に長けているのでコマンドの返り値を処理するのが簡単。さらにPythonのライブラリも使える。
導入コストがほぼゼロ。
デコレーターとリスト内包表記さえ知れば問題なく使える学習コストの低さ。
Shell vs FabricShell Fabric
導入コスト-
プリインストール低~中程度
Pythonのpipによる
可読性 低い 謎文法, ワンライナー
高い Pythonのコード
文字列操作 難~普通程度 perl, awk等を利用
楽 ライブラリ等を利用
学習コスト 無し~高い 普段使い/初心者
低い~普通 リスト内包表記, decorator
情報量 多い 言わずもがな
中 ほぼ枯れている
Shell vs FabricShell Fabric
導入コスト - プリインストール
低~中程度 Pythonのpipによる
可読性 低い 謎文法, ワンライナー
高い Pythonのコード
文字列操作 難~普通程度 perl, awk等を利用
楽 ライブラリ等を利用
学習コスト 無し~高い 普段使い/初心者
低い~普通 リスト内包表記, decorator
情報量 多い 言わずもがな
中 ほぼ枯れている
後の事を考えるならFabric
Fabricサイコー
Shellでやってるの?
それって…
Fabricでいいじゃん!!
逆にね
実践Fabric1つのサーバーに対して特有の操作を行うことは少ない。
• 多数のサーバーに対して同じコマンドを実行
• 段階的,多段的なデプロイ
• ユーザーを変えたサーバー接続
など
実践Fabric
まずはfabfileの分割から
Example of Fabricfabfile.py
サーバー実行コマンドタスク名
ローカル実行コマンド
Pythonで実行結果を処理
#!/usr/bin/env python # -‐*-‐ coding: utf-‐8 -‐*-‐
from fabric.api import env, local, run import difflib
env.hosts = [ ‘mydevelopment.jp' ] env.key_filename = [ '~/.ssh/mydevelopment.rsa' ] env.user = 'airtoxin' env.port = 9724
def get_date(): remote_date = run( 'date' ) local_date = local( 'date', capture=True ) for line in difflib.ndiff( [ remote_date ], [ local_date ] ): print line
fabfileの分割
fabfileをディレクトリ化しPythonのライブラリとして定義することが可能。
操作のまとまり毎にファイル分割して見通しをよくする。
fabfileディレクトリ内のファイルにタスクを定義。
__init__.pyで各ファイルをインポート
操作毎にファイルを分割。必要ならばサーバーへの接続情報のみを定義するタスクも書く。
fabfile構成
. ├── .gitignore └── fabfile ├── __init__.py ├── deploy.py ├── hosts.py ├── monitor.py └── test.py
ホストの設定のみ
hosts.py
. ├── .gitignore └── fabfile ├── __init__.py ├── deploy.py ├── hosts.py ├── monitor.py └── test.py
@taskdef staging():
env.hosts = ['mystaging.jp'
]
@taskdef production():
env.hosts = ['production.com','myhost.jp','myapp.jp'
]
実行タスク
. ├── .gitignore └── fabfile ├── __init__.py ├── deploy.py ├── hosts.py ├── monitor.py └── test.py
deploy.py
@task( default=True )def deploy():
with cd( '/path/to/myapp' ):run( 'git checkout .' )run( 'git pull' )run( 'npm install' )run( 'npm run compile' )run( 'forever restart app.js' )
@taskdef tagging():
hostname = local( 'hostname' )run( 'git tag {host}-
{datetime}'.format( host=hostname, datetime=now ) )
run( 'git push --tags' )
. ├── .gitignore └── fabfile ├── __init__.py ├── deploy.py ├── hosts.py ├── monitor.py └── test.py
__init__.py
#!/usr/bin/env python# -*- coding: utf-8 -*-
import hostsimport deployimport monitorimport test
Task List
fu:fabric_test$ fab -l Available commands:
deploy deploy.deploy deploy.tagging hosts.production hosts.staging monitor monitor.all monitor.disc_capacity monitor.load_average
@task( default=True )def deploy():
実行コマンド$ fab [task1] [task2] [task3]…
$ fab hosts.staging deploystagingサーバー群に対してdeployコマンドが実行される
hostを直接指定するなら$ fab -H myhost [tasks…]
Fabricの実行順Fabricはデフォルトでtaskを直列実行する。
host1,host2 と taskA,taskB がある時host1のtaskA
host2のtaskA
host1のtaskB
host2のtaskB と順次実行される
直列タスクfrom fabric.decorators import task, parallel
@taskdef deploy():
print env.host
fu:fabric_test$ fab hosts.production deploy [production.com] Executing task 'deploy' production.com [myhost.jp] Executing task 'deploy' myhost.jp [myapp.jp] Executing task 'deploy' myapp.jp
Done.
host毎に直列実行されている
並列タスクfrom fabric.decorators import task, parallel
@task@paralleldef deploy():
print env.host
fu:fabric_test$ fab hosts.production deploy [production.com] Executing task 'deploy' [myhost.jp] Executing task 'deploy' [myapp.jp] Executing task 'deploy' myapp.jp production.com myhost.jp
Done.
これだけ
並列実行されている
Fabricサイコー
fabfileの構成まとめ対象ホストが多数ある場合はホスト設定のみを行うタスクを作るのが便利。
[対象ホスト]と[実行コマンド]が分離できるので、[どこに] [何を]するのかが明確に区別できるようになる。
fabfileの構成まとめ@parallelした時に並列化されるのはタスク単位なので、実行のまとまりとしてタスクを定義する。
同時に実行されたらやばそうな所をまとめる感じでタスク定義を行えば良い。
Fabricまとめ
保守とか考えない・書捨てのワンライナーとかならShellでいい。
保守性を考えるならFabricを使おう。
おわり