关于Kubernetes的相关内容

最初

作为之前关于Docker学习的延续,我将总结学习Kubernetes的内容。我认为我已经涵盖了Kubernetes的基本概念和命令,希望您在学习时可以参考。

■Kubernetes 是什么

Kubernetes是一种用于管理Docker等容器的工具。在处理多个主机上的容器时非常方便。

Docker run和docker-compose的区别在于是管理多个容器还是单个容器。但是,在这种情况下,如果主机消失,容器也会消失。因此,需要创建多个主机,并将多个容器分配给这些创建的主机集群,这就是容器编排工具。最常用的容器编排工具是Kubernetes。

使用Kubernetes的好处包括以下几点:
– 可以在多个主机上对多个容器进行负载均衡和工作负载分散。
– 即使一个Pod(容器)停止,也可以进行自动修复。
– 可以进行无停机更新(滚动更新)。
– 可以在应用程序运行期间进行扩展和缩小。

■学习环境

– 学习的地方或条件

如果要在本地环境中构建学习环境,请参考以下文章进行安装。
https://qiita.com/khara_nasuo486/items/08d7918690c4416ec28c
此外,作为可以在网页上使用Kubernetes的站点,我在此提供以下信息。如果对在本地环境中构建环境感到麻烦,请使用此站点。
https://labs.play-with-k8s.com/

■关于Kubernetes中的节点

在Kubernetes中,通过从客户端发送命令到类似于Docker中的守护程序的节点,这些节点被称为主节点,并且主节点接收到命令后会将其发送到工作节点,这就构成了一种结构。

作为主节点的角色,可以列举以下几点:
– 控制集群
– 调度和生命周期监控
– 负载均衡和自动修复

工作节点的角色如下所示:
– 服务器上执行容器
– 在多个节点上形成集群
– 根据主节点的命令创建或删除Pod

客户端是指写入执行命令的控制台,但在Kubernetes上,通过kubectl命令可以创建包含各种设置的清单文件,或者根据清单文件指示主节点对资源进行操作。

■使用Hello World进行亲自体验指导

▶Kubernetes容器组启动

Pod被称为将容器组成一个组的虚拟主机。Pod是Kubernetes管理的基本单位,它具有共享虚拟网络接口(相同的IP和文件系统)的能力,因此扮演着虚拟主机的角色。

我们将看一下如何创建这样的Pod并确认信息。

●使用kubectl运行

首先是启动Pod。通过执行下面的命令,可以启动Pod。在这种情况下,我想要启动Pod,所以加入了”–restart Never”选项,但根据创建的对象的不同,需要进行相应的更改。

kubectl run –image [イメージ名]:[タグ名] –restart Never [Pod名]

=====HelloWorldのイメージ=====
$kubectl run --image hello-world:latest --restart Never helloworld

#####実行結果#####
pod/helloworld created

可以像docker run一样,使用kubectl run命令指定多种选项。例如,通过使用-e选项可以设置环境变量。有关其他选项的详细信息,请参考以下页面:
https://kubernetes.io/ja/docs/reference/kubectl/overview/

●查看kubectl列表

要显示Pod的列表,请执行以下命令。

$kubectl get pod

#####実行結果#####
NAME         READY   STATUS      RESTARTS   AGE
helloworld   0/1     Completed   0          3m6s
●查看 kubectl 的日志

如果想查看Pod的日志,请执行以下命令。

kubectl logs [Pod名]

=====HelloWorldのイメージ=====
$kubectl logs helloworld

#####実行結果#####
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
kubectl 详细描述

如果你想查看Pod的元数据,请执行下面的命令。

kubectl describe pod [Pod名]

=====HelloWorldのイメージ=====
$kubectl describe pod helloworld

#####実行結果#####
Name:         helloworld
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Mon, 18 Jul 2022 15:18:17 +0900
Labels:       run=helloworld
Annotations:  <none>
Status:       Succeeded
IP:           172.17.0.3
IPs:
  IP:  172.17.0.3
Containers:
  helloworld:
    Container ID:   docker://c9c20f5ebe1ffe3d5f69767e80f6f3ae0c515bb743028a38ab66f169c010b0af
    Image:          hello-world:latest
    Image ID:       docker-pullable://hello-world@sha256:53f1bbee2f52c39e41682ee1d388285290c5c8a76cc92b42687eecf38e0af3f0
###############################中略###############################
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  11m   default-scheduler  Successfully assigned default/helloworld to minikube
  Normal  Pulling    11m   kubelet            Pulling image "hello-world:latest"
  Normal  Pulled     11m   kubelet            Successfully pulled image "hello-world:latest" in 4.342894157s
  Normal  Created    11m   kubelet            Created container helloworld
  Normal  Started    11m   kubelet            Started container helloworld
●删除kubectl

