Kubernetes環境を構築して、実際にコンテナを動かしてみよう

2021年3月19日(金)
加藤 修三

はじめに

今回は、実際に手を動かしてkubernetesを理解していきましょう。まずはコンテナとkubernetesによるコンテナオーケストレーションについて説明します。その後、kubernetesクラスタを構築していきます。構築ができたら、実際にコンテナをクラスタ上で動かしてみます。

コンテナとは

コンテナは仮想化方式の1つとされています。アプリケーションの実行に必要なファイル群をコンテナという形でパッケージングして、ホストOSのカーネルを共有しつつユーザ空間でリソースを分離することで仮想的に分離された環境を生成し、アプリケーションを実行します。この実行環境はホストOSからは通常のプロセスとして扱われます。

この仕組みには、ハイパーバイザー型仮想化などの方法に比べて、以下のような利点があります。

  • 高速な起動/停止
  • 最小限のリソース消費
  • 再現性の保証(Immutable Infrastructure)

これらの点により、構成管理やスケーリングに適したアプリケーション実行環境が実現されています。

Kubernetesとは

Kubernetesは、前述したコンテナをクラスタとして管理・実行する基盤(コンテナオーケストレータ)です。複数のノード(サーバ)をクラスタとして統合し、コンテナを各ノードに相互に通信可能な状態で配置して実行します。それだけではなく、コンテナを実行するノードの割り当て・計画実行、サービスの状態の自律的な制御など、拡張性/可用性の高いアーキテクチャを提供します。

コンテナオーケストレータの中でも、特にKubernetesは2つの特徴があります。

  • 宣言的なコードによる自律的なインフラ運用
  • 拡張可能な構成

「宣言的なコードとしての自律的なインフラ」とは、インフラにおけるすべての構成とその運用がコードによって表記されることを指します。Kubernetesは宣言されたコード通りの状態(アプリケーションコンテナの数や各リソースのエンドポイントの指定など)を保つための動作を自動で行います。加えて、コンテナやノードに障害が発生した際の対処や高負荷時の自動スケールアップ、ブルーグリーンデプロイやカナリアリリースなどのデプロイパターンまでコードとして表現できるため、多くの運用プロセスの自動化が可能になります。

「拡張可能な構成」とは、kubernetesの持つ様々なリソースを外部のサービスと連携させることで、ユーザ自身が高機能な構成をカスタマイズできることを指します。現在、kubernetesはCI/CD(継続的インテグレーション・デプロイメント)や監視・ロギング、セキュリティなど、多くのソリューションがサードパーティのOSSとして提供されています。ユーザーはこれらを必要に応じて使用し、各自の目的に沿ったインフラストラクチャーを構築できます。このようなkubernetesをとりまく様々なサービスを総称して「kubernetes ecosystem」と呼びます

以上のような特徴により、拡張性/可用性の高いアプリケーション基盤を実現しています。

kubernetesのインストール

以降では、実際に手を動かしながら、kubernetesを理解していきましょう。

構築する環境について

今回は、下記の環境でkubernetesクラスタを構築し、下図のような構成を目指します。

  • サーバ台数: 3台 (コントロールプレーン1台、ワーカー2台)
  • マシンスペック: vCPU x 2、メモリ 4 GB (Google Compute Engine e2-medium インスタンス)
  • OS: Ubuntu 20.04LTS

この構成について、少し詳しく見てみましょう。

kubernetesはコントロールプレーンと複数のワーカーでクラスタを構成します。コントロールプレーンはkubernetesの管理サーバーとして振る舞い、ワーカーにアプリケーションをデプロイします。このコントロールプレーンはHA構成をとることも可能ですが、今回は単一構成とします。

続いて、kubernetesの内部を構成するコンポーネントを簡単に紹介します。kube-apiserverは、その名の通りkubernetesのAPIサーバであり、kubernetesクラスタの中心です。ユーザがコンテナを作成したり一覧したりする場合に、このkube-apiserverにリクエストします。

