参考文档:K8S太火了!花10分钟玩转它不香么?

1. k8s 简介

Kubernetes(简称 K8S,K 和 S 之间有 8 个字母)是用于自动部署,扩展和管理容器化应用程序的开源系统。它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现。Kubernetes 源自 Google 15 年生产环境的运维经验,同时凝聚了社区的最佳创意和实践。

Kubernetes 具有如下特性:

  • 服务发现与负载均衡:无需修改你的应用程序即可使用陌生的服务发现机制。
  • 存储编排:自动挂载所选存储系统,包括本地存储。
  • Secret 和配置管理:部署更新 Secrets 和应用程序的配置时不必重新构建容器镜像,且不必将软件堆栈配置中的秘密信息暴露出来。
  • 批量执行:除了服务之外,Kubernetes 还可以管理你的批处理和 CI 工作负载,在期望时替换掉失效的容器。
  • 水平扩缩:使用一个简单的命令、一个 UI 或基于 CPU 使用情况自动对应用程序进行扩缩。
  • 自动化上线和回滚:Kubernetes 会分步骤地将针对应用或其配置的更改上线,同时监视应用程序运行状况以确保你不会同时终止所有实例。
  • 自动装箱:根据资源需求和其他约束自动放置容器,同时避免影响可用性。
  • 自我修复:重新启动失败的容器,在节点死亡时替换并重新调度容器,杀死不响应用户定义的健康检查的容器。

2. k8 核心概念

2.1 Node

Kubernetes 集群是指 Kubernetes 协调一个高可用计算机集群,每个计算机作为独立单元互相连接工作。

一个 Kubernetes 集群包含两种类型的资源:

  • Master:负责管理整个集群。协调集群中的所有活动,例如调度应用、维护应用的所需状态、应用扩容以及推出新的更新。
  • Node:用于托管正在运行的应用。可以是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色,每个 Node 都有 Kubelet,它管理 Node 而且是 Node 与 Master 通信的代理,Node 还具有用于处理容器操作的工具,例如 Docker 或 rkt。

k8s node

开发环境一般为单集群,master 和 node 组件部署在一台物理机上。

在生产环境中,通常会将 Master 组件单独部署在独立的机器上,而不与 Node 共享。这有助于提高集群的可用性和稳定性。

2.2 Deployment

Deployment 负责创建和更新应用程序的实例。创建 Deployment 后,Kubernetes Master 将应用程序实例调度到集群中的各个节点上。如果托管实例的节点关闭或被删除,Deployment 控制器会将该实例替换为群集中另一个节点上的实例。这提供了一种自我修复机制来解决机器故障维护问题。

可以使用 Kubernetes 命令行界面 Kubectl 创建和管理 Deployment。Kubectl 使用 Kubernetes API 与集群进行交互。

deployment

2.3 Pod

Pod相当于逻辑主机的概念,负责托管应用实例。包括一个或多个应用程序容器(如 Docker),以及这些容器的一些共享资源(共享存储、网络、运行信息等)。

pod

2.4 Service

Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露、负载平衡和服务发现。

尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service,这些 IP 不会暴露在群集外部。Service 允许您的应用程序接收流量。Service 也可以用在 ServiceSpec 标记 type 的方式暴露,type 类型如下:

  • ClusterIP(默认):在集群的内部 IP 上公开 Service。这种类型使得 Service 只能从集群内访问。
  • NodePort:使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service。使用 <NodeIP>:<NodePort> 从集群外部访问Service。是 ClusterIP 的超集。
  • LoadBalancer:在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部 IP。是 NodePort 的超集。
  • ExternalName:通过返回带有该名称的 CNAME 记录,使用任意名称(由 spec 中的 externalName 指定)公开 Service。不使用代理。

service

2.5 ReplicaSet

ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。通常用来保证给定数量的、完全相同的 Pod 的可用性。建议使用 Deployment 来管理 ReplicaSet,而不是直接使用 ReplicaSet。

2.6 Ingress

Ingress 类似于 K8S 中的网关服务,是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。

