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をインストールします。

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

cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sudo sysctl --system

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

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

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

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

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

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

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

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

sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -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
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

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

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

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

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

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

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

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

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

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

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

ワーカーのセットアップ

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

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

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

sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -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
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

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

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

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

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

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

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

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

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

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

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

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

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

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

kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml

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

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

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

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

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

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

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx:1.17
    name: nginx

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

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

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

$ kubectl get pods
No resources found in default namespace.

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

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

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

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

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

$ kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0
Node:         worker-2/10.146.0.26
Start Time:   Sun, 28 Feb 2021 08:39:01 +0000
Labels:       <none>
Annotations:  cni.projectcalico.org/podIP: 192.168.133.195/32
              cni.projectcalico.org/podIPs: 192.168.133.195/32
Status:       Running
IP:           192.168.133.195
IPs:
  IP:  192.168.133.195
Containers:
  nginx:
    Container ID:   containerd://ca0fbebe2e055407f4a03a23ebb2875a3000ca141d0efaa366e4f7f8447
834b8
    Image:          nginx:1.17
    Image ID:       docker.io/library/nginx@sha256:6fff55753e3b34e36e24e37039ee9eae1fe38a642
0d8ae16ef37c92d1eb26699
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 28 Feb 2021 08:39:02 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-7xdpg (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-7xdpg:
    Type:        Secret (a volume populated by a Secret)

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

$ curl 192.168.133.195
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

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

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

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

$ kubectl delete pod nginx
pod "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メルマガ会員のサービス内容を見る

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