総務部技術課!?エンジニアのための業務完全自動化へのアプローチ
株式会社フィックスポイント 服部健太
フィックスポイント社について
2014/6/22JTF2014
2
事業内容 システム運用自動化プラットフォーム「 Kompira」の開発 運用自動化導入サービス 業務コンサルティングサービス
所在:東京都渋谷区 設立:2013年4月 社員数:8名 http://www.fixpoint.co.jp
要するに Kompira を作って売っているベン
チャー企業
エンジニアに降りかかる雑用の数々
Web コンテンツ更新 SSL サーバ証明書更新 FW 設定変更 DNS 設定変更 データバックアップ アカウント追加・削除 サーバ構築 脆弱性対応 ソフトウェア更新作業
アプリセットアップ 不要ファイルの削除 ビルメンテ停電対応 障害対応 ログファイル分析 問い合わせ対応 ・・・
2014/6/22
3
JTF2014
いちいち専用ツールを導入すると・・・
2014/6/22JTF2014
4
中途半端な自動化の風景
2014/6/22JTF2014
5
中途半端な自動化の課題
2014/6/22JTF2014
6
自作スクリプトの問題 自作スクリプトがいろんなサーバに散らばっていて、どこに
何があるのか把握しきれていない 設定変更のためスクリプトを直接修正する必要がある 作った人でないと、そのスクリプトを修正できない 昔作ったスクリプトとかだと使い方を忘れる
複数のサーバや管理ツールにわたる作業なため、各サーバにログインしてスクリプトやコマンドを実行している
作業依頼や通知メールを受け取るたびに、自分の業務が中断されてしまう
完全自動化しないとエンジニアの負荷はなかなか減らない
運用自動化の段階
•コマンド実行も含めて全て手作業
Level 0 : 原始状態
•1サーバに閉じた作業がスクリプト化されている
Level 1 : スクリプト化
•ファイル転送やメール送信、複数のサーバにまたがる作業もスクリプト化されている
Level 2 : 半自動化
•業務依頼を受けるとワンクリック(ワンコマンド)で実行できる
Level 3 : 全自動化
•業務自体がシステムに組み込まれ、人が介在することなく実行される
Level 4 : システム化
2014/6/22JTF2014
7
難易度高
完全自動化の壁と対応方法
2014/6/22JTF2014
8
複数のサーバにまたがる作業⇒ Fabric を使う
設定ファイルを書き換える必要がある⇒ sed を駆使するか設定ファイルのテンプレートを用意する
実行するコマンドが対話形式でコンソールからの入力待ちになる⇒ バッチ実行可能なオプションを探す⇒ expect スクリプトと組み合わせる
ブラウザにアクセスして外部ツールを操作する必要がある⇒ 外部ツールが API を提供していれば、それを利用する⇒ ブラウザアクセス時の HTTP リクエストを解析し、スクリプトから適切な POST リクエ
ストを投げる 作業依頼ごとに微妙に内容が異なる
⇒ バリエーションを整理し設定やオプションを整理し、 YAML などで設定できるようにする
スクリプトが複雑になったり、数が増えたりする⇒ Git や SVN などのリポジトリでバージョン管理する⇒ スクリプトは必要に応じて、実行対象サーバに転送する
基本的なシステム構成
2014/6/22JTF2014
9
Fabric とは
2014/6/22JTF2014
10
アプリケーションのデプロイやシステム管理といった仕事を自動化するためのツール Python ライブラリ、 CUI ツールから構成される SSH を使ってリモートコマンドを自動実行する
特徴: Python で書ける ローカルからリモートへ SSH 接続してできる作業なら、なんで
も自動化可能 リモートサーバを複数定義しておくと、自動化した作業を一括
で適用可能 Cf. Capistrano
Ruby で書かれている Rake 風の DSL ( Domain Specific Language )で記述
Fabric によるタスク記述例
2014/6/22JTF2014
11
fabfile.py
タスクの実行方法: $ fab install_python -H <host> -u <user> -p <passwd>
from fabric.api import cd, run, sudo
def install_python(ver='3.3.3'): run('wget http://www.python.org/ftp/python/{0}/Python{0}.tgz'.format(ver)) run('tar zxvf Python-{0}.tgz'.format(ver)) with cd('Python-{0}'.format(ver)): run('./configure --prefix=/opt/local') sudo('make & make install')
題材: Wordpress サーバの新規構築
AWS インスタンスを新規作成@ローカル1. インスタンス生成2. Public IP アドレスを取得3. SSH ログイン可能になるまで待つ
Wordpress サーバをインストール@インスタンス1. 最新の Wordpressパッケージを取得2. 必要なパッケージをインストールする3. MySQL データベースを作成する4. WordPress の設定を行い /var/www/html に配置する5. install.php にアクセスして WordPress を初期化する
2014/6/22JTF2014
12
Fabric で実装する場合
2014/6/22JTF2014
13
リモートコマンドの実行は run を使って簡単に書けるが・・・ YAML 設定ファイルの読み込み
ファイルオープンして PyYAML でパース インスタンスのログインチェック
ログイン可能になるまで sleep しながらリトライ処理 install.php にアクセスしての初期化
requests ライブラリで POST リクエスト生成 タスクファイルを分割して管理
Python のモジュール機構を利用Python プログラムをゴリゴリ書いていく必要あり
Kimpira を作ってみた
2014/6/22JTF2014
14
http://github.com/khattori/kimpira Fabric のラッパーツール
タスク(作業手順)を YAML で記述できる hello.yml
タスクの実行:
TASK: echo-hello-worldPARAMS: message='hello world'DO: - COMMAND: echo $message - PRINT: $RESULT
$ kimpira hello.yml
Ansible もどきでは!?というツッコミはこの際
無視
リモートコマンド実行
2014/6/22JTF2014
15
実行対象のホストやアカウント情報が記述された YAML ファイルパスを制御変数で指定
test-account.yml
TASK: execute-remote-commandDO: - SET: HOST=test-server ACCOUNT=@./test-account.yml - COMMAND: whoami - COMMAND: hostname
user: test-userpassword: test-passwordkeyfile: ./test-user.pem
スクリプト実行
2014/6/22JTF2014
16
任意のスクリプトをリモートサーバ上で実行可能
スクリプトファイルは実行時に対象サーバに転送され、実行完了後は自動で削除される
TASK: execute-scriptPARAMS: NODE=@./test-server.ymlDO: - SCRIPT: @./shell-script.sh - SCRIPT: @./perl-script.pl - SCRIPT: @./ruby-script.rb - SCRIPT: @./python-script.py
タスク制御機構
2014/6/22JTF2014
17
別タスク呼び出し
条件分岐
繰り返し
REPEAT~WHILE, REPEAT~UNTIL, FOR~ IN もある
- CALL: echo-hello-world 'hello JTF2014' IN: '@./hello.yml'
- IF: '"${ $result != "root" }"' THEN: - PRINT: please run as root user!
- REPEAT: 10 DO: - SLEEP: 1 - COMMAND: date
Kimpira で Wordpress サーバ構築
2014/6/22JTF2014
18
ディレクトリ構成samples├── lib/│ └── aws/│ ├── account.yml│ ├── api.yml│ ├── conf.yml│ └── utils.yml└── wordpress/ ├── conf.yml ├── setup.yml └── wordpress.yml
AWS インスタンスの生成
2014/6/22JTF2014
19
AWS CLI ツールを呼び出してインスタンス生成し、名前を設定 その後、インスタンスが running 状態になるまで待つ
- TASK: create-instance-and-wait-running PARAMS: name image_id key_name security_groups= ... DO: - CALL: ec2-run-instances $image_id $key_name ... IN: "@./api.yml" RESULT: instance_id - CALL: ec2-create-tags $instance_id Name $name IN: "@./api.yml" - CALL: wait-instance-running $instance_id - RETURN: $instance_id
インスタンス起動待ち
2014/6/22JTF2014
20
5秒おきにインスタンス状態を取得 running 状態になるまで最大で30回繰り返す
- TASK: wait-instance-running PARAMS: instance_id DO: - REPEAT: 30 DO: - SLEEP: 5 - CALL: get-instance-status $instance_id RESULT: status UNTIL: ${status == "running"}
ログイン待ち
2014/6/22JTF2014
21
成功するまで5秒おきに id コマンドをリモート実行
- TASK: check-login PARAMS: host account=@./account.yml DO: - SET: HOST=$host ACCOUNT=$account - REPEAT: 30 DO: - SLEEP: 5 - COMMAND: id WARN_ONLY: - SET: status=$RESULT.return_code UNTIL: ${status == "0"} - IF: ${status!='"0"'} THEN: - ABORT: Failed to login $host
コマンドが失敗してもアボートしないように WARN_ONLY 設
定
Wordpress インストール
2014/6/22JTF2014
22
インストール手順の各ステップを記述したサブタスクを順番に呼び出す
- TASK: setup-wordpress PARAMS: host account DO: - WITH: HOST=$host ACCOUNT=$account DO: - CALL: package-download - CALL: start-services - CALL: create-db - CALL: configure-and-copy - CALL: initialize
Wordpress初期化
2014/6/22JTF2014
23
- TASK: initialize DO: - DEFAULT: conf=@./conf.yml - yaml.load: $conf RESULT: conf - http.post: http://$HOST/wordpress/wp-admin/install.php?step=2 DATA: weblog_title: $conf.wp_title user_name: admin admin_password: $conf.wp_admin_password admin_password2: $conf.wp_admin_password admin_email: $conf.wp_admin_email log_public: '1' Submit: WordPress をインストール - WITH: SUDO=True DO: - COMMAND: rm /var/www/html/wordpress/wp-admin/install.php - RETURN: http://$HOST/wordpress
ブラウザからアクセスするかわりに POST リクエストを投げて
初期化
全部をまとめる
2014/6/22JTF2014
24
- TASK: create-wordpress-server PARAMS: name=JTF_Test image_id=ami-c9562fc8 ... DO: - CALL: create-instance-and-wait-running $name ... IN: "@../lib/aws/utils.yml" RESULT: instance_id - CALL: get-instance-public-ip $instance_id IN: "@../lib/aws/utils.yml" RESULT: server_ip - CALL: check-login $server_ip $account IN: "@../lib/aws/utils.yml" - CALL: setup-wordpress $server_ip $account IN: "@./setup.yml" RESULT: url - PRINT: "**** SETUP COMPLETED! --- $url"
完全自動化まであと一歩
2014/6/22JTF2014
25
メールを受信したら、自動的に Wordpress 構築
定期的にメールチェックするよう crontab に登録しておく
- TASK: recv-mail DO: - email.recv: $imap4_conf RESULT: mails - FOR: mail IN: $mails DO: - IF: ${$mail.Subject=='"Install Wordpress"'} THEN: - CALL: create-wordpress-server IN: '@./wordpress/wordpress.yml' RESULT: url - CALL: send-mail $mail.From $url
GUI で作業依頼を受け付ける
2014/6/22JTF2014
26
Google フォームを使う フォーム送信ボタンが押されたらメールを送信す
るように設定しておく
デモ
2014/6/22JTF2014
27
https://docs.google.com/a/fixpoint.co.jp/forms/d/1Iu1pmCPlcmjaUNamH4EJpPtxcZhrdrQ4EhwAY9nioig/viewform
自動化=プログラミング
2014/6/22JTF2014
28
タスクを YAML で書いても、それはプログラム
GUIでグリグリ書いても、それはプログラム
どこまで自動化すべきか?29
自動化に向いているもの 手順化が簡単(単純な規則にもとづく作業) 何度も繰り返し行う作業
自動化に向いていないもの 手順化できない、手間が大変(高度、複雑な判断が必要な作業) 一回ポッキリの作業人間向きの
高度な作業単純な
定型処理
・・・ ・・・
オペレータ オペレータ
自動化によって削減されるコスト > 自動化にかかるコスト
Kompira のご紹介
2014/6/22
30
JTF2014
Kompira の概要
2014/6/22JTF2014
31
運用自動化のためのプラットフォーム オペレータはサーバの運用手順をジョブフローとして記述し、それを Kompira サーバ上で実行する
独自 DSL によるジョブフロー記述
2014/6/22JTF2014
32
実行するリモートコマンドを「 -> 」でつないでいく
メール受信など外部イベントをチャネル経由で取得可能
| __node__ = ../ テストサーバ | print('1. WordPressパッケージをダウンロードします ')-> ['wget -q -nc http://ja.wordpress.org/latest-ja.tar.gz']-> print('2. 必要なパッケージをインストールし、サービスを起動します')-> [__sudo__ = true]-> ['yum install -q -y httpd mysql-server php php-mysql php-mbstring']-> ['chkconfig mysqld on'] -> ['service mysqld start']-> ['chkconfig httpd on'] -> ['service httpd start']
<./ メール受信 > -> [./Wordpress サーバ構築 : $RESULT]
Kompira サーバのシステム構成
33
デモ
2014/6/22JTF2014
34
詳細はA会場フィックスポイント社ブースにて!
Kompira利用事例
2014/6/22JTF2014
35
セキュリティ監視業務でのチケット自動クローズ アプリケーションログの定期監視と異常検出時
のエスカレーション 監視サーバからのアラートを受けて障害復旧 Kompira ライセンスファイルの発行業務 Excel顧客名簿にもとづくダイレクトメールの送
信とバウンスメールの処理 ウェブサイトのコンテンツ更新作業 ・・・
まとめ
2014/6/22JTF2014
36
自動化の効果は完全自動化することで実感できる
自動化とはプログラミング(システム開発)である
自動化に魔法の杖(銀の弾丸)は無い
自動化プラットフォームをベースに自動化しやすいところから手をつけていくのがよい
自動化にはコストがかかるので、自動化と手作業の見極め(割り切り)が重要