执行下面的命令以删除创建的Pod。

kubectl delete pod [Pod名]

=====HelloWorldのイメージ=====
$kubectl delete pod helloworld

#####実行結果#####
pod "helloworld" deleted
●运行kubectl exec命令

为了进入创建的Pod中,请执行以下命令。

kubectl exec -it [Pod名] [シェル名]

=====HelloWorldのイメージ=====
$kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
$kubectl exec -it helloworld sh

#####実行結果#####
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ #

通过Service在集群内外进行公开。

●来自簇内部的连接

首先,我们将从集群内部进行连接确认。我们创建一个包含curl容器的Pod,并进行Shell连接,然后对helloworld Pod进行Curl访问测试。

$kubectl run --port 8080 --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
$kubectl get pod

#####実行結果#####
NAME         READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
helloworld   1/1     Running   0          3m25s   172.17.0.3   minikube   <none>           <none>
$kubectl run --image curlimages/curl:latest -it --restart Never --rm curl sh

#####開いたシェルで下記を入力#####
#curl 172.17.0.3:8080

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

通过查看这个结果,我们可以看到通过在curl中指定helloworld的IP地址为”172.17.0.3″,并开放端口8080,通过这样指定,我们可以确认curl容器可以连接到hellorowld容器。
为了确认其存在于内部,我们需要在curl容器处于运行状态时,通过显示包括IP在内的pod列表(使用-o wide选项),结果如下,我们可以确认它确实存在于相同的网络中。

$kubectl get pod -o wide

#####実行結果#####
NAME         READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
curl         1/1     Running   0          2m43s   172.17.0.4   minikube   <none>           <none>
helloworld   1/1     Running   0          2m53s   172.17.0.3   minikube   <none>           <none>
●来自集群外部的连接

接下来进行与群集外的连接,但说实话,这是不可能的。这与Docker的情况相同,主机的IP和Pod的IP范围不同。因此,为了使其可访问,需要创建一个称为Service的实体来公开Pod到外部。

Service是指具有静态IP地址的L4负载平衡器,用于将Pod发布到集群内外。由于无法确定Pod何时停止和消失,因此需要将原始Service公开。

服务有三种类型,每种类型都具有以下特点:
– ClusterIP Service(集群内连接)
通过将具有不确定消失时间的Pod IP进行抽象化,并放置具有静态IP的代理,可以获得以下优点:
1. 在访问Pod时,无需知道Pod的IP。
2. 在访问Pod时,可以进行负载均衡。

– NodePort Service(集群内外连接)
NodePort Service可以通过Node IP和Node Port来实现对集群外的Pod进行公开,这是ClusterIP无法实现的优点。然而,存在以下缺点:
1. 需要知道Node IP。
2. 需要知道Node Port。

– LoadBalancer Service(集群内外连接)
通过从提供商的L4负载均衡器DNS路由到每个节点的特定端口来访问Pod,因此不需要了解Node IP和Node Port。然而,也存在以下缺点:
1. 每个Service都需要创建一个负载均衡器,成本较高。
2. 由于是L4负载均衡器,无法进行基于L7的HTTP主机和路径的负载均衡分配。

我们将逐一确认上述每个服务的内容。

●集群 IP 服务

我们将把HelloWorld Pod作为ClusterIP的Service,在集群内部进行公开,以便可以从同一集群内的其他Pod访问。
通过在以下启动的Pod上指定–type ClusterIP选项,可以将其作为ClusterIP的Service进行公开。

kubectl expose pod [Pod名] --type ClusterIP [Service名]

=====helloworld Podをhelloworld-clusteripというService名で公開=====
$kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
$kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip

#####実行結果#####
service/helloworld-clusterip exposed

通过使用下面的命令,可以获取服务的列表。

$kubectl get service

#####実行結果#####
NAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
helloworld-clusterip   ClusterIP   10.102.43.35   <none>        8080/TCP   4m43s
kubernetes             ClusterIP   10.96.0.1      <none>        443/TCP    10h

通过这个结果,我们可以确认确实创建了类型为ClusterIP的服务。

然后,重新启动 curl 容器,并通过 helloworld-clusterip 访问 helloworld。

$kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh 

#####開いたシェルで下記を入力#####
$curl 10.102.43.35:8080

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

根据此结果,确认可以访问helloworld。这个结果与前面解释的”从集群内连接”的部分的结果相同。然而,前面所做的是从curl容器直接连接到helloworld容器。
本次所做的结果是从curl容器访问helloworld-clusterip服务,然后通过负载均衡(由于只创建了一个Pod,所以具体是特定的Pod)的功能,服务将访问helloworld。
因此,由于意义不同,需要注意。

●节点端口服务

