サーバーサイドエンジニアがKubernetesに入門してみた

はじめに

こんにちは。ラクマでサーバーサイドエンジニアをやっているYuです。 このあいだ半年ぶりに出社したら、強いノスタルジーを感じてしまいました。

業務時間の10%を委員会活動に使えるのですが、私は半年以上KubernetesなどのCNCFのプロジェクトを触っていました。 今回は、そこで学んだ内容をもとにKubernetesについてお話したいと思います。Kubernetesという言葉を聞いたことはあるけれども触ったことはない、ぐらいの方をターゲットにしています。

目次

  • Kubernetesについて
  • Kubernetesを触ってみる

Kubernetesについて

Kubernetesとは?

公式ドキュメントをみると、以下のようにあります。

Kubernetesは、宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォームです。 https://kubernetes.io/ja/docs/concepts/overview/what-is-kubernetes/

これはちょっと抽象的です。私は以下のように考えます。

  • コンテナ実行環境
  • PodをはじめとしたリソースをRestAPIで操作できる
  • 宣言した理想状態を保つように、オートリカバリやオートスケールが行われる

コンテナ実行環境

これはほとんどの人が納得できることと思います。

PodをはじめとしたリソースをRestAPIで操作できる

Podとは、ネットワークとストレージを共有し、密接に結合したコンテナのグループのことです。 KubernetesのAPIによって、Podを含むインフラのリソースをRestAPIで操作することができます。 なので、操作がわかりやすく、使いやすいです。

宣言した理想状態を保つように、オートリカバリやオートスケールが行われる

Kubernetesでは、マニフェストファイルというものを書きます。 そのマニフェストファイルに宣言されている状態を保つようにオートリカバリやオートスケールが行われます。

Kubernetesの構成

次に中身をみてみましょう。

f:id:Rakuma:20200918155602p:plain
Khtan66 - 投稿者自身による作品, CC 表示-継承 4.0, https://commons.wikimedia.org/w/index.php?curid=53571935による

上半分の緑色がコントロールプレーン、下半分の青色がデータプレーンになります。 開発者はコントロールプレーンに向けてRestAPIを叩き、データプレーンのリソースが操作されます。 たとえば、nginxのPodを3つ作りたいとAPIを叩けば、データプレーン上にnginxのPodが3つ作成されます。

Podには内部IPアドレスが割り当てられます。 Podは作られたり壊されたりとせわしなく変化するので、適切にPodにアクセスするためには、抽象化が必要になります。 その抽象化を担うのがServiceです。以下の図がわかりやすいです。

f:id:Rakuma:20200918162242p:plain Marvin The Paranoid - 投稿者自身による作品, CC 表示-継承 4.0, https://commons.wikimedia.org/w/index.php?curid=75140812による

PodへのアクセスはService Xによって抽象化されていることがわかります(PodへのアクセスはすべてService Xを経由しています)。

Kubernetesを触ってみる

それでは少し触ってみたいと思います。 minikubeというローカル環境用のクラスタを使いたいと思います。 動作確認しているバージョンは以下になります。

minikube: v1.12.3
kubectl-client-version: v1.18.3
kubectl-server-version: v1.18.3

環境構築については、公式ドキュメントを参照してください。 kubernetes.io

環境構築ができたら、はじめましょう。minikubeを起動しておいてください。

$ minikube start

先ほど、マニフェストファイルというものを書きます、と話していました。 まずはこれを作ってみましょう。ターミナルで以下を実行してください。

$ kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10 –dry-run –o yaml > deployment.yml

このコマンドの意味はこうです。

  • createします
  • deploymentを(deploymentは同一のPodを複数集めたものとお考えください)
  • hello-minikubeという名前で
  • k8s.gcr.io/echoserver:1.10というDockerイメージから
  • dry runしてyamlファイルにアウトプットします

これでマニフェストファイルができました。中身は以下のようになっているはずです。(バージョンによって多少内容は異なります)

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: hello-minikube
  name: hello-minikube
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-minikube
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: hello-minikube
    spec:
      containers:
      - image: k8s.gcr.io/echoserver:1.10
        name: echoserver
        resources: {}
status: {}

なんとなく、コマンドの内容とマニフェストの内容の関係性を確認できると思います。 今回はせっかくなので、replicas: 3にしておきましょう。これでPodが3つ作成されるようになります。

...
spec:
  replicas: 3
  selector:
...

これでdeployment(Podの集合)のマニフェストファイルは完成です。まずはこれをデプロイしてみましょう。

$ kubectl apply -f deployment.yml

確かにデプロイできていることは以下で確認できます。

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
hello-minikube-64b64df8c9-4dxpc   1/1     Running   0          4s
hello-minikube-64b64df8c9-jgmch   1/1     Running   0          4s
hello-minikube-64b64df8c9-nhc67   1/1     Running   0          4s

次に、このPodを公開するためのServiceを作成しましょう。先ほどと同様に以下コマンドを実行してください。

kubectl expose deployment hello-minikube --type=LoadBalancer --port=8080 –dry-run –o yaml > service.yml

type=LoadBalancerとありますが、これはPodをKubernetesクラスタの外部に公開するときに使うServiceになります。

これでマニフェストファイルができました。中身は以下のようになっているはずです。(バージョンによって多少内容は異なります)

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: hello-minikube
  name: hello-minikube
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: hello-minikube
  type: LoadBalancer
status:
  loadBalancer: {}

では、以下のコマンドを実行してServiceもデプロイしましょう。

$ kubectl apply -f service.yml

確かにデプロイできていることは以下で確認できます。

$ kubectl get svc
NAME              TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
hello-minikube    LoadBalancer   10.99.50.109     <pending>     8080:30182/TCP   11s

それでは最後に、デプロイしたPodにアクセスしてみましょう。以下を実行してください。 ブラウザが開き、Pod内のechoサーバーへのアクセスができるはずです。

$ minikube service hello-minikube

おまけ

せっかくなので少し遊んでみましょう。 以下スクリプトを実行してみると、3つのPodへアクセスがロードバランシングされていることを確認できます。 (実行時の第一引数にminikube serviceコマンドで表示されたURIを渡してください。例: http://127.0.0.1:58183)

#!/bin/sh

URL=$1;

while true;
do
    sleep 1;
    curl -s $URL | grep Hostname
done

このスクリプトを実行したまま、Podを削除してみると、Pod数を3に維持しながらロードバランシングされていることも確認できます。 Podの削除は以下のコマンドです。

$ kubect delete pods <PodのNAME>