順を追って学ぶKubernetesのキホン〜ローカル環境でKubernetesクラスターを作成してKubernetesの概念を理解する〜


こちらの記事は、Jonathan Natanael Siahaan 氏により2019年 10月に公開された『 Step by Step Introduction to Basic Concept of Kubernetes 』の和訳です。
本記事は原著者から許可を得た上で記事を公開しています。

Kubernetesを聞いたことがありますか?
興味があることは間違いないはずです。
だからこそこの記事を開いたのでしょう。

この記事では、Kubernetesの基本概念とその使い方について説明します。

最終的には、Minikube上で動くKubernetesを使用してdockerコンテナを動かします。

クラウドの有料アカウントは必要ありません。

Kubernetesとは何か?

Kubernetesは、Googleが作成したオープンソースのプラットフォーム/ツールです。
GO-Langで書かれています。
そのため、現在KubernetesはApache 2.0ライセンスの下でのオープンソースプロジェクトとなっています。
業界では、Kubernetesは「K8s」としても知られています。
Kubernetesを使うと、プライベート、パブリック、およびハイブリッドクラウド環境で任意のLinuxコンテナを動かすことができます。
Kubernetesは、ロードバランサー、サービスディスカバリー、ロールベースアクセス制御(RBAC)などの周辺機能も提供します。

(訳注)サービスディスカバリーとは、サービスとIPを紐づける機構のこと。これによりコンテナの作成・削除に伴ってIPが変わっても通信が可能となる。

なぜKubernetesが必要なのか?

答えは、コンテナの管理を支援するためです。
多くのコンテナを使用しマイクロサービスパターンで本番環境を運用する場合、多くのことを確認する必要があります。
ヘルスチェック、バージョン管理、スケーリング、ロールバック機構など。
これら全てが正常であることを確認するのは非常にイライラするでしょう。
Kubernetesは、コンテナを大規模にデプロイするために必要なオーケストレーションおよび管理機能を提供します。
Kubernetesのオーケストレーション機能を使用すると、複数のコンテナにまたがるアプリケーションサービスを構築し、クラスター全体でそのコンテナのスケジューリング、コンテナのスケーリング、そしてコンテナの状態を管理し続けることができます。
一言で言えば、Kubernetesは多くの部下(コンテナ)を持つマネージャーのようなものです。
マネージャーのすることは、部下が実施する必要のあることを、できるように取り計らうことです。

Kubernetesを使用する前に、新しいマイクロサービスをデプロイするためのインフラを用意する必要があります。
これには数日から数週間かかるでしょう。
Kubernetesが無かったら、大規模なチームはデプロイフローを手動でスクリプト化しなければならないでしょう。
Kubernetesがあると、デプロイスクリプトを手動で作成する必要が無くなり、DevOpsに費やす時間とリソースが減ります。

Kubernetesの主な機能:

(訳注)一部のユーザにのみ展開する手法のこと。

Kubernetesはどう動いているのか?

公式ドキュメントを読んでKubernetesを始めると、用語が多く出てきて圧倒されるかもしれません。
概念をより深く理解するには、概要が必要な場合があります。
ここでは、Kubernetesアーキテクチャの完全な概要図を示します。

お役に立てば幸いです。

デプロイの流れ:
DevOps -> API Server -> Scheduler -> Cluster ->Nodes -> Kubelet -> Container Engine -> Pod内にコンテナ作成

アプリユーザーのリクエストの流れ:
App user -> Kube proxy -> Pod -> Container(ここでアプリが動きます)

Kubernetesのアーキテクチャ図

図を見るとわかるように、理解できない用語が多くあります。一つづつ説明します。

Master

Masterは、クラスターを制御する要素です。

Masterには3つの要素があります。

  • API Server: RESTfulインターフェイスを通じてKubernetesの機能を提供し、クラスターの状態を保持するアプリケーション。
  • Scheduler: Schedulerは新しいPod要求を受けつけるためにAPI Serverを監視します。 Nodeと通信して新しいPodを作成し、リソースを割り当てたり制約を課しながらNodeにタスクを割り当てます。
  • Controller Manager: Controllerを動かすMaster上の要素。 Node controller、Endpoint Controller、Namespace Controllerなどが含まれます。