我们将把HelloWorld Pod作为NodeIP的Service在集群内外进行公开,并确保其他Pod可以从同一集群内访问它。您可以通过在下面示例的Pod启动命令中指定选项”–type NodePort”来将其作为ClusterIP的Service进行公开。

kubectl expose pod [Pod名] --type NodePortIP [Service名]

=====helloworld Podをhelloworld-nodeportというService名で公開=====
$kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
$kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport

#####実行結果#####
service/helloworld-nodeport exposed

下記コマンドを用いることでServiceの一覧を取得します。

$kubectl get service

#####実行結果#####
NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
helloworld-nodeport   NodePort    10.107.162.126   <none>        8080:30224/TCP   57s
kubernetes            ClusterIP   10.96.0.1        <none>        443/TCP          11h

この結果、確かにType NodeportのServiceが作成されていることが確認できます。

まずは同一クラスタ内からアクセスできることを確認します。手順はClusterIPの場合と同じです。

$kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh 

#####開いたシェルで下記を入力#####
$curl 10.107.162.126:8080

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

この結果、helloworld-nodeportを経由してhelloworldにアクセスが行えたことが確認できました。

次にクラスタ外(ローカル環境)からアクセス可能なことを確認していきます。接続のためにminikubeのIPが必要となるので、下記のコマンドを実行しIPを取得します。

$minikube ip

#####実行結果#####
192.168.49.2

このIPに対して、curlコマンドをローカル環境で実行してアクセスを行います。この際、ポートはPod側の30224を指定します。

$curl 192.168.49.2:30224

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

この結果、helloworldにアクセスが行えたことが確認できました。(minikube起動時の設定によって、アクセスできない場合があるようです。その場合はminikube service –url helloworld-nodeportコマンドを実行し、出力されたurlに対してcurlコマンドを実行してください。)

负载均衡器服务

HelloWorld PodをNodeIPのServiceとして、クラスタの内外に公開し、同一クラスタ内の別のPodからアクセス可能なことを見ていきます。
下記のように起動しているPodに対して–type LoadBalancerオプションを指定することでClusterIPのServiceとして公開を行うことができます。

kubectl expose pod [Pod名] --type NodePortIP [Service名]

=====helloworld Podをhelloworld-loadbalancerというService名で公開=====
$kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
$kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-loadbalancer

#####実行結果#####
service/helloworld-loadbalancer exposed

下記コマンドを用いることでServiceの一覧を取得します。

$kubectl get service

#####実行結果#####
NAME                      TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
helloworld-loadbalancer   LoadBalancer   10.105.4.118   <pending>     8080:31006/TCP   37s
kubernetes                ClusterIP      10.96.0.1      <none>        443/TCP          11h

この結果、確かにType LoadBalancerのServiceが作成されていることが確認できます。

まずは同一クラスタ内からアクセスできることを確認します。手順はClusterIPの場合と同じです。

$kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh 

#####開いたシェルで下記を入力#####
$curl 10.105.4.118:8080

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

通过helloworld-LoadBalancer,我们确认能够访问到helloworld。

接下来,我们将确认集群外(本地环境)可以访问。

$curl $(minikube service helloworld-loadbalancer --url)

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

この結果、helloworldにアクセスが行えたことが確認できました。

▶Ingressを用いたクラスタ外部への公開

IngressとはPodをクラスタ内外に公開するL7(httpに基づいて振り分け可能)のロードバランサのことです。クラスタ外部からのURLのホスト・パスによるServiceの振り分けが可能となります。外部からのアクセスはパブリックDNSを用いて行います。

これを用いる方法を見ていきます。下記コマンドを用いて、minikubeにIngressのアドオンを有効化します。

$minikube addons enable ingress

然后执行以下命令,在minikube上显示插件列表,并确认ingress已启用(enable)。

$minikube addons list