ingress

2.7 ConfigMap

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时,Pod 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。使用 ConfigMap 可以将你的配置数据和应用程序代码分开。

2.8 Secret

在 Kubernetes 中,Secret(密钥)是一种用于存储敏感信息的资源类型。它可以用来保存诸如密码、API 密钥、令牌等敏感数据。Secret 的主要作用是提供一种安全的方式,使容器能够访问这些敏感信息而不需要直接在配置文件或 Pod 规范中暴露它们。

2.9 ServiceAccount

ServiceAccount(服务账号)是一种用于定义 Pod 如何与 Kubernetes集群中的 API 交互的对象。每个 Pod 都关联一个 ServiceAccount,该账号确定了 Pod 对 Kubernetes API 的访问权限。

以下是 ServiceAccount 的主要特点和作用:

  1. **身份认证: ** ServiceAccount 用于身份认证,允许 Pod 通过 API Server 进行操作。它为 Pod 提供了一个身份,使得 Kubernetes 可以追踪和控制该 Pod 对集群资源的访问。
  2. **访问控制: ** 通过为 ServiceAccount 分配适当的 RBAC(Role-Based Access Control)角色和角色绑定,可以精确控制 Pod 对集群资源的权限。这有助于实现最小特权原则,确保 Pod 只能执行其需要的操作。
  3. **自动装配: ** 当创建 Pod 时,如果未指定 ServiceAccount,将自动分配默认的 ServiceAccount。这有助于简化配置,但也可以通过显式指定 ServiceAccount 进行更精细的控制。
  4. **凭据挂载: ** ServiceAccount 可以与 Secrets 结合使用,将相应的凭据挂载到 Pod 中,以便 Pod 可以使用这些凭据进行身份验证和访问其他资源。

ServiceAccount 是 Kubernetes 中实现多租户和安全的一部分,通过它可以确保 Pod 在集群中的行为受到适当的限制和控制。

2.10 Role

Role(角色)是一种资源对象,用于定义一组权限,允许用户或服务账号对集群中的资源进行操作。Role 主要用于 RBAC(Role-Based Access Control)机制,以确保对 Kubernetes 资源的访问受到适当的控制。

以下是 Role 的主要特点和作用:

  1. **权限定义: ** Role 定义了一组权限规则,这些规则描述了用户或服务账号对某些资源的访问权限。权限可以包括创建、更新、删除等操作。
  2. **资源范围: ** Role 通常关联到特定的命名空间(Namespace),以确定其权限的作用范围。这样可以在不同的命名空间中使用相同的 Role 名称,实现权限隔离。
  3. **与 ServiceAccount 配合: ** Role 通常与 ServiceAccount 结合使用,将权限规则分配给特定的服务账号,从而控制与 Pod 相关联的权限。
  4. **RBAC 规则: ** Role 可以包含多个 RBAC 规则,每个规则定义了对一个或多个 API 组的访问权限。这有助于灵活地控制对不同资源类型的权限。

创建 Role 后,需要通过 RoleBinding 将其绑定到用户或服务账号,以实际应用这些权限规则。

下面是一个 Role 的简单示例:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: example
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]

这个示例 Role 允许在命名空间 "example" 中的所有服务账号执行对 "pods" 资源的 "get" 和 "list" 操作。

2.11 RoleBinding

RoleBinding(角色绑定)是一种资源对象,用于将 Role(角色)的权限规则绑定到用户、组或服务账号,从而实际赋予它们相应的权限。RoleBinding 是 RBAC(Role-Based Access Control)机制的关键组成部分,用于定义谁有权访问集群中的特定资源。

以下是 RoleBinding 的主要特点和作用:

  1. **权限绑定: ** RoleBinding 将 Role 中定义的权限规则绑定到特定的用户、组或服务账号。这样,被绑定的实体就具备了 Role 所定义的对应权限。
  2. **命名空间范围: ** RoleBinding 通常与 Role 结合使用,并可以指定要在哪个命名空间中应用这些权限。这有助于实现在不同命名空间中应用相同角色的权限而不产生冲突。
  3. **多个绑定: ** 一个 Role 可以被多个 RoleBinding 绑定到不同的用户、组或服务账号上,实现权限的共享和复用。
  4. **ClusterRoleBinding: ** 除了 RoleBinding,还有 ClusterRoleBinding,用于在整个集群范围内绑定 ClusterRole(集群角色)的权限规则。ClusterRoleBinding 没有命名空间的概念。

以下是一个简单的 RoleBinding 示例:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: example
subjects:
- kind: ServiceAccount
  name: pod-reader-sa
  namespace: example
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

这个示例 RoleBinding 将名为 "pod-reader" 的 Role 的权限绑定到名为 "pod-reader-sa" 的服务账号上,作用于 "example" 命名空间。

2.12 Volume

Volume 指的是存储卷,包含可被Pod中容器访问的数据目录。容器中的文件在磁盘上是临时存放的,当容器崩溃时文件会丢失,同时无法在多个 Pod 中共享文件,通过使用存储卷可以解决这两个问题。

常用的存储卷有如下几种:

  • configMap:configMap 卷提供了向 Pod 注入配置数据的方法。ConfigMap 对象中存储的数据可以被 configMap 类型的卷引用,然后被 Pod 中运行的容器化应用使用。
  • emptyDir:emptyDir 卷可用于存储缓存数据。当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建,并且 Pod 在该节点上运行期间,卷一直存在。当 Pod 被从节点上删除时 emptyDir 卷中的数据也会被永久删除。
  • hostPath:hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。
  • local:local 卷所代表的是某个被挂载的本地存储设备,例如磁盘、分区或者目录。local 卷只能用作静态创建的持久卷,尚不支持动态配置。
  • nfs:nfs 卷能将 NFS(网络文件系统)挂载到你的 Pod 中。
  • persistentVolumeClaim:persistentVolumeClaim 卷用来将持久卷(PersistentVolume)挂载到 Pod 中。持久卷(PV)是集群中的一块存储,可以由管理员事先供应,或者使用存储类(Storage Class)来动态供应,持久卷是集群资源类似于节点。

3. kubectl 的使用

开发环境集群建议使用 docker desktop 自带的集群。

3.1 kubectl config

查看配置(文件位于 .kube/config

kubectl config view
apiVersion: v1
kind: Config
preferences: {}

clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://kubernetes.docker.internal:6443
  name: docker-desktop
  
contexts:
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-desktop
current-context: docker-desktop

users:
- name: docker-desktop
  user:
    client-certificate-data: DATA+OMITTED
    client-key-data: DATA+OMITTED
  • 集群(Cluster): 描述 Kubernetes 集群的连接信息,包括集群的名称、API 服务器的地址等。
  • 用户(User): 定义与集群通信时使用的身份验证信息,可以是用户名密码、客户端证书等。
  • 上下文(Context): 将集群和用户组合在一起,定义了使用的默认集群和用户。
  • 当前上下文(Current Context): 指定 kubectl 使用的默认上下文。

3.2 Deployment

3.2.1 创建 Deployment

  • 指定好应用镜像并创建一个 Deployment,这里创建一个 Nginx 应用:
kubectl create deployment kubernetes-nginx --image=nginx:1.10
  • 创建一个 Deployment 时 K8S 会产生如下操作:
    • 选择一个合适的 Node 来部署这个应用;
    • 将该应用部署到 Node 上;
    • 当应用异常关闭或删除时重新部署应用。

3.2.2 查看 Deployment

kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-nginx      1/1     1            1           21h

3.3 访问 k8s api

  • 我们可以通过 kubectl proxy 命令创建一个代理,这样就可以通过暴露出来的接口直接访问 K8S 的 API 了,这里调用了查询 K8S 版本的接口;

    [macro@linux-local root]$ kubectl proxy
    Starting to serve on 127.0.0.1:8001
    [root@linux-local ~]# curl http://localhost:8001/version
    {
      "major": "1",
      "minor": "20",
      "gitVersion": "v1.20.0",
      "gitCommit": "af46c47ce925f4c4ad5cc8d1fca46c7b77d13b38",
      "gitTreeState": "clean",
      "buildDate": "2020-12-08T17:51:19Z",
      "goVersion": "go1.15.5",
      "compiler": "gc",
      "platform": "linux/amd64"
    }
    

3.4 pod

3.4.1 列出 pods

kubectl get pods
NAME                                   READY   STATUS             RESTARTS   AGE
kubernetes-nginx-78bcc44665-8fnnn      1/1     Running            1          21h

3.4.2 查看 pod 详情

查看 Pod 的详细状态,包括 IP 地址、占用端口、使用镜像等信息;

kubectl describe pods
Name:         kubernetes-nginx-78bcc44665-8fnnn
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Tue, 05 Jan 2021 13:57:46 +0800
Labels:       app=kubernetes-nginx
              pod-template-hash=78bcc44665
              version=v1
Annotations:  <none>
Status:       Running
IP:           172.17.0.7
IPs:
  IP:           172.17.0.7
Controlled By:  ReplicaSet/kubernetes-nginx-78bcc44665
Containers:
  nginx:
    Container ID:   docker://31eb1277e507ec4cf8a27b66a9f4f30fb919d17f4cd914c09eb4cfe8322504b2
    Image:          nginx:1.10
    Image ID:       docker-pullable://nginx@sha256:6202beb06ea61f44179e02ca965e8e13b961d12640101fca213efbfd145d7575
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 06 Jan 2021 09:22:40 +0800
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Tue, 05 Jan 2021 14:24:55 +0800
      Finished:     Tue, 05 Jan 2021 17:32:48 +0800
    Ready:          True
    Restart Count:  1
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dhr4b (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-dhr4b:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-dhr4b
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:          <none>

3.4.3 查看日志

kubectl logs $POD_NAME

3.4.4 执行命令

使用 exec 可以在 Pod 的容器中执行命令,这里使用 env 命令查看环境变量

kubectl exec $POD_NAME -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubernetes-nginx-78bcc44665-8fnnn
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
NGINX_VERSION=1.10.3-1~jessie
HOME=/root

进入容器内部并执行 bash 命令,如果想退出容器可以使用 exit 命令:

kubectl exec -ti $POD_NAME -- bash

3.5 Service

3.5.1 暴漏端口

默认 Pod 无法被集群外部访问,需要创建 Service 并暴露端口才能被外部访问。

  • 创建一个 Service 来暴露 kubernetes-nginx 这个 Deployment:
kubectl expose deployment/kubernetes-nginx --type="NodePort" --port 80
  • 查看 K8S 中所有 Service 的状态:
kubectl get services
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes         ClusterIP   10.96.0.1        <none>        443/TCP        5h16m
kubernetes-nginx   NodePort    10.105.177.114   <none>        80:31891/TCP   5s
  • 查看 Service 的详情,通过 NodePort 属性可以得到暴露到外部的端口;
kubectl describe services/kubernetes-nginx
Name:                     kubernetes-nginx
Namespace:                default
Labels:                   app=kubernetes-nginx
Annotations:              <none>
Selector:                 app=kubernetes-nginx
Type:                     NodePort
IP Families:              <none>
IP:                       10.106.227.54
IPs:                      10.106.227.54
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30158/TCP
Endpoints:                172.17.0.7:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
  • 通过 curl 即可访问 pod

3.6 标签的使用

通过给资源添加 Label,可以方便地管理资源(如 Deployment、Pod、Service 等)。

  • 查看 Deployment 中所包含的 Label;
kubectl describe deployment
Name:                   kubernetes-nginx
Namespace:              default
CreationTimestamp:      Tue, 05 Jan 2021 13:57:46 +0800
Labels:                 app=kubernetes-nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=kubernetes-nginx
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
  • 通过 Label 查询 Pod:
kubectl get pods -l app=kubernetes-nginx
NAME                                READY   STATUS    RESTARTS   AGE
kubernetes-nginx-78bcc44665-8fnnn   1/1     Running   1          21h
  • 通过 Label 查询 Service:
kubectl get services -l app=kubernetes-nginx
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes-nginx   NodePort   10.106.227.54   <none>        80:30158/TCP   4m44s
  • 给 Pod 添加 Label:
kubectl label pod $POD_NAME version=v1
  • 查看 Pod 的详细信息,可以查看 Label 信息:
kubectl describe pods $POD_NAME
Name:         kubernetes-nginx-78bcc44665-8fnnn
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Tue, 05 Jan 2021 13:57:46 +0800
Labels:       app=kubernetes-nginx
              pod-template-hash=78bcc44665
              version=v1
  • 通过 Label 查询 Pod:
kubectl get pods -l version=v1
  • 通过 Label 删除服务:
kubectl delete service -l app=kubernetes-nginx
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes         ClusterIP   10.96.0.1       <none>        443/TCP        30h

4. helm 介绍

4.1 简介

Helm 是一个用于简化 Kubernetes 应用部署和管理的包管理工具。它允许你定义、安装和升级 Kubernetes 应用程序的结构化集合,这些集合被称为 "Charts"(图表)。每个 Chart 包含了定义 Kubernetes 资源的模板,例如 Deployments、Services、ConfigMaps 等。

一些 Helm 的关键概念包括:

  1. Chart(图表): Helm 的包是称为 Chart 的预定义 Kubernetes 资源集。Chart 包含了应用程序的描述、依赖关系、配置信息等。
  2. Release(发布): 当你使用 Helm 安装一个 Chart 时,创建的实例称为 Release。一个 Release 包含了特定版本的 Chart 和用户定义的配置。
  3. Repository(仓库): Helm Charts 可以存储在仓库中,允许用户轻松分享和发现 Charts。Helm 有一个默认的公共仓库,同时你也可以使用私有仓库。
  4. Values 文件: 在 Helm 中,用户可以使用 Values 文件来提供配置信息,这些信息将被注入到 Chart 模板中,从而自定义安装。

Helm 简化了在 Kubernetes 中部署和管理复杂应用的过程,使得应用的打包、分享和部署变得更加容易和可重复。

4.2 安装

brew install helm

5. Dashboard 可视化

本节均在 namespace:kubernetes-dashboard 下执行。

5.1 安装 Dashboard

使用 helm 安装 dashboard

helm install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --namespace kubernetes-dashboard --create-namespace
  • kubernetes-dashboard:releases 的 name
  • kubernetes-dashboard/kubernetes-dashboard: chart 的地址
  • --namespace: 指定命名空间
  • --create-namespace: 命名空间不存在则创建

5.2 配置端口转发

获取 pod name

$ kubectl get pods
NAME                                    READY   STATUS    RESTARTS   AGE
kubernetes-dashboard-798dd48467-d4wcp   1/1     Running   0          3m10s

配置端口转发

kubectl -n kubernetes-dashboard port-forward $POD_NAME 8443:8443

生产环境使用 service 暴漏端口。

开发环境可以使用 kubectl port-forward 将本地端口转发至固定 pod 端口,便于开发。

访问地址:http://localhost:8443

5.3 获取 token

创建 sa(serviceAccount)

kubectl create sa dashboard-admin-sa

创建 clusterrolebinding

kubectl create clusterrolebinding dashboard-admin-sa --clusterrole=cluster-admin  --serviceaccount=kubernetes-dashboard:dashboard-admin-sa
  • dashboard-admin-sa:clusterrolebinding 的 name
  • cluster-admin:一个 clusterrole,集群级别的管理员
  • kubernetes-dashboard:dashboard-admin-sa:命名空间:sa

创建 token,有效期 1h

kubectl create clusterrolebinding dashboard-admin-sa --clusterrole=cluster-admin  --serviceaccount=kubernetes-dashboard:dashboard-admin-sa