Slide 1

Slide 1 text

Ansibleを結構使ってみた 2015/9/14 日本経済新聞社 デジタル編成局 梅崎裕利 1

Slide 2

Slide 2 text

自己紹介 • 2014年入社(2年目) • 社内では基盤チーム • サーバ管理からアプリ開発まで • PythonとElasticsearchで検索API開発 2

Slide 3

Slide 3 text

Ansibleを使った目的 • ドキュメントと実サーバの状態を合わせたい • これまではExcelでミドルウェア管理(更新されない) • なるべくイミュータブルに • インスタンス起動から設定変更・デプロイまで • 同じサーバをポコポコ増やしたい • 環境ごとに若干設定が違うのでAMIコピーは面倒 3

Slide 4

Slide 4 text

Ansibleを選んだ理由 • 社内にPython開発者が多いから • djangoやflaskを使っているためJinja2も慣れてる • Agentを入れなくていい • Chefは社内で何人かが挫折した • Windowsにも対応しているらしい • @r_rudiさんにサポートをお願いできた(重要) • 困ったときに相談できる人がいると安心 4

Slide 5

Slide 5 text

Ansibleを使った場所 • 電子版のWebサーバ群 • 約300台、30種類以上 • データセンターからAWSへ基盤移行のタイミング 5

Slide 6

Slide 6 text

サーバ構成 6 HAProxy Varnish Varnish HAProxy ELB NAS LogServer StaticFiles App1 App2 DB Elasticsearch Zabbix Batch 青い部分を環境数分 (production, staging, dev1, dev2…) Ansible 構築・デプロイ 基盤サーバ (Zabbix,HAProxy, Varnishなど) 配信サーバ (appやDB)

Slide 7

Slide 7 text

運用までの流れ • 体制(時期別) • 実験フェーズ • 設計 • 決定内容(すること・しないこと) • ディレクトリ構造 • クラウド向けへ構成変更 • 構築 • フロー • RolesのCI方法 • 運用 7

Slide 8

Slide 8 text

体制 • 2014/9~12月 実験的にAnsible利用 • 構成を決める(自分+@r_rudiさんサポート) • 2015/1~4月 クラウドベンダーと設計・開発 • ベンダーがRole作成、日経でレビュー • 2015/5~7月 リファクタリング・Ansibleを広める • ServerSpecを用意・テスト • 環境毎に使いまわせるよう変数化 • 社員や常駐SEにAnsibleの使い方を伝える • 2015/8月~ 社員と常駐SEで運用 • 常駐SEや社員がプルリクエスト、基盤チームでレビュー 8

Slide 9

Slide 9 text

実験期間(2014/9~12月) • 新規開発のAPI群構築にAnsibleを利用 • 実際に使ってみて気になった点を @r_rudiさんに教えてもらった • 一般的なディレクトリ構成 • よくあるAnsible.cfgの設定 • xxxするモジュールはあるか、作り方 • 再起動チェックの方法 • xxxはバグか仕様か • 環境変数の読み込み方 • … 9

Slide 10

Slide 10 text

設計時に決めたこと • アプリケーションとAnsibleどこで分けるか • 理想はアプリをDockerなどでHerokuライクに分ける • 今回は変更頻度(高いのはアプリ)と 環境依存(本番・開発で違うのはAnsible)で分けた • HAProxyなど設定がシンプルなものはすべてAnsibleで • ディレクトリ構造 • リポジトリをCommonと配信サーバ群・基盤サーバ群に 分けcommonをsubmoduleで読み込み • 環境変数の切り替えはhostsでやる • Rolesの分割単位 • ミドルウェア単位 • role内での条件分岐はなるべく避ける 10

Slide 11

Slide 11 text

ディレクトリ構造例 (Zabbix-server) 基盤Playbooks/ |--zabbix-server.yml |--roles/ | └─zabbix-server/ | └─ (defaults, handlers, meta, tasks, teplates...) |--spec/ | └─zabbix-server/ | └─main_spec.rb | |--ansible-common-repository/ | |--filter_plugins/ | |-- development/ | |--production/ | |--roles/ | | |--common/ | | └─zabbix-agent/ | └─spec/ | └─zabbix-agent/ 11

Slide 12

Slide 12 text