#####実行結果#####
|-----------------------------|----------|--------------|--------------------------------|
|         ADDON NAME          | PROFILE  |    STATUS    |           MAINTAINER           |
|-----------------------------|----------|--------------|--------------------------------|
| ambassador                  | minikube | disabled     | 3rd party (Ambassador)         |
| auto-pause                  | minikube | disabled     | Google                         |
| csi-hostpath-driver         | minikube | disabled     | Kubernetes                     |
| dashboard                   | minikube | disabled     | Kubernetes                     |
| default-storageclass        | minikube | enabled ✅   | Kubernetes                     |
| efk                         | minikube | disabled     | 3rd party (Elastic)            |
| freshpod                    | minikube | disabled     | Google                         |
| gcp-auth                    | minikube | disabled     | Google                         |
| gvisor                      | minikube | disabled     | Google                         |
| headlamp                    | minikube | disabled     | kinvolk.io                     |
| helm-tiller                 | minikube | disabled     | 3rd party (Helm)               |
| inaccel                     | minikube | disabled     | InAccel <info@inaccel.com>     |
| ingress                     | minikube | enabled ✅   | 3rd party (unknown)            |
| ingress-dns                 | minikube | disabled     | Google                         |
| istio                       | minikube | disabled     | 3rd party (Istio)              |
| istio-provisioner           | minikube | disabled     | 3rd party (Istio)              |
| kong                        | minikube | disabled     | 3rd party (Kong HQ)            |
| kubevirt                    | minikube | disabled     | 3rd party (KubeVirt)           |
| logviewer                   | minikube | disabled     | 3rd party (unknown)            |
| metallb                     | minikube | disabled     | 3rd party (MetalLB)            |
| metrics-server              | minikube | disabled     | Kubernetes                     |
| nvidia-driver-installer     | minikube | disabled     | Google                         |
| nvidia-gpu-device-plugin    | minikube | disabled     | 3rd party (Nvidia)             |
| olm                         | minikube | disabled     | 3rd party (Operator Framework) |
| pod-security-policy         | minikube | disabled     | 3rd party (unknown)            |
| portainer                   | minikube | disabled     | Portainer.io                   |
| registry                    | minikube | disabled     | Google                         |
| registry-aliases            | minikube | disabled     | 3rd party (unknown)            |
| registry-creds              | minikube | disabled     | 3rd party (UPMC Enterprises)   |
| storage-provisioner         | minikube | enabled ✅   | Google                         |
| storage-provisioner-gluster | minikube | disabled     | 3rd party (unknown)            |
| volumesnapshots             | minikube | disabled     | Kubernetes                     |
|-----------------------------|----------|--------------|--------------------------------|

然后执行以下命令,确认 Ingress controller pod 已被创建。

$kubectl get pods -n ingress-nginx

#####実行結果#####
NAME                                        READY   STATUS      RESTARTS      AGE
ingress-nginx-admission-create-g95fq        0/1     Completed   0             27m
ingress-nginx-admission-patch-6t9vb         0/1     Completed   0             27m
ingress-nginx-controller-755dfbfc65-gflns   1/1     Running     1 (16m ago)   27m

对于 minikube,您可以通过启用插件来创建 Ingress 控制器,但在云环境中,需要安装 Ingress 控制器。

次にアクセスを公開したいパスをyamlで定義する必要があります。今回はhello-world Podを全てのパス「/」で公開するように実施を行います。そのために下記のようなyamlファイルを用います。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: helloworld
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: helloworld-nodeport
                port:
                  number: 8080

このyamlファイルではIngressの名前をhelloworldにして、httpの下にパスに関するルールを記載しているという構造になっています。またpathとして「/」に来たらどのServiceにアクセスさせるのかということをbackendの箇所にて記載していて、この場合はhelloworld-nodeportにポート8080でアクセスすることを定義しています。

このファイルを用いてマニフェストの作成を行います。マニフェストに関しては後ほど説明を行いますが、ここでは設定を反映させる程度の認識でよいです。下記のコマンドを用いて、これを実行します。

$kubectl apply -f ingress.yaml

#####実行結果#####
ingress.networking.k8s.io/helloworld created

执行以下命令以列出Ingress,并确认已创建了由上述命令创建的helloworld的Ingress。

$kubectl get ingress

#####実行結果#####
NAME         CLASS   HOSTS   ADDRESS        PORTS   AGE
helloworld   nginx   *       192.168.49.2   80      4m20s

要查看Ingress资源的详细信息,请执行以下命令。

kubectl describe ingress [Ingress名]

=====helloworldの場合=====
$kubectl describe ingress helloworld

#####実行結果#####
Name:             helloworld
Labels:           <none>
Namespace:        default
Address:          192.168.49.2
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /   helloworld-nodeport:8080 (172.17.0.4:8080)
Annotations:  nginx.ingress.kubernetes.io/rewrite-target: /$1
Events:
  Type    Reason  Age                    From                      Message
  ----    ------  ----                   ----                      -------
  Normal  Sync    7m50s (x2 over 7m54s)  nginx-ingress-controller  Scheduled for sync

可以通过执行以下命令获取Ingress控制器的IP,并使用此IP通过Ingress访问helloworld-nodeport服务。

$kubectl get ingress | awk '{ print $4 }'|tail -1

#####実行結果#####
192.168.49.2

=====Ingress経由でアクセス=====
$curl 192.168.49.2

#####実行結果#####
Hello, world!
Version: 1.0.0
Hostname: helloworld

从这个结果可以看出,成功地通过Ingress访问到了helloworld-nodeport的Service,并且进一步访问到了helloworld Pod。

▶通过复制进行规模扩大

システムの冗長化を行うためにはReplicaというリソースを用います。ReplicaではSpecにて定義したレプリカの数を自動配置・維持(Podが停止した場合に自動修復)する機能を持っています。

