オープンソースで学ぶ最新クラウド技術


はじめに

皆さん、こんにちは。レッドハットの中井です。Red Hat Enterprise Linux (RHEL)やその関連製品を利用する方々に向けて、レッドハットの最新技術情報をお届けするコラムの第2回です。前回は「RHEL7.1でKubernetesを実体験(概要編)」ということで、RHEL7.1で利用可能になった「Kubernetes(クーバーネティス)」について、サーバー構成やネットワーク構成の概要をお伝えしました。

今回は「構築編」として、実際にKubernetesが動作する環境を構築してみます。

・実際のところ、Kubernetesで何ができるのか?

・Kubernetesは、内部的にどのようにコンテナーを管理しているのか?

これらを理解することが目標ですので、まずは、管理機能を提供するマスターサーバー1台と、Dockerのコンテナーが起動するMinion(ミニオン)が2台の最小構成で構築していきます。Linux KVMの仮想マシン3台で構築することもできますので、気軽に試してみるとよいでしょう。

構築環境の全体像

はじめに、これから構築する環境の全体像を説明しておきます。下図のように、3台のサーバーを単一のサービスネットワークに接続して利用します。コンテナーと通信するための内部ネットワークは、後ほど、Flannelを用いてオーバーレイネットワークとして構成します。また、バックエンドデータベースの「etcd」とDockerイメージを保存するレジストリーサーバーの機能については、マスターサーバーに同居させています。簡単のため、レジストリーに登録するイメージの作成もマスターサーバー上で行ってしまいます。

なお、構築中は、インターネット上のRed Hat network (RHN) やRed Hatの公式イメージを提供するレジストリーにアクセスするため、それぞれのサーバーは、インターネットにも接続できる必要があります。

サーバー構成

サーバー構成

RHEL7.1の導入と準備作業

それでは、まずは各サーバーにRHEL7.1を導入していきましょう。それぞれのホストネームとIPアドレスは、次表のとおりとします。インストーラーで指定するソフトウェア環境は、最小構成で構いません。本節の作業は、すべてのサーバーで共通に実施してください。

ホストネームとIPアドレス
役割 ホストネーム IPアドレス
マスター kubemaster01 192.168.122.100
Minion#1 minion01 192.168.122.101
Minion#2 minion02 192.168.122.102

RHEL7.1のインストールが完了したら、 RHNに登録して、Kubernetesの利用に必要なリポジトリーを有効化した上で、最新のパッケージにアップデートしておきます。

# subscription-manager register                ← RHNのID,パスワードを入力
# subscription-manager list --available        ← 利用可能なサブスクリプションを確認
# subscription-manager attach --pool=<プールID> ← RHEL7が利用可能なプールIDを指定
# subscription-manager repos --disable=*
# subscription-manager repos --enable=rhel-7-server-rpms \
  --enable=rhel-7-server-extras-rpms \
  --enable=rhel-7-server-optional-rpms \
  --enable=rhel-atomic-host-rpms
# yum -y update

また、名前解決用に各サーバー共通で、「/etc/hosts」に下記のエントリーを追加します。

/etc/hosts

192.168.122.100 kubemaster01
192.168.122.101 minion01
192.168.122.102 minion02

最後に、ファイアウォール機能を提供する「firewalldサービス」を停止して、一度、サーバーを再起動しておきます。(もちろんこれは、この後の構築手順を簡単にするためのもので、セキュリティの観点で推奨されるものではありません。)

# systemctl stop firewalld.service
# systemctl mask firewalld.service
# reboot

マスターサーバーの構成

続いて、マスターサーバーを構成します。本節の作業は、「kubemaster01」のrootユーザーとして実施してください。

Dockerレジストリーの用意

はじめに、Dockerレジストリーの機能を用意します。後ほど、このサーバー上でDockerイメージの構築も行うため、併せて、Dockerも導入しておきます。それぞれに必要なパッケージを追加します。

# yum -y install docker docker-registry

Dockerの設定ファイル「/etc/sysconfig/docker」に下記の行を追加します。これは、このサーバー上のDockerレジストリーを利用するために必要となります。

/etc/sysconfig/docker

INSECURE_REGISTRY='--insecure-registry kubemaster01:5000'

Docker、および、Dockerレジストリーのサービスを有効化して、起動します。

# systemctl enable docker.service
# systemctl start docker.service
# systemctl enable docker-registry
# systemctl start docker-registry

Kubernetesマスターの構成

続いて、バックエンドデータベースとなるetcd、および、Kubernetesマスターとしての機能を構成します。Kubernetesのパッケージを導入すると、etcdを含めて、必要なパッケージがまとめて導入されます。

