Kubernetes基础 ( 1 ) - 环境搭建及概念说明

一、概述

1.1 Kubernetes是什么?

Kubernetes的名字来自希腊语,意思是“舵手” 或 “领航员”。K8s是将8个字母ubernete替换为8的缩写,也就是仅保留了头尾2个字母(ks),中间的8个字母都去掉了,用8代替。

Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。

通过Kubernetes你可以:

Kubernetes 特点

KubernetesGoogle2014年创建管理的,是Google10多年大规模容器管理技术Borg的开源版本。

1.2 Kubernetes设计架构

Kubernetes集群包含有节点代理kubeletMaster组件(APIs, scheduler, etc),一切都基于分布式的存储系统。下面这张图是Kubernetes的架构图 [1]

来看这张图,左侧是Master节点,右边是Node节点。

Master节点上有:

Node节点上有:

kubectl命令操作主节点,主节点要操作Node节点则通过和Node节点上的kubelet交互实现,Client访问则通过防火墙规则访问到Node节点里的特定Pod

了解到这里后可能就开始懵圈了,好多文章里还会看到DeploymentServiceReplicaSets/Replication Controller等,一堆概念容易混淆。所以接下来我们先忽略概念,看怎么在个人电脑上部署个k8s环境,操作一遍之后再来梳理概念和交互。

二、安装K8s

通过Docker方式部署比较简单,打开已搭建好的Docker Dashboard界面,设置里有个Kubernetes,默认是没有勾选的,但这里直接勾选应用后卡死了,大概是因为墙的原因,有些镜像无法下载,所以在点击之前需要先手动下载镜像。

2.1 下载依赖镜像

参考 gotok8s [2] 的安装方法:

$ git clone git@github.com:gotok8s/k8s-docker-desktop-for-mac.git
$ ./load_images.sh

脚本比较简单,用后面的镜像替换前面的镜像,替换完成之后重新打TAG还原。

$ cat image_list
k8s.gcr.io/kube-proxy:v1.16.5=gotok8s/kube-proxy:v1.16.5
k8s.gcr.io/kube-controller-manager:v1.16.5=gotok8s/kube-controller-manager:v1.16.5
k8s.gcr.io/kube-scheduler:v1.16.5=gotok8s/kube-scheduler:v1.16.5
k8s.gcr.io/kube-apiserver:v1.16.5=gotok8s/kube-apiserver:v1.16.5
k8s.gcr.io/coredns:1.6.2=gotok8s/coredns:1.6.2
k8s.gcr.io/pause:3.1=gotok8s/pause:3.1
k8s.gcr.io/etcd:3.3.15-0=gotok8s/etcd:3.3.15-0
k8s.gcr.io/kubernetes-dashboard-amd64=gotok8s/kubernetes-dashboard-amd64:v1.10.1

2.2 启用Kuberenetes

打开Docker,启用Kubernetes,应用后若正常则可以看到左下角有2个running状态。

命令行敲kubectl就可以输出信息了。

2.3 安装Dashboard

Dashboard是可选组件,部署Kubernetes Dashboard

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml

# 开启本机访问代理
$ kubectl proxy

创建Dashboard管理员用户并用token登陆

# 创建 ServiceAccount kubernetes-dashboard-admin 并绑定集群管理员权限
$ kubectl apply -f https://raw.githubusercontent.com/gotok8s/gotok8s/master/dashboard-admin.yaml

# 获取登陆 token
$ kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep kubernetes-dashboard-admin | awk '{print $1}')

通过下面的连接访问Dashboard:

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

输入上一步获取的token, 验证并登陆。到这里环境就装好了。

三、尝试部署镜像

一般可以通过YAML文件进行部署,这里先尝试走通流程,类似docker run的用法让容器先跑起来。整个过程只需要执行2条命令即可。

3.1 创建deployment

首先,执行第一条命令:

$ kubectl run itopic --image=pengbotao/itopic.go:alpine --replicas=3 --port=8001

说明:使用的是我们前面用docker构建的镜像,容器使用的是8001端口,启动3个副本。操作run之后就创建好了deploymentrspod,可以查看相关信息:

查看Node

$ kubectl get node
NAME             STATUS   ROLES    AGE     VERSION
docker-desktop   Ready    master   2d21h   v1.16.6-beta.0

查看deployment、rs和pod

$ kubectl get deployment
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
itopic   3/3     3            3           16s

$ kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
itopic-6f9dd4f4cd   3         3         3       21s

$ kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
itopic-6f9dd4f4cd-2q2xp   1/1     Running   0          23s
itopic-6f9dd4f4cd-7pj8f   1/1     Running   0          23s
itopic-6f9dd4f4cd-vfdx9   1/1     Running   0          23s

查看pod详情

$ kubectl describe pod itopic-6f9dd4f4cd-2q2xp
Name:         itopic-6f9dd4f4cd-2q2xp
Namespace:    default
Priority:     0
Node:         docker-desktop/192.168.65.3
Start Time:   Thu, 27 Aug 2020 13:57:42 +0800
Labels:       pod-template-hash=6f9dd4f4cd
              run=itopic
Annotations:  <none>
Status:       Running
IP:           10.1.0.16
IPs:
  IP:           10.1.0.16
Controlled By:  ReplicaSet/itopic-6f9dd4f4cd
Containers:
  itopic:
    Container ID:   docker://3896614a1b1f3f2d11f709cfad56a2579769c51fb212eb2402e0dea668d95584
    Image:          pengbotao/itopic.go:alpine
    Image ID:       docker-pullable://pengbotao/itopic.go@sha256:1a1a98ffe435e34da61956be22eb61382eb5732120c4e216922f90ace0ad504b
    Port:           8001/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Thu, 27 Aug 2020 13:57:43 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-lmjrh (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-lmjrh:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-lmjrh
    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:          <none>

也可以进入容器

$ kubectl exec -it itopic-6f9dd4f4cd-2q2xp /bin/sh
/www/itopic.go #

3.2 创建service

到这里容器已经建好了,但是还无法从外部访问。接下来,执行第二条命令:

$ kubectl expose deployment itopic --type=LoadBalancer --port=38001 --target-port=8001 

查看service

$ kubectl get service
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)           AGE
itopic       LoadBalancer   10.100.230.169   localhost     38001:31234/TCP   26s
kubernetes   ClusterIP      10.96.0.1        <none>        443/TCP           2d20h


$ kubectl describe service itopic
Name:                     itopic
Namespace:                default
Labels:                   run=itopic
Annotations:              <none>
Selector:                 run=itopic
Type:                     LoadBalancer
IP:                       10.100.230.169
LoadBalancer Ingress:     localhost
Port:                     <unset>  38001/TCP
TargetPort:               8001/TCP
NodePort:                 <unset>  31234/TCP
Endpoints:                10.1.0.15:8001,10.1.0.16:8001,10.1.0.17:8001
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

这个时候就可以通过http://localhost:38001访问了。

注:Mac DockerDesktop环境下type指定其他没有走通,正常指定NodePort应该可以。

3.3 扩容 / 缩容

通过调整副本数量可以进行扩容与缩容。

$ kubectl scale --replicas=3 deploy/itopic

$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
itopic-6f9dd4f4cd-2q2xp   1/1     Running   0          38m
itopic-6f9dd4f4cd-7pj8f   1/1     Running   0          38m
itopic-6f9dd4f4cd-k56dl   1/1     Running   0          35m
itopic-6f9dd4f4cd-lnzpq   1/1     Running   0          35m
itopic-6f9dd4f4cd-vfdx9   1/1     Running   0          38m

如果要删除deploymentservice:

$ kubectl delete deployment,service itopic

到这里一个简单的镜像通过2条k8s命令就部署好了,来看看Dashboard的展示情况:

从演示上使用到了DeploymentReplicaSetPodService,从Dashboard左侧可以看到更多的名词,接写来对k8s的基础架构做一些描述。

四、节点说明

4.1 Master

集群的控制节点,负责整个集群的管理和控制,kubernetes的所有的命令基本都是发给Master,由它来负责具体的执行过程,平常执行的操作命令基本都是在Master上执行。

Master的组件:

4.2 Node

Node是集群的工作负载节点,默认情况kubelet会向Master注册自己,一旦Node被纳入集群管理范围,kubelet会定时向Master汇报自身的情报,包括操作系统,Docker版本,机器资源情况等。

如果Node超过指定时间不上报信息,会被Master判断为“失联”,标记为Not Ready,随后Master会触发Pod转移。

Node的组件:

4.3 Pod

PodKubernetes中操作的基本单元,一个Pod下可以有多个容器。每个Pod中都有个根容器(Pause容器),Pause容器的状态代表整个容器组的状态,其他业务容器共享PauseIP,即Pod IP,共享Pause挂载的Volume,这样简化了同个Pod中不同容器之间的网络问题和文件共享问题。

  1. Kubernetes集群中,同宿主机的或不同宿主机的Pod之间要求能够TCP/IP直接通信,因此采用虚拟二层网络技术来实现,例如FlannelOpenvswitch(OVS)等,这样在同个集群中,不同的宿主机的Pod IP为不同IP段的IP,集群中的所有Pod IP都是唯一的,不同Pod之间可以直接通信
  2. Pod有两种类型:普通Pod静态Pod静态Pod即不通过K8S调度和创建,直接在某个具体的Node机器上通过具体的文件来启动。普通Pod则是由K8S创建、调度,同时数据存放在ETCD中。
  3. Pod IP和具体的容器端口(ContainnerPort)组成一个具体的通信地址,即Endpoint。一个Pod中可以存在多个容器,可以有多个端口,Pod IP一样,即有多个Endpoint
  4. Pod Volume是定义在Pod之上,被各个容器挂载到自己的文件系统中,可以用分布式文件系统实现后端存储功能。
  5. Pod中的Event事件可以用来排查问题,可以通过kubectl describe pod xxx来查看对应的事件。
  6. 每个Pod可以对其能使用的服务器上的计算资源设置限额,一般为CPUMemoryK8S中一般将千分之一个的CPU配置作为最小单位,用m表示,是一个绝对值,即100m对于一个Core的机器还是48个Core的机器都是一样的大小。Memory配额也是个绝对值,单位为内存字节数。
  7. 资源配额的两个参数
    • Requests:该资源的最小申请量,系统必须满足要求。
    • Limits:该资源最大允许使用量,当超过该量,K8S会kill并重启Pod。

这几个概念应该还比较好理解。

通过查看kube-system名称空间下的pod可以看到:

$ kubectl get pod -n kube-system
NAME                                     READY   STATUS    RESTARTS   AGE
coredns-5644d7b6d9-5tjhf                 1/1     Running   0          29d
coredns-5644d7b6d9-mjw4w                 1/1     Running   0          29d
etcd-docker-desktop                      1/1     Running   0          29d
kube-apiserver-docker-desktop            1/1     Running   0          29d
kube-controller-manager-docker-desktop   1/1     Running   0          29d
kube-proxy-db9g7                         1/1     Running   0          29d
kube-scheduler-docker-desktop            1/1     Running   0          29d
storage-provisioner                      1/1     Running   1          29d
vpnkit-controller                        1/1     Running   0          29d

五、概念说明 - Master

5.1 kube-apiserver

k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watchHTTP Rest接口,是整个系统的数据总线和数据中心。kubernetes API Server的功能: [4]

  1. 提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更);
  2. 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd);
  3. 是资源配额控制的入口;
  4. 拥有完备的集群安全机制.

5.2 kube-controller-manager

编号 控制器 说明 应用场景
1 Deployment 部署无状态应用 Web应用
2 StatefulSet 部署有状态应用 数据库
3 DaemonSet 在每一个Node上面运行一个Pod;新加入的Node也同样会自动运行一个Pod Agent
4 Job/CronJob 一次性任务/周期任务 脚本、备份
5 ReplicaSet
ReplicationController
控制容器应用的副本数量
6 HPA Pod水平自动缩放

5.2.1. 关于无状态与有状态的说明:

5.2.2 Deployment

DeploymentPodReplicaSet提供了一个声明式定义方法发,用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包含:

5.2.3 ReplicationController 和 ReplicaSet

在新版的Kubernetes中建议使用ReplicaSet (RS)来取代ReplicationController(RC)ReplicaSetReplicationController没有本质的不同,只是名字不一样,但ReplicaSet支持集合式selector

虽然ReplicaSet可以独立使用,但如今它主要被Deployment用作协调Pod的创建、删除和更新的机制。当使用Deployment时,你不必担心还要管理它们创建的ReplicaSetDeployment会拥有并管理它们的ReplicaSet

5.2.4 DaemonSet

DaemonSet确保全局(或者一些)Node上运行一个Pod的副本。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除他创建的所有Pod。

DaemonSet的一些典型用法:

5.2.5 Job/CronJob

5.2.6 HPA - Horizontal Pod Autoscaling

应用的资源使用率通常都有高峰和骶骨的时候,如何削峰填谷提供集群的整体资源利用率,让service的pod个数自动调整呢?这就依赖于HPA了,顾名思义,使Pod水平自动缩放。

5.3 kube-scheduler

kube-scheduler是Kubernetes中的关键模块,扮演管家的角色遵从一套机制为Pod提供调度服务,例如基于资源的公平调度、调度Pod到指定节点、或者通信频繁的Pod调度到同一节点等。容器调度本身是一件比较复杂的事,因为要确保以下几个目标:

  1. 公平性:在调度Pod时需要公平的进行决策,每个节点都有被分配资源的机会,调度器需要对不同节点的使用作出平衡决策。
  2. 资源高效利用:最大化群集所有资源的利用率,使有限的CPU、内存等资源服务尽可能更多的Pod。
  3. 效率问题:能快速的完成对大批量Pod的调度工作,在集群规模扩增的情况下,依然保证调度过程的性能。
  4. 灵活性:在实际运作中,用户往往希望Pod的调度策略是可控的,从而处理大量复杂的实际问题。因此平台要允许多个调度器并行工作,同时支持自定义调度器。

为达到上述目标,kube-scheduler通过结合Node资源、负载情况、数据位置等各种因素进行调度判断,确保在满足场景需求的同时将Pod分配到最优节点。显然,kube-scheduler影响着Kubernetes集群的可用性与性能,Pod数量越多集群的调度能力越重要,尤其达到了数千级节点数时,优秀的调度能力将显著提升容器平台性能。

到这里我们可以对Pod的整个启动流程进行总结: [6]

  1. 资源管控中心Controller Manager创建新的Pod,将该Pod加入待调度的Pod列表。
  2. kube-scheduler通过API Server提供的接口监听Pods,获取待调度pod,经过预选和优选两个阶段对各个Node节点打分排序,为待调度Pod列表中每个对象选择一个最优的Node。
  3. kube-scheduler将Pod与Node的绑定写入etcd(元数据管理服务)。
  4. 节点代理服务kubelet通过API Server监听到kube-scheduler产生的绑定信息,获得Pod列表,下载Image并启动容器,然后由kubelet负责拉起Pod。

5.4 etcd

Etcd是Kubernetes集群中的一个十分重要的组件,用于保存集群所有的网络配置和对象的状态信息。 [7]

六、概念说明 - Node

6.1 kubelet

在kubernetes集群中,每个Node节点都会启动kubelet进程,用来处理Master节点下发到本节点的任务,管理Pod和其中的容器。kubelet会在API Server上注册节点信息,定期向Master汇报节点资源使用情况,并通过cAdvisor监控容器和节点资源。可以把kubelet理解成【Server-Agent】架构中的agent,是Node上的pod管家。 [8]

6.2 kube-proxy

kube-proxy是Kubernetes的核心组件,部署在每个Node节点上,它是实现Kubernetes Service的通信与负载均衡机制的重要组件; kube-proxy负责为Pod创建代理服务,从apiserver获取所有server信息,并根据server信息创建代理服务,实现server到Pod的请求路由和转发,从而实现K8s层级的虚拟转发网络。

在k8s中,提供相同服务的一组pod可以抽象成一个service,通过service提供的统一入口对外提供服务,每个service都有一个虚拟IP地址(VIP)和端口号供客户端访问。

简单来说: [9]

七、小结

回过头来看一下我们之前的操作 [10]

$ kubectl run itopic --image=pengbotao/itopic.go:alpine --replicas=3 --port=8001
$ kubectl expose deployment itopic --type=LoadBalancer --port=38001 --target-port=8001 

最后,本文档是一个边学习边整理的过程,先通过比较简单的一个环境熟悉起来,了解其中的概念、模块及交互,所以仅当一个入门知识介绍。本章引用的文档、涉及的概念也比较多,可以先熟悉下在进入下一篇。


-- EOF --
最后更新于: 2020-09-25 17:14
发表于: 2020-08-28 19:06
标签: Kubernetes 容器化