こちらもyamlファイルに設定を記載していく必要があります。ここでSampleとして用いるのは下記のようなyamlファイルです。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: helloworld
  labels:
    app: helloworld
spec:
  replicas: 5
  selector:
    matchLabels:
      app: helloworld
  template:
    metadata:
      labels:
        app: helloworld
    spec:
      containers:
        - name: helloworld
          image: gcr.io/google-samples/hello-app:1.0

根据此yaml文件中指定的replicas数值,Pod将被复制。在此文件中,设置为5,因此将创建5个Pod。

使用此YAML文件来将Pod作为ReplicaSet启动,请执行以下命令。

$kubectl apply -f replicaset.yaml

#####実行結果#####
replicaset.apps/helloworld created

为了确认复制集已经被创建,执行以下命令。

$kubectl get replicaset

#####実行結果#####
NAME         DESIRED   CURRENT   READY   AGE
helloworld   5         5         5       3m21s

=====Podを確認=====
$kubectl get pod

#####実行結果#####
NAME               READY   STATUS    RESTARTS   AGE
helloworld-8nkgp   1/1     Running   0          4m32s
helloworld-8rf9j   1/1     Running   0          4m32s
helloworld-jcdgd   1/1     Running   0          4m32s
helloworld-tltwb   1/1     Running   0          4m32s
helloworld-x4mf5   1/1     Running   0          4m32s

可以确认replicaset已经创建,并且显示有5个Pod已经创建。通过显示Pod列表的结果,可以确认确实已经创建了Pod。同时还可以确认这些Pod都是以helloworld-[哈希值]的名称创建的。

在运行期间增加已创建的Pod的数量也是可能的。这可以通过在kubectl scale命令后添加–replicas选项来实现。我们可以以将其增加到10个为例进行尝试。

$kubectl scale --replicas=10 replicaset/helloworld

=====replicasetを確認=====
$kubectl get replicaset

#####実行結果#####
NAME         DESIRED   CURRENT   READY   AGE
helloworld   10        10        10      13m

=====Podを確認=====
$kubectl get pod

#####実行結果#####
NAME               READY   STATUS    RESTARTS   AGE
helloworld-8nkgp   1/1     Running   0          14m
helloworld-8rf9j   1/1     Running   0          14m
helloworld-j6jzt   1/1     Running   0          2m15s
helloworld-jcdgd   1/1     Running   0          14m
helloworld-r8tcj   1/1     Running   0          2m15s
helloworld-tltwb   1/1     Running   0          14m
helloworld-tqb9g   1/1     Running   0          2m15s
helloworld-vmbk7   1/1     Running   0          2m15s
helloworld-wltrq   1/1     Running   0          2m15s
helloworld-x4mf5   1/1     Running   0          14m

当查看执行结果时,可以确认Pod的数量增加到了10个。

我想要尝试停止接下来启动的一个Pod。在这种情况下,当其中一个Pod停止时,replicaset会判断并重新创建Pod。在这个过程中,Pod将被分配一个与停止之前不同的哈希值,因此一个Pod将被改变为另一个哈希值。下面是停止上述的helloworld-8nkgp的情况描述。

$kubectl delete pod helloworld-8nkgp

#####実行結果#####
pod "helloworld-8nkgp" deleted

=====Podの状態確認=====
$kubectl get pod

#####実行結果#####
NAME               READY   STATUS    RESTARTS   AGE
helloworld         1/1     Running   0          23h
helloworld-8rf9j   1/1     Running   0          20m
helloworld-c7gn7   1/1     Running   0          2s
helloworld-j6jzt   1/1     Running   0          8m22s
helloworld-jcdgd   1/1     Running   0          20m
helloworld-r8tcj   1/1     Running   0          8m22s
helloworld-tltwb   1/1     Running   0          20m
helloworld-tqb9g   1/1     Running   0          8m22s
helloworld-vmbk7   1/1     Running   0          8m22s
helloworld-wltrq   1/1     Running   0          8m22s
helloworld-x4mf5   1/1     Running   0          20m

你可以确认在这种情况下,已经自动生成了helloworld-c7gn7来取代停止的helloworld-8nkgp。

滚动更新,回滚

次にDeploymentというリソースを用いてPodのRolling Update、Rollback(無停止更新)を行います。DeploymentではPodのDeploy時に新しいReplicaSetを作成し、古いReplicaSetで管理されているPodを停止させながら、新しいReplicaSetで管理されているPodを作成するという手順を段階的に行います。そのため、新しい(Version Up後等)ReplicaSetに更新後のアプリケーションを載せることで無停止での更新を実現します。上記はUpdateについてですが、Rollback(元の状態に戻す)こともでき、この場合にも同様に停止と起動を段階的に行うことで、無停止でのRollbackを行うことも可能です。
このDeploymentの作成にはkubectl create deploymentコマンドを使用します。