# yum -y install kubernetes

「/etc/kubernetes/config」「/etc/kubernetes/apiserver」「/etc/kubernetes/controller-manager」の3種類の設定ファイルを編集します。

/etc/kubernetes/config

KUBE_ETCD_SERVERS="--etcd_servers=http://127.0.0.1:4001"    ← 変更前
KUBE_ETCD_SERVERS="--etcd_servers=http://kubemaster01:4001" ← 変更後

 

/etc/kubernetes/apiserver

KUBE_API_ADDRESS="--address=127.0.0.1"          ← 変更前
KUBE_API_ADDRESS="--address=0.0.0.0"            ← 変更後

KUBE_MASTER="--master=127.0.0.1:8080"           ← 変更前
KUBE_MASTER="--master=http://kubemaster01:8080" ← 変更後

KUBE_SERVICE_ADDRESSES="--portal_net=10.254.0.0/16" ← 変更前 
KUBE_SERVICE_ADDRESSES="--portal_net=172.16.0.0/16" ← 変更後

 

/etc/kubernetes/controller-manager

KUBELET_ADDRESSES="--machines=127.0.0.1"         ← 変更前
KUBELET_ADDRESSES="--machines=minion01,minion02" ← 変更後

 

ここで、ディレクトリー「/etc/systemd/system/kube-apiserver.service.d」を作成して、この中に次の設定ファイル「pre-start.conf」を保存します。(これは、本来は不要な操作ですが、記事執筆時点の既知の問題としてこれが必要です。)

# mkdir /etc/systemd/system/kube-apiserver.service.d

pre-start.conf

[Service]
PermissionsStartOnly=yes
ExecStartPre=/usr/bin/mkdir -p /var/run/kubernetes
ExecStartPre=/usr/bin/chown kube.kube /var/run/kubernetes

(参考)Bug 1201965 – kube-apiserver fails to create /var/run/kubernetes

最後に、etcd、および、Kubernetes Masterとして必要なサービスを有効化して、起動します。

# for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do
    systemctl enable $SERVICES
    systemctl start $SERVICES
  done

これでマスターサーバーの構成は完了です。次のコマンドで、APIリクエストに応答があることを確認してください。

# curl -s -L http://kubemaster01:8080/version | python -mjson.tool
{
    "gitCommit": "96af0c3e5bac4c07635ac3653724c0721ed64403",
    "gitTreeState": "clean",
    "gitVersion": "v0.9.0",
    "major": "0",
    "minor": "9"
}

Minionサーバーの構成

2台のMinionを構成します。本節の作業は、「minion01」「minion02」のそれぞれで、rootユーザーとして実施してください。

Minionの構成

はじめに、Dockerを導入します。

# yum -y install docker

Dockerの設定ファイル「/etc/sysconfig/docker」に下記の行を追加します。これは、マスターサーバー上のDockerレジストリーを利用するために必要となります。

/etc/sysconfig/docker

INSECURE_REGISTRY='--insecure-registry kubemaster01:5000'

Dockerのサービスを有効化して、起動します。

# systemctl enable docker.service
# systemctl start docker.service

続いて、Kubernetesのパッケージを導入します。

# yum -y install kubernetes

「/etc/kubernetes/config」「/etc/kubernetes/kubelet」「/etc/kubernetes/proxy」の3種類の設定ファイルを編集します。

/etc/kubernetes/config

KUBE_ETCD_SERVERS="--etcd_servers=http://127.0.0.1:4001"    ← 変更前
KUBE_ETCD_SERVERS="--etcd_servers=http://kubemaster01:4001" ← 変更後

 

/etc/kubernetes/kubelet

KUBELET_ADDRESS="--address=127.0.0.1"            ← 変更前
KUBELET_ADDRESS="--address=0.0.0.0"              ← 変更後

KUBELET_HOSTNAME="--hostname_override=127.0.0.1"  ← 変更前
#KUBELET_HOSTNAME="--hostname_override=127.0.0.1" ← 変更後(コメントアウト)

 

/etc/kubernetes/proxy

KUBE_PROXY_ARGS=""                                  ← 変更前
KUBE_PROXY_ARGS="--master=http://kubemaster01:8080" ← 変更後

 

また、認証ファイル「/var/lib/kubelet/auth」を作成しておきます。(これは、本来は不要な操作ですが、記事執筆時点の既知の問題としてこれが必要です。)

# echo "{}" > /var/lib/kubelet/auth

Minionとして必要なサービスを有効化して、起動します。

# for SERVICES in kubelet.service kube-proxy.service; do
    systemctl enable $SERVICES
    systemctl start $SERVICES
  done

