狠狠撸

狠狠撸Share a Scribd company logo
Ansible 2.0を使って組む
kubernetesクラスタ vol.1
Ansible Meetup in Tokyo 2015.09
廣川英寿@realglobe Inc.
自己紹介
? 廣川英寿
? Github: h-hirokawa
? 技師@realglobe Inc. (2011.9~)
? メイン言語はPython、とりわけDjango
? ansibleは2012末から利用中
ansibleとコンテナ周り
結構やってますよアピール
? NiftyCloud C4SA (2012)
? ウェブアプリ開発+運用環境構築PaaS
? LXCコンテナベース
? C4SA エクスポート機能 (2013)
? コンテナ上に展開されたアプリケーション環境をIaaSに移行
? 移行機能はpure-ansible
? Deplow (2015)
? AaaS (Ansible as a Service)
? Dockerコンテナで切り分けられたAnsible環境と管理UIを提供
? 毎月の無料Ansible勉強会主催やCI導入支援、プレイブック代
書もやってます
Kubernetesって
何者?
Kubernetesの説明を駆け足で
Kubernetes(略称: k8s)とは
? Google主導で開発された、コンテナ用クラスタ管理ツール
? コンテナ群を用いた大きな実環境の運用を実現
? やってくれること
? コンテナを組み合わせてのアプリケーション環境構築
? Pod: 1アプリケーションを構成するコンテナの組
? Rep. Controllers: Podを冗長構成で稼働。死活監視付きで自動増減する。
? Service: 冗長化されたPodに接続を振り分けてくれるLB的なもの
? ノードのクラスタ管理
? ノード間コンテナ通信
やりたい事
? Ansible v2でk8sクラスタを自動構築する
? CoreOSで作る
? 複数IaaS対応(今回はgce & idcf)
? 1クラスタを複数基盤にのせる
? 非推奨パターンなので今回はやめました
? クラスタ間の接続をPrivate IPからGlobalに変えれば可能
CoreOSとは?
? コンテナ稼働専用の軽量ディストリビューション
? etcd, ?eet等、k8sのクラスタリング基板が組み込み済
? いずれもCoreOS社がオープンソースで開発
? rktなどのDockerに代わるコンテナ基盤も作っている
? コンテナ専用だから、/usr 以下はReadOnly
? コンテナ専用だから、パッケージマネージャも無い
极め付けに
笔测迟丑辞苍が入っていない!
Pythonないのに何故Ansible?
? Ansibleには rawがある
? SSHログイン?シェル上で直接コマンドを実行
? scriptモジュールでも同様に生スクリプトを実行でき
る
? モジュールがどんな言語でも書ける
? SSHで繋がる以外に事前準備は「一切」不要
Pythonがホストになくたって自動化できる
そう、Ansibleならね
とは言ったものの…
? 全部rawでやるのはキツい
? 返り値を直接読んで処理しなければならない
? rc, stdout, stderror
? 冪等性を守るも守らないも自分次第
? register, whenの嵐で見通しも悪い
? v2のblockディレクティブである程度は緩和出来る
? いっそscriptで全部やっちゃう?
? あれ、何でAnsible使ってるんだっけ
そんなあなたに笔测笔测
PyPyとは
? RPythonで書かれたPythonの実装系(かっこいい)
? JITコンパイルされるのでCPythonより高速(かっこい
い)
? 任意のパスで実行可能なバイナリが配布されている(かっ
こいい)
* RPython: バイナリコンパイル可能な制約付きPython
CoreOSにPyPyを入れるメリット
? いつも通りにAnsibleが使えるようになる
? pipや他のpythonパッケージも問題なく使用可能
? どのAnsibleモジュールでも問題なく動くかは未確認
? とは言え、CPythonとの違いはGCの方式などのプリミティブな所
なので、ほとんどの場合問題ないはず
? /opt等に置いてそのままCoreOSホスト上で動かせる
? バイナリパッケージを配置するだけなので、デプロイが短時間で済む
CoreOS上でPyPyを動かす注意点
? ansible_python_interpreterでpypyへのパスを指定する必要あり
? pypy/lib/libtinfo.so.5 => /lib64/libncurses.so.5.9 のsymlinkが必要
? PyPy 2.4.0を使う
? CPython 2.7.8互換
? 最新のPyPy 2.6.1だと現段階では動いてくれない
? “no version information available” 警告が出てしまうのは諦める
Let’s playbook!
Playbook
今回作ったサンプルをgithubで公開してます
https://github.com/h-hirokawa/ansible-kubernetes-coreos
方針
1. IaaS上にCoreOSノードを作成
2. CoreOSにPyPyをインストール
3. CoreOSにkubernetesをインストール
? master: kubernetesのAPIを立てる(今回は1台)
? minion: 各コンテナを稼働させるノード(複数台)
迟颈辫蝉やハマりどころを解説
1. IaaS上にCoreOSノードを作成
~Ansibleからの効率的なIaaS操作~
? これはCoreOSに限った話ではないですが、御存知の通
りAnsibleからはデプロイ対象ホストの操作に留まらず、
IaaSの操作も簡単に行えます。
? 組み込みクラウド?モジュール例
AWS, Azure, Cloudstack,
Google, Openstack, Vmware…
ただし、注意が必要なポイントも
? IaaS操作は、localhostからクラウドのAPIを操作する事
になります
ということは、
並列化が効かない!
? 何も気にせずに複数台にまたがるIaaS操作を実行する
と、1台1台のVMインスタンス作成リクエストからVM作
成(起動)完了までが同期で進んでしまうため、APIを
叩いて待つだけの操作に大幅な時間がかかってしまいま
す。
? 実はほとんどのクラウド操作モジュールには、操作完了
までの待機をせず、APIリクエストを送った時点で次の
タスクに進んでくれるオプションがあります。
各モジュールとパラメータの対応
? ec2
? wait: no
? azure
? wait: no
? cs_instance
? poll_async: no
? gce
? なし…
? os_server
? wait: no
? vca_vapp
? wait: no
CloudStackの場合
- name: まとめてインスタンス作成リクエスト
cs_instance:
name: "{{ item }}"
hypervisor: VMware
template: MyOwnImage
service_offering: xLarge
ssh_key: ssh-key
poll_async: no # ここが肝
with_items: [ vm1, vm2, vm3 ]
## 必要ならここで待っている間の処理
- name: インスタンス作成完了するまで待つ
cs_instance:
name: "{{ item }}"
with_items: [ vm1, vm2, vm3 ]
gceの場合
? 待機制御用のパラメ?タが無いけれど、どうするの?
? 自分でカスタム?モジュール作れば良いじゃん
そうだ、补蝉测苍肠があった!
asyncを使った非同期タスク
- name: 非同期処理開始
command: sleep 60
async: 100 # 最大待機時間。pollが0の場合は正の数であればなんでも良い
poll: 0 # ポーリング間隔。タスクを非同期に先に進める場合は0
register: async_job
## 間の処理
- name: 非同期処理終了待機
async_status:
jid: "{{ async_job.ansible_job_id }}"
register: job_result
until: job_result.finished # ジョブ終了までループ
retries: 30 # 最大試行回数
delay: 10 # 試行間隔
asyncを使うと
? 時間がかかる処理を非同期で実行可能
? 各非同期タスク毎に個別プロセスが立つ
? poll を 0 に設定すると、タスクを実行した後、即時タス
クを次に進められる
? 非同期実行しているタスクの結果は async_status 経由
で取得が可能。
v2ではループも使える
- name: 複数ジョブを同時実行
command: sleep 60
async: 100
poll: 0
with_sequence: count=5
register: async_jobs
- name: ループで全ジョブの終了を待機
async_status:
jid: "{{ item.ansible_job_id }}"
register: jobs_result
with_items: "{{ async_jobs.results }}"
until: jobs_result.finished
retries: 5
delay: 30
asyncでgceインスタンス作成
- name: 非同期インスタンス作成
gce:
instance_names: vm-name
machine_type: g1.small
image: coreos
async: 1000
poll: 0
register: create_instances_job
with_items: [ vm1, vm2, vm3 ]
- name: インススタンス作成終了待機
async_status:
jid: "{{ item.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 30
with_items: create_instances_job.results
これを実行すると!
動かない…
TASK [非同期インスタンス作成] 
ok: [localhost] => (item=vm1)
ok: [localhost] => (item=vm2)
ok: [localhost] => (item=vm3)
TASK [インススタンス作成終了待機] *
fatal: [localhost]: FAILED! => {"failed": true, "msg":
"ERROR! The conditional check 'job_result.finished'
failed. The error was: ERROR! error while evaluating
conditional: job_result.finished ({% if
job_result.finished %} True {% else %} False {% endif
%})"}
? 下記のようなstderrがjobの実行結果ファイルに含まれているのが
原因
? 出力をJSONとしてパース出来ないためエラー
? ansibleのバグか?
? stdout、stderrを別ファイルに吐くようにするのが望ましいと
思われる
? モジュールがstderrを吐いていること自体微妙なので、今回はロ
グハンドラーを追加したgce-modをplaybook中に含める対応を
とった
No handlers could be found for logger
"libcloud.common.google"
1. まとめ
IaaSのインスタンス操作には
非同期処理を上手く使おう!
2. CoreOSのセットアップ①
~Ansible v2での非Pythonモジュール~
Ansibleモジュールの自由度
? Ansibleの大きな特徴の一つが、どんな言語でも
1. shebang(#!/bin/bashなど)でインタプリタ指
定可能、もしくは実行可能なバイナリに事前コンパ
イル可能
2. JSONで入出力可能
? 入力: モジュールに与えられた引数
? 出力: Ansibleが解釈する実行結果
上記条件を満たせば、ansibleモジュールに出来る所です
raw_stat モジュール
? 今回はPyPyインストールの手順中で複数回実行される、
「あるパスが存在するかどうか」を判定するモジュールを
ShellScriptで書いてみました
? statモジュールの入出力を意識して、raw_statとしています
が、今回実装しているのは最低限必要な存在チェックのみ
? 因みに、ShellScriptでのJSON操作には jq コマンドが便利
? 最近のCoreOS(717.0.0以降)ではjqが組み込まれてます
raw_stat
#!/bin/bash
# WANT_JSON
ANSIBLE_VERSION="<<ANSIBLE_VERSION>>"
# jqがなかったらエラー
if ! type jq >/dev/null 2>&1; then
echo "{"failed": true, "msg": "jq not found."}"
exit 1
fi
# v1の場合は$1に引数ファイルのパスが入る
if [[ $ANSIBLE_VERSION == 1.* ]]; then
MODULE_COMPLEX_ARGS=$(cat $1)
# v2の場合はINCLUDE_ANSIBLE_MODULE_WINDOWS_ARGSを使う
else
MODULE_COMPLEX_ARGS=$(cat << 'EOF'
<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>
EOF
)
fi
path=$(echo $MODULE_COMPLEX_ARGS | jq -r '.path')
if [ -e $path ]; then
exists="true"
else
exists="false"
fi
echo $MODULE_COMPLEX_ARGS | jq -r ".changed=false | .stat.exists=$exists"
raw_stat解説
? 実はAnsible v2では、現在の公式ドキュメントで解説され
ている、モジュールへの引数を「hoge=fuga foo=bar」の
様なスペース区切りファイル経由で渡す方法は使われなく
なっています
? 代わりに、モジュールファイル内のリプレイサー文字列を
経由して引数を埋め込む形式を使わなければなりません
? リプレイサー文字列は、template モジュールでの変数
と同じ様なものだと考えてください
リプレイサー文字列
? <<ANSIBLE_VERSION>>
? 使っているAnsibleのバージョンで置換される
? v1でも使えるので、v2との互換モジュールで必要
? <<INCLUDE_ANSIBLE_MODULE_WINDOWS_ARGS>>
? モジュール引数がJSONとして置換される
? 引用符などもエスケープされていないので、heredoc経由で読む様
にするなどの工夫が必要
? 最新develブランチでは
<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>> も使える(プル
リク出したら通りました)
? 他にもあるが、とりあえず非Pythonモジュールで使うのは上記2つ位
v1では WANT_JSON を使おう
? これもドキュメントでは触れられていないが、v1では、モジュール内
に WANT_JSON と言うコメントを入れると、引数ファイルの形式がス
ペース区切りからJSONに代わる
? この形式を使うと、v1とv2での引数処理がJSONの処理として同様に
書ける。
? そもそも、元のスペース区切り形式だと複雑な文字列処理がとても厄
介(場合によっては対応不能)なので、積極的に WANT_JSON を使っ
て行くのが良いと思います
hoge=fuga foo=bar #これが
{"hoge": "fuga", "foo": "bar"} #こうなる
2. まとめ
? Ansibleでのモジュール実装は言語を問わない
? v2で非Pythonモジュールに引数を埋め込むには
<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>> を使う
? v1-v2互換モジュールを作るには
<<ANSIBLE_VERSION>> で場合分け
? v1でも WANT_JSON を積極的に使っていこう
3. CoreOSのセットアップ②
~Cloud-Con?g with Ansible~
Cloud-Con?gとは
? IaaS上のインスタンスの各種設定変更やサービス起動な
どを起動時に自動で実行するための仕組み
? 設定ファイルはyamlで書く(やったね)
? CoreOSでは専用の coreos-cloudinit コマンドが使われる
#cloud-config
coreos:
units:
- name: "etcd2.service"
command: "start"
- name: "fleet.service"
command: "start"
k8s用のCloud-Con?g
? k8sの公式リポジトリ内で、master用のmaster.yaml、
minion用のnode.yamlが提供されており、ほぼそのまま
使える
? サンプルプレイブックでは、node.yaml中で使うmaster
のIPアドレスなどを変数化したテンプレートにしました
Cloud-Con?gの問題点
? 設定が正常に完了したかを確認するのに別の機構が必要
? ベンダー毎に設定の渡し方が違う
? ec2: UserDataにyamlを入れる
? gce: Metadata中のuser-dataキーにyamlを入れる
? idcf: UserDataにyamlを入れられるが2KB制限あり
2碍叠じゃ足りない…
全部Ansibleでやっちゃおう
? 折角Ansibleを使っているんだから、Cloud-Con?gで
やっていることもAnsibleで置き換えれば、どんな環境で
もセットアップ可能になるはず!
やってみた結果
? 1つのyamlが10以上の設定ファイルテンプレートに増殖
? Cloud-Con?g上の設定項目と実設定ファイルの対応は、
coreos-cloudinitのソースを見ないとわからない
? かなりの苦行な上、プレイブックの見通しも悪くなって
しまった
既存の资产はうまく使うべき
結論: いいとこ取り
? 最終的に、ブート完了後にAnsibleでログインしてCloud-
Con?g用のyamlをCoreOS内に設置し、Ansibleから
coreos-cloudinitを実行する様にした
? Ansibleがyamlを配置するので、ベンダーの実装を気に
する必要なし
? coreos-cloudinit実行後のサービス正常起動確認まで、
まとめて実施可能
master用playbook
---
- name: Set cloud-config.yml.
template:
src: master.yml
dest: /opt/cloud-config.yml
register: set_cloud_config
- name: Run cloudinit.
command: /usr/bin/coreos-cloudinit -from-file=/opt/cloud-config.yml
when: set_cloud_config|changed
- name: Start required services.
service:
name: "{{ item.name }}"
state: started
with_items:
- name: generate-serviceaccount-key.service
- name: setup-network-environment.service
- name: fleet.service
- name: flanneld.service
- name: docker.service
- name: kube-apiserver.service
- name: kube-controller-manager.service
- name: kube-scheduler.service
3. まとめ
? AnsibleからCloud-Con?gを扱うことで、IaaSベンダー
の制約を気にしないで良くなった
? Ansibleなら動作確認までをワンストップで実施できる
? 「Ansibleだけで」にこだわる必要は無い。どんなツール
や手法とも上手く連携出来るのがAnsible
今後やりたいこと
? minionノードのオートスケールをAnsibleから組む
? オートスケール操作はgce系モジュールでは未提供
? k8sの操作自体をAnsibleから実施できるようにする
? kubectlかkubernetes-apiを操作するモジュールが必要
? k8s内のコンテナ内をAnsibleから操作可能にする
? v2で登場したdocker connection plugin を kubectl
execコマンドとつなげることができるか
vol. 2に続く?
ご静聴ありがとうございました
Ansible本 年内発表予定

More Related Content

Ansible 2.0を使って組む kubernetesクラスタ vol.1