repl.info

kubesprayを使ってOpenStack上にKubernetesを構築する

kubernetes-incubator/kubesprayは複数の環境(AWS、GCE、Azure、OpenStack、Baremetal)に対応したKubernetesクラスタのデプロイツールです。kubespray自体はAnsibleやTerraform用のコードで構成されています。今回はkubersprayを使い、OpenStack上にKubernetes環境を構築します。

Terraformでクラスタ用のインスタンスを作成する

まずはクラスタ用のインスタンスを作成します。kubesprayにはTerraformでインスタンスを建てるためのconfigurationファイルが付属しているので、これを使ってみます。なお、Configurationはv1.0以降ではRemovedな機能を使っているので、v0.9.11を使います。

添付されているConfigurationはかなりよくできていて、tfvarsで設定を変えるだけでいろいろな構成のクラスタを構築できます。今回はk8s-masterを3台、k8s-nodeを2台(内1台はFloatingIPを持たない)という構成にするので、terraform.tfvarsは以下のようになりました。

number_of_etcd = "0"

number_of_k8s_masters = "3"

number_of_k8s_masters_no_etcd = "0"

number_of_k8s_masters_no_floating_ip = "0"

number_of_k8s_masters_no_floating_ip_no_etcd = "0"

number_of_k8s_nodes_no_floating_ip = "1"

number_of_k8s_nodes = "2"



network_name = "int-net-name"

floatingip_pool = "ext-net-name"

az = "nova"

image = "ubuntu-16.04-server-cloudimg-amd64"

cluster_name = "alpaca"

terraform apply 前の注意点として、作成されるセキュリティグループに 0.0.0.0/0 からのアクセスを許可するルールが2つあるのでここを修正しておくのがよいかもしれません。リソースを作成し終わると以下のようにインスタンスが作られています。

$ openstack server list --name alpaca-k8s --column Name

+----------------------+

| Name |

+----------------------+

| alpaca-k8s-node-nf-1 |

| alpaca-k8s-master-1 |

| alpaca-k8s-master-2 |

| alpaca-k8s-node-2 |

| alpaca-k8s-node-1 |

| alpaca-k8s-master-3 |

+----------------------+

Ansibleを適用し、Kubernetesクラスタを作る

各インスタンスにSSHでアクセスできるかチェックする

インスタンスを作成できたので次はAnsibleを適用します。まず、各インスタンスにSSHでアクセスできるのかどうかを確認します。以下のコマンドで疎通確認が可能です。ansible_python_interpreter を指定しているのは、各インスタンスのOSであるubuntu-16.04には /usr/bin/python がなく、/usr/bin/python3 であるためです。

$ ansible -i contrib/terraform/openstack/hosts -m ping all --private-key=~/.ssh/id_rsa -e 'ansible_python_interpreter=/usr/bin/python3'

alpaca-k8s-master-1 | SUCCESS => {

    "changed": false,

    "failed": false,

    "ping": "pong"

}

alpaca-k8s-node-1 | SUCCESS => {

    "changed": false,

    "failed": false,

    "ping": "pong"

}

alpaca-k8s-master-2 | SUCCESS => {

    "changed": false,

    "failed": false,

    "ping": "pong"

}

alpaca-k8s-master-3 | SUCCESS => {

    "changed": false,

    "failed": false,

    "ping": "pong"

}

alpaca-k8s-node-2 | SUCCESS => {

    "changed": false,

    "failed": false,

    "ping": "pong"

}

alpaca-k8s-node-nf-1 | SUCCESS => {

    "changed": false,

    "failed": false,

    "ping": "pong"

}

ここで、アクセス先のIPアドレスを全く指定していないことに気づくかもしれません。AnsibleにはDynamic Inventoryという機能があり、ファイルやAPIから自動的に適用先の情報を取得することができます。ここでは、Terraformのtfstateファイルから適用先を取得しているというわけです。また、FloatingIPがついていないalpaca-k8s-node-nf-1 へSSHするため、terraform apply 時点で踏み台の設定も生成しています。contrib/terraform/openstack/group_vars/no-floating.yml というファイルがそれで、no-floating グループであればこの設定を用い、踏み台経由でSSHするというわけです。非常によくできているなーと思います。

Ansibleを適用する

各インスタンスにSSHでアクセスできることを確認したので、Ansibleを適用します。

$ ansible-playbook --become -i contrib/terraform/openstack/hosts cluster.yml --private-key=~/.ssh/id_rsa -e '{"ansible_python_interpreter": "/usr/bin/python3", "kubeconfig_localhost": true, "loadbalancer_apiserver": {"address": "XXX.XX.XXX.XXX", "port": 6443}, "apiserver_loadbalancer_domain_name": "kubernetes.default"}'

extra-varsをpretty printしたものは以下の通りです。

{

  "ansible_python_interpreter": "/usr/bin/python3",

  "kubeconfig_localhost": true,

  "loadbalancer_apiserver": {

    "address": "XXX.XX.XXX.XXX",

    "port": 6443

  },

  "apiserver_loadbalancer_domain_name": "kubernetes.default"

}

実行したら30分〜40分ほどかかるので、コーヒーを飲んだりして待ちます。

PLAY RECAP ************************************************************************************************************************************************

alpaca-k8s-master-1 : ok=256 changed=14 unreachable=0 failed=0

alpaca-k8s-master-2 : ok=257 changed=15 unreachable=0 failed=0

alpaca-k8s-master-3 : ok=265 changed=10 unreachable=0 failed=0

alpaca-k8s-node-1 : ok=232 changed=14 unreachable=0 failed=0