これで、Minionとしての機能はそろいましたが、内部ネットワークがまだ構成されていません。続いて、Flannelを用いて、内部ネットワークを構成します。

Flannelの構成

Flannelは、etcdのデータベース内に設定ファイルを格納します。まず、minion01において、次の設定ファイルを用意します。

flannel-config.json

{
  "Network": "10.1.0.0/16",
  "SubnetLen": 24,
  "Backend": {
    "Type": "vxlan",
    "VNI": 1
  }
}

次のコマンドで、設定ファイルをetcdに格納します。

# curl -L http://kubemaster01:4001/v2/keys/coreos.com/network/config \
    -XPUT --data-urlencode value@flannel-config.json

正しく格納された事を次のコマンドで確認します。

# curl -s -L http://kubemaster01:4001/v2/keys/coreos.com/network/config | python -mjson.tool
 {
    "action": "get",
    "node": {
        "createdIndex": 18,
        "key": "/coreos.com/network/config",
        "modifiedIndex": 18,
        "value": "{\n  \"Network\": \"10.1.0.0/16\",\n  \"SubnetLen\": 24,\n  \"Backend\": {\n      \"Type\": \"vxlan\",\n      \"VNI\": 1\n  }\n}\n"
    }
}

続いて、minion01, minion02のそれぞれにFlannelのパッケージを導入します。

# yum -y install flannel

設定ファイル「/etc/sysconfig/flannled」を次のように修正します。「eth0」の部分は、パブリックネットワークに接続したNICを指定します。

/etc/sysconfig/flanneld

FLANNEL_ETCD="http://127.0.0.1:4001"     ← 変更前
FLANNEL_ETCD="http://kubemaster01:4001"  ← 変更後

#FLANNEL_OPTIONS=""                      ← 変更前
FLANNEL_OPTIONS="eth0"                   ← 変更後

最後に、Flannelのサービスを有効化して、一度、サーバーを再起動します。

# systemctl enable flanneld
# reboot

再起動後にネットワーク構成を確認すると、「flannel.1」というインターフェースが用意されて、サブネット「10.1.0.0/16」のゲートウェイに設定されていることが分かります。

# ip a show flannel.1
3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
    link/ether fe:07:49:6a:6f:04 brd ff:ff:ff:ff:ff:ff
    inet 10.1.24.0/16 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::fc07:49ff:fe6a:6f04/64 scope link 
       valid_lft forever preferred_lft forever
# ip route
default via 192.168.122.1 dev eth0  proto static  metric 100 
10.1.0.0/16 dev flannel.1  proto kernel  scope link  src 10.1.24.0 
10.1.24.0/24 dev docker0  proto kernel  scope link  src 10.1.24.1 
192.168.122.0/24 dev eth0  proto kernel  scope link  src 192.168.122.101  metric 100

flannel.1に送り込まれたパケットは、宛先ノードのflannel.1にVXLANでカプセル化して転送されます。(この際、Flannelデーモン「flanneld」は、VXLANの処理に必要な情報をLinuxカーネルに受け渡します。) これにより、複数ノードにまたがったサブネット「10.1.0.0/16」のオーバーレイネットワークが構成されることになります。それぞれのMinionの「docker0」(コンテナーが接続するブリッジ)には重複しないサブネット「10.1.X.0/24」が割り当てられています。

Flannelによるオーバーレイ・ネットワーク

Flannelによるオーバーレイ・ネットワーク

以上で、環境構築は完了です。

動作確認

それでは、実際にコンテナーを起動して動作確認を行いましょう。ここからの操作は、kubemaster01のrootユーザーで実施します。

まず、2台のMinionがマスターから認識されていることを確認します。

# kubectl get minion
NAME                LABELS              STATUS
minion01            <none>              Ready
minion02            <none>              Ready

続いて、コンテナーを起動するための設定ファイル「httpd.json」を次の内容で用意します。これは、Webサーバー(httpd)が稼働するコンテナーを2つ起動するものになります。本来は、マスターサーバーのDockerレジストリーに登録したイメージを使用する想定ですが、ここでは簡単のため、Docker Hubに事前に用意しておいたサンプルのコンテナイメージ(enakai00/test-httpd:ver1.0)を使用しています。

httpd.json