Slave(Node)

この機構は、要求され割り当てられたタスクを実行します。
KubernetesのMasterがそれらを制御します。Node内には4つの要素があります。

  • Pod: 全てのコンテナはPod内で動きます。 Podは、内部にあるコンテナからネットワークとストレージを抽象化します。 アプリはここで動きます。
  • Kubelet: KubeletはNodeをクラスターに登録し、Schedulerからのタスク割り当てを監視し、新しいPodをインスタンス化し、Masterに報告します。 (訳注)原文では「Kubectl registering ...」とあり、Kubectlが出てきていますが、誤記と思われるため、「Kubelet registering ...」と解釈し翻訳しています。なお、KubectlはKubernetesのCLIツールです。
  • Container Engine: コンテナの管理、イメージのプル、コンテナの停止、コンテナの起動、コンテナの削除などを担当します。
  • Kube Proxy: アプリユーザーのリクエストを適切なPodに転送します。 退屈だと思うので、ここでは詳細な概念は説明しませ ん。

この記事はもっとざっくりで楽しいはずです。

詳細については、公式ドキュメントをご覧ください。

こちらをクリックしてください。

DockerとKubernetesのハンズオン

そろそろ手を動かしてみましょう。
このセクションでは、Github上の既存のdockerプロジェクトを使用し、Kubernetesに焦点を当てます。
Minikubeを使用します。
Minikubeは、Kubernetesをローカルで簡単に動かせるツールです。

  1. Minkubeのインストール
    このMinikube公式インストールドキュメントに従って実施してみてください。

  2. 以下の手順に従ってください

Minikubeを起動してクラスターを作成します

minikube start

ローカルの作業ディレクトリ内にこのリポジトリをクローンします

git clone https://github.com/buildkite/nodejs-docker-example.git

ご自身のDockerクライアントがMinikubeのDockerデーモンを指すようにします

eval $(minikube docker-env)

上記でクローンしたリポジトリのディレクトリに移動します。

cd nodejs-docker-example

このコマンドを使用してDockerイメージを作成し、ローカルで動かせることを確認します。

docker build -t example-node-app .

Dockerイメージが正常に作成されたことを確認します。

docker images

example-node-appという名前の既存の イメージを使ってKubernetes Deploymentを作成しましょう。そのイメージは簡易なNodeのHTTPサーバーで、3000番ポートで公開します。
ファイルを作成し、deployment-script.yaml という名前にします。

deployment-script.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
 name: kubernetes-deployment
 namespace: default
 labels:
   app: node-app
 spec:
   replicas: 1
   selector:
     matchLabels:
       app: node-app
   template:
     metadata:
       labels:
         app: node-app
     spec:
       containers:
         - name: node-app-container
           image: example-node-app
           resources: {}
           imagePullPolicy: IfNotPresent
       restartPolicy: Always
       terminationGracePeriodSeconds: 30
terminationGracePeriodSeconds: 30

それから

kubectl apply -f deployment-script.yaml

これでnode-app Podが起動し、node-appコンテナ がPod内で動きますが、公開Service経由でアクセスするには、Podが立ち上がるまで待つ必要があります。

Podが立ち上がっているかどうかを確認します:

kubectl get pod

Podが立ち上がって、動いています

NAME                              READY     STATUS    RESTARTS   AGE
node-app-3383150820-vctvh         1/1       Running   0          13s

喜ぶのはまだ早いです。

ここで終わりではありません。

Podにアクセスするには、サービスプロキシが必要です。

ロードバランサーサービスを作成し、targetPort(宛先ポート):3000port(ユーザーへの公開ポート):8000とします。
下記内容でnode-app-service.yamlというファイルを作成します。

node-app-service.yaml
kind: Service
apiVersion: v1
metadata:
 name: node-app-service
 namespace: default
 labels:
   app: node-service
spec:
 ports:
   - protocol: TCP
     port: 8000
     targetPort: 3000
 selector:
   app: node-app
 type: LoadBalancer
 sessionAffinity: None
 externalTrafficPolicy: Cluster
status:
 loadBalancer: {}

