この記事は 富士通クラウドテクノロジーズ Advent Calendar 2017 の15日目の記事です。
昨日は mini_act4 さんの 認定スクラムプロダクトオーナー研修を受けて気づいた大切なこと でした。
mini_act4 さんがオーナーをするプロダクトやチームに期待が高まります!
TL;DR
- ニフクラでも Kubernetes を使うことができます。(あたりまえ
- ansible-role-nifcloud と kubespray-cli を組み合わせて、クラスタのデプロイも簡単にできます。
はじめに
Serverlessconf Tokyo や Kubernetes Meetpup Tokyo #8 に参加して、物理サーバーやVMといったインフラを抽象化し、設定ファイルやプログラムといったコードによってシステムを管理・運用するのすげー!と感じて Kubernetes について色々調べる中で、何はともあれクラスタ作らないとな、と言うことで仕事で触る機会の多いニフクラで簡単に構築できるように試してみました。
Kubernetes についての概要は MahoTakara さんの 今さら人に聞けない Kubernetes とは? が分かりやすかったかなと思いました。
Kubernetes クラスタのデプロイについては albatross さんの kubespray (kargo-cli) で20分で Kubernetes クラスタを作る を参考にさせていただきました。ありがとうございます。
kubespray を使うとサーバーさえ用意すればサクッとクラスタを構築できちゃうので、すごい世の中です。
やること
- サーバーを準備する
- ansible-role-nifcloud を使ってサーバーを構築します。
- クラスタをデプロイする
- kubespray-cli を使ってクラスタをデプロイします。
- 私はとりあえず試してみたいというモチベーションなので、運用性とかセキュリティーは一旦無視しちゃいます。
なので諸々のクラスタ設定はデフォルト.....
構築するクラスタの情報
※ 引用:https://github.com/kubespray/kubespray-cli
- node:3台
ansible-role-nifcloud でサーバー作成
-
ansible-playbook のディレクトリ構成は下記のような感じです。
tree├── group_vars │ └── all.yml ├── roles │ └── nifcloud_vm │ ├── tasks │ │ └── main.yml │ └── templates │ └── startup.sh └── site.yml
ansible-playbook のファイルたち
-
site.yml
ansible-playbook コマンドで直接実行するymlファイルです。
nifcloud.nifcloud という名前の ansible-role-nifcloud を読みこんだり、
自作の nifcloud_vm ロールを読みこんで実行したりします。
ちなみに、nifcloud.nifcloud をモジュールとして使うために、site.yml で読み込ませないと動かないのですが、
その情報に辿りつけずに数日ハマりました...site.yml- name: provision vms hosts: all connection: local # nifcloud.nifcloud はAPIを使うだけなので connection は local です roles: - nifcloud.nifcloud # デプロイ用ロールの前に、nifcloud.nifcloud を読ませるのが必要です。 - nifcloud_vm # 後述
-
group_vars/all.yml
全ホスト共通の設定です。all.ymlcomputing: region: <YOUR_CLUSTER_REGION> # クラスタをデプロイするリージョン:jp-east-1 とか availability_zone: <YOUR_CLUSTER_ZONE> # クラスタをデプロイするゾーン:jp-east-14 とか instance_type: <INSTANCE_TYPE_NAME> # サーバータイプ:kubespray-cli は 2GB以上のメモリが必須なので small2 とか image_id: <YOUR_IMAGE_IE> # イメージID:コントロールパネルのOSイメージメニューを確認 CentOS 7.1 なら 68 key_name: <YOUR_SSH_KEY_NAME> # 登録したSSHキーの名前 security_group: <YOUR_SECURITY_GROUP_NAME> # 適用するファイアウォールの名前 root_password: <YOUR_ROOT_PASSWORD> # インスタンスに設定するルートパスワード credentials: access_key: <YOUR_ACCESS_KEY> # アクセスキー secret_key: <YOUR_SECRET_ACCESS_LEY> # シークレットキー private_network: id: <YOUR_PLAN_ID> # クラスタをデプロイするネットワークのID:net-XXXXXXXXX みたいなやつ address: <YOUR_PLAN_ADDRESS> # プライベートLANのネットワークアドレス:10.0.0.0/24 とか gateway: <YOUR_PLAN_GATEWAY> # ゲートウェイ: 10.0.0.1 とか
-
roles/nifcloud_vm
サーバーをプロビジョニングするansibleロールです。-
roles/nifcloud_vm/tasks/main.yml
GitHubのサンプルを参考に作成しました。main.yml- name: Install (Requests) python package local_action: module: pip name: requests - name: Start server local_action: module: nifcloud access_key: "{{ credentials.access_key }}" secret_access_key: "{{ credentials.secret_key }}" endpoint: "computing.{{ computing.region }}.api.cloud.nifty.com" instance_id: "{{ inventory_hostname }}" state: "running" image_id: "{{ computing.image_id }}" key_name: "{{ computing.key_name }}" instance_type: "{{ computing.instance_type }}" availability_zone: "{{ computing.availability_zone }}" security_group: "{{ computing.security_group}}" accounting_type: "2" ip_type: "none" startup_script: "roles/nifcloud_vm/templates/startup.sh" startup_script_vars: # 後述のサーバー起動時スクリプトに渡す値 root_password: "{{ computing.root_password }}" ip_addr: "{{ ansible_ssh_host }}/24" network_addr: "{{ private_network.address }}" gateway: "{{ private_network.gateway }}" network_interface: - network_id: "{{ private_network.id }}" ipAddress: "static"
-
roles/nifcloud_vm/templates/startup.sh
- ニフクラの サーバー起動時スクリプト の機能を使って諸々設定します
- インスタンスIDをホスト名に設定
- root のパスワードを設定(やらなくても良い)
- プライベートLANのインターフェースに任意のアドレスを設定
- ysaotome さんの Gist を参考に作成しました
starup.sh#!/bin/sh ( #=============================================== # Settings #=============================================== ##rootのパスワード ROOT_PASSWORD='{root_password}' #=============================================== ARC=$(/bin/uname -m) SALT=$(/usr/bin/uuidgen| /usr/bin/tr -d '-') ## hostname変更 HOSTNAME=$(/usr/bin/vmtoolsd --cmd 'info-get guestinfo.hostname') /bin/hostname ${{HOSTNAME}} /bin/sed -i.org -e 's/localhost.localdomain/'${{HOSTNAME}}'/' /etc/hostname ## ROOTパスワード設定 /usr/sbin/usermod -p $(/usr/bin/perl -e 'print crypt(${{ARGV[0]}}, ${{ARGV[1]}})' ${{ROOT_PASSWORD}} ${{SALT}}) root ## swap領域 無効化 /usr/sbin/swapoff `awk '{{print $1}}' /proc/swaps | grep -v 'Filename'` /usr/bin/sed -i -e "/swap/s/^/#/g" /etc/fstab ## network 設定 IPADDR={ip_addr} # yaml から渡された値 CONNECTION="System ens160" # 注意!:共通グローバルが有効な場合はプライベートLANのコネクションは ens192 になります。 DISABLE_CONNECTION="System ens192" NETWORK_ADDR={network_addr} # yaml から渡された値 GATEWAY={gateway} # yaml から渡された値 /usr/bin/nmcli connection modify "${{DISABLE_CONNECTION}}" connection.autoconnect no /usr/bin/nmcli connection modify "${{CONNECTION}}" ipv4.addresses ${{IPADDR}} /usr/bin/nmcli connection modify "${{CONNECTION}}" ipv4.gateway ${{GATEWAY}} /usr/bin/nmcli connection modify "${{CONNECTION}}" ipv4.dns ${{GATEWAY}} /usr/bin/nmcli connection modify "${{CONNECTION}}" ipv4.method manual /usr/bin/nmcli connection down "${{CONNECTION}}" /usr/bin/nmcli connection up "${{CONNECTION}}" /bin/systemctl restart NetworkManager.service /bin/systemctl restart network.service ) 2>&1 | /usr/bin/tee /var/log/niftycloud-init.log
- ニフクラの サーバー起動時スクリプト の機能を使って諸々設定します
-
-
インベントリファイルは?
- kubespray-cli prepare コマンドを使うと、
.kubespray/inventory/inventory.cfg
にansible のインベントリファイルが作成されるため、コレを使います。-
例えばこうすると、
$ kubespray prepare --nodes \ node1[ansible_ssh_host=10.0.0.101] \ node2[ansible_ssh_host=10.0.0.102] \ node3[ansible_ssh_host=10.0.0.103]
こうなります。
.kubespray/inventory/inventory.cfg[kube-master] node1 node2 [all] node1 ansible_ssh_host=10.0.0.101 node2 ansible_ssh_host=10.0.0.102 node3 ansible_ssh_host=10.0.0.103 [k8s-cluster:children] kube-node kube-master [kube-node] node1 node2 node3 [etcd] node1 node2 node3
-
- kubespray-cli prepare コマンドを使うと、
サーバー作成
インベントリファイルに↑のやつを指定すれば良いので、例えば↓のように実行します。
$ ansible-playbook -i .kubespray/inventory/inventory.cfg site.yml
-
実行結果サンプル
bash-4.2# time ansible-playbook -i .kubespray/inventory/inventory.cfg site.yml --diff PLAY [provision vms] *********************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************* ok: [node3] ok: [node1] ok: [node2] TASK [nifcloud.nifcloud : Gathering facts from localhost] ********************************************************************** ok: [node1 -> localhost] TASK [nifcloud.nifcloud : Import EPEL GPG Key (for CentOS)] ******************************************************************** ok: [node1 -> localhost] TASK [nifcloud.nifcloud : Check EPEL repository (for CentOS)] ****************************************************************** ok: [node1 -> localhost] TASK [nifcloud.nifcloud : Add EPEL repository (for CentOS)] ******************************************************************** skipping: [node1] TASK [nifcloud.nifcloud : Install python-pip (for CentOS)] ********************************************************************* ok: [node1 -> localhost] TASK [nifcloud.nifcloud : Install python-pip (for Ubuntu)] ********************************************************************* skipping: [node1] TASK [nifcloud.nifcloud : Install "Requests" python package] ******************************************************************* ok: [node1 -> localhost] TASK [nifcloud_vm : Install (Requests) python package] ************************************************************************* ok: [node1 -> localhost] ok: [node2 -> localhost] ok: [node3 -> localhost] TASK [nifcloud_vm : Start server] ********************************************************************************************** changed: [node2 -> localhost] changed: [node1 -> localhost] changed: [node3 -> localhost] PLAY RECAP ********************************************************************************************************************* node1 : ok=8 changed=1 unreachable=0 failed=0 node2 : ok=3 changed=1 unreachable=0 failed=0 node3 : ok=3 changed=1 unreachable=0 failed=0 real 2m22.832s user 0m21.668s sys 0m6.400s bash-4.2#
kubespray-cli で Kubernetes のデプロイ
サーバーができたら kubespray-cli を実行するだけです。
サーバーにSSH接続ができるホストで下記を実行します。( time
で時間をはかってみています。)
-u
オプションでユーザー、 -k
オプションでSSHキーを指定しています。
-n
オプションではネットワークプラグインを指定できますが、今回は flannel を使ってみました。他にも weave,calico,canal,contiv,cloud が指定できるみたいです。何も指定しないと calico になるそうです。
bash-4.2# time kubespray deploy -u root -k .ssh/kubernetes_rsa -n flannel
Identity added: /root/.ssh/kubernetes_rsa (/root/.ssh/kubernetes_rsa)
CHECKING SSH CONNECTIONS *******************************************************************************************************
/usr/bin/ansible --ssh-extra-args -o StrictHostKeyChecking=no -u root -b --become-user=root -m ping all -i /root/.kubespray/inventory/inventory.cfg
node2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
node3 | SUCCESS => {
"changed": false,
"ping": "pong"
}
node1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
All hosts are reachable
/usr/bin/ansible-playbook --ssh-extra-args -o StrictHostKeyChecking=no -u root -b --become-user=root -i /root/.kubespray/inventory/inventory.cfg /root/.kubespray/cluster.yml -e kube_network_plugin=flannel
Run kubernetes cluster deployment with the above command ? [Y/n]
...途中割愛...
PLAY RECAP *********************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
node1 : ok=359 changed=111 unreachable=0 failed=0
node2 : ok=316 changed=105 unreachable=0 failed=0
node3 : ok=277 changed=85 unreachable=0 failed=0
Kubernetes deployed successfuly
real 11m15.910s
user 6m40.516s
sys 2m1.336s
bash-4.2#
という感じでクラスタのデプロイが完了します。
動作確認
kubectl を使ってクラスタの状態を確認しますが、
その前に Kubernetes のAPIを利用するための鍵と設定を取得(デプロイしたノードから拝借)します。
bash-4.2# scp -r -i .ssh/kubernetes_rsa root@10.0.0.101:~/.kube .
クラスタの状態を確認すると...
bash-4.2# kubectl cluster-info
Kubernetes master is running at https://10.0.0.101:6443
KubeDNS is running at https://10.0.0.101:6443/api/v1/namespaces/kube-system/services/kube-dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
bash-4.2#
どうやら動いているみたいなので、nginx のポッドをデプロイしてみます。
bash-4.2# kubectl run nginx --image=nginx:latest
deployment "nginx" created
bash-4.2# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-5db977d67c-zctf9 1/1 Running 0 43s 10.233.66.4 node3
bash-4.2#
node3 にデプロイされました。
ポッドにIPが振ってありますが、クラスタ内に閉じたIPなので、ノードのポートにエクスポーズして外からアクセスしてみます。
bash-4.2# kubectl expose deployment nginx --port 80 --type=NodePort
service "nginx" exposed
bash-4.2# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 19m <none>
nginx NodePort 10.233.21.221 <none> 80:32251/TCP 3s run=nginx
bash-4.2#
32551 ポートにマッピングされたのでブラウザでアクセスしてみます。
どのノードにアクセスしても同じ画面が得られるので、ちゃんと node3 にルーティングされているようです。
まとめ
ニフクラでも Kubernetes クラスタを作ることが出来ました。
ansible-role-nifcloud と kubespray を使うことで、かなり簡単にクラスタをデプロイすることが出来ます。
簡単な構成で実験しているので、本番運用に向けた凝った構成にするにはもう少し工夫が必要そうです。
GitHubに上記の諸々を公開 しています。実行環境のコンテナを作る諸々も一緒に置いてありますのでご参考いただければ幸いです。
Kubernetes の勉強は始まったばかりなので、クラスタを壊したり直したりしながら理解を深めて行きたいと思います。
明日は clutter さんです!お楽しみに!
参考サイト
- https://qiita.com/albatross/items/7f472a973d0c04041a4d
- https://github.com/kubespray/kubespray-cli
- https://github.com/nifcloud/ansible-role-nifcloud/blob/master/library/documents/nifcloud.md
- https://gist.github.com/ysaotome/378205689c7b6ef0a6bf
- https://kubernetes-v1-4.github.io/docs/user-guide/kubectl/kubectl_expose/
- https://qiita.com/MahoTakara/items/85096f8b2632c802ab22