kube-apiserverがリクエストを受けて、実際にデータを読み書きするデータストアがetcdです。kube-controller-managerはコンテナ起動数の保持やローリングデプロイの実行など、運用に関する自律的な管理を行います。ユーザがコンテナを作成したり削除したりするのと同じように、kube-apiserverに対してアクセスしながらこれを実現します。

kube-schedulerは、作成されたコンテナをどのノードに配置するかを決定します。kubeletは各ノードに常駐するプロセスです。kube-apiserverの情報に基づいて、ノード上でコンテナランタイムにリクエストしてコンテナの状態を管理します。実際にコンテナを作成するのはコンテナランタイムです。ここではcontainerdを採用しています。

コンポーネントが多く少し複雑な構成に思えますが、インストールツールを利用すれば簡単に構築できます。それでは、実際にやってみましょう。

コンテナランタイムのインストール(コントロールプレーン、ワーカー)

コントロールプレーン、ワーカーの環境に、コンテナランタイムのcontainerdをインストールします。

まず、環境設定を行います。以下のコマンド群を実行してください。

01cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
02overlay
03br_netfilter
04EOF
05 
06sudo modprobe overlay
07sudo modprobe br_netfilter
08 
09cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
10net.bridge.bridge-nf-call-iptables  = 1
11net.ipv4.ip_forward                 = 1
12net.bridge.bridge-nf-call-ip6tables = 1
13EOF
14 
15sudo sysctl --system

続いて、コンテナランタイムのcontainerdをインストールします。以下のコマンド群を実行してください。

1sudo apt-get update && sudo apt-get install -y containerd
2sudo mkdir -p /etc/containerd
3containerd config default | sudo tee /etc/containerd/config.toml
4sudo systemctl restart containerd

以上で、コントロールプレーン、ワーカーの環境にコンテナランタイムがインストールできました。

コントロールプレーンのセットアップ

続いて、コントロールプレーンの環境のセットアップを行います。

kubeadm、kubelet、kubectlのインストール(コントロールプレーン、ワーカー)

まず、Kubernetesのインストールツールであるkubeadmをインストールします。kubeadmはKubernetesコミュニティが公式に提供している簡易な構築ツールです。Kubernetesを構成するコンポーネントや証明書、各種設定ファイルを自動で作成し、素早くKubernetesクラスタを作成できます。 加えて、Kubernetesのノードコンポーネントであるkubelet、コマンドラインツールであるkubectlのインストールをします。

以下のコマンド群を実行してください。

1sudo apt-get update && sudo apt-get install -y apt-transport-https curl
3cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
4deb https://apt.kubernetes.io/ kubernetes-xenial main
5EOF
6sudo apt-get update
7sudo apt-get install -y kubelet kubeadm kubectl
8sudo apt-mark hold kubelet kubeadm kubectl

コントロールプレーンの起動

kubeadmを使用してコントロールプレーンを起動します。以下のコマンドを実行してください。

1sudo kubeadm init --pod-network-cidr=192.168.0.0/16

コマンド実行後、下記のように表示されれば成功です。

01[init] Using Kubernetes version: v1.20.4
02....
03Your Kubernetes control-plane has initialized successfully!
04To start using your cluster, you need to run the following as a regular user:
05  mkdir -p $HOME/.kube
06  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
07  sudo chown $(id -u):$(id -g) $HOME/.kube/config
08Alternatively, if you are the root user, you can run:
09  export KUBECONFIG=/etc/kubernetes/admin.conf
10You should now deploy a pod network to the cluster.
11Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
13Then you can join any number of worker nodes by running the following on each as root:
14kubeadm join 10.146.0.22:6443 --token rob5u6.id7c9nj028eacutg \
15    --discovery-token-ca-cert-hash sha256:5e746b01ceb1d459ffd7a7758e07f699a817e67784640f78aa
16e7710dc5ab77e0

このときに最後に表示されるコマンドは、ワーカーをコントロールプレーンに登録するコマンドです。後ほどワーカーの環境で使用するので、どこかにメモしておきましょう。

1kubeadm join 10.146.0.22:6443 --token rob5u6.id7c9nj028eacutg \
2    --discovery-token-ca-cert-hash sha256:5e746b01ceb1d459ffd7a7758e07f699a817e67784640f78aa
3e7710dc5ab77e0

