サイオステクノロジー武井です。今回はkubernetesによるコンテナクラスタ管理について書いてみようと思います。最後にKubernetesとは?Kubernetes(クーべネティスと呼ぶようで、略称はk8sと書いたりします)とは、Dockerを始めとするコンテナを管理するオープンソース・ソフトウェアです。具体的に以下のことができます。Update(無停止更新)ができるSelf-Healingする。障害が発生してコンテナが稼働できなくなると、なんとか既定の台数を維持しようとして、Kubernetesが頑張る。アプリケーションを運用するための嬉しい機能がたくさんです。本ブログでは、実際の開発におけるユースケース(開発、リリース、障害発生等)を想定し、そのユースケースごとにKubernetesがどのように役に立つかを書いてみたいと思います。Kubernetesの構成Kubernetesの構成をざっくり解説します。KubernetesはMasterとNodeの複数台の構成になります。Nodeは実際にコンテナが動作するマシンで、そのNodeたちの状態をMasterが管理しています。Serverという複数のプロセスが連携して動作する複雑な構成となっています。以下にそれらの構成要素について一つずつ解説します。IPなど)を管理します。Serverを介して、お互いの情報をやり取りします。etcdkubernetesの情報を保存する高信頼分散KVSです。Serverは、etcdに情報を保存します。他にもflannel(Pod間の通信を実現するVXLAN管理サービス)も利用します。kubeletPodの生成や停止を行います。Serverに問い合わせて、生成や停止の数やタイミングを決めています。Serverを通じて、kubeletに伝える役割を持っています。この情報を参考にして、kubeletはコンテナを生成します。後述しますが、ReplicaSetで複数台スケールするクラスタを作成したときは、このSchedulerが開いているNodeにコンテナを作成するようkubeletに指示します。コンテナは複数のNodeに配置されます。IPの管理を行います。IPとは、サービスにアクセスするための代表的なIPアドレスになります。BalancerなどのVIPに近いイメージです。このIPアドレスにアクセスすると、そのリクエストは複数のPodに分散されます。Server経由でKubernetesのリソース情報にアクセスし、必要に応じてiptableseのルールを作成し、iptablesの機能によって負荷分散を行います。コマンド群kubectlなどのコマンド群です。ユーザーのインターフェースになります。このコマンドを使って、クラスタを作成したり削除したりとか、Kubernetesにおける全ての管理をします。Serverにリクエストを投げているます。PodKubernetesのデプロイの単位になります。Podは複数のコンテナをまとめる論理的な単位です。実際の開発フローと照らし合わせてみるさて、ここからは、実際のアプリケーション開発フローの中で、Kubernetesがどのように使われるのか、実際にKubernetesの構築や管理をしながら、説明していきたいと思います。設計フェーズは終了していると仮定します。その場合、開発フローは以下のようになるかと思います。開発環境構築これから複数のプログラマにガリガリコーディングを行ってもらうために、彼ら専用の開発環境を用意します。Javaの開発で言えば、Eclipseで開発環境構築したり、Gitリポジトリ作成したりです。一般的には、インフラとアプリケーションの両方に精通するエンジニア(以降、アプリケーションアーキテクトと呼称)が担当することが多いです。Registry(後述)にPushするといった作業になります。開発・テストプログラマが、事前に用意された開発環境を使ってガリガリコーディングとテストを繰り返す作業です。したアプリケーションを動作させるための本番環境を構築します。今回の要であるKubernetesの構築になります。RegistryからPullしたイメージをデプロイするだけで、簡単に本番環境が出来上がります。ここでポイントなのは、開発環境と本番環境で同じDockerイメージを利用していることです。Dockerを使う以前のレガシーな開発でよくあった「開発環境では動いたのだけど、本番環境では動かないよー」という問題は解決します。このフェーズを担当するのは「開発環境構築」を担当したアーキテクトになることが多いと思います。機能追加ユーザーからの無茶な要望があり、機能追加をするフェーズになります。RegistryにPush、Kubernetesにデプロイします。Updateつまりアプリケーションを無停止で更新が可能ということです。ユーザー影響なく、アプリケーションをリリースできるというのは運用上非常に大きなメリットがあります。リソース増強アプリケーションの利用者が増え、レスポンスが遅くなったことへの対応策として、リソースを増強するケースを想定しています。KubernetesはReplicaSetと概念があり、設定ファイルでReplicaSetを増やすだけで、簡単にスケールアウトが可能です。指定したReplicaSetの数を維持するよう、Podが各ノードに立ち上がります。上記のフローをイメージとしたのは以下の図になります。今回開発するアプリケーション先程説明した開発フローの中で開発するアプリケーションは以下の様なものになります。$_SERVER['SERVER_ADDR'];?>[/code]PHPで記述した簡単なアプリケーションで、このアプリケーションが動作しているサーバーのIPアドレスを表示するものです。IPを使った負荷分散の設定を行いますが、これであれば、きちんと負荷分散されていることを確認できます。本ブログを記載するために、今回Azure上に以下の環境を構築します。MasterKubernetesのMasterです。Nodeを管理します。node01及びnode02Kubernetesのnodeです。Registryになります。Kubernetesは、Registry上のDockerイメージをPullして、デプロイを行い、Node上にコンテナを配置します。何らかのRegistryが必要なのです。Hubがありますが、作成したDockerイメージをPublicなところに上げるのが抵抗あることが多いと思いますので、今回はPrivateなRegistryを立てます。開発環境構築それではいよいよ開発フローに基づき、Kubernetesを利用していきます。Registryを構築します。docker-distributionをインストールします。Registryが稼働するIPアドレスとポート番号を定義します。10.4.4.8:5000docker-distributionを起動し、さらにOS起動時に自動起動しておくようにします。Registryの構築は完了です。次に、開発環境用のDockerイメージを作成します。Dockerの稼働している環境で以下のDockerfileを作成します。HubからPullします。実際はもっと色々なものをインストールしたりして、複雑な開発環境になると思いますが、ここでは説明を簡略化するために、上記のように単純にしております。RegistryにPushします。RegistryのIPアドレス:ポート番号/イメージ名:タグ名でなくてはなりません。これで開発環境の構築は完了です。開発・テスト次にプログラマが開発・テストを行うケースを想定します。Registryから開発環境用のDockerイメージをPullします。Composeがインストールされていることが条件になります。開発PCの任意のディレクトリでdocker-compose.ymlという名前のファイル名を作成し、以下のような内容を記述します。Registryに上げた開発用のDockerイメージをPullしています。(2)では、ホストの80番ポートからコンテナの80番ポートにポートフォワードしております。内部のWebサーバーにアクセスするためです。(3)は、ホストのsrcディレクトリをコンテナ内の/var/www/htmlにマウントしています。することで、ホストのsrcディレクトリにPHPのファイルを置けば、すぐに実行可能になります。ADDやCOPYでは、ソースを変更するためにビルドのし直しが発生するのでかなり不便になります。次に、srcディレクトリ配下にtest.phpという名前で以下の内容のファイルを作成します。$_SERVER['SERVER_ADDR'];?>[/code]test.phpにcurlコマンドでアクセスして、以下のようになることを確認します。address[コンテナのIPアドレス]このソースをソースコード管理リポジトリにPushします。実際の案件では、開発したソースは何らかのソースコード管理リポジトリ(Gitやsvn)にて管理することが通常ですが、本記事では、そのあたりの説明は割愛させて頂きます。本番環境構築Kubernetesの本番環境を構築します。はじめにMasterでの作業です。Kubertenes、etcd、flannelをインストールします。flannel/etc/hostsにMaster、Node01、Node02のホスト名を定義します。node02/etc/etcd/etcd.confを以下のように修正し、etcdがどのクライアントからでも接続を受け付けるようにします。ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"123ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"↓ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"etcdを起動し、OS再起動後も自動起動するようにします。etcd次に、flannelの設定を行います。flannelは詳細な説明はここでは割愛させて頂きます(後日、別記事でご紹介します)。Pod間の通信をVXLANという方式で実現するためのソフトフェアです。ここでは、Pod全体のネットワークを172.30.0.0/16、Pod内部のネットワークのIPアドレスのレンジを24ビットで構築するということを前提とします。/etc/sysconfig/flanneld内に定義されているFLANNEL_ETCD_PREFIXの値を確認します。FLANNEL_ETCD_PREFIX="/atomic.io/network"1FLANNEL_ETCD_PREFIX="/atomic.io/network"上記の値を覚えておいた上で、etcdに以下の設定を登録します。}'flannelを起動し、OS再起動後も自動起動するようにします。flanneldこれでflannelの設定は完了です。Serverと各種コンポーネントが通信するために必要な鍵を作成します。2048/etc/kubernetes/apiserverを修正して、以下のように変更します。Serverの稼働するサーバーのIPアドレスを指定し、合わせて先程作成した鍵のパスも指定します。/etc/kubernetes/controller-managerを以下のように修正します。KUBE_CONTROLLER_MANAGER_ARGS="--service_account_private_key_file=”/etc/kubernetes/serviceaccount.key"123KUBE_CONTROLLER_MANAGER_ARGS="--service_account_private_key_file=”"↓KUBE_CONTROLLER_MANAGER_ARGS="--service_account_private_key_file=”/etc/kubernetes/serviceaccount.key"先程作成した鍵のパスを指定します。/etc/kubernetes/configを以下のように修正します。KUBE_MASTER="--master=http://master:8080"123KUBE_MASTER="--master=http://127.0.0.1:8080"↓KUBE_MASTER="--master=http://master:8080"各種コンポーネントの起動、OS再起動後の自動起動設定を行います。kube-proxyKubernetesのコマンドラインツールkubectlの設定を行います。defaultこれでMasterの設定は完了です。次に、Node01、Node02の設定を行います。2つのNodeで同じ設定を行います。/etc/hostsにMaster、Node01、Node02のホスト名を定義します。node02/etc/sysconfig/dockerに以下の設定を追加します。Registryにアクセスするための設定になります。Docker、Kurbernetes、flannelをインストールします。flannel/etc/sysconfig/flanneldを以下のように修正します。FLANNEL_ETCD_ENDPOINTS="http://master:2379"123FLANNEL_ETCD_ENDPOINTS="http://127.0.0.1:2379"↓FLANNEL_ETCD_ENDPOINTS="http://master:2379"これは、flannelが参照するetcdのアクセス情報を設定しています。flannelは自身の設定情報をetcdに保存する仕様なのです。flannel、dockerを起動し、OS再起動後の自動起動設定をします。↓KUBE_MASTER=”–master=http://master:8080′′/etc/kubernetes/kubeletを以下のように修正します。Serverへの接続先を定義しています。kube-proxy、kubletを起動し、OS再起動後の自動起動設定をします。kubelet以上で、Node01、Node02の設定が完了し、本番環境構築が終わりました。リリース先程作成したアプリケーションを本番環境にリリースします。本番稼働用のイメージを作成します。Dockerの稼働している環境の任意のディレクトリで、以下のDockerfileを作成します。/var/www/htmlこれは、先程作成した開発用のDockerイメージをPullして、test.phpのソースをコンテナにコピーしているという内容になります。Registryにアップロードします。10.4.4.8:5000/web:1.01.0というタグを付けました。リリースをするたびに、このバージョン番号を増やしていきます。次に、Masterにて、先程作成したイメージをKubernetesにデプロイする作業を行います。Masterの任意の場所で、deploy.ymlというファイル名の以下の内容のファイルを作成します。(7)Kubernetesの設定ファイルは一般的にYAMLで記載することが多いです。今回もそのようにしています。Kubernetesの設定は、このような設定ファイルを作成し、kubectlでこのファイルを引数に指定するという作業になります。(1)は、設定ファイルの種別を表します。この設定ファイルはでデプロイするための設定なので、Deploymetを記述します。(2)は、このデプロイの設定を一意に識別するためのキーになります。(3)は、Podを起動する数です。この値に基づき、Podが各Nodeに作成されます。リリース所期時のPod数は、まず1とします。利用者のアクセスが増え次第、この値を変更していきます。(4)は、このデプロイを適用するコンテナのラベルになります。(5)でコンテナのラベルを定義していますが、ここで定義したラベルのコンテナがデプロイ対象ということになります。(5)は、Pod内に作成するコンテナのコンテナ名です。(6)は、Pod内に作成するコンテナのイメージです。先程作成したアプリケーションのイメージのバージョン1.0を指定していることがわかります。(7)は、Pod内で開放するポート番号です。HTTP経由でアクセスさせるので、80を指定しています。kubectlコマンドで、いよいよKubernetesにデプロイします。deploy.ymlこれで終わりです。確認するためには以下のようにします。13h2つのPodが作成されていることが確認できます。Statusが2つとも「Running」となっていればOKです。これだけでは、サービスにアクセスできません。このサービスにアクセスするためには、Nodeのインターフェース(IPアドレスで言えば、10.4.4.5、10.4.4.7)を通じて、アクセスできるようにする必要があり、このための仕組みがKubernetesには用意されています。Serviceという仕組みです。Serviceのイメージ図は以下のとおりです。Serviceを作成すると、上記のように仮想的なIPアドレス(10.254.108.241)、port、nodePort、targetPortが作成されます。外部からアクセスする場合は、まず、eth0のtargetPort(3000)にアクセスし、Serviceインターフェースのport(80)を通じて、PodのインターフェースのtargetPort(80)にアクセスします。このあたりの処理は、iptablesのNATによって実現されておりますが、複雑な処理ですので、ここでは詳細を割愛させて頂きます。このServiceを作成するためには、service.ymlというファイル名(ファイル名は任意)で、以下のようなファイルを作成します。(7)(1)は、種別を指定しています。ここではServiceを定義しますので、Serviceとします。(2)は、このServiceを一意に識別するための名称です。任意の名前でOKです。(3)は、ラベルを指定しています。ここで指定したラベルがService経由でアクセスする対象のPodになります。web」というラベルを指定したので、その値をここで指定します。(4)は、Serviceのタイプを定義します。Nodeのインターフェース経由でもアクセスさせたい場合は、「NodePort」と指定します。(5)、(6)、(7)はそれぞれ、先のServiceのイメージ図で示したport、targetPort、nodePortになります。確認方法は以下になります。23m先程指定したweb-npの値が上記のように表示されていればOKです。Masterからアクセス確認してみましょう。address172.30.98.2上記のように表示されていてばOKです。したアプリケーションに対して、何らかの機能追加要望があったとします。test.phpを以下のように修正します。$_SERVER['SERVER_ADDR'];?>[/code]冒頭にv2.0と表示するようにしました。こちらをソースコード管理システムにPushします。実際の案件では、開発したソースは何らかのソースコード管理リポジトリ(Gitやsvn)にて管理することが通常ですが、本記事では、そのあたりの説明は割愛させて頂きます。再リリース先程機能追加したアプリケーションを再リリースします。Registryにアップロードします。「リリース」の章でリリースした方法と基本的には変わりません。test.phpのファイルを新しいのに入れ替えて、以下のコマンドを実行します。10.4.4.8:5000/web:2.0tagに記載のバージョンを2.0に変更しています。ReigstryにPushされます。次に、Masterにて、最初のリリース時に利用したdeploy.ymlを以下のように修正します。RegistryにPushしたもの)に変更をしています。この設定を以下のコマンドでKubernentesに適用します。deploy.yaml動作確認を実施します。address172.30.98.2v2.0が冒頭に表示されるようになりました。上記のように表示されていればOKです。Update(無停止更新)が行われています。サービスの停止なく、リリースができるのは、嬉しい限りですね。幸いなことに、サービスの利用者が増え、レスポンスが遅くなってきたので、リソースを増強することにしました。今まで1台のPodで動かしていましたが、2台のPodで動かすようにしましょう。リリース時に利用したdeploy.ymlを以下のように修正します。80変更点はreplicasです。1から2に変更しました。これで2台のPodで稼働するようになります。いつものように適用してみましょう。deploy.yaml本当にPodが2台で稼働しているかどうか確認してみます。16m上記のように表示されていればOKです。実際にサービスにアクセスしてみましょう。address172.30.2.2もう一度アクセスしてみます。address172.30.98.2一度目とはIPアドレスが異なってますね。適切にロードバランスされていることがわかりました(^o^)この時のイメージは以下の通りになります。labelにapp:webが付与されているPodがServiceの配下にぶら下がりロードバランスされます。node01もしくはnode02どちらのインターフェースにアクセスしても2台のPodに負荷分散されます。最後にいかがでしたしょうか?実際の開発フローに合わせて、Kubernetesの利用ケースを書いてみました。皆さんのお役に立てれば幸いです。雑誌等の執筆依頼を受付しております。役に立たなかった3人がこの投稿は役に立ったと言っています。コメントをキャンセルメールアドレスは表示されません。Reserved.本サイトに掲載されている社名、製品名、サービス名等は各社の商標または登録商標です。プライバシーポリシーお問い合わせ。