alpaca-k8s-node-2 : ok=206 changed=9 unreachable=0 failed=0

alpaca-k8s-node-nf-1 : ok=206 changed=9 unreachable=0 failed=0

localhost : ok=2 changed=0 unreachable=0 failed=0

終わったら artifacts/admin.conf にkubectl用のコンフィグが生成されているので、~/.kube/config へ配置します。

$ cp artifacts/admin.conf ~/.kube/config

また、admin.conf内のアクセス先がhttps://kubernetes.default:6443となっているはずです。 /etc/hosts に設定して、アクセスできるようにします。

XXX.XX.XXX.XXX kubernetes.default

さて、いよいよノード一覧を見てみましょう。6台のノードが全てReadyになっているはずです。

PMC02V437VHV2R% kubectl get nodes

NAME STATUS ROLES AGE VERSION

alpaca-k8s-master-1 Ready master,node 27m v1.8.1+coreos.0

alpaca-k8s-master-2 Ready master,node 27m v1.8.1+coreos.0

alpaca-k8s-master-3 Ready master,node 27m v1.8.1+coreos.0

alpaca-k8s-node-1 Ready node 18m v1.8.1+coreos.0

alpaca-k8s-node-2 Ready node 18m v1.8.1+coreos.0

alpaca-k8s-node-nf-1 Ready node 18m v1.8.1+coreos.0

サービスを動かしてみる

Kubernetes環境ができたので、試しにサービスを動かしてみます。今回はmicroservices-demo/microservices-demo にします。まず、ネームスペースを作成します。

$ kubectl create namespace sock-shop

その後は各種サービスを一気に作成します。

$ kubectl create -f ~/src/github.com/microservices-demo/microservices-demo/deploy/kubernetes/complete-demo.yaml

deployment "carts-db" created

service "carts-db" created

deployment "carts" created

service "carts" created

deployment "catalogue-db" created

service "catalogue-db" created

deployment "catalogue" created

service "catalogue" created

deployment "front-end" created

service "front-end" created

deployment "orders-db" created

service "orders-db" created

deployment "orders" created

service "orders" created

deployment "payment" created

service "payment" created

deployment "queue-master" created

service "queue-master" created

deployment "rabbitmq" created

service "rabbitmq" created

deployment "shipping" created

service "shipping" created

deployment "user-db" created

service "user-db" created

deployment "user" created

service "user" created

ポッド一覧。

$ kubectl --namespace sock-shop get pods

NAME READY STATUS RESTARTS AGE

carts-794f6cc876-96gn2 1/1 Running 0 1m

carts-db-787f4b7896-kdlpw 1/1 Running 0 1m

catalogue-845484987d-s68f6 1/1 Running 0 1m

catalogue-db-67dffd76dc-r26kq 1/1 Running 0 1m

front-end-6786c5b4b9-69fhm 1/1 Running 0 1m

orders-5568884f5-kzvt6 1/1 Running 0 1m

orders-db-66f56c7d6d-t8zfm 1/1 Running 0 1m

payment-9f56ff4d-hm7rm 1/1 Running 0 1m

queue-master-75987c9876-br6bv 1/1 Running 0 1m

rabbitmq-55998c84cd-s96pl 1/1 Running 0 1m

shipping-6b7599657-swqkl 1/1 Running 0 1m

user-7dd55b89b6-s66kk 1/1 Running 0 1m

user-db-57689444f9-rzcq5 1/1 Running 0 1m

サービス一覧。

$ kubectl --namespace sock-shop get service

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

carts ClusterIP 10.233.56.72 <none> 80/TCP 1m

carts-db ClusterIP 10.233.29.40 <none> 27017/TCP 1m

catalogue ClusterIP 10.233.22.32 <none> 80/TCP 1m

catalogue-db ClusterIP 10.233.22.88 <none> 3306/TCP 1m

front-end NodePort 10.233.23.23 <none> 80:30001/TCP 1m

orders ClusterIP 10.233.62.13 <none> 80/TCP 1m

orders-db ClusterIP 10.233.31.36 <none> 27017/TCP 1m

payment ClusterIP 10.233.13.237 <none> 80/TCP 1m

queue-master ClusterIP 10.233.4.189 <none> 80/TCP 1m

rabbitmq ClusterIP 10.233.36.199 <none> 5672/TCP 1m

shipping ClusterIP 10.233.28.86 <none> 80/TCP 1m

user ClusterIP 10.233.44.29 <none> 80/TCP 1m

user-db ClusterIP 10.233.63.41 <none> 27017/TCP 1m

front-endサービスからアクセスするのだけど、これはデフォルトではNodePortとなっています。ノードにアタッチされているFIPの30001番ポートにアクセスするとsock-shopを利用できるはずです。

$ kubectl --namespace sock-shop describe pod front-end-6786c5b4b9-f6kf4 | grep "Node: "

Node: alpaca-k8s-master-2/XX.XX.XXX.XXX

front-endポッドはalpaca-k8s-master-2 にいるので、そのFIPにアクセスして、HTMLが帰ってくればOKです。

$ curl http://XXX.XX.XXX.XXX:30001

まとめ

複数の環境に対応したKubernetesクラスタのデプロイツールであるkubersprayを用いて、OpenStack上にKubernetesクラスタを構築しました。また、その上でmicroservices-demo/microservices-demo を動かし、NodePort経由でアクセスできることを確認しました。

Kubernetes v1.9では、OpenStackのOctaviaがサポートされたようです。LBaaSとしてOctaviaを使っている場合、これを使うことで外部ネットワークとうまくやりとりできるのではないか、と期待します。