構成をクラウド向けに • サーバ相乗りをやめる • 1機能1サーバにすることで設定を変数化しやすくする • 立て直しできるようにする • ログを別サーバに転送するようにして状態を持たない • サーバのrole名を統一する • 同じサーバなのに呼び名いろいろ NASサーバ、シェアサーバ、ファイルサーバ、etc… 12

Slide 13

Slide 13 text

Ansibleでしないこと • 複数ディストリビュージョン対応 • ソフトウェアバージョンの固定 • 自前のリポジトリを立てる必要が出てくる • 最新のものでも動くように随時対応する • Dynamic Inventryの活用 • サーバを固定IPで運用することにした • hostsをもとにサーバを起動・構築する • Ansibleでオートスケーリング • hostsとの相性が悪い • AMIイメージをAnsibleで作成 13

Slide 14

Slide 14 text

Playbook作成(2015/1~7) • クラウドベンダー(cloudpack)にPlaybookを作成してもら う • 期間が短かったため1ヶ月ほどは直接masterで作業 • 日経側でCI環境を用意 • ある程度できたところでPull-requestフロー開始 • ベンダーがプルリクエスト、日経でレビュー • Masterマージ後に反映 • レビューが遅れると開発も遅延するのでなるべく早く確認 • cloudpackにServerspecを書いてもらう • リファクタリング • 日経側で運用しやすいように変更 14

Slide 15

Slide 15 text

CI環境(CircleCI) • 初期はAnsible-lintで簡単な構文チェック • Typoなどのあからさまなバグは発見できる。 • Ansibleに慣れていない人がshell使いまくるのを防げた • CircleCI上にDockerコンテナを用意してコンテナに Ansibleを流す • 設定ファイルのバグなどが大幅に減った • Template展開後の値確認が出来るようになった • Serverspecでコンテナをテスト • 期待どおり設定されているかまでわかるようになった 15

Slide 16

Slide 16 text

CircleCIの内容 • テスト箇所 • コンテナを作成して自身にPlaybookを流しイメージ化 • イメージにServerspecを流す 16 test: override: - ansible-lint *.yml - docker run -t -v `pwd`:/data -w=/data/tests/ nikkei/ansible_centos6 ansible-playbook -i hosts haproxy.yml && docker commit `docker ps --latest --quiet` haproxy - docker run -t -v `pwd`:/data -w=/data/ haproxy rake -f tests/Rakefile spec:haproxy SPEC_BACKEND=CI

Slide 17

Slide 17 text

CIの課題 • どこまでテストするかが悩み • 実機かDockerか。Serverspecでどこまで確認するか • テスト時間とのトレードオフ • AMIイメージとDockerコンテナがそもそも違う • LXC上のDockerなのでテスト出来ないものがちょっとある • カーネルパラメータ変更やsystemdでサービス起動 • 流すとエラーになるのは変数でスキップ • Dockerは早いと言われるけど、それでも遅い • Roles数のテストがあるため開発につれて増加(30分かかる) • CircleCIの契約コンテナ数不足(2時間待ち…) • 並列化やキャッシュで少しだけ短縮(20分) • サーバ間連携のテストが出来ない • ロードバランサの振り分けテスト 17

Slide 18

Slide 18 text

