K8S入门教程

简介

  • 本文基于K8S官方基础教程,从现实运维使用场景出发,结合上述新手入门困境,基于基本组件的定义、功能和使用角度进行讲解,帮助新手在最小化复杂度的前提下上手K8S

环境

目标

  • K8S集群上部署应用程序。
  • 对应用程序进行扩容缩容(多实例)。
  • 对应用程序进行版本更新。
  • 使用K8S工具排查部署问题。

集群

  • 首先,让我们对K8S集群有1个整体的掌握:
  • 上图描述的是1Master节点和6Node节点的K8S集群。
  • Master节点负责管理集群,负责协调集群中的所有活动,例如调度应用程序、维护应用程序的状态、扩展和更新应用程序。
  • Node节点负责实际承载容器运行的工作节点,每个Node节点都有1Kubelet
  • Kubelet管理Node节点并负责与Master节点通信。
  • Node节点还具有处理容器操作的工具,例如:Dockerrkt

概念

Deployment

  • 上图是在之前的基础上,添加了DeploymentPodContainer
  • Deployment: 在K8S中通过发布Deployment,可以创建应用程序(image)的实例(container),这个实例会被包含在Pod中。
  • 其中Deployment位于Master节点上,通过发布DeploymentMaster节点会选择合适的Node节点创建Container
  • 其中Container会被包含在Pod中,PodK8S中最小可管理单元。
  • 创建应用程序实例后,Kubernetes Deployment Controller会持续监控这些实例。若运行实例的Node节点关机或被删除,则Kubernetes Deployment Controller将在集群中重新选择合适的Node节点,创建新的实例。通过这样的方式提供了1种自我修复机制来解决机器故障或维护问题。
  • 在容器编排之前的时代,各种安装脚本通常用于启动应用程序,但是不能够使应用程序从机器故障中恢复。通过创建应用程序实例并确保它们在集群节点中的运行实例个数,Kubernetes Deployment提供了1种完全不同的方式来管理应用程序。

Pod

  • K8S中创建了1Deployment之后,K8S会创建1Pod(容器组)来放置Container(容器)。
  • Pod:用于存放1Container(可包含1个或多个Container,即图上的正方体),以及这些Container的共享资源:
    • 共享存储:Volumes(卷),即图上的紫色圆柱体。
    • 网络:每个Pod在集群中有个唯一的IPPod中的Container共享该IP地址。
    • 容器的基本信息:容器的镜像版本、对外暴露的端口等。
  • Pod中的容器共享IP地址和端口空间,同1Pod中的不同容器的端口不能冲突,同1Pod中的容器可以使用localhost + Port互相访问。
  • PodK8S集群上的最基本的单元。当在K8S上创建Deployment时,会在集群上创建包含容器的Pod(而非直接创建容器)。
  • 每个Pod都与运行它的Node节点绑定,并保持在那里直到终止或被删除。若节点发生故障,则会在集群中的其他可用节点上运行相同的Pod(从相同的镜像创建容器,使用相同的配置,不同的IP地址,不同的Pod名称)。
  • 若多个容器紧密耦合并且需要共享磁盘等资源,则他们应该被部署在同1Pod中。

Node

  • Pod总是在Node节点上运行,Node节点是K8S集群中的工作节点。每个Node节点都由Master节点管理。
  • 1Node节点可以有多个PodMaster节点会根据每个Node节点上可用资源的情况,自动调度Pod到最佳的Node节点上。
  • Node节点所需的基础服务:
    • Kubelet:负责Master节点和Node节点之间通信的进程,管理PodPod内运行的Container
    • 容器运行环境:Dockerrkt,负责下载镜像、创建和运行容器等。

Service

  • Pod有自己的生命周期,当Node节点故障时,节点上运行的Pod也会销毁。然后Deployment可以通过创建新的Pod来动态地将群集调整回原来的状态,以使应用程序保持运行,K8S通过Service服务的方式为前端屏蔽了后端Pod在销毁、创建过程中所带来IP地址的变化。
  • Service通过LabelSelector选择1组的Pod,把这些Pod的指定端口公布到到集群外部并支持负载均衡和服务发现。
  • Service使Pod之间的相互依赖解耦,互相访问时不再需要知道对方的IP
  • 在创建Service的时,通过设置配置文件中的spec.type字段的值,可以以不同方式对外暴露服务:
    • ClusterIP:默认,在集群中的内部IP上公布服务,这种方式下,服务只能在集群内部可以访问到。
    • NodePort:使用NAT方式在集群中每个节点的同1个端口上公布服务。这种方式下,可以通过访问集群中任意节点加端口号的方式访问服务<NodeIP>:<NodePort>。此时ClusterIP的访问方式仍然可用。
    • LoadBalancer:在云环境中(需要云服务商支持)创建1个集群外部的负载均衡器,并使用此负载均衡器的IP地址作为服务的访问地址。此时ClusterIPNodePort的访问方式仍然可用。
  • 图上有Service AService BService A将请求转发到IP10.10.10.1Pod上,Service B将请求转发到IP10.10.10.210.10.10.310.10.10.4Pod上。
  • Service将外部请求路由到1Pod中,提供了1个抽象层,使得K8S可以在不影响服务调用者的情况下,动态调度容器组,维持Deployment对应Pod的数量。
  • Service使用Labels(标签)、LabelSelector(标签选择器)匹配1PodLabels是附加到K8S对象的键/值对,其用途有多种:
    • K8S对象(NodeDeploymentPodService等)指派用于开发环境、测试环境或生产环境。
    • 嵌入版本标签,使用标签区别不同应用软件版本。
    • 使用标签对K8S对象进行分类。
  • 上图体现了Labels(标签)和LabelSelector(标签选择器)之间的关联关系:
    • Deployment B含有LabelSelectorapp=B,通过此方式声明与含有app=B标签的Pod关联。
    • 通过Deployment B创建的Pod包含标签为app=B
    • Service B通过标签选择器app=B选择可以路由的Pod
  • Labels(标签)可以在创建K8S对象时附加上去,也可以在创建之后再附加上去。任何时候都可以修改1K8S对象的Labels

操作

创建服务

  • 创建deployment
1
vim deployment.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:stable-alpine
  • apiVersion:声明API的版本,可通过kubectl api-versions查看集群所支持的版本。

  • kind:声明资源类型,可通过kubectl api-resources查看集群所支持的资源。

  • metadata:元数据,即Deployment的一些基本属性和信息。

    • nameDeployment的名称。
    • labelsDeployment的标签,允许为1个或多个。
  • specDeployment的描述信息,期望DeploymentK8S集群中的状态。

    • replicas:副本数。
    • selector:标签选择器,与metadatalabels一起工作。
      • matchLabels:选择匹配的标签,允许为1个或多个。
    • template:选择或创建Pod的模板。
      • metadataPod的元数据。
        • labelsPod的标签,与selector中的matchLabels一起工作,允许为1个或多个。
      • specPod的描述信息,期望PodK8S集群中的状态。
        • containers:生成容器。
          • namecontainer的名称。
          • imagecontainer的镜像。
  • 应用yaml文件:

1
kubectl apply -f deployment.yaml

服务信息

  • 获取资源:
1
2
3
4
5
6
7
8
9
10
11
# 命令格式
kubectl get 资源类型

# 资源类型:Deployment
kubectl get deployments

# 资源类型:Pod
kubectl get pods -o wide

# 资源类型:Node
kubectl get nodes -o wide
  • 获取指定命名空间的资源:
1
2
3
4
5
6
7
8
9
# 命令空间:所有空间
kubectl get deployments -A
kubectl get deployments --all-namespaces

# 命令空间:default
kubectl get deployments -n default

# 命令空间:kube-system
kubectl get deployments -n kube-system
  • 获取指定资源的详细信息:
1
2
3
4
5
# 命令格式
kubectl describe 资源类型 资源名称

# 资源类型:Deployment
kubectl describe deployment nginx
  • 获取指定Pod中容器的日志:
1
2
3
4
5
6
7
8
# 命令格式
kubectl logs NAME

# 获取全部日志
kubectl logs nginx-678d55ffb-v8j5s

# 获取实时日志
kubectl logs -f nginx-678d55ffb-v8j5s
  • 在指定Pod的容器中执行命令:
1
2
3
4
5
# 命令格式
kubectl exec NAME COMMAND

# 执行sh命令
kubectl exec -it nginx-678d55ffb-v8j5s /bin/sh

发布服务

  • 创建service
1
vim service.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx
ports:
- name: nginx
protocol: TCP
port: 80
nodePort: 32600
targetPort: 80
type: NodePort
  • apiVersion:声明API的版本,可通过kubectl api-versions查看集群所支持的版本。

  • kind:声明资源类型,可通过kubectl api-resources查看集群所支持的资源。

  • metadata:元数据,即Service的一些基本属性和信息。

    • nameService的名称。
    • labelsService的标签,允许为1个或多个。
  • specService的描述信息,期望ServiceK8S集群中的状态,如何选择Pod,如何对外提供服务。

    • selector:标签选择器,选择包含以下标签的Pod
    • ports:端口信息。
      • name:端口名称。
      • protocol:端口协议,可选TCP/UDP
      • port:集群内其他Pod可通过此端口访问Service
      • nodePort:通过任意节点的指定端口访问Service
      • targetPort:将请求转发到匹配Pod的端口。
    • typeService的类型,可选ClusterIP/NodePort/LoaderBalancer
  • 应用yaml文件:

1
kubectl apply -f service.yaml

伸缩服务

  • 在之前的操作中,我们创建了Deployment仅包含1Pod,当流量增加时,我们可以对应用程序进行伸缩操作以满足服务的性能要求。
  • 伸缩的实现可以通过更改deployment.yaml文件中部署的replicas(副本数)来完成。
  • 上图中,Service A只将访问流量转发到IP10.0.0.5Pod上。
  • 修改了Deploymentreplicas4后,K8S又为此Deployment创建了3个新的Pod,这4Pod有相同的标签。因此Service A通过标签选择器与新的Pod建立了对应关系,将访问流量通过负载均衡在4Pod之间进行转发。

  • 更新deployment

1
vim deployment.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:stable-alpine
  • 应用yaml文件:
1
kubectl apply -f deployment.yaml
  • 获取资源:
1
2
# 资源类型:Pod
kubectl get pods -o wide

滚动更新

  • 用户期望服务始终可用,为此开发者/运维者在更新应用程序时要分多次完成。在K8S中,这是通过Rolling Update滚动更新完成的。
  • 滚动更新通过使用新版本的Pod逐步替代旧版本的Pod来实现Deployment的更新,从而实现零停机。新的Pod将在具有可用资源的Node(节点)上进行调度。
  • 我们将应用程序扩容为多个实例,这是执行更新而不影响应用程序可用性的前提。
  • 默认情况下,滚动更新过程中,K8S会逐个使用新版本Pod替换旧版本Pod,以便使服务一直处于可用状态。
  • 最大不可用Pod数为1、最大新建Pod数为1。这两个参数可以配置为数字或百分比。在K8S中,更新是版本化的,任何部署更新都可以恢复为以前的稳定版本。
  • 环境中Service A将流量负载均衡到4个旧版本的Pod(绿色)上。
  • 更新部署文件中的镜像版本后,Master节点选择了1Node节点,并根据新的镜像版本创建Pod(紫色)。新Pod拥有唯一的新的IP。同时,Master节点会选择1个旧版本的Pod将其移除。
  • 重复上一步骤,再创建1个新的Pod替换1个原有的Pod
  • 执行滚动更新,直到所有旧版本Pod均移除,新版本Pod也达到Deployment部署文件中定义的副本数,则滚动更新完成。

  • 更新deployment

1
vim deployment.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
  • 应用yaml文件:
1
kubectl apply -f deployment.yaml

请作者喝瓶肥宅快乐水