在下面的例子中,我们从tag为1.0的helloworld切换到tag为2.0的helloworld。首先,由于只有一个Pod,切换很难理解,所以我们将Pod扩展到5个。

kubectl create deployment --image [イメージ名] [deployment名]

=====tag 1.0のhelloworld Podの立ち上げ=====
$kubectl create deployment --image gcr.io/google-samples/hello-app:1.0 helloworld

=====deploymentの確認=====
$kubectl get deployment 

#####実行結果#####
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
helloworld   1/1     1            1           17s

=====スケールアップ=====
$kubectl scale --replicas=5 deploy/helloworld

=====deploymentの確認=====
$kubectl get deployment 

#####実行結果#####
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/helloworld   3/3     3            3           13m

次にRolling Updateを行いますが、そのためにはPod群のnameを取得する必要があります。(上記のやり方では各Pod名helloworldとは異なるnameが付く。合わせる方法もあるがここでは解説は行わない)そのために作成したdeploymentを構成するyamlファイルを出力します。出力は下記のコマンドで行えます。

kubectl get deployment helloworl --output yaml

#####出力結果#####
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2022-07-20T13:57:15Z"
  generation: 2
  labels:
    app: helloworld
  name: helloworld
  namespace: default
  resourceVersion: "99302"
  uid: 6fd303f4-c30a-433b-909f-1cb49ffe3d50
spec:
  progressDeadlineSeconds: 600
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: helloworld
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: helloworld
    spec:
      containers:
      - image: gcr.io/google-samples/hello-app:1.0
        imagePullPolicy: IfNotPresent
        name: hello-app
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
status:
  availableReplicas: 3
  conditions:
  - lastTransitionTime: "2022-07-20T13:57:15Z"
    lastUpdateTime: "2022-07-20T13:57:17Z"
    message: ReplicaSet "helloworld-7b8f9795b8" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  - lastTransitionTime: "2022-07-20T14:10:49Z"
    lastUpdateTime: "2022-07-20T14:10:49Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  observedGeneration: 2
  readyReplicas: 3
  replicas: 3
  updatedReplicas: 3

这个输出结果的spec-template-spec-containers-name是Pod群的名称。在这种情况下,它是hello-app,所以我们使用它。使用下面的命令进行滚动更新。

kubectl set image deploy/[deployment名] [上記で取得したname]=[イメージ名]

=====tag2.0のhelloworld Podの立ち上げ=====
$kubectl set image deploy/helloworld helloworld=gcr.io/google-samples/hello-app:2.0

=====途中結果を出力=====
$kubectl get pod

#####出力結果#####
NAME                          READY   STATUS        RESTARTS   AGE
helloworld-666776755c-4x8hl   1/1     Running       0          2s
helloworld-666776755c-qpcdv   1/1     Running       0          2s
helloworld-666776755c-qtvkh   0/1     Pending       0          0s
helloworld-666776755c-tx254   1/1     Running       0          2s
helloworld-7b8f9795b8-4fkmh   1/1     Running       0          12m
helloworld-7b8f9795b8-hdppp   1/1     Terminating   0          12m
helloworld-7b8f9795b8-p8qp6   1/1     Running       0          11m
helloworld-7b8f9795b8-ph7b9   1/1     Running       0          11m

=====最終結果を出力=====
$kubectl get pod

#####出力結果#####
NAME                          READY   STATUS    RESTARTS   AGE
helloworld-666776755c-4x8hl   1/1     Running   0          2m42s
helloworld-666776755c-6cxnv   1/1     Running   0          2m40s
helloworld-666776755c-qpcdv   1/1     Running   0          2m42s
helloworld-666776755c-qtvkh   1/1     Running   0          2m40s
helloworld-666776755c-tx254   1/1     Running   0          2m42s

出力結果を見ることで、古いhelloworldが徐々に削除され、新しいhelloworldが作成されていることが確認できます。今回の出力結果ではPodとして存在している個数が途中経過の時点で8個となっています。これは停止途中に作成が行われたりするために存在しているPodの個数が増えています。この最大個数は運用環境のリソース(メモリなど)によって違いがあります。そのため、最大で何個まで存在できるのかを指定することもできます。詳細については下記記事等を参照ください。
https://qiita.com/Esfahan/items/f9c246e3c60fe8490af3

またRollbackについては下記のコマンドにて実行できます。動きとしては同様となるため、確認は記載しておりません。

$deployment.apps/helloworld rolled back

#####実行結果#####
deployment.apps/helloworld rolled back

■Kubernetes配置文件