CIでは実施しないことに • 冪等性のテスト • 何度も流して破綻しないか • Tasksを目視で確認、開発環境でテスト • 実機テスト • LXCやDockerの制約でテストできない箇所 • masterマージ後に開発環境へ流してテスト • 失敗したら開発環境ごと作りなおす • 連携テスト • HAProxyの振り分けルールが正しいか • 開発環境で手動確認 • テスト用アプリサーバを建てて自動化予定 (https://github.com/bungoume/debug-server) 18

Slide 19

Slide 19 text

運用期間(2015/8~) • Ansibleの使い方を常駐SEやアプリベンダーに伝える • 常駐SEはAnsibleを使ってデプロイ出来るようになった • 基盤チームでPlaybook作成・レビューできる人が増えた • アプリベンダーへの普及はこれから • Jenkinsで自動デプロイ • 開発には自動でmasterブランチを流すように • 本番デプロイは確認しながら • Productionブランチを用意してデプロイ前に差分確認 • --diff --checkをつけてデプロイ時にも差分確認 19

Slide 20

Slide 20 text

運用してみて • 「やらないこと」の範囲であれば破綻していない • CIが動いているので設定ファイルのミスがわかる • ApacheやVarnishの設定ミスも検出できる • Pull-requestフローの体制 • 破綻する変更がないか確認できる • 複雑度が増す前にプラグイン作成で対応 20

Slide 21

Slide 21 text

よかったこと • 全台への設定変更が楽 • カーネルパラメータの変更をあとから変えたくなった等 • コスト削減につながった • インスタンスに状態を持たなくなったので AMIバックアップの必要性がなくなった • 開発環境の追加が簡単 • 「dev3,dev4が欲しいんだけど…」にもすぐ対応できた 21

Slide 22

Slide 22 text

共同開発で困ったこと・事故 • 冪等性のないコード • 初期構築のみAnsibleを利用し、何度も流さない認識だった • Task化されていない変更 • 従来の作業にそって実サーバにログインして設定される • とはいえ、ログインを禁止すると作業スピードが落ちる • 設定ファイルだけ違うコピペroles • Windowsのtemplateモジュールがなかった • みんなGitに慣れてない • サーバの秘密鍵をコミット • push -fで1週間戻った… • この半年でかなり使えるようになった 22

Slide 23

Slide 23 text

解決方法 • 変更はすべてAnsibleコードでという認識合わせ • 最初に • なるべくカバー出来るようにCIを用意する • 初期作成時にCI用意が間に合わなかった • Vagrantを利用する • GithubのProtected branchesを使う • 今月からGithubに実装された機能 • 構築が落ち着いてからリファクタリング • コードが複雑化しそうなものはfilter_pluginを書く 23

Slide 24

Slide 24 text

Windowsつらい • templateモジュールが使えない • 1.7から待ち焦がれていたのに • copyすら使えなかった(1.9.2) • S3にあげてダウンロードする仕組みを作成 • 完成した頃にwin_templateモジュール入った(1.9.2) • useraddにも冪等性がなかった • Playbook流すとパスワードが初期化される(1.9まで) • Playbook流すとパスワードが平文表示される • no_log: Trueを付けると動作しないバグあり(2.0で解決予定?) • 最近やっと対応されてきた 24

Slide 25

Slide 25 text

よかったこと • @r_rudiさんがサポートしてくれた • ちょっとした困りごとが大きくなる前に解決できた • 記述が複雑化しそうなときに相談 • プラグイン作成について相談 • バグか仕様か相談 • 変数に日本語つかえる?など • バグにはAnsibleへプルリクもしてもらえた 25

Slide 26

Slide 26 text

その他やっていること 26

Slide 27

Slide 27 text

サーバの自動起動・停止 • AnsibleとJenkinsで実行 • 開発環境の夜間停止 • 負荷予測に応じた起動・停止 • EC2モジュールを利用 27

Slide 28

Slide 28 text

HAProxy(LB)の振り先を自動生成 • Pluginでhostsから振り先を自動生成 28 [webserver] 10.0.4.1 name=webserver01a zone=a 10.0.5.1 name=webserver01c zone=c webservers: - {ip: 10.0.4.1, name: webserver01a, zone: a} - {ip: 10.0.5.1, name: webserver01c, zone: c} webservers: "{{ hostvars | get_group(‘webserver') }}" backend webserver {% for host in webservers -%} server {{host.name}} {{host.ip}}:80 check{% if host.zone != zone %} backup{% endif %} {% endfor %} hosts vars 展開後 変数 backend webserver server webserver01a 10.0.4.1:80 check server webserver01c 10.0.5.1:80 check backup HAProxy- template 展開後

Slide 29

Slide 29 text

• 前述のget_groupはこのようなプラグイン 簡単なプラグインを用意 29

Slide 30

Slide 30 text

監視の方法 • Zabbix-agentをAnsibleでインストール • Ansibleでの自動登録はしなかった • Zabbixの通知をSlackに飛ばして確認 • FluentdでログをSentryに飛ばして確認 • アクセスログをElasticsearchで可視化 30

Slide 31

Slide 31 text

最後に • 日経電子版ではエンジニア採用中です • 見学はウェルカムなので連絡ください! • [email protected] 31