Kubernetesの基本を学ぶ
Kubernetesの基本
このチュートリアルでは、Kubernetesクラスターオーケストレーションシステムの基本について学びます。各モジュールには、Kubernetesの主な機能と概念に関する背景情報と、一緒に進めるためのチュートリアルが含まれています。
このチュートリアルでは、以下のことを学ぶことができます:
- コンテナ化されたアプリケーションをクラスターにデプロイ
- Deploymentのスケーリング
- 新しいソフトウェアのバージョンでコンテナ化されたアプリケーションをアップデート
- コンテナ化されたアプリケーションのデバッグ
Kubernetesはどんなことができるの?
モダンなWebサービスでは、ユーザはアプリケーションが24時間365日利用可能であることを期待しており、開発者はそれらのアプリケーションの新しいバージョンを1日に数回デプロイすることを期待しています。コンテナ化は、パッケージソフトウェアがこれらの目標を達成するのを助け、アプリケーションをダウンタイムなしでリリース、アップデートできるようにします。Kubernetesを使用すると、コンテナ化されたアプリケーションをいつでもどこでも好きなときに実行できるようになり、それらが機能するために必要なリソースとツールを見つけやすくなります。Kubernetesは、コンテナオーケストレーションにおけるGoogleのこれまでの経験と、コミュニティから得られた最善のアイデアを組み合わせて設計された、プロダクションレディなオープンソースプラットフォームです。
1 - クラスターの作成
1.1 - Minikubeを使ったクラスターの作成
Kubernetesクラスターとは何かを学ぶ。
Minikubeとは何かを学ぶ。
Kubernetesクラスターを起動する。
目標
- Kubernetesクラスターとは何かを学ぶ
- Minikubeとは何かを学ぶ
- Kubernetesクラスターをローカルで動かす
Kubernetesクラスター
Kubernetesは、単一のユニットとして機能するように接続された、可用性の高いコンピューターのクラスターをまとめあげます。Kubernetesの抽象化により、コンテナ化されたアプリケーションを個々のマシンに特に結び付けることなくクラスターにデプロイできます。この新しいデプロイモデルを利用するには、アプリケーションを個々のホストから切り離す方法でアプリケーションをパッケージ化(つまり、コンテナ化)する必要があります。コンテナ化されたアプリケーションは、アプリケーションがホストに深く統合されたパッケージとして特定のマシンに直接インストールされていた従来のデプロイモデルよりも柔軟で、より迅速に利用可能です。Kubernetesはより効率的な方法で、クラスター全体のアプリケーションコンテナの配布とスケジューリングを自動化します。Kubernetesはオープンソースのプラットフォームであり、プロダクションレディです。
Kubernetesクラスターは以下の2種類のリソースで構成されています:
- コントロールプレーンがクラスターを管理する
- ノードがアプリケーションを動かすワーカーとなる
Kubernetesは、コンピュータークラスター内およびコンピュータークラスター間でのアプリケーションコンテナの配置(スケジューリング)および実行を調整する、プロダクショングレードのオープンソースプラットフォームです。
コントロールプレーンはクラスターの管理を担当します。コントロールプレーンは、アプリケーションのスケジューリング、望ましい状態の維持、アプリケーションのスケーリング、新しい更新のロールアウトなど、クラスター内のすべての動作をまとめあげます。
ノードは、Kubernetesクラスターのワーカーマシンとして機能するVMまたは物理マシンです。各ノードにはKubeletがあり、これはノードを管理し、Kubernetesコントロールプレーンと通信するためのエージェントです。ノードにはcontainerd や CRI-O などのコンテナ操作を処理するためのツールもあるはずです。プロダクションのトラフィックを処理するKubernetesクラスターには、最低3つのノードが必要です。これは、1ノードがダウンすると、etcd メンバーとコントロールプレーンのインスタンスの両方を同時に失うリスクがあり、冗長性が損なわれてしまうからです。このリスクを軽減するには、コントロールプレーンノードを複数構成することで対応できます。
コントロールプレーンは実行中のアプリケーションをホストするために使用されるノードとクラスターを管理します。
Kubernetesにアプリケーションをデプロイするときは、コントロールプレーンにアプリケーションコンテナを起動するように指示します。コントロールプレーンはコンテナがクラスターのノードで実行されるようにスケジュールします。ノードは、コントロールプレーンが公開しているKubernetes APIを使用してコントロールプレーンと通信します。エンドユーザーは、Kubernetes APIを直接使用して対話することもできます。
Kubernetesクラスターは、物理マシンまたは仮想マシンのどちらにも配置できます。Kubernetes開発を始めるためにMinikubeを使うことができます。Minikubeは、ローカルマシン上にVMを作成し、1つのノードのみを含む単純なクラスターをデプロイする軽量なKubernetes実装です。Minikubeは、Linux、macOS、およびWindowsシステムで利用可能です。Minikube CLIは、起動、停止、ステータス、削除など、クラスターを操作するための基本的なブートストラップ操作を提供します。
Kubernetesが何であるかがわかったので、Hello Minikube に行き、最初のクラスターを動かしましょう!
2 - アプリケーションのデプロイ
2.1 - Deploymentを作成するためにkubectlを使う
目標
- アプリケーションのデプロイについて学ぶ。
- kubectlを使って、Kubernetes上にはじめてのアプリケーションをデプロイする。
KubernetesのDeployment
Deploymentは、アプリケーションのインスタンスを作成および更新する責務があります。
備考:
このチュートリアルでは、AMD64アーキテクチャを必要とするコンテナを使用します。
異なるCPUアーキテクチャのコンピューターでminikubeを使用する場合は、AMD64をエミュレートできるドライバーでminikubeを使用してみてください。
例えば、Docker Desktopドライバーはこれが可能です。
実行中のKubernetesクラスターを入手すると、その上にコンテナ化アプリケーションをデプロイすることができます。
そのためには、KubernetesのDeploymentの設定を作成します。
DeploymentはKubernetesにあなたのアプリケーションのインスタンスを作成し、更新する方法を指示します。
Deploymentを作成すると、KubernetesコントロールプレーンはDeployment内に含まれるアプリケーションインスタンスをクラスター内の個々のノードで実行するようにスケジュールします。
アプリケーションインスタンスが作成されると、Kubernetes Deploymentコントローラーは、それらのインスタンスを継続的に監視します。
インスタンスをホストしているノードが停止、削除された場合、Deploymentコントローラーはそのインスタンスをクラスター内の別のノード上のインスタンスと置き換えます。
これは、マシンの故障やメンテナンスに対処するためのセルフヒーリングの仕組みを提供しています。
オーケストレーションが登場する前の世界では、インストールスクリプトを使用してアプリケーションを起動することはよくありましたが、マシン障害が発生した場合に復旧する事はできませんでした。
アプリケーションのインスタンスを作成し、それらをノード間で実行し続けることで、Kubernetes Deploymentはアプリケーションの管理に根本的に異なるアプローチを提供します。
Kubernetes上にはじめてのアプリケーションをデプロイする
Kubernetesにデプロイするには、アプリケーションをサポートされているコンテナ形式のいずれかにパッケージ化する必要があります。
Kubernetesのコマンドラインインターフェースであるkubectlを使用して、Deploymentを作成、管理できます。
kubectlはKubernetes APIを使用してクラスターと対話します。
このモジュールでは、Kubernetesクラスターでアプリケーションを実行するDeploymentを作成するために必要な、最も一般的なkubectlコマンドについて学びます。
Deploymentを作成するときは、アプリケーションのコンテナイメージと実行するレプリカの数を指定する必要があります。
Deploymentを更新することで、あとでその情報を変更できます。
ブートキャンプのModule 5とModule 6では、Deploymentをどのようにスケール、更新できるかについて説明します。
最初のDeploymentには、NGINXを使用して全てのリクエストをエコーバックする、Dockerコンテナにパッケージ化されたhello-nodeアプリケーションを使用します。
(まだhello-nodeアプリケーションを作成して、コンテナを使用してデプロイしていない場合、Hello Minikube tutorialの通りにやってみましょう。)
kubectlもインストールされている必要があります。
インストールが必要な場合は、ツールのインストールからインストールしてください。
Deploymentが何であるかがわかったので、最初のアプリケーションをデプロイしましょう!
kubectlの基本
kubectlコマンドの一般的な書式はkubectl action resourceです。
これは指定された resource(node、deploymentなど)に対して指定された action(create、describe、deleteなど)を実行します。
指定可能なパラメーターに関する追加情報を取得するために、サブコマンドの後に--helpを使うこともできます(例:kubectl get nodes --help)。
kubectl versionコマンドを実行して、kubectlがクラスターと通信できるように設定されていることを確認してください。
kubectlがインストールされていて、クライアントとサーバーの両方のバージョンを確認できることを確認してください。
クラスター内のノードを表示するには、kubectl get nodesコマンドを実行します。
利用可能なノードが表示されます。
後で、KubernetesはNodeの利用可能なリソースに基づいてアプリケーションをデプロイする場所を選択します。
アプリケーションをデプロイする
最初のアプリケーションをkubectl create deploymentコマンドでKubernetesにデプロイしてみましょう。
デプロイ名とアプリケーションイメージの場所を指定する必要があります(Docker Hub外でホストされているイメージはリポジトリの完全なURLを含める必要があります)。
kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
素晴らしい!Deploymentを作成して、最初のアプリケーションをデプロイしました。
これによっていくつかのことが実行されました。
- アプリケーションのインスタンスを実行可能な適切なノードを探しました(利用可能なノードは1つしかない)。
- アプリケーションをそのノードで実行するためのスケジュールを行いました。
- 必要な場合にインスタンスを新しいノードで再スケジュールするような設定を行いました。
Deploymentの一覧を得るにはkubectl get deploymentsコマンドを使います。
アプリケーションの単一のインスタンスを実行しているDeploymentが1つあることが分かります。
インスタンスはノード上のコンテナ内で実行されています。
アプリケーションを見る
Kubernetes内部で動作しているPodは、プライベートに隔離されたネットワーク上で動作しています。
デフォルトでは、同じKubernetesクラスター内の他のPodやServiceからは見えますが、そのネットワークの外からは見えません。
kubectlを使用する場合、アプリケーションと通信するためにAPIエンドポイントを通じてやりとりしています。
アプリケーションをKubernetesクラスターの外部に公開するための他のオプションについては、後ほどModule 4で説明します。
また、これは基本的なチュートリアルであるため、ここではPodとは何かについては詳しく説明しません。
kubectl proxyコマンドによって、通信をクラスター全体のプライベートネットワークに転送するプロキシを作成することができます。
プロキシはcontrol-Cキーを押すことで終了させることができ、実行中は何も出力されません。
プロキシを実行するにはもう一つターミナルウィンドウを開く必要があります。
ホスト(端末)とKubernetesクラスター間の接続ができました。
プロキシによって端末からAPIへの直接アクセスが可能となります。
プロキシエンドポイントを通してホストされている全てのAPIを確認することができます。
例えば、curlコマンドを使って、APIを通じて直接バージョンを調べることができます。
curl http://localhost:8001/version
備考:
ポート8001にアクセスできない場合は、上で起動したkube proxyがもう一つのターミナルで実行されていることを確認してください。
APIサーバーはPod名に基づいて各Pod用のエンドポイントを自動的に作成し、プロキシからもアクセスできるようにします。
まずPod名を取得する必要があるので、環境変数POD_NAMEに格納しておきます。
export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
echo Name of the Pod: $POD_NAME
以下を実行することで、プロキシされたAPIを通してPodにアクセスすることができます。
curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME:8080/proxy/
プロキシを使わずに新しいDeploymentにアクセスするには、Module 4で説明するServiceが必要です。
次の項目
3 - アプリケーションの探索
3.1 - Podとノードについて
目標
- KubernetesのPodについて学ぶ
- Kubernetesのノードについて学ぶ
- デプロイされたアプリケーションのトラブルシューティング
Kubernetes Pod
モジュール2でDeploymentを作成したときに、KubernetesはアプリケーションインスタンスをホストするためのPodを作成しました。Podは、1つ以上のアプリケーションコンテナ(Dockerなど)のグループとそれらのコンテナの共有リソースを表すKubernetesの抽象概念です。 Podには以下のものが含まれます:
- 共有ストレージ(ボリューム)
- ネットワーキング(クラスターに固有のIPアドレス)
- コンテナのイメージバージョンや使用するポートなどの、各コンテナをどう動かすかに関する情報
Podは、アプリケーション固有の「論理ホスト」をモデル化し、比較的密接に結合されたさまざまなアプリケーションコンテナを含むことができます。 たとえば、Podには、Node.jsアプリケーションを含むコンテナと、Node.js Webサーバによって公開されるデータを供給する別のコンテナの両方を含めることができます。Pod内のコンテナはIPアドレスとポートスペースを共有し、常に同じ場所に配置され、同じスケジュールに入れられ、同じノード上の共有コンテキストで実行されます。
Podは、Kubernetesプラットフォームの原子単位です。 Kubernetes上にDeploymentを作成すると、そのDeploymentはその中にコンテナを持つPodを作成します(コンテナを直接作成するのではなく)。 各Podは、スケジュールされているノードに関連付けられており、終了(再起動ポリシーに従って)または削除されるまでそこに残ります。 ノードに障害が発生した場合、同じPodがクラスター内の他の使用可能なノードにスケジュールされます。
Podは1つ以上のアプリケーションコンテナ(Dockerなど)のグループであり、共有ストレージ(ボリューム)、IPアドレス、それらの実行方法に関する情報が含まれています。
ノード
Podは常にノード上で動作します。ノードはKubernetesではワーカーマシンであり、クラスターによって仮想、物理マシンのどちらであってもかまいません。各ノードはマスターによって管理されます。ノードは複数のPodを持つことができ、Kubernetesマスターはクラスター内のノード間でPodのスケジュールを自動的に処理します。マスターの自動スケジューリングは各ノードで利用可能なリソースを考慮に入れます。
すべてのKubernetesノードでは少なくとも以下のものが動作します。
- Kubelet: Kubernetesマスターとノード間の通信を担当するプロセス。マシン上で実行されているPodとコンテナを管理します。
- レジストリからコンテナイメージを取得し、コンテナを解凍し、アプリケーションを実行することを担当する、Dockerのようなコンテナランタイム。
コンテナ同士が密接に結合され、ディスクなどのリソースを共有する必要がある場合は、コンテナを1つのPodにまとめてスケジュールする必要があります。
kubectlを使ったトラブルシューティング
モジュール2では、kubectlのコマンドラインインターフェースを使用しました。モジュール3でもこれを使用して、デプロイされたアプリケーションとその環境に関する情報を入手します。最も一般的な操作は、次のkubectlコマンドで実行できます。
- kubectl get - リソースの一覧を表示
- kubectl describe - 単一リソースに関する詳細情報を表示
- kubectl logs - 単一Pod上の単一コンテナ内のログを表示
- kubectl exec - 単一Pod上の単一コンテナ内でコマンドを実行
これらのコマンドを使用して、アプリケーションがいつデプロイされたか、それらの現在の状況、実行中の場所、および構成を確認することができます。
クラスターのコンポーネントとコマンドラインの詳細についてわかったので、次にデプロイしたアプリケーションを探索してみましょう。
ノードはKubernetesではワーカーマシンであり、クラスターに応じてVMまたは物理マシンになります。 複数のPodを1つのノードで実行できます。
4 - アプリケーションの公開
4.1 - Serviceを使ったアプリケーションの公開
目標
- KubernetesにおけるServiceについて理解する
- ラベルとLabelSelectorオブジェクトがServiceにどう関係しているかを理解する
- Serviceを使って、Kubernetesクラスターの外にアプリケーションを公開する
Kubernetes Serviceの概要
Kubernetes Podの寿命は永続的ではありません。実際、Podにはライフサイクルがあります。ワーカーのノードが停止すると、そのノードで実行されているPodも失われます。そうなると、ReplicaSetは、新しいPodを作成してアプリケーションを実行し続けるために、クラスターを動的に目的の状態に戻すことができます。別の例として、3つのレプリカを持つ画像処理バックエンドを考えます。それらのレプリカは交換可能です。フロントエンドシステムはバックエンドのレプリカを気にしたり、Podが失われて再作成されたとしても配慮すべきではありません。ただし、Kubernetesクラスター内の各Podは、同じノード上のPodであっても一意のIPアドレスを持っているため、アプリケーションが機能し続けるように、Pod間の変更を自動的に調整する方法が必要です。
KubernetesのServiceは、Podの論理セットと、それらにアクセスするためのポリシーを定義する抽象概念です。Serviceによって、依存Pod間の疎結合が可能になります。Serviceは、すべてのKubernetesオブジェクトのように、YAML(推奨)またはJSONを使って定義されます。Serviceが対象とするPodのセットは通常、LabelSelectorによって決定されます(なぜ仕様にセレクタを含めずにServiceが必要になるのかについては下記を参照してください)。
各Podには固有のIPアドレスがありますが、それらのIPは、Serviceなしではクラスターの外部に公開されません。Serviceによって、アプリケーションはトラフィックを受信できるようになります。ServiceSpecでtypeを指定することで、Serviceをさまざまな方法で公開することができます。
- ClusterIP (既定値) - クラスター内の内部IPでServiceを公開します。この型では、Serviceはクラスター内からのみ到達可能になります。
- NodePort - NATを使用して、クラスター内の選択された各ノードの同じポートにServiceを公開します。
<NodeIP>:<NodePort>を使用してクラスターの外部からServiceにアクセスできるようにします。これはClusterIPのスーパーセットです。
- LoadBalancer - 現在のクラウドに外部ロードバランサを作成し(サポートされている場合)、Serviceに固定の外部IPを割り当てます。これはNodePortのスーパーセットです。
- ExternalName - 仕様の
externalNameで指定した名前のCNAMEレコードを返すことによって、任意の名前を使ってServiceを公開します。プロキシは使用されません。このタイプはv1.7以上のkube-dnsを必要とします。
さまざまな種類のServiceに関する詳細情報はUsing Source IP tutorialにあります。アプリケーションとServiceの接続も参照してください。
加えて、Serviceには、仕様にselectorを定義しないというユースケースがいくつかあります。selectorを指定せずに作成したServiceについて、対応するEndpointsオブジェクトは作成されません。これによって、ユーザーは手動でServiceを特定のエンドポイントにマッピングできます。セレクタがない可能性があるもう1つの可能性は、type:ExternalNameを厳密に使用していることです。
まとめ
- Podを外部トラフィックに公開する
- 複数のPod間でトラフィックを負荷分散する
- ラベルを使う
Kubernetes Serviceは、Podの論理セットを定義し、それらのPodに対する外部トラフィックの公開、負荷分散、およびサービス検出を可能にする抽象化層です。
Serviceは、一連のPodにトラフィックをルーティングします。Serviceは、アプリケーションに影響を与えることなく、KubernetesでPodが死んだり複製したりすることを可能にする抽象概念です。(アプリケーションのフロントエンドおよびバックエンドコンポーネントなどの)依存Pod間の検出とルーティングは、Kubernetes Serviceによって処理されます。
Serviceは、ラベルとセレクタを使用して一連のPodを照合します。これは、Kubernetes内のオブジェクトに対する論理操作を可能にするグループ化のプリミティブです。ラベルはオブジェクトに付けられたkey/valueのペアであり、さまざまな方法で使用できます。
- 開発、テスト、および本番用のオブジェクトを指定する
- バージョンタグを埋め込む
- タグを使用してオブジェクトを分類する
ラベルは、作成時またはそれ以降にオブジェクトにアタッチでき、いつでも変更可能です。Serviceを使用してアプリケーションを公開し、いくつかのラベルを適用してみましょう。
5 - アプリケーションのスケーリング
5.1 - アプリケーションの複数インスタンスを実行
目標
- kubectlを使用してアプリケーションをスケールする
アプリケーションのスケーリング
前回のモジュールでは、Deploymentを作成し、それをService経由で公開しました。該当のDeploymentでは、アプリケーションを実行するためのPodを1つだけ作成しました。トラフィックが増加した場合、ユーザーの需要に対応するためにアプリケーションをスケールする必要があります。
スケーリングは、Deploymentのレプリカの数を変更することによって実現可能です。
kubectl create deploymentコマンドの--replicasパラメーターを使用することで、最初から複数のインスタンスを含むDeploymentを作成できます。
Deploymentをスケールアウトすると、新しいPodが作成され、使用可能なリソースを持つノードにスケジュールされます。スケールすると、Podの数が増えて新たな望ましい状態になります。KubernetesはPodのオートスケーリングもサポートしていますが、このチュートリアルでは範囲外です。スケーリングを0に設定することも可能で、指定された配置のすべてのPodを終了させます。
アプリケーションの複数インスタンスを実行するには、それらすべてにトラフィックを分散する方法が必要になります。Serviceには、公開されたDeploymentのすべてのPodにネットワークトラフィックを分散する統合ロードバランサがあります。Serviceは、エンドポイントを使用して実行中のPodを継続的に監視し、トラフィックが使用可能なPodにのみ送信されるようにします。
スケーリングは、Deploymentのレプリカの数を変更することによって実現可能です。
アプリケーションの複数のインスタンスを実行すると、ダウンタイムなしでローリングアップデートを実行できます。それについては、次のモジュールで学習します。それでは、オンラインのターミナルを使って、アプリケーションをデプロイしてみましょう。
6 - アプリケーションのアップデート
6.1 - ローリングアップデートの実行
目標
- kubectlを使ってローリングアップデートを実行する
アプリケーションのアップデート
ユーザーはアプリケーションが常に利用可能であることを期待し、開発者はそれらの新しいバージョンを1日に数回デプロイすることが期待されます。Kubernetesでは、アプリケーションのアップデートをローリングアップデートで行います。ローリングアップデートでは、Podインスタンスを新しいインスタンスで段階的にアップデートすることで、ダウンタイムなしでDeploymentをアップデートできます。新しいPodは、利用可能なリソースを持つノードにスケジュールされます。
前回のモジュールでは、複数のインスタンスを実行するようにアプリケーションをデプロイしました。これは、アプリケーションの可用性に影響を与えずにアップデートを行うための要件です。デフォルトでは、アップデート中に使用できなくなる可能性があるPodの最大数と作成できる新しいPodの最大数は1です。どちらのオプションも、Podの数または全体数に対する割合(%)のいずれかに設定できます。Kubernetesでは、アップデートはバージョン管理されており、Deploymentにおけるアップデートは以前の(stable)バージョンに戻すことができます。
ローリングアップデートでは、Podを新しいインスタンスで段階的にアップデートすることで、ダウンタイムなしDeploymentをアップデートできます。
アプリケーションのスケーリングと同様に、Deploymentがパブリックに公開されている場合、Serviceはアップデート中に利用可能なPodのみにトラフィックを負荷分散します。 利用可能なPodは、アプリケーションのユーザーが利用できるインスタンスです。
ローリングアップデートでは、次の操作が可能です。
- コンテナイメージのアップデートを介した、ある環境から別の環境へのアプリケーションの昇格
- 以前のバージョンへのロールバック
- ダウンタイムなしでのアプリケーションのCI/CD
Deploymentがパブリックに公開されている場合、Serviceはアップデート中に利用可能なPodにのみトラフィックを負荷分散します。
次の対話型チュートリアルでは、アプリケーションを新しいバージョンにアップデートし、ロールバックも実行します。