Kubernetes in Action 笔记 —— 部署第一个应用

Minikube & kubectl

Minikube 是一个能够在本地环境搭建 Kubernetes 集群的工具,支持 Windows、Linux 和 MacOS 等平台,由 Kubernetes 社区进行维护。
它通常在 Linux 虚拟机中运行 Kubernetes。如果宿主机是基于 Linux 的系统,也可以通过 Docker 实现。
即为了运行 Minikube,需要先安装 Hypervisor 比如 Virtualbox;对于 Linux 系统,也可以直接使用 Docker。

具体的安装配置步骤可以参考官方文档 Getting Started Guide。

kubectl 是一个命令行工具,能够向 Kubernetes 集群发送命令并执行,支持的功能包括部署应用、查询和管理资源、查看日志等。
安装步骤可参考官方文档 Install Tools。

kubectl

部署应用

通常情况下,部署应用时要准备一个 JSON 或者 YAML 文件,里面包含对该应用的所有组件的描述信息,再把该描述文件应用到 Kubernetes 集群。
从演示的角度来看,也可以通过单行命令的方式部署简单的应用。

创建 deployment

可以使用 kubectl create deployment 命令部署应用。

$ kubectl create deployment kubia --image=luksa/kubia:1.0
deployment.apps/kubia created

其中 kubia 表示创建的 deployment 对象的名称,luksa/kubia:1.0 指代需要使用的容器镜像。

kubia 对象的存在告诉 Kubernetes luksa/kubia:1.0 容器必须运行在集群中。它定义了一种用户期待的状态,而 Kubernetes 负责确保实际的状态一定会满足该期望。

kubectl get deployment 命令可以列出当前集群中存在的所有 deployment 对象及其状态。

$ kubectl get deployment
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
kubia   0/1     1            0           5m17s
Pods

容器并不是 Kubernetes 中部署的最小单位。不同于直接部署独立的容器,Kubernetes 实际上会部署一组相互关联的容器,称为 pod
pod 包含一组一个或一个以上关系密切的容器实例,同时运行在同一个工作节点上,并共享特定的 Linux 命名空间。
同一个 pod 中的容器共享相同的网络和 UTS 命名空间,因而共享同样的网络接口、IP 地址、端口空间和主机名等。也可以在描述文件中定义其他需要共享的命名空间。

pods

每个 pod 都有自己的 IP、机器名、进程、网络接口以及其他资源。同一个 pod 中的容器都会将自己看作是 pod 中唯一运行的容器,它们并不能看到其他容器中的进程。

创建 Deployment 对象后就表示已经部署了 pod,Kubernetes 会基于 Deployment 对象创建一个或多个 pod。
可以使用 kubectl get pods 来列出系统中的 pod:

$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
kubia-767f9bc59d-77d2z   1/1     Running   0          41m

如果某些 issue 导致 pod 运行失败,或者单纯想查看更多 pod 相关的信息,可以使用 kubectl describe pod 命令:

$ kubectl describe pod
Name:         kubia-767f9bc59d-77d2z
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Tue, 14 Dec 2021 11:16:58 +0800
Labels:       app=kubia
              pod-template-hash=767f9bc59d
Annotations:  
Status:       Running
IP:           172.17.0.3
IPs:
  IP:           172.17.0.3