ここまでの話では基本的にコマンド内にPod等の情報を記載するようにコマンドを記載し、都度ほしいものが手に入るようにコマンドの例を挙げていきました。例えば一つ前の節のDeploymentを立ち上げ、その後にPod数を増やすといったような書き方が典型例になります。このように都度行いたいことを命令することを命令的であるといいます。この方法ではhowに注目していることになります。
これに対して、最終的に得たい状態を記載して指定して作成を行うことを宣言的といいます。宣言的な場合にはwhatに注目して作成を行っていきます。
Kubernetesでは宣言的な記述方法として、yamlファイル(マニフェスト)に情報を記載するという方法を用います。このyamlファイルの中に最終的に得たいPod等の情報(what)を書き込むことで目的のものをKubernetes側で自動で作成します。このときKubernetesではどのように(how)に作るのかは考える必要はなくなるため、このhowを抽象化できるという点が宣言的な方法のメリットと言えます。

例えば以下の2つは同じことを命令的(kubectl run)に記載したものと宣言的(yaml)に記載したものの例になります。

=====宣言的=====
kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never Helloworld
#=====命令的=====
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - env:
    - name: TEST_ENV
      value: Hello_World
    image: gcr.io/google-samples/hello-app:1.0
    ports:
    - containerPort: 8080

命令的な記載から宣言的な記載への変換は下記のコマンドを通じて行うことも可能です。

$kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld --dry-run -o yaml helloworld > pod.yaml

このyamlを指定して、kubectl runと同じPodを作成するには、kubectl applyコマンドにて、作成したyamlファイルを指定することで可能です。

$kubectl apply -f pod.yaml

次にyamlファイルの記載内容に関してみていきたいと思います。ただし、全てをここに記載すると、量が膨大になるので一部のみ記載し、他の箇所に関しては公式ページ等を参考にしてください。上記で記載したPod.yamlがおそらく最も単純な形になります。ただし大雑把な構成としては同じです。

このyamlファイルの1段目に記載されているものから見ていきます。大きく4つの項目があることがわかると思います。これらはそれぞれ下記のような意味を持ちます。