加えて、kubectlを使用可能にするため、以下のコマンドを実行します。

1mkdir -p $HOME/.kube
2sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
3sudo chown $(id -u):$(id -g) $HOME/.kube/config

以上で、コントロールプレーンのセットアップは完了です。

ワーカーのセットアップ

続いて、ワーカー環境のセットアップを行います。

kubeadm、kubelet、kubectlのインストール

ワーカーの環境にも同様に、kubeadm、kubelet、kubectlをインストールします。 以下のコマンド群を実行してください。

1sudo apt-get update && sudo apt-get install -y apt-transport-https curl
2curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
3deb https://apt.kubernetes.io/ kubernetes-xenial main
4EOF
5sudo apt-get update
6sudo apt-get install -y kubelet kubeadm kubectl
7sudo apt-mark hold kubelet kubeadm kubectl

ワーカーのコントロールプレーンへの接続

次に、kubeadmコマンドを使用してワーカーの起動およびコントロールプレーンに接続を行います。

先ほどメモした以下のコマンドを2台のワーカーの環境で実行してください。

1sudo kubeadm join 10.146.0.22:6443 --token rob5u6.id7c9nj028eacutg --discovery-token-ca-cert-hash sha256:5e746b01ceb1d459ffd7a7758e07f699a817e67784640f78aae7710dc5ab77e0

コマンド実行後、下記のように表示されれば成功です。

1[preflight] Running pre-flight checks
2...
3This node has joined the cluster:
4* Certificate signing request was sent to apiserver and a response was received.
5* The Kubelet was informed of the new secure connection details.
6Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

ワーカーがクラスターに接続されました。この段階で、kube-proxyがワーカーに自動的に配置されます。

以上で、ワーカーのセットアップは完了です。これでkubernetesクラスターができました。

ネットワークプラグインのインストールと接続確認

クラスタにワーカーを登録できたら、kubectlコマンドkubectl get nodesを使用してワーカーの情報を取得してみましょう。

1$ kubectl get nodes
2NAME            STATUS     ROLES                  AGE     VERSION
3control-plane   NotReady   control-plane,master   15m     v1.20.4
4worker-1        NotReady   <none>                 4m41s   v1.20.4
5worker-2        NotReady   <none>                 24s     v1.20.4

表示を見るとSTATUSがNotReadyになっており、このままではkubernetesはオーケストレーションを始めることができません。これは、ノード間でネットワークが隔離され、ノード間の各コンテナが相互に通信できなくなっているためです。これを可能にするのがネットワークプラグイン(CNIプラグイン)です。今回は、CNIプラグインにCalicoを使用します。

以下のコマンドをコントロールプレーンで実行してください。

そして、もう一度kubectl get nodesをしてみましょう。STATUSがReadyになっていることが確認できます。

1$ kubectl get nodes
2NAME            STATUS   ROLES                  AGE     VERSION
3control-plane   Ready    control-plane,master   17m     v1.20.4
4worker-1        Ready    <none>                 6m57s   v1.20.4
5worker-2        Ready    <none>                 2m40s   v1.20.4

以上で、kubernetesの環境構築は終了です。

Podを作成してコンテナを動かす

kubernetesの環境構築ができたので、実際にkubernetes上でアプリケーションを実行してみましょう。ここで、Podと呼ばれるリソースが登場します。

Podはコンテナを管理するリソースで、デプロイにおける最小単位です。1つ以上のコンテナによって構成されます。はじめに、リソースを定義するマニフェストを見てみましょう。

1apiVersion: v1
2kind: Pod
3metadata:
4  name: nginx
5spec:
6  containers:
7  - image: nginx:1.17
8    name: nginx

このマニフェストは、YAMLと呼ばれる形式で記述されています。各項目について解説すると、以下のようになります。

  • apiVersion: kubernetes APIのバージョン
  • kind: リソースの種類
  • metadata: リソースの名前等
  • spec: containersではコンテナ名やイメージ、コマンドを指定