実行:

kubectl apply -f node-app-service.yaml

サービスに関する情報を取得するには:

kubectl get service

これが表示されます:

NAME             Type         EXTERNAL-IP  PORT(S)         AGE
node-app-service LoadBalancer <pending>    8000:31386/TCP  36m

サービスを作成した後、クラウドインフラを使っている場合は、ロードバランサーを作成して、そのIPアドレスをServiceオブジェクトに書き込むのには時間がかかります。
さて、時間が経っても 外部IP がまだ保留になっているのはなぜでしょう?

ロードバランサーサービス をサポートしない環境でKubernetesが動いている場合、ロードバランサーは作成されません。
その場合、サービスに付与できるIPが必要です。

Minikube IPを使用できます。

minikube ip

表示されたMinikube IPをコピーし、EXTERNAL-IPサービスに付与します

kubectl patch svc node-app-service  -p '{"spec": {"type": "LoadBalancer", "externalIPs":["YOUR_MINIKUBE_IP"]}}'

サービスに関する情報の表示:

kubectl get service

結果:

NAME             Type         EXTERNAL-IP      PORT(S)         AGE
node-app-service LoadBalancer 192.168.99.100   8000:31386/TCP  36m

これで、そのIPアドレスでサービスにアクセスするか、Webブラウザーでアクセスできます。

curl 192.168.99.100:8000

補足

Kubernetesクラスターを表示するインタラクティブなUIが必要ですか?

ダッシュボードUIはデフォルトでは入っていません。入れるには:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml

デフォルトでは、Kubernetesダッシュボードのユーザーは権限が制限されています。

このセクションでは、管理者レベルの権限でダッシュボードに安全に接続するのに使用する、eks-adminというサービスアカウントとクラスタロールバインディングを作成します。

下記内容でeks-admin-service-account.yamlというファイルを作成します。
このマニフェストは、eks-adminというサービスアカウントとクラスターロールバインディングを定義しています。

apiVersion: v1
kind: ServiceAccount
metadata:
 name: eks-admin
 namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
 name: eks-admin
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
- kind: ServiceAccount
 name: eks-admin
 namespace: kube-system

サービスアカウントとクラスターロールバインディングをクラスターに適用します。

kubectl apply -f eks-admin-service-account.yaml

eks-adminサービスアカウントの認証トークンが必要です。
出力結果から<authentication_token>の値をコピーします。このトークンを使用して、ダッシュボードに接続します。

kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')

出力結果:

Name:         eks-admin-token-b5zv4
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name=eks-admin               kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
Type:  kubernetes.io/service-account-token
Data
====
ca.crt:     1025 bytes
namespace:  11 bytes
token:      <authentication_token>

kubectlコマンドラインツールで次のコマンドを実行して、ダッシュボードにアクセスできます。

kubectl proxy

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#!/login
にアクセスできます

Tokenを選択し、前のコマンド出力結果の<authentication_token>の値をTokenフィールドに貼り付けて、SIGN INを選択します。

参考文献

Kubernetes Documentation
Amazon EKS

やったね、これで終わりです🤗

楽しんでいただけましたでしょうか。

下にコメントをください。

問題が発生した場合は、コメントを残してください。対応いたします😉
このリポジトリhttps://github.com/contentful/the-example-app.nodejsを作成した方に感謝します。この記事の中でサンプルアプリとして使用することができました。
また別の記事でお会いしましょう!

関連記事

翻訳協力

Original Author: Jonathan Natanael Siahaan
Thank you for letting us share your knowledge!

この記事は以下の方々のご協力により公開する事が出来ました。
改めて感謝致します。
選定担当: yumika tomita
翻訳担当: @satosansato3
監査担当: @nyorochan
公開担当: asuma yamada

ご意見・ご感想をお待ちしております

今回の記事は、いかがだったでしょうか?
・こうしたら良かった、もっとこうして欲しい、こうした方が良いのではないか
・こういったところが良かった
などなど、率直なご意見を募集しております。
いただいたお声は、今後の記事の質向上に役立たせていただきますので、お気軽にコメント欄にてご投稿ください。
みなさまのメッセージをお待ちしております。