key意味apiVersion表示させたいKubernetes ObjectのVersionを指定(以下参照)
https://qiita.com/soymsk/items/69aeaa7945fe1f875822kindapiVersion で指定した Kubernetes Object セットの中から使いたいタイプを指定
例:Pod、ReplicaSet、Deploymentmetadataオブジェクトの情報を指定 (名前など一意に特定するための情報specオブジェクトに適用する(したい)ものを指定

上記の4項目はyamlファイルを作成する際には必須の項目となります。また、作成対象の種類によって2段目以降はに記載する内容は変わってくるため、詳細な説明は割愛します。下記のページなどにそれぞれの意味について記載されているので、参照してください。
https://tanakakns.github.io/kubernetes/manifest/

今回作成したファイルについては下記のような設定を記載しています。

1段目2段目3段目説明metadata—-creationTimestamp-ノードの作成時刻残すかの設定-labels-Kubernetes ノード ラベル(下記参照)
https://kubernetes.io/ja/docs/concepts/overview/working-with-objects/labels/-name-namespace内で一意なオブジェクトの名前を設定spec—-containers-コンテナの仕様を設定する–env環境変数をコンテナに指定する–imagedockerイメージのリポジトリとタグ–portsポッド外部からリクエストをうけとるために開いたポートのリスト

■Kubernetesのストレージ

▶配置图 (Pei Zhi Tu)

Config Mapというリソースを用いることで、環境変数などをKey Valueペアで保存することが可能です。Config Mapでは設定した環境変数をvolumeとしてPodにマウントを行います。
環境変数の設定はマニフェスト内のspecの中にenvという項目を設けて、設定することも可能です。しかし、この場合変数の再利用ができなくなってしまします。この問題点をConfig Mapを用いることで解決を行うことができます。

具体的にどのように作成を行うのかについて見ていきます。まずはConfig Mapマニフェストの作成を行います。これはkubectl createコマンドにて、configmapを指定することで実現可能です。下記の例ではyamlファイルの作成を行っています。この場合TEST_ENVという環境変数の中にHello_worldという文字列を格納しています。

$kubectl create configmap my-config --from-literal=TEST_ENV=Hello_World --dry-run -o yaml > configmap.yaml 

上記コマンドを実行して作成したyamlファイルが下記のものになります。

apiVersion: v1
data:
  TEST_ENV: Hello_World
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: my-config

这种情况下,在yaml文件的第一行创建了一个名为”data”的部分,这是指定要创建的节点所具有的数据的项目。在这种情况下,简单地将键“TEST_ENV”对应到值“Hello_world”。

通过使用创建的 yaml 文件来生成节点(kubectl apply),如果要使用环境变量,可以在创建 Pod 时引用该 Config Map 来使用。
通过将以下内容记录在用于生成 Pod 的 yaml 文件中来反映 Config Map 的信息。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - env:
    #Pod内で利用する環境変数名を指定
    - name: TEST_ENV_POD
      #valueFromにてnameで指定した環境変数に何を入れるのかを指定
      valueFrom:
        #configMapから引用することを指定
        configMapKeyRef: 
          #名前がmy-config(上で作成した)というconfigMapを指定
          name: my-config
          #nameで指定したconfigMap内でkeyがTEST_ENVとなっている環境変数を参照することを指定
          key: TEST_ENV
    image: gcr.io/google-samples/hello-app:1.0
    ports:
    - containerPort: 8080

对于上述的Pod.yaml,它是一个用于创建名为helloworld的Pod的yaml文件。在helloworld内部,我们创建了一个名为TEST_ENV_POD的环境变量,并将其值设置为存储在Config Map的TEST_ENV中的值(即my-config)。通过这种指定方式,可以在其他Pod中也可以使用相同的方式进行利用,从而提高了可重用性。

続いてPodにVolumeのマウントを行う方法を見ていきます。Podは管理上の基本単位になっていて、仮想NetworkInterface(IP、ファイルシステム)を共有するといことを上記で記載しましたが、これはつまりPod自体がKubernetes上では仮想ホストのように考えられることを指しています。このようなPodにvolumeとして、Config Mapをマウントします。Config Mapでは環境変数だけでなく、Key-Valueペアを保存して、そのデータをファイルとしてvolumeへのマウントを行うことが可能です。上記で見たものではConfig Mapに保存したデータを環境変数として呼び出していました。

これを実現するためにPod.yamlファイルを下記のように修正します。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld-configmap-volume
  name: helloworld-configmap-volume
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld-configmap-volume
    ports:
    - containerPort: 8080
    resoueces: {}
    volumeMounts:
      #volume名を指定
    - name:my-config-volume
      #volumeをマウントするコンテナ内のファイルパスを指定
      mountPath: /my-config/TEST_ENV
    volume:
     #作成するvolume名を指定
    - name: my-config-volume
      configMap:
        #Config Map名を指定
        name: my-config
        items:
          #Config Map内にあるKeyの名前を指定
        - key: TEST_ENV
          path: keys

このyamlファイルではvolumeに関して、my-configという名前のConfig Mapをmy-config-volumeという名前のvolumeで指定し、この名前を指定してマウントを行い、その際に対応するコンテナ内のパス名を/my-config/TEST_ENVにするということを行っています。これによりファイル化されているため変更を行うことができるというメリットがあります。

▶永久的大小

続いて永続 Volumme(Persistest Volume)についてみていきます。

コンテナではデータはPod内にあるVolumeに変更を行うことでデータの書き込みを行っています。そのため、Podが消えた場合にはデータも消えます。それを防ぐために、クラスターワイドにあるNode上に存在するPersistest Volumeにデータを保存するということを行います。実際動きとしては、複数のNodeがあるクラスタ内に各Nodeが共有できるvolume(Persistest Volume)を作成し、各Nodeが必要な分だけこの共通volumeに要求を行い、得たvolumeを要求元のNodeでマウントするというものです。
そのため、共通的なvolumeを定義するyamlファイル(pv.yaml)と要求事項を記載したyamlファイル(pvc.yaml)を用意し、Pod(Node)作成時に用いるyamlファイル(Pod.yaml)には、この要求事項を参照するよう記載を行います。それぞれのファイルのサンプルは下記の通りです。

apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv
spec:
 storageClassName: manual
 #volumeのサイズを指定
 capacity: 100M
 #アクセス権限範囲を指定
 accessModes: ReadWriteOnce
 hostPath:
  #Node上のパスを指定
  path: "/mnt/pvc"
apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: pvc
spec:
 storageClassName: manual
 #アクセス権限範囲を指定
 accessModes: ReadWriteOnce
 resources:
  #要求事項を指定
  requests:
    #ほしい容量を指定
    storage: 10M
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld-pvc
  name: helloworld-pvc
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld-pvc
    ports:
    - containerPort: 8080
    resoueces: {}
    volumeMounts:
      #volume名を指定
    - name:my-pv
      #volumeをマウントするコンテナ内のファイルパスを指定
      mountPath: /mnt/pvc
    volume:
     #作成するvolume名を指定
    - name: my-pv
      #永続volume要求名を指定
      persistentVolumeClaim:
        name: pvc

如果要执行的话,需要按照上述的顺序使用kubectl apply逐个执行这3个文件,但在此之前,需要在集群上创建一个文件夹。因此,如果使用minikube,可以使用以下命令连接到集群并进行创建。

$minikube ssh
$sudo mkdir mnt/pvc
广告
将在 10 秒后关闭
bannerAds