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

61
Ansible 2.0 を使って組む kubernetes クラスタ vol.1 Ansible Meetup in Tokyo 2015.09 廣川英寿 @realglobe Inc.

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

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

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

Ansible Meetup in Tokyo 2015.09 廣川英寿@realglobe Inc.

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

自己紹介

• 廣川英寿

• Github: h-hirokawa

• 技師@realglobe Inc. (2011.9~)

• メイン言語はPython、とりわけDjango

• ansibleは2012末から利用中

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

ansibleとコンテナ周り 結構やってますよアピール

• NiftyCloud C4SA (2012) • ウェブアプリ開発+運用環境構築PaaS • LXCコンテナベース

• C4SA エクスポート機能 (2013) • コンテナ上に展開されたアプリケーション環境をIaaSに移行 • 移行機能はpure-ansible

• Deplow (2015) • AaaS (Ansible as a Service) • Dockerコンテナで切り分けられたAnsible環境と管理UIを提供

• 毎月の無料Ansible勉強会主催やCI導入支援、プレイブック代書もやってます

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

Kubernetesって何者?

Kubernetesの説明を駆け足で

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

Kubernetes(略称: k8s)とは• Google主導で開発された、コンテナ用クラスタ管理ツール

• コンテナ群を用いた大きな実環境の運用を実現

• やってくれること

• コンテナを組み合わせてのアプリケーション環境構築

• Pod: 1アプリケーションを構成するコンテナの組

• Rep. Controllers: Podを冗長構成で稼働。死活監視付きで自動増減する。

• Service: 冗長化されたPodに接続を振り分けてくれるLB的なもの

• ノードのクラスタ管理

• ノード間コンテナ通信

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

やりたい事• Ansible v2でk8sクラスタを自動構築する

• CoreOSで作る

• 複数IaaS対応(今回はgce & idcf)

• 1クラスタを複数基盤にのせる • 非推奨パターンなので今回はやめました • クラスタ間の接続をPrivate IPからGlobalに変えれば可能

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

CoreOSとは?• コンテナ稼働専用の軽量ディストリビューション

• etcd, fleet等、k8sのクラスタリング基板が組み込み済 • いずれもCoreOS社がオープンソースで開発 • rktなどのDockerに代わるコンテナ基盤も作っている

• コンテナ専用だから、/usr 以下はReadOnly

• コンテナ専用だから、パッケージマネージャも無い

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

極め付けに

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

Pythonが入っていない!

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

Pythonないのに何故Ansible?• Ansibleには rawがある

• SSHログイン・シェル上で直接コマンドを実行

• scriptモジュールでも同様に生スクリプトを実行できる

• モジュールがどんな言語でも書ける

• SSHで繋がる以外に事前準備は「一切」不要

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

Pythonがホストになくたって自動化できる そう、Ansibleならね

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

とは言ったものの…• 全部rawでやるのはキツい

• 返り値を直接読んで処理しなければならない

• rc, stdout, stderror

• 冪等性を守るも守らないも自分次第

• register, whenの嵐で見通しも悪い

• v2のblockディレクティブである程度は緩和出来る

• いっそscriptで全部やっちゃう?

• あれ、何でAnsible使ってるんだっけ

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

そんなあなたにPyPy

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

PyPyとは

• RPythonで書かれたPythonの実装系(かっこいい)

• JITコンパイルされるのでCPythonより高速(かっこいい)

• 任意のパスで実行可能なバイナリが配布されている(かっこいい)

* RPython: バイナリコンパイル可能な制約付きPython

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

CoreOSにPyPyを入れるメリット• いつも通りにAnsibleが使えるようになる

• pipや他のpythonパッケージも問題なく使用可能

• どのAnsibleモジュールでも問題なく動くかは未確認

• とは言え、CPythonとの違いはGCの方式などのプリミティブな所なので、ほとんどの場合問題ないはず

• /opt等に置いてそのままCoreOSホスト上で動かせる

• バイナリパッケージを配置するだけなので、デプロイが短時間で済む

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

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” 警告が出てしまうのは諦める

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

Let’s playbook!

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

Playbook

今回作ったサンプルをgithubで公開してます

https://github.com/h-hirokawa/ansible-kubernetes-coreos

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

