LoginSignup
478

More than 1 year has passed since last update.

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

Last updated at Posted at 2019-04-30

はじめに

本記事は、これから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, 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がインストール済み

  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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
478