Edited at

独学Kubernetes コンテナ開発の基本を最速で理解する


はじめに

本記事は、これから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と呼ばれます。

ss_2.png

コンテナを実行するために、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等多様なランタイムが登場すると見込まれており、コンテナ型仮想化技術の動向踏まえて、今後も目が離せません。


アーキテクチャ

k8s_arc.png


  • Kubernetesを構成する要素はリソースとして区別され、Kubernetes Cluster(以降、クラスタ)はKubernetesの管理するリソースの集合体である

  • NodeはKubernetes クラスタで管理されるDockerホストであり、MasterとNodeに区別される

  • クラウドサービスで提供されるGKEの様なマネージドサービスでは、開発者がMasterを意識することはほとんどない

  • Kubernetes クラスタのリソースに対する操作は標準化されたAPIによる行う

  • Deploymentを1つの単位として、アプリケーションをデプロイする


Kubernetesのコンポーネント

k8s_com.png

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, andKubernetesから、知ることができます。


その他

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がインストール済み


  1. 画面上部のDockerアイコンから、「Preferences」をクリックして、「Kubernetes」を選択します。

    スクリーンショット 2019-03-02 09.17.34.png


  2. 「Install」をクリックします。

    スクリーンショット 2019-03-02 09.18.10.png


  3. インストールが始まるので少し待ちます。

    スクリーンショット 2019-03-02 09.18.42.png


  4. インストールが終わったら「Close」をクリックして、「Kubernetes is running」と緑色で表示されたら正常に起動しています。

    スクリーンショット 2019-03-02 09.21.12.png



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」をクリックします。

(※)実際に運用で使用する際は、認証機能を使用した方がセキュリティ的に望ましいです。

スクリーンショット 2019-03-02 09.37.21.png

ダッシュボードが表示されます。

スクリーンショット 2019-04-17 19.12.27.png


トークンの取得方法

ダッシュボードログイン時に、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



公式


GitHub