Controlled By:  ReplicaSet/kubia-767f9bc59d
Containers:
  kubia:
    Container ID:   docker://e9bd5cf8f2eb15959c08bc8f154742b7194030d8ce0f9e6290cd80fc21b48692
    Image:          luksa/kubia:1.0
    Image ID:       docker-pullable://luksa/kubia@sha256:a961dc8f377916936fa963508726d77cf77dcead5c97de7e5361f0875ba3bef7
    Port:           
    Host Port:      
    State:          Running
      Started:      Tue, 14 Dec 2021 11:26:25 +0800
    Ready:          True
    Restart Count:  0
    Environment:    
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-n9n9b (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  kube-api-access-n9n9b:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  11m   default-scheduler  Successfully assigned default/kubia-767f9bc59d-77d2z to minikube
  Normal  Pulling    11m   kubelet            Pulling image "luksa/kubia:1.0"
  Normal  Pulled     115s  kubelet            Successfully pulled image "luksa/kubia:1.0" in 9m24.3380576s
  Normal  Created    113s  kubelet            Created container kubia
  Normal  Started    113s  kubelet            Started container kubia

输出的最后就包含 pod 创建和启动时触发的一系列事件(Events)。

Pods 的创建流程
  • 运行 kubectl create deployment 命令,向 Kubernetes API Server 发送 HTTP 请求,创建一个新的 Deployment 对象
  • 之后 Kubernetes 创建一个新的 Pod 对象,该 Pod 对象被分配给某个工作节点
  • 工作节点上的 Kubelet agent 得知新的 Pod 对象被创建,且分配给了自己。于是 Kubelet 控制 Docker 拉取特定的镜像并创建、运行容器
Deployment object to a running container

向外部暴露应用

应用已经成功运行了,接下来就是控制它如何被外部访问。每个 pod 都会获得一个专属的 IP 地址,但该地址是只有集群内部可见的。为了使 pod 能够从外部访问,还需要创建一个 Service 对象。

Service 对象有好几种类型,其中一种 LoadBalancer 会生成一个外部的负载均衡器,令服务能够从集群外部访问。
可以使用 kubectl expose 命令创建 Service:

$ kubectl expose deployment kubia --type=LoadBalancer --port 8080
service/kubia exposed

使用 kubectl get svc 命令查看当前系统中存在的 Service:

$ kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1               443/TCP          29d
kubia        LoadBalancer   10.106.111.39        8080:30077/TCP   2m28s

创建 LoadBalancer 服务时,正常情况下 Kubernetes 会访问云服务提供商,令其创建负载均衡器并获取公共 IP。
Minikube 是本地模拟的集群环境,因而无法完成上述操作。kubia Service 的 EXTERNAL-IP 会一直处于 状态。

在没有获取到外部 IP 的情况下,minikube 可以使用下面的方法获取服务的 url:

$ minikube service kubia --url
  Starting tunnel for service kubia.
|-----------|-------|-------------|------------------------|
| NAMESPACE | NAME  | TARGET PORT |          URL           |
|-----------|-------|-------------|------------------------|
| default   | kubia |             | http://127.0.0.1:39529 |
|-----------|-------|-------------|------------------------|
http://127.0.0.1:39529
❗  Because you are using a Docker driver on linux, the terminal needs to be open to run it.

打开一个新的命令行窗口,可以成功访问上面的 url:

$ curl http://127.0.0.1:39529
Hey there, this is kubia-767f9bc59d-77d2z. Your IP is ::ffff:172.17.0.1.
LoadBalancer 的创建流程
Service object to LoadBalancer

横向扩展应用

在容器中部署应用的一个主要好处就是,横向扩展应用变得非常简单和直观。
可以使用下列命令扩展 kubia 应用,令其同时运行 3 个实例副本。

$ kubectl scale deployment kubia --replicas=3
deployment.apps/kubia scaled
$ kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
kubia   3/3     3            3           3h58m

此时共有 3 个 pod 实例运行:

$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
kubia-767f9bc59d-77d2z   1/1     Running   0          3h59m
kubia-767f9bc59d-rvsdq   1/1     Running   0          3m56s
kubia-767f9bc59d-sfn42   1/1     Running   0          3m56s

可以加上 -o wide 选项获取更详细的 pods 信息,比如 IP、运行的节点等:

kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
kubia-767f9bc59d-77d2z   1/1     Running   0          4h      172.17.0.3   minikube              
kubia-767f9bc59d-rvsdq   1/1     Running   0          5m31s   172.17.0.5   minikube              
kubia-767f9bc59d-sfn42   1/1     Running   0          5m31s   172.17.0.4   minikube              

再次访问 Service 的 URL,可以看到多次访问返回的信息并不一样,可以证实后台提供服务的 pod 并不是同一个,而是 3 个 pod 轮流接收请求并提供服务:

$ curl http://127.0.0.1:39529
Hey there, this is kubia-767f9bc59d-sfn42. Your IP is ::ffff:172.17.0.1.
$ curl http://127.0.0.1:39529
Hey there, this is kubia-767f9bc59d-77d2z. Your IP is ::ffff:172.17.0.1.
$ curl http://127.0.0.1:39529
Hey there, this is kubia-767f9bc59d-sfn42. Your IP is ::ffff:172.17.0.1.
$ curl http://127.0.0.1:39529
Hey there, this is kubia-767f9bc59d-rvsdq. Your IP is ::ffff:172.17.0.1.

负载均衡架构示意图:


Load balancing

总结

  • 部署应用可以使用 kubectl create deployment 命令,暴露应用使用 kubectl expose deployment 命令,横向扩展应用使用 kubectl scale deployment 命令。
  • 应用部署的基本单位不是容器而是 pod,一个 pod 可以包含一个或多个相互关联的容器。
  • Deployments、Services、Pods 和 Nodes 都是 Kubernetes 对象/资源。可以使用 kubectl get 命令获取这些对象的列表,或者使用 kubectl describe 命令获取对象的详细信息。
  • Deployment 对象负责部署指定数量的 pods。Services 对象则可以令这些 pods 能够通过一个单一的 IP 地址访问。
  • Service 在集群内部提供负载均衡。如果指定其类型为 LoadBalancer,则 Kubernetes 会请求云服务提供商令应用可以通过公共地址访问。

参考资料

Kubernetes in Action, Second Edition

你可能感兴趣的:(Kubernetes in Action 笔记 —— 部署第一个应用)