{
  "kind": "ReplicationController",
  "id": "httpd-controller",
  "apiVersion": "v1beta1",
  "labels": { "name": "httpd-controller" },
  "namespace": "default",
  "desiredState": {
    "replicaSelector": { "name": "test-httpd" },
    "replicas": 2,
    "podTemplate": {
      "desiredState": {
        "manifest": {
          "id": "httpd",
          "containers": [
            { 
              "image": "enakai00/test-httpd:ver1.0",
              "name": "test-httpd",
              "ports": [ { "containerPort": 80, "protocol": "TCP" } ]
            }
          ],
          "restartPolicy": { "always": {} },
          "version": "v1beta1",
          "volumes": null
        }
      },
      "labels": { "name": "test-httpd" }
    }
  }
}

次のコマンドを実行すると、設定ファイルに従ってコンテナーが起動します。

# kubectl create -f httpd.json

起動したコンテナーの状態は次のコマンドで確認します。「minion01」「minion02」のそれぞれでコンテナが起動していることが分かります。「STATUS」が「Unknown」から「Running」に変われば、コンテナーの起動が完了しています。

# kubectl get pod
POD                                    IP                  CONTAINER(S)        IMAGE(S)                     HOST                LABELS              STATUS
45071486-c9eb-11e4-8012-525400c788eb                       test-httpd          enakai00/test-httpd:ver1.0   minion02/           name=test-httpd     Unknown
4507671d-c9eb-11e4-8012-525400c788eb                       test-httpd          enakai00/test-httpd:ver1.0   minion01/           name=test-httpd     Unknown

このように複数のコンテナーを起動する機能は、「Replication Controller」が担っています。次のコマンドでReplication Controllerの状態が確認できます。

# kubectl get rc
CONTROLLER          CONTAINER(S)        IMAGE(S)                     SELECTOR            REPLICAS
httpd-controller    test-httpd          enakai00/test-httpd:ver1.0   name=test-httpd     2

次に、「サービス」を定義して、これらのコンテナーにアクセスするためのIPアドレスを用意します。サービスの設定ファイル「httpd-service.json」を次の内容で用意します。ここでは、2台のMinionのIPアドレス(192.168.122.101, 192.168.122.102)に対して999番ポートで接続すると、コンテナー内の80番ポートに接続するという指定を行っています。

httpd-service.json

{ 
  "kind": "Service",
  "id": "httpd-service",
  "apiVersion": "v1beta1",
  "labels": { "name": "httpd-service" },
  "namespace": "default",
  "selector": { "name": "test-httpd" },
  "containerPort": 80,
  "port": 999, 
  "publicIPs": [ "192.168.122.101", "192.168.122.102" ]
}

次のコマンドを実行すると、設定ファイルに従ってサービスが定義されます。

# kubectl create -f httpd-service.json

定義済みのサービスは次のコマンドで確認します。

# kubectl get service
NAME                LABELS                                    SELECTOR            IP                  PORT
kubernetes          component=apiserver,provider=kubernetes   <none>              172.16.182.238      443
kubernetes-ro       component=apiserver,provider=kubernetes   <none>              172.16.248.74       80
httpd-service       name=httpd-service                        name=test-httpd     172.16.131.179      999

それでは、curlコマンドで、実際にコンテナー内のApacheにアクセスしてみます。このApacheは、次のように、コンテナーIDを返答するよう事前に構成されています。繰り返しアクセスすると、2種類のコンテナーIDが返ってくることから、2つのコンテナーにロードバランスされていることが分かります。

# curl http://minion01:999/cgi-bin/hello.cgi
This is 4507671d-c9eb-11e4-8012-525400c788eb.
# curl http://minion01:999/cgi-bin/hello.cgi
This is 45071486-c9eb-11e4-8012-525400c788eb.

これで動作確認ができました。

それでは、最後の後始末として、コンテナーを停止して、Replication Controllerとサービスの定義を削除しておきます。これは次のコマンドで行います。最初のコマンドは、Replication Controllerに対して、起動するコンテナー数を0にするように指示しています。

# kubectl resize --replicas=0 rc httpd-controller
# kubectl delete rc httpd-controller
# kubectl delete service httpd-service

次回予告

今回は、RHEL7.1を用いて、実際にKubernetesが稼働する環境を構築しました。次回は、この環境を用いながら、どのような仕組みでコンテナーが管理されているのかという、内部構造の解説を進めていきます。

それでは、次回もお楽しみに!

 

(変更履歴)

2014/04/03 Flannelによるオーバーレイ・ネットワークの説明を修正しました。

レッドハット・エバンジェリスト・プロフィール

中井 悦司

中井 悦司

レッドハット株式会社 クラウドエバンジェリスト
予備校講師から転身、外資系ベンダーでLinux/OSSを中心とするプロジェクト、問題解決をリードするかたわら、多数のテクニカルガイド、雑誌記事など・・・
詳細はこちら »