これをnginx.yamlとして保存し、クラスタにデプロイしてみましょう。まず、kubectl get podsを実行して、まだ環境にPodがないことを確認します。

1$ kubectl get pods
2No resources found in default namespace.

次に、マニフェストnginx.yamlを使用してPodをデプロイします。マニフェストを適用する際には、kubectl applyを使用します。

1$ kubectl apply -f nginx.yaml
2pod/nginx created

kubectl get podsを実行すると、デプロイされたPodを確認できます。

1$ kubectl get pods
2NAME    READY   STATUS    RESTARTS   AGE
3nginx   1/1     Running   0          17s

さらにkubectl describe pod nginxを実行すると、Podの詳しい情報を確認できます。

01$ kubectl describe pod nginx
02Name:         nginx
03Namespace:    default
04Priority:     0
05Node:         worker-2/10.146.0.26
06Start Time:   Sun, 28 Feb 2021 08:39:01 +0000
07Labels:       <none>
08Annotations:  cni.projectcalico.org/podIP: 192.168.133.195/32
09              cni.projectcalico.org/podIPs: 192.168.133.195/32
10Status:       Running
11IP:           192.168.133.195
12IPs:
13  IP:  192.168.133.195
14Containers:
15  nginx:
17834b8
18    Image:          nginx:1.17
19    Image ID:       docker.io/library/nginx@sha256:6fff55753e3b34e36e24e37039ee9eae1fe38a642
200d8ae16ef37c92d1eb26699
21    Port:           <none>
22    Host Port:      <none>
23    State:          Running
24      Started:      Sun, 28 Feb 2021 08:39:02 +0000
25    Ready:          True
26    Restart Count:  0
27    Environment:    <none>
28    Mounts:
29      /var/run/secrets/kubernetes.io/serviceaccount from default-token-7xdpg (ro)
30Conditions:
31  Type              Status
32  Initialized       True
33  Ready             True
34  ContainersReady   True
35  PodScheduled      True
36Volumes:
37  default-token-7xdpg:
38    Type:        Secret (a volume populated by a Secret)

今回は、nginxをデプロイしました。nginxがホストしているIPがkubectl describe pod nginxの結果にあるIP:に記載されているので、そのIPをcurlしてみましょう。

01$ curl 192.168.133.195
02<!DOCTYPE html>
03<html>
04<head>
05<title>Welcome to nginx!</title>
06<style>
07    body {
08        width: 35em;
09        margin: 0 auto;
10        font-family: Tahoma, Verdana, Arial, sans-serif;
11    }
12</style>
13</head>
14<body>
15<h1>Welcome to nginx!</h1>
16<p>If you see this page, the nginx web server is successfully installed and
17working. Further configuration is required.</p>
18<p>For online documentation and support please refer to
19<a href="http://nginx.org/">nginx.org</a>.<br/>
20Commercial support is available at
21<a href="http://nginx.com/">nginx.com</a>.</p>
22<p><em>Thank you for using nginx.</em></p>
23</body>
24</html>

nginxのレスポンスが表示されたら成功です。Podの正常動作を確認できました。kubectl execコマンドを使うと、Pod内でコマンドを実行できます。

1$ kubectl exec nginx -it  -- /bin/sh
2# ls
3bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
4boot  etc  lib   media  opt  root  sbin  sys  usr

kubectl deleteコマンドを使うと、デプロイしたPodを削除できます。

1$ kubectl delete pod nginx
2pod "nginx" deleted

ほかにも、Podのログを取得するkubectl logsなどのコマンドがあります。興味のある方は試してみてください。

おわりに

今回は、kubernetesを学ぶ上で基本的な概念であるコンテナとkubernetesの概要から、実際に手を動かしてkuberenetesの構築とPodのハンズオンを行いました。次回からは、サービスやデプロイメントなど、その他のリソースを見ていきます。お楽しみに。

大学院生の傍ら、2020年2月よりクリエーションライン株式会社においてkubernetesを活用した開発に従事。 開発未経験からkubernetesを学び、2020年10月にCKAを取得。クラウドネイティブ時代のエンジニアになるために奮闘中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています