はじめに
本記事は、これからKubernetesをはじめる方を対象とし、コンテナ開発の基本を最速で理解するための入門記事になります。
入門記事といっても、コンテナ型仮想化技術に対する単なる抽象概念の理解は前提知識とし、少し掘り下げながら、Kubernetesの導入や、基本的な操作及び周辺技術の理解を目的にまとめています。
前提知識
Kubernetesをはじめるにあたり、コンテナ型仮想化技術に関する知識が求められます。
本記事では、コンテナ型仮想化技術としてDockerを使用しますが、Dockerの基本的なことについてはTL;DRになるので割愛します。なお、おさえておきたい知識としては、以下になります。
- コンテナ型仮想化技術(概要レベル)
- コンポーネント(Docker Engine/Docker Compose/Docker Swarm/Docker Machine/Docker Kitematic/Docker Registry等)
- Dockerの操作(イメージ・コンテナ)
- オーケストレーションツールの知識
- Docker Hub
コンテナ型仮想化技術について少し深堀
コンテナ型仮想化技術は、OSのカーネルの機能により実現さています。
OSのカーネルの機能を使用することで、ホストのリソースを各コンテナごとに隔離及び分配することで、独立した空間を作り出しています。また、この独立した空間を作り出す仕組みを提供しているソフトウェアとして、LXCがあります。
LXCは、Linux カーネルが持つコンテナ機能のためのユーザスペースのインターフェースです。 DockerとLXCは混合しやすいですが、それぞれ別のソフトウェアになります。Dockerは、アプリケーションのデプロイを目的として設計されているため、「1コンテナ1プロセス」をうたっていますが、LXCは「OSレベル仮想化のソフトウェア」と言われています。 Dockerも0.8まではLXCを使用していました。
現在、Dockerアーキテクチャは4つのコンポーネントに分割されています。Docker Engine、containerd、containerd-shm、及びrunC。バイナリはそれぞれdocker、docker-containerd、docker-containerd-shim、及びdocker-runcと呼ばれます。
コンテナを実行するために、Docker Engineはイメージを作成し、それをcontainerdに渡します。containerdは、runCを使用してコンテナを実行するcontainerd-shimを呼び出します。その後、containerd-shimはランタイム(この場合はrunC)がコンテナの起動後に終了できるようにします。このようにすると、コンテナ用の長時間のランタイムプロセスを持つ必要がなくなるため、デーモンレスコンテナを実行できます。
ランタイム
ランタイムは、プログラム実行時のことや、実行するときに必要な物を意味します。
コンテナランタイムについて少し捕捉します。
containerd
containerdは、ランタイムが実行したコンテナを管理します。
containerdはもともとDocker社によって開発されてきましたが、標準的なランタイム実装を実現するために、Docker社から中立的な団体である**Cloud Native Computing Foundationに(CNCF)**に、2017年3月に寄贈されました。
containerd-shim
containerd-shimは、デーモンレスコンテナを可能にします。
起動されたすべてのコンテナの親プロセスであり、デーモンなしのコンテナも許可されます。
runC
runCは、コンテナを作成や起動したりするバイナリのプログラムです。また、runCはDocker Engineと同じ技術であるlibcontainer上に実装されています。
Docker社によって開発され、オープンソース化されていますが、現在はコンテナ型仮想化技術の標準化に取り組む**Open Container Initiative(OCI)**(※1)が定義する仕様で、事実上コンテナ型仮想化技術のデファクトスタンダードとなっています。実装としては、Namespace、cgroups、pivot_root、AppArmor、SELinux、seccomp等により、セキュア(※2)なコンテナを作り出しています。
(※1)Open Container Initiative(OCI)は、コンテナエコシステム内での潜在的な断片化や分割を回避するために、ソフトウェアコンテナの共通標準を確立することを目的とし、二つの指定が含まれています。
- runtime-spec:ランタイム仕様
- image-spec:イメージ仕様
(※2)2019年2月12日に、runcの脆弱性(CVE-2019-5736)が発見されています。この脆弱性により、悪意のあるコンテナが(最小限のユーザーで)許可されます。ホストのruncバイナリを上書きして、rootレベルになるホスト上で任意のコマンドを実行することができるようになります。
- Dockerで使用しているランタイムの確認
docker info | grep 'Runtime'
libcontainer
libcontainerは、Go言語で実装されたライブラリです。
Dockerのコンテナ機能は、0.8までLXCに依存してきましたが、0.9以降はカーネルのコンテナAPIを直接コールするlibcontainerドライバに変更されました。
カーネル
カーネルは、オペレーティングシステム (OS) のコアとなる部分です。
CPU、メモリ、デバイスの入出力といったハードウェアリソースを抽象化します。
コンテナ型仮想化技術は、ホスト型やハイパーバイザー型等他の仮想化技術に比べて、オーバーヘッドが少ないため、軽量で高速に動作するのが特徴です。
ファイルシステム
Dockerでは、複数のファイルシステム上のディレクトリやファイルをレイヤとして重ね合わせ、それらを仮想的に一つのファイルシステムとして扱うことにより、イメージを実現しています。また、イメージレイヤに対するコンテナ上でのファイルの更新は、コピーオンライトによって実現しています。コピーオンライト処理は、ストレージドライバによって実装が異なります。
例として、Aufsは、複数の異なるファイルシステム (ブランチと呼ばれる) のファイルやディレクトリ同士を透過的に重ねる (マージする) ことができる技術です。
-
Dockerで使用しているドライバの確認
docker info | grep 'Storage Driver'
-
Docker イメージレイヤの確認
docker history イメージ
Namespace
Namespaceは、コンテナ毎に異なる論理的な空間を提供し、隔離するための技術です。
名前空間 | 定数 | 概要 |
---|---|---|
IPC | CLONE_NEWIPC | System V プロセス間通信オブジェクトと呼ばれる、POSIXメッセージキュー等内部のプロセス間通信を分離する。 |
MOUNT | CLONE_NEWNS | Namespace内に隔離されたファイルシステムツリーを作り、ファイルシステムツリーを分離する。 |
Network | CLONE_NEWNET | ネットワークデバイス、IPアドレス、ポート番号、ルーティングテーブル、フィルタリングテーブル等ネットワークリソースを分離する |
PID | CLONE_NEWPID | PID(プロセスID)を分離する。 |
UID | CLONE_NEWUSER | UIDやGIDを分離する。 |
UTS | CLONE_NEWUTS | uname() システムコールから返される2つのシステム識別子(ホスト名やNISドメイン名)を分離する。 |
cgroups
cgroupsは、プロセスグループのリソース(CPU、メモリ、ディスクI/O等)の利用を制限・隔離するLinuxカーネルの機能です。グループ内のプロセスから他のグループのリソースが見えないようにできているのは、名前空間による隔離機能が働いているためです。
興味があれば、カーネルソースのtask_struct()を見てみるといいかもしれません。
Linux カーネル内部では、プロセスは task_struct と呼ばれるかなり大きな構造体で表現されます。task_struct は ./linux/include/linux/sched.h に含まれています。
chroot
chrootは古い技術ですが、仮想化技術をより理解するためには、知ってるといいでしょう。
chrootは、ファイルシステムの名前空間を隔離します。もう少し分かりやすく言うと、これ以上のディレクトリに行かせないように、ルートディレクトリを変更します。但し、隔離するのは、あくまでファイルシステムのみです。他のリソースは隔離しないため、ユーザーIDやネットワークインターフェイスは共通のものが見えます。
身近な例としては、bindの構築で使用されています。chrootすることで、/var/named/chrootがルートディレクトリになり、bindプロセスがアクセス可能な範囲を制限することを目的としています。これにより、万が一攻撃を受けて侵入されても、/var/namedディレクトリだけが影響を受けます。
chrootを使用する場合は、どこを起点にしているかで相対的位置を理解しておくと、トラブルの防止になります。
Kubernetes概要
Kubernetesは、宣言型構成及びコンテナ自動運用を可能とするコンテナオーケストレーションツールの一つです。分散システムとしてAPIを提供するために、信頼性・可用性・拡張性を実現します。
Googleが開発(※1)して2014年にオープンソース化されたKubernetesは、2017年10月のDockerCon EUでの、DockerのKubernetes統合発表を機に、取り巻く状況は大きく変わっていきました。現在は主要なクラウドサービスでもサポートされ、依然コンテナオーケストレーションツールとして、その重要性は変わっていません。
- GKE(Google Kubernetes Engine)
- Amazon EKS(Amazon Elastic Container Service for Kubernetes)
- AKS(Azure Kubernetes Service)(※2)
- CEK(Container Engine for Kubernetes)(※3)
(※1)Googleが社内のアプリケーション基盤として利用していた「Borg」と呼ばれるシステムが元
(※2)ACS(Azure Container Service)のサポートは2020年1月31日をもって終了
(※3)Oracleが提供するクラウドサービス
オーケストレーションツール
オンプレミスにおけるシステムの拡張方式は、スケールアップやスケールアウトの運用が一般的でしたが、クラウドの登場により、必要なときに、必要なリソースを迅速に構築する仕組みとしてオーケストレーションツールが生まれました。コンテナに係るオーケストレーションツールとして、主要なクラウドサービス以外でも以下のような種類があります。
開発元 | サービス |
---|---|
Red Hat | OpenShift |
Pivotal | PKS |
Docker | Swarm |
Apache | Apache Mesos |
Rancher Labs | Rancher |
Mesosphere | Mesosphere DC/OS |
Cloud Foundry | CFCR(Cloud Foundry Container Runtime) |
オーケストレーションツールは、Kubernetesのシェアが高いですが、Googleがオープンソース化したgVisor、OpenStack Foundationが開発したKata Containers、Kubernetesにネイティブ対応したコアランタイムのcontainerd等多様なランタイムが登場すると見込まれており、コンテナ型仮想化技術の動向踏まえて、今後も目が離せません。
アーキテクチャ
- Kubernetesを構成する要素はリソースとして区別され、Kubernetes Cluster(以降、クラスタ)はKubernetesの管理するリソースの集合体である
- NodeはKubernetes クラスタで管理されるDockerホストであり、MasterとNodeに区別される
- クラウドサービスで提供されるGKEの様なマネージドサービスでは、開発者がMasterを意識することはほとんどない
- Kubernetes クラスタのリソースに対する操作は標準化されたAPIによる行う
- Deploymentを1つの単位として、アプリケーションをデプロイする
Kubernetesのコンポーネント
MasterでAPIの受け付けを行い、Nodeの管理やKubernetes クラスタのコントロールを行なっています。Node内のkubeleteにより、Pod内のコンテナを管理します。また、ダッシュボードやDNS等のアドオンにより、Kubernetes クラスタとして機能します。
Kubernetesのコンポーネントの詳細は、Kubernetes Componentsを参照。
CRI(Container Runtime Interface)
KubernetesとDockerのあいだでは、Kubernetesで標準化されたAPIであるCRI(Container Runtime Interface)によってやりとりが行われます。以下は、KubernetesでのContainer Runtime Interface(CRI)の紹介についてのブログ記事です。
Introducing Container Runtime Interface (CRI) in Kubernetes
なお、KubernetesとCRIの対応についていは、Git Hubのcontainerd/criのリポジトリのREADMEを参照。
Kubernetesの意義
Kubernetesの意義を知りましょう。
Borgの歴史は、Borg, Omega, and Kubernetesから、知ることができます。
その他
Kubernetesに関連するツールや、フレームワーク等について以下に記載します。
- kubeadm
kubeadmは、ベストプラクティスに準拠した最低限実行可能なKubernetesクラスタを構築することができます。ラップトップ、サーバー、Raspberry Pi等色々なプラットフォームに対応しています。 - minikube
minikubeは、macOS、Linux、およびWindows上にローカルKubernetesクラスタを構築することができます。 - k3s
k3sは、Rancher Labs社がオープンソースで公開したKubernetesのディストリビューションです。わずか40MBでありながら、標準のKubernetesとしての機能を備えつつ、Kubernetes認証プログラムである「Certified Kubernetes」を取得。Rancher Labsよりダウンロードできます。 - Knative
Knativeは、最新のサーバーレス ワークロードをビルド、デプロイ、管理できる Kubernetes ベースのプラットフォーム。ワークロードをオンプレミスで実行している環境においてもコンテナをビルドできます。 - OpenFaaS
OpenFaaSは、Docker SwarmとKubernetesをサポートしているFaaSフレームワークで、リクエストに応じてコードを実行、状況に応じて自動的にインスタンスをスケールさせるということができます。オンプレミスや各社のクラウドサービス上でも導入することができます。 - kubeless
Kubelessは、Kubernetes固有のサーバーレスフレームワークで、基盤となるインフラストラクチャを気にせずに小さなコード(関数)をデプロイできます。 - Osiris
Osirisは、アイドル状態のワークロードを自動的にゼロまでスケールアップし、ゼロまでのスケールのワークロードをインバウンド要求によってオンデマンドで自動的に再アクティブ化することを可能にすることで、Kubernetesクラスター内のリソース効率を向上させます。まだ、開発中のコンポーネントのようです。 - Virtual Kubelet
Virtual Kubeletは、Microsoftが始めたOSSプロジェクトです。Kubernetesを拡張して、特定のワークロードをノードレスのサービスとして実行することができます。イメージとしては、VMwareのvMotionのように、Virtual Kubeletが動作するノードとは別のコンピューティングリソースに、コンテナを展開できます。 - Anthos
Anthosは、Kubernetesをベースにアプリケーションのマルチクラウド対応を実現する新サービスです。Google Cloud上ではGoogle Kubernetes Engine(GKE)上で稼働し、オンプレミスではGKE on Prem上で稼働。さらにAWS上でも稼働予定のため、Google以外のクラウドサポートが見込まれています。また、オンプレミスでのAnthosの実行環境は、現時点ではGKE on premの稼働条件であるVMware 6.5以上、F5 BIG-IPとされています。
Kubernetesのインストール
ローカル環境でKubernetesをインストールして使ってみましょう。
本記事の環境は以下になります。
環境:iMac
前提条件:Docker Desktop for Macがインストール済み
- 画面上部のDockerアイコンから、「Preferences」をクリックして、「Kubernetes」を選択します。
- 「Install」をクリックします。
- インストールが始まるので少し待ちます。
- インストールが終わったら「Close」をクリックして、「Kubernetes is running」と緑色で表示されたら正常に起動しています。
Kubernetesの操作
Kubernetesは、コマンドラインとGUIで操作ができます。
kubectl
kubectlは、Kubernetesをコマンドラインで操作するためのツールです。kubectlの概要(コマンドの構文等)は、 Overview of kubectlを参照。
Kubernetes クラスタの状態確認
Kubernetes クラスタの状態確認行うコマンドを以下に記載します。
- クラスタのバージョン確認
kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.11", GitCommit:"637c7e288581ee40ab4ca210618a89a555b6e7e9", GitTreeState:"clean", BuildDate:"2018-11-26T14:38:32Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.11", GitCommit:"637c7e288581ee40ab4ca210618a89a555b6e7e9", GitTreeState:"clean", BuildDate:"2018-11-26T14:25:46Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
- クラスタの正常性確認
kubectl get componentstatus
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health": "true"}
- クラスタのノード一覧表示
kubectl get nodes
NAME STATUS ROLES AGE VERSION
docker-for-desktop Ready master 59d v1.10.11
- クラスタのノード詳細情報表示
kubectl describe nodes ノード名
ダッシュボード
ダッシュボードを使用することで、ブラウザからKubernetes クラスタを管理することができます。
以下のコマンドを実行し、ダッシュボードを追加します。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.8.3/src/deploy/recommended/kubernetes-dashboard.yaml
secret "kubernetes-dashboard-certs" created
serviceaccount "kubernetes-dashboard" created
role.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created
rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created
deployment.apps "kubernetes-dashboard" created
service "kubernetes-dashboard" created
以下のコマンドを実行し、デプロイされたことを確認します。
kubectl get pod --namespace=kube-system -l k8s-app=kubernetes-dashboard
NAME READY STATUS RESTARTS AGE
kubernetes-dashboard-7d5dcdb6d9-6tpxv 1/1 Running 0 1m
以下のコマンドを実行し、ダッシュボードへのプロキシサーバを起動します。
kubectl proxy
Starting to serve on 127.0.0.1:8001
ブラウザから、ダッシュボードにアクセスすると、以下の様な画面が表示されるので「SKIP」をクリックします。
(※)実際に運用で使用する際は、認証機能を使用した方がセキュリティ的に望ましいです。
ダッシュボードが表示されます。
トークンの取得方法
ダッシュボードログイン時に、Tokenを指定してログインする方法を以下に記載します。
以下のコマンドを実行し、デフォルトトークンを特定します。
kubectl -n kube-system get secret | grep default-token
default-token-fx2v4 kubernetes.io/service-account-token 3 52d
以下のコマンドを実行し、tokenの内容を出力します。
kubectl -n kube-system describe secret default-token-fx2v4
Name: default-token-fx2v4
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name=default
kubernetes.io/service-account.uid=d9b76415-3c80-11e9-9164-025000000001
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 11 bytes
token: (※)トークンの内容が出力される
ダッシュボードログイン時に、Tokenを指定し、上記コマンド出力結果のtokenを入力することでログインができます。
Kubernetes API オブジェクト
Kubernetes上にある全てのリソースは、RESTfulリソース(Kubernetesオブジェクト)で表現されます。
例えば、Kubernetes Deploymentは、Kubernetes クラスタ上で実行されているアプリケーションを表すことができるオブジェクトです。Kubernetesオブジェクトを操作するために、Kubernetes APIを使用します。
Kubernetes APIのオブジェクトは、YAMLあるいはJSONで表現できます。オブジェクトの作成、更新、削除等の操作はYAMLやJSONのファイルを使用してAPIによる操作が行えます。
Pod
Podは、Kubernetes クラスタ上での最小のデプロイ単位です。Pod内のアプリケーションは、同じIPアドレスとポートを使用します。Podの設定は、Podマニフェストに記述します。
Podマニフェストは、YAMLあるいはJSONで記述します。一般的にはYAMLで記述する方法が汎用的です。YAMLではインデントを使ってデータの階層構造を表すため、非常に読みやすく書きやすいですが、デプロイ時のエラーの原因でもあります。
KubernetesのYAMLフォーマットの書き方はUnderstanding Kubernetes Objectsを参照。
Pod操作
kuardを例に、基本的なPod操作を行うコマンドを以下に記載します。
kubectlコマンドの引数で指定するリソース種別は、「pod」または「pods」のどちらでも実行できます。また、略して「po」で指定することもできます。
- kuard-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- name: kuard
image: gcr.io/kuar-demo/kuard-amd64:1
ports:
- containerPort: 8080
name: echo
protocol: TCP
- インスタンス起動
kubectl apply -f kuard-pod.yaml
pod "kuard" created
- Podの一覧表示
kubectl get pod
NAME READY STATUS RESTARTS AGE
kuard 1/1 Running 0 5s
- Podの詳細情報表示
kubectl describe pod kuard
Name: kuard
Namespace: default
Node: docker-for-desktop/192.168.65.3
Start Time: Sun, 21 Apr 2019 20:41:37 +0900
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"kuard","namespace":"default"},"spec":{"containers":[{"image":"gcr.io/kuar-demo/kua...
Status: Running
IP: 10.1.0.65
Containers:
kuard:
Container ID: docker://c5440df7d9eec2b10aa77baf29fe690597a98d68681d4ea49d1ee075745d5f78
Image: gcr.io/kuar-demo/kuard-amd64:1
Image ID: docker-pullable://gcr.io/kuar-demo/kuard-amd64@sha256:bd17153e9a3319f401acc7a27759243f37d422c06cbbf01cb3e1f54bbbfe14f4
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Sun, 21 Apr 2019 20:41:39 +0900
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-vgzn7 (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-vgzn7:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-vgzn7
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 41s default-scheduler Successfully assigned kuard to docker-for-desktop
Normal SuccessfulMountVolume 41s kubelet, docker-for-desktop MountVolume.SetUp succeeded for volume "default-token-vgzn7"
Normal Pulled 40s kubelet, docker-for-desktop Container image "gcr.io/kuar-demo/kuard-amd64:1" already present on machine
Normal Created 39s kubelet, docker-for-desktop Created container
Normal Started 39s kubelet, docker-for-desktop Started container
- Podの削除
kubectl delete pod/kuard
kubectl delete -f kuard-pod.yaml
pod "kuard" deleted
- インスタンスのログ取得
kubectl logs kuard
2019/04/23 09:10:58 Starting kuard version: v0.8.1-1
2019/04/23 09:10:58 **********************************************************************
2019/04/23 09:10:58 * WARNING: This server may expose sensitive
2019/04/23 09:10:58 * and secret information. Be careful.
2019/04/23 09:10:58 **********************************************************************
2019/04/23 09:10:58 Config:
{
"address": ":8080",
"debug": false,
"debug-sitedata-dir": "./sitedata",
"keygen": {
"enable": false,
"exit-code": 0,
"exit-on-complete": false,
"memq-queue": "",
"memq-server": "",
"num-to-gen": 0,
"time-to-run": 0
},
"liveness": {
"fail-next": 0
},
"readiness": {
"fail-next": 0
},
"tls-address": ":8443",
"tls-dir": "/tls"
}
2019/04/23 09:10:58 Could not find certificates to serve TLS
2019/04/23 09:10:58 Serving on HTTP on :8080
-
コンテナ接続(対話的)
kubectl exec -it kuard ash
-
ポートフォワード
kubectl port-forward kuard 8080:8080
ReplicaSet
レプリカという言葉は、複製と言う意味です。
Kubernetes クラスタ上でのReplicaSetは、Podの複製を行います。
ReplicaSetマニフェストで定義したreplicasの値の通り(※)にPodの複製を行います。
(※)既にPodが起動していて、不足していればその分Podを複製します。多い場合にReplicaSetマニフェストを適用すると、その分削除されます。
ReplicaSet操作
kuardを例に、基本的なReplicaSet操作を行うコマンドを以下に記載します。
kubectlコマンドの引数で指定するリソース種別は、「replicaset」または「replicasets」のどちらでも実行できます。また、略して「rs」で指定することもできます。
- kuard-rs.yaml
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: kuard
spec:
replicas: 1
template:
metadata:
labels:
app: kuard
version: "2"
spec:
containers:
- name: kuard
image: gcr.io/kuar-demo/kuard-amd64:2
- ReplicaSetの作成
kubectl apply -f kuard-rs.yaml
replicaset.extensions "kuard" created
- ReplicaSetの一覧表示
kubectl get replicaset
NAME DESIRED CURRENT READY AGE
kuard 1 1 1 6s```
- ReplicaSetの詳細情報表示
kubectl describe rs kuard
Name: kuard
Namespace: default
Selector: app=kuard,version=2
Labels: app=kuard
version=2
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"extensions/v1beta1","kind":"ReplicaSet","metadata":{"annotations":{},"name":"kuard","namespace":"default"},"spec":{"replicas":1,"templat...
Replicas: 1 current / 1 desired
Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=kuard
version=2
Containers:
kuard:
Image: gcr.io/kuar-demo/kuard-amd64:2
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 1m replicaset-controller Created pod: kuard-d65gb
- ReplicaSetのスケール
kubectl scale replicasets kuard --replicas=4
replicaset.extensions "kuard" scaled
- ReplicaSetの削除
kubectl delete rs kuard
replicaset.extensions "kuard" deleted
Service
Serviceは、サービスディスカバリを定義します。
サービスディスカバリとは、システム上のインフラにおけるサービスの問題を検出すると言うことを意味します。
例えば、マイクロサービスとしてサービスを提供しているコンテナにシステム障害が起きて停止した場合、障害が発生したコンテナ(Pod)に対するトラフィックを制御することができます。他にも、何らかのシステム障害発生時に、システム監視による検知でDNSレコードを更新したりして、DNSでサービスのディスカバリが行うことができます。
仕組みとして、各Podには固有のIPアドレスがありますが、それらのIPはServiceなしではクラスタの外部に公開されません。Serviceにより、アプリケーションはトラフィックを受信できます。
ClusterIP
デフォルトは、ClusterIPになります。ClusterIPはクラスタ内の内部にサービスを公開できます。ClusterIPにより、クラスタ内のPod間通信はServiceを介して行うことはできますが、外部からのアクセスはできません。
NodePort
NATを使用して、外部からクラスタに対するアクセスが可能になります。
LoadBalancer
主にクラウドサービスで提供されているロードバランサと連携して使用します。ロードバランサがサポートされている場合、サービスに固定の外部IPを割り当てることができます。
ExternalName
クラスタ内から外部のホストの名前解決を行うためのエイリアス(CNAME record)を設定することができます。なお、本機能はkube-dns v1.7以上になります。
Ingress
Kubernetes v1.1で追加されたIngressは、クラスタ外からのHTTP及びHTTPSの通信をクラスタ内のServiceに公開します。
Job
Jobは、指定された数のポッドの処理が成功するまで実行されるため、バッチ処理などに適しています。処理が成功するまで、JobコントローラがPodを作り直します。
ConfigMap
コンテナ運用で重要なのは、コンテナの特性を失わずに運用を行うことです。
例えば、Webサーバ機能を持つコンテナの設定を変えるために、Nginxの設定ファイルを変更するのはポータビリティを低下させます。環境変数を使用することで、チューニングがしやすくなります。環境変数の組み込みは色々やり方があると思いますが、KubernetesにはConfigMapという便利な機能があります。
ConfigMap操作
kuardを例に、基本的なConfigMap操作を行うコマンドを以下に記載します。
- my-config.txt
parameter1 = value1
parameter2 = value2
- ConfigMapの作成
kubectl create configmap my-config --from-file=my-config.txt --from-literal=extra-param=extra-value --from-literal=another-param=another-value
configmap "my-config" created
- ConfigMapの一覧表示
kubectl get configmap
NAME DATA AGE
my-config 3 2d
- ConfigMapの詳細情報表示
kubectl get configmap my-config -o yaml
apiVersion: v1
data:
another-param: another-value
extra-param: extra-value
my-config.txt: |
parameter1 = value1
parameter2 = value2
kind: ConfigMap
metadata:
creationTimestamp: 2019-04-25T06:23:43Z
name: my-config
namespace: default
resourceVersion: "1030540"
selfLink: /api/v1/namespaces/default/configmaps/my-config
uid: ac8694d8-6722-11e9-97d1-025000000001
- ConfigMapの削除
kubectl delete configmap my-config
configmap "my-config" deleted
Deployment
Deploymentは、Kubernetesクラスタ上で、デプロイされたアプリケーションのバージョン管理ができるオブジェクトです。Deploymentにより、ダウンタイムを発生させることなく、アプリケーションのバージョンのロールアウトが行えます。また、DeploymentはReplicaSetを管理します。
Deployment操作
基本的なDeployment操作を行うコマンドを以下に記載します。
kubectlコマンドの引数で指定するリソース種別は、「deployment」または「deployments」のどちらでも実行できます。また、略して「deploy」で指定することもできます。
- runコマンドでデプロイ
kubectl run nginx --image=nginx:1.7.12
kubectl run nginx --image=nginx:1.7.12
- Deploymentの一覧表示
kubectl get deployment
kAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 1 1 1 1 52s
- Deploymentの詳細情報表示
kubectl describe deployment nginx
dName: nginx
Namespace: default
CreationTimestamp: Sat, 27 Apr 2019 16:13:52 +0900
Labels: run=nginx
Annotations: deployment.kubernetes.io/revision=1
Selector: run=nginx
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: run=nginx
Containers:
nginx:
Image: nginx:1.7.12
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-7d9bf79f9b (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 29s deployment-controller Scaled up replica set nginx-7d9bf79f9b to 1
- Deploymentのスケール
kubectl scale deployment nginx --replicas=2
deployment.extensions "nginx" scaled
- Deploymentの削除
kubectl delete deployment nginx
deployment.extensions "nginx" deleted
-
Deploymentの作成
kubectl get deployment nginx --export -o yaml > nginx-deployments.yaml
-
nginx-deployments.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: null
generation: 1
labels:
run: nginx
name: nginx
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
run: nginx
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
run: nginx
spec:
containers:
- image: nginx:1.7.12
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status: {}
kubectl scale
コマンドではなく、Deploymentを宣言的に管理するする場合は、YAMLファイルのレプリカ数を変更して、kuberctl apply
コマンドでDeploymentを更新します。また、合わせてコンテナイメージの部分を変更することで、新しいバージョンのロールアウトを可能とします。
- ロールアウトの状態確認
kubectl rollout status deployment nginx
deployment "nginx" successfully rolled out
- Deploymentが管理しているReplicaSetsのイメージ確認
kubectl get replicasets -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
nginx-784d96dbff 1 1 1 1m nginx nginx:1.9.10 pod-template-hash=3408528699,run=nginx
nginx-7d9bf79f9b 0 0 0 35m nginx nginx:1.7.12 pod-template-hash=3856935956,run=nginx
- ロールアウト履歴
kubectl rollout history deployment nginx
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
2 Update nginx to 1.9.10
- デプロイしたリビジョンの詳細情報表示
kubectl rollout history deployment nginx --revision=2
deployments "nginx" with revision #2
Pod Template:
Labels: pod-template-hash=3408528699
run=nginx
Annotations: kubernetes.io/change-cause=Update nginx to 1.9.10
Containers:
nginx:
Image: nginx:1.9.10
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
- ロールバック
kubectl rollout undo deployment nginx
deployment.apps "nginx"
Persistent Volumes
Kubernetesは、ストレージをプロビジョニングする方法として、静的または動的による二つの方法があります。
Persistent Volumesは、コンテナとは別に独立した永続化データを管理するための仕組みを静的に提供します。また、Kubernetesでは、NFS、iSCSI、クラウドプロバイダー固有のストレージシステムをサポートしています。
PePersistent Volumesの使い方は、Configure a Pod to Use a PersistentVolume for Storageを参照。
PersistentVolumeClaim
Persistent Volumesを作成したら、PersistentVolumeClaimも作成します。
Persistent Volumesを使用することで、論理的なストレージ割り当てを行い、Podがストレージに対するアクセスを要求できます。
その他、動的ボリューム割り当ては、StorageClassesオブジェクトを使用することで可能になります。
永続的ボリュームの詳細については、Persistent Volumesを参照。
エラー時の勘所
以下は、本記事執筆時に遭遇したエラーです。
-
Podにアクセスできない場合(ローカル環境)
ホストのFWやウイルス対策ソフトの設定を確認します。例として、ウイルス対策ソフトによりポート通信が遮断されることはよく考えられます。 -
ConfigMapを使用して、Podが作成できない
kubectl describe pod ポッド名
の出力結果より、「Events」を見て、「Error: Couldn't find key 環境変数 in ConfigMap 」のログが出力されていたら、ConfigMapの環境変数に謝りがあります。ConfigMapの環境変数が正しいか見直しましょう。
Warning Failed 4m (x7 over 5m) kubelet, docker-for-desktop Error: Couldn't find key extra-param in ConfigMap default/my-config
- StatefulSetオブジェクトを使用して、MongoDBのPodを作成できない
原因は、YAMLフォーマットの「spec」-「serviceName」で大文字を使用していたため。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedCreate 3s (x10 over 5s) statefulset-controller create Pod mongo-0 in StatefulSet mongo failed error: Pod "mongo-0" is invalid: spec.subdomain: Invalid value: "Mongo": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')
おわりに
これからDevOpsエンジニア(※)を目指すにあたり、Kubernetesは必要不可欠なスキルです。
また、Kubernetesを更に理解するためには、コンテナ型仮想化技術やLinux等の知識も必須になってきます。
Kubernetesは深淵の海のように範囲が広く深いため、学習コストは高いですが、オンプレミスのインフラ経験を活かしてステップアップすることは十分に可能です。インフラエンジニアからDevOpsエンジニアへの階段を登りましょう。
(※)日本で言うインフラエンジニアは、オンプレミスのサーバ(OS/MW)・ネットワーク等幅広いですが、海外にならい開発と運用を組み合わせたDevOpsというアプローチとともに、SRE(Site Reliability Engineering)をイメージしています。
参考
本記事で記載している一部のサンプルコードは、以下の書籍を参考にしています。
出典:日本語版「入門 Kubernetes」Kelsey Hightower、Brendan Burns、Joe Beda 著、オライリー・ジャパン、ISBN978-4-87311-840-6