方針

1. IaaS上にCoreOSノードを作成

2. CoreOSにPyPyをインストール

3. CoreOSにkubernetesをインストール

• master: kubernetesのAPIを立てる(今回は1台)

• minion: 各コンテナを稼働させるノード(複数台)

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

tipsやハマりどころを解説

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

1. IaaS上にCoreOSノードを作成

~Ansibleからの効率的なIaaS操作~

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

• これはCoreOSに限った話ではないですが、御存知の通りAnsibleからはデプロイ対象ホストの操作に留まらず、IaaSの操作も簡単に行えます。

• 組み込みクラウド・モジュール例

AWS, Azure, Cloudstack,

Google, Openstack, Vmware…

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

ただし、注意が必要なポイントも

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

• IaaS操作は、localhostからクラウドのAPIを操作する事になります

ということは、

並列化が効かない!

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

• 何も気にせずに複数台にまたがるIaaS操作を実行すると、1台1台のVMインスタンス作成リクエストからVM作成(起動)完了までが同期で進んでしまうため、APIを叩いて待つだけの操作に大幅な時間がかかってしまいます。

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

• 実はほとんどのクラウド操作モジュールには、操作完了までの待機をせず、APIリクエストを送った時点で次のタスクに進んでくれるオプションがあります。

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

各モジュールとパラメータの対応

• ec2

• wait: no

• azure

• wait: no

• cs_instance

• poll_async: no

• gce

• なし…

• os_server

• wait: no

• vca_vapp

• wait: no

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

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 ]

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

gceの場合

• 待機制御用のパラメ−タが無いけれど、どうするの?

• 自分でカスタム・モジュール作れば良いじゃん

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

そうだ、asyncがあった!

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

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 # 試行間隔

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

asyncを使うと

• 時間がかかる処理を非同期で実行可能

• 各非同期タスク毎に個別プロセスが立つ

• poll を 0 に設定すると、タスクを実行した後、即時タスクを次に進められる

• 非同期実行しているタスクの結果は async_status 経由で取得が可能。

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

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

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

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

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

これを実行すると!

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

動かない…

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 %})"}

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

• 下記のようなstderrがjobの実行結果ファイルに含まれているのが原因

• 出力をJSONとしてパース出来ないためエラー

• ansibleのバグか?

• stdout、stderrを別ファイルに吐くようにするのが望ましいと思われる

• モジュールがstderrを吐いていること自体微妙なので、今回はログハンドラーを追加したgce-modをplaybook中に含める対応をとった

No handlers could be found for logger "libcloud.common.google"

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

1. まとめ

IaaSのインスタンス操作には

非同期処理を上手く使おう!

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

2. CoreOSのセットアップ①

~Ansible v2での非Pythonモジュール~

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

Ansibleモジュールの自由度• Ansibleの大きな特徴の一つが、どんな言語でも

1. shebang(#!/bin/bashなど)でインタプリタ指定可能、もしくは実行可能なバイナリに事前コンパイル可能

2. JSONで入出力可能 • 入力: モジュールに与えられた引数 • 出力: Ansibleが解釈する実行結果

上記条件を満たせば、ansibleモジュールに出来る所です

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

raw_stat モジュール• 今回はPyPyインストールの手順中で複数回実行される、「あるパスが存在するかどうか」を判定するモジュールをShellScriptで書いてみました

• statモジュールの入出力を意識して、raw_statとしていますが、今回実装しているのは最低限必要な存在チェックのみ

• 因みに、ShellScriptでのJSON操作には jq コマンドが便利 • 最近のCoreOS(717.0.0以降)ではjqが組み込まれてます

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

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"

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

raw_stat解説• 実はAnsible v2では、現在の公式ドキュメントで解説されている、モジュールへの引数を「hoge=fuga foo=bar」の様なスペース区切りファイル経由で渡す方法は使われなくなっています

• 代わりに、モジュールファイル内のリプレイサー文字列を経由して引数を埋め込む形式を使わなければなりません • リプレイサー文字列は、template モジュールでの変数と同じ様なものだと考えてください

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

リプレイサー文字列• <<ANSIBLE_VERSION>>

• 使っているAnsibleのバージョンで置換される

• v1でも使えるので、v2との互換モジュールで必要

• <<INCLUDE_ANSIBLE_MODULE_WINDOWS_ARGS>> • モジュール引数がJSONとして置換される

• 引用符などもエスケープされていないので、heredoc経由で読む様にするなどの工夫が必要

• 最新develブランチでは <<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>> も使える(プルリク出したら通りました)

• 他にもあるが、とりあえず非Pythonモジュールで使うのは上記2つ位

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

v1では WANT_JSON を使おう• これもドキュメントでは触れられていないが、v1では、モジュール内に WANT_JSON と言うコメントを入れると、引数ファイルの形式がスペース区切りからJSONに代わる

• この形式を使うと、v1とv2での引数処理がJSONの処理として同様に書ける。

• そもそも、元のスペース区切り形式だと複雑な文字列処理がとても厄介(場合によっては対応不能)なので、積極的に WANT_JSON を使って行くのが良いと思います

hoge=fuga foo=bar #これが {"hoge": "fuga", "foo": "bar"} #こうなる

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

2. まとめ• Ansibleでのモジュール実装は言語を問わない

• v2で非Pythonモジュールに引数を埋め込むには <<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>> を使う

• v1-v2互換モジュールを作るには <<ANSIBLE_VERSION>> で場合分け

• v1でも WANT_JSON を積極的に使っていこう

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

3. CoreOSのセットアップ②

~Cloud-Config with Ansible~

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

Cloud-Configとは• IaaS上のインスタンスの各種設定変更やサービス起動などを起動時に自動で実行するための仕組み

• 設定ファイルはyamlで書く(やったね)

• CoreOSでは専用の coreos-cloudinit コマンドが使われる

#cloud-config coreos: units: - name: "etcd2.service" command: "start" - name: "fleet.service" command: "start"

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

k8s用のCloud-Config

• k8sの公式リポジトリ内で、master用のmaster.yaml、minion用のnode.yamlが提供されており、ほぼそのまま使える

• サンプルプレイブックでは、node.yaml中で使うmasterのIPアドレスなどを変数化したテンプレートにしました

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

Cloud-Configの問題点

• 設定が正常に完了したかを確認するのに別の機構が必要

• ベンダー毎に設定の渡し方が違う

• ec2: UserDataにyamlを入れる

• gce: Metadata中のuser-dataキーにyamlを入れる

• idcf: UserDataにyamlを入れられるが2KB制限あり

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

2KBじゃ足りない…

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

全部Ansibleでやっちゃおう

• 折角Ansibleを使っているんだから、Cloud-ConfigでやっていることもAnsibleで置き換えれば、どんな環境でもセットアップ可能になるはず!

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

やってみた結果

• 1つのyamlが10以上の設定ファイルテンプレートに増殖

• Cloud-Config上の設定項目と実設定ファイルの対応は、coreos-cloudinitのソースを見ないとわからない

• かなりの苦行な上、プレイブックの見通しも悪くなってしまった

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

既存の資産はうまく使うべき

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

結論: いいとこ取り• 最終的に、ブート完了後にAnsibleでログインしてCloud-

Config用のyamlをCoreOS内に設置し、Ansibleからcoreos-cloudinitを実行する様にした

• Ansibleがyamlを配置するので、ベンダーの実装を気にする必要なし

• coreos-cloudinit実行後のサービス正常起動確認まで、まとめて実施可能

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

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

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

3. まとめ

• AnsibleからCloud-Configを扱うことで、IaaSベンダーの制約を気にしないで良くなった

• Ansibleなら動作確認までをワンストップで実施できる

• 「Ansibleだけで」にこだわる必要は無い。どんなツールや手法とも上手く連携出来るのがAnsible

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

今後やりたいこと• minionノードのオートスケールをAnsibleから組む

• オートスケール操作はgce系モジュールでは未提供

• k8sの操作自体をAnsibleから実施できるようにする • kubectlかkubernetes-apiを操作するモジュールが必要

• k8s内のコンテナ内をAnsibleから操作可能にする • v2で登場したdocker connection plugin を kubectl

execコマンドとつなげることができるか

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

vol. 2に続く?

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

ご静聴ありがとうございました

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

Ansible本 年内発表予定