Kubernetes入门

kubectl 的安装

Install and Set Up kubectl

kubernetes 含义

Kubernetes Master

Kubernetes Master 主要负责管理集群,它会协调集群内的所有活动,包括:scheduling applications, maintaining applications’ desired state, scaling applications, and rolling out new updates。
Master 实际上是三个进程的集合,它们运行在集群的一个 Master Node 上,这三个进程包括:

  • kube-apiserver:提供REST-API来操作 Kubernetes Objects,包括 pods、services、replicationcontrollers 等,并可用于控制集群状态。
  • kube-controller-manager:通过 apiserver 监听集群状态并做状态转移操作。
  • kube-scheduler:scheduler 可以根据集群的拓扑结构、性能、容量等动态分配资源。

Node

Node 是一台虚拟机或物理电脑,在集群中作为 Worker。Master 管理 Cluster,而 Node 则管理应用。
每个 Node 都有一个 Kubelet,是管理 Node 的媒介,且负责与 Kubernetes Master 进行交互。
每个 Node 还需要有工具来处理容器操作,比如 Docker 或 rkt。
一个生产环境的 cluster 必须由至少 3 个 Node 组成。

kubelet

节点代理,负责和 Kubernetes Master 交互:

  • 向 apiserver 注册节点
  • 其他云计算指定逻辑。

kube-proxy

运行于每个 Node 上的一个网络代理,可以执行简单的 TCP、UDP、SCTP 流转发或提供多后端进程的负载均衡。
相当于在主机和 Cluster 之间创建了一个连接,让我们能直接访问 API。

Pod

一个或多个应用容器集合的抽象,并且包含一些共享资源,包括:

  • 共享存储,如 Volumes;
  • 网络连接,每个 Pod 具有 Cluster 中唯一的一个 IP 地址;
  • 运行每个容器所必须的信息,比如容器镜像的版本、端口等。

Pod 建模了一种“logical host”,可以同时运行多种不同的容器。
当 Pod 所处的 Node 挂了,ReplicaSet会动态地创建新 Pod 来使得 Cluster 回到原来的状态。

Service

Service 定义了 Pod 的逻辑集合及其访问规则,虽然每个 Pod 都有一个唯一的 IP 地址(Cluster 范围内),但是如果没有 Service 的话这些 IP 也是没法暴露到 Cluster 外的,可以通过指定 ServiceSpec 中的type来指定暴露服务的方式:

  • ClusterIP (default) - Exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster.
  • NodePort - Exposes the Service on the same port of each selected Node in the cluster using NAT. Makes a Service accessible from outside the cluster using <NodeIP>:<NodePort>. Superset of ClusterIP.
  • LoadBalancer - Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP to the Service. Superset of NodePort.
  • ExternalName - Exposes the Service using an arbitrary name (specified by externalName in the spec) by returning a CNAME record with the name. No proxy is used. This type requires v1.7 or higher of kube-dns.

Volumes

Namespaces

Deployments

负责创建和更新应用实例,创建 Deployment 后,Master 会持续监听并在各 Node 中调度应用实例,一旦有实例挂掉或被删掉,Deployment controller 就会用 Cluster 中另一 Node 上的实例取代之。

  • searched for a suitable node where an instance of the application could be run (we have only 1 available node)
  • scheduled the application to run on that Node
  • configured the cluster to reschedule the instance on a new Node when needed

DaemonSet

StatefulSets

ReplicaSet

Jobs

kubernetes 使用

可以采用kubectl命令来和 Cluster 交互,kubectl最常用的操作只有如下 4 种:

  • kubectl get - list resources
  • kubectl describe - show detailed information about a resource
  • kubectl logs - print the logs from a container in a pod
  • kubectl exec - execute a command on a container in a pod

创建Cluster

例子中使用minikube创建 Cluster,然后使用kubectl来和创建的 Cluster 交互:

1
2
3
4
5
6
7
8
9
minikube version
# 启动一个Cluster
minikube start
# 查看客户端(kubectl的版本)和服务端(Kubernetes的版本)的版本
kubectl version
# Cluster的详细信息
kubectl cluster-info
# 获取Cluster内的Node列表
kubectl get nodes
  1. 创建部署单元(Deployment)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 创建Deploymnet
    kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
    # 查看Deployment
    kubectl get deployments

    # 查看Pod
    kubectl get pods
    # 查看Pod内Container的属性,比如使用的是什么镜像
    kubectl describe pods

访问

  1. 使用 proxy 访问 Service 和 Pod
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 创建proxy实例
    kubectl proxy
    # 创建proxy后可以在另一个终端调用REST API来查看Cluster信息
    curl http://localhost:8001/version
    # 查看Pod的名字
    export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
    echo Name of the Pod: $POD_NAME
    # 可以通过proxy直接访问Pod
    curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
  2. 查看日志
    1
    2
    # 所有应用发送给STDOUT的信息都会成为Pod容器的日志
    kubectl logs $POD_NAME
  3. 使用 exec 命令访问 Pod
    1
    2
    3
    4
    # 查看Pod内的环境变量
    kubectl exec $POD_NAME env
    # 在Pod中一个容器内启动一个bash会话,相当于登入了该容器
    kubectl exec -ti $POD_NAME bash

Service

  1. 创建 Service
    1
    2
    3
    4
    5
    6
    # 查看Service
    kubectl get services
    # 创建一个新的Service并暴露端口(type=NodePort可以用于占用一个Node上的端口来暴露服务)
    kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
    # 查看Service信息
    kubectl describe services/kubernetes-bootcamp
  2. Deployment 与 Service
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 8080其实是集群内的一个逻辑端口,可以通过以下命令获取Node上暴露的端口
    export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
    # 然后我们可以通过curl访问Node上的端口来确认Service已经被暴露到了Cluster外
    echo NODE_PORT=$NODE_PORT

    # Deployment会自动为Pod创建一个label,可以通过如下命令来查看
    kubectl describe deployment
    # 通过label查看Pod列表和Service列表
    kubectl get pods -l run=kubernetes-bootcamp
    kubectl get services -l run=kubernetes-bootcamp
  3. Service 中的 Pod
    1
    2
    3
    4
    5
    6
    7
    8
    # 先获取Pod的名字
    export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
    echo Name of the Pod: $POD_NAME
    # 通过label命令可以设置一个新的label
    kubectl label pod $POD_NAME app=v1
    # 之后可以使用describe 命令来查看这些label,也可以使用label来查询Pod
    kubectl describe pods $POD_NAME
    kubectl get pods -l app=v1
  4. 删除 Service
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 删除一个Service
    kubectl delete service -l run=kubernetes-bootcamp
    # 查看服务列表,该服务已经被删除
    kubectl get services
    # curl端口确认不再暴露服务
    curl $(minikube ip):$NODE_PORT
    # 我们可以在Pod中运行curl来确定应用仍运行于Pod中
    kubectl exec -ti $POD_NAME curl localhost:8080
    # 如果需要终止应用,则需要同时删除Deployment

app 扩展

scaling
上图来自官网教程,Scaling 即修改 Deployment 中的 Pod 数。

  1. 扩展 ReplicaSet(Scale Up)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 先看下部署了几个Pod
    kubectl get deployments
    # 查看Deployment创建的ReplicaSet,ReplicaSet名的格式为[DEPLOYMENT-NAME]-[RANDOM-STRING]
    kubectl get rs
    # 将Deployment扩展为4个复制
    kubectl scale deployments/kubernetes-bootcamp --replicas=4
    # 查看Deployment及其中的Pod
    kubectl get deployments
    kubectl get pods -o wide
    # 查看Deployment的时间日志
    kubectl describe deployments/kubernetes-bootcamp
  2. Load Balancing
    1
    2
    3
    4
    5
    # 使用一个NODE_PORT环境变量来保存Node暴露的端口
    export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
    echo NODE_PORT=$NODE_PORT
    # curl访问多次,会发现请求被负载均衡到了不同的Pod上
    curl $(minikube ip):$NODE_PORT
  3. 缩小(Scale Down)
    1
    2
    3
    4
    5
    # 再运行一次scale命令来缩小ReplicaSet
    kubectl scale deployments/kubernetes-bootcamp --replicas=2
    # 查看伸缩结果
    kubectl get deployments
    kubectl get pods -o wide

滚动更新(Rolling Update)

  1. 更新应用版本
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 先看看Cluster里有啥
    kubectl get deployments
    kubectl get pods
    # 查看应用当前使用的镜像版本
    kubectl describe pods
    # 使用set image命令设置应用的镜像版本
    kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
    # 可以通过Pod查看应用的更新过程
    kubectl get pods
  2. 验证更新
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 确认应用正在运行中
    kubectl describe services/kubernetes-bootcamp
    # 用一个NODE_PORT环境变量保存Node暴露的端口,然后用curl确认暴露的服务可以使用
    export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
    echo NODE_PORT=$NODE_PORT
    curl $(minikube ip):$NODE_PORT
    # 更新同样可以使用rollout status命令来确认
    kubectl rollout status deployments/kubernetes-bootcamp
    # 查看应用当前使用的镜像的版本
    kubectl describe pods
  3. 回滚(Rollback)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 设置镜像进行更新,但是这个镜像的v10版本是不存在的,因此会引起更新失败
    kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
    # 查看Deployment的当前状态,会发现某些Pod运行不正常
    kubectl get deployments
    # 查看Pod状态,describe能提供更多信息
    kubectl get pods
    kubectl describe pods
    # 发现问题,可以使用rollout undo命令来回滚,rollout命令会复原deployment到上一已知状态。实际上所有更新操作都是版本化的,并且每次更新都可以回滚到之前的任意版本
    kubectl rollout undo deployments/kubernetes-bootcamp
    # 接下来再查看Pod的状态可以发现所有的Pod都已经恢复运行了
    kubectl get pods
    kubectl describe pods

k8s Helm

Helm是k8s的包管理工具

  • Chart:每个包称为一个 Chart,一个 Chart 是一个目录(一般情况下会将目录进行打包压缩,形成 name-version.tgz 格式的单一文件,方便传输和存储)。
  • Tiller:Tiller 是 Helm 的服务端,部署在 Kubernetes 集群中。Tiller 用于接收 Helm 的请求,并根据 Chart 生成 Kubernetes 的部署文件( Helm 称为 Release ),然后提交给 Kubernetes 创建应用。Tiller 还提供了 Release 的升级、删除、回滚等一系列功能。
  • Repository:Helm 的软件仓库,Repository 本质上是一个 Web 服务器,该服务器保存了一系列的 Chart 软件包以供用户下载,并且提供了一个该 Repository 的 Chart 包的清单文件以供查询。Helm 可以同时管理多个不同的 Repository。首次安装 Helm 时,它已预配置为使用官方 Kubernetes chart 存储库 repo。该 repo 包含许多精心设计和维护的 charts。此 charts repo 默认以 stable 命名。
  • Release:使用 helm install 命令在 Kubernetes 集群中部署的 Chart 的一个实例称为 Release。在同一个集群上,一个 Chart 可以安装很多次。每次安装都会创建一个新的 release。例如一个 MySQL Chart,如果想在服务器上运行两个数据库,就可以把这个 Chart 安装两次。每次安装都会生成自己的 Release,会有自己的 Release 名称。

原理

Chart Install 过程:

  1. Helm 从指定的目录或者 tgz 文件中解析出 Chart 结构信息
  2. Helm 将指定的 Chart 结构和 Values 信息通过 gRPC 传递给 Tiller
  3. Tiller 根据 Chart 和 Values 生成一个 Release
  4. Tiller 将 Release 发送给 Kubernetes 用于生成 Release

Chart Update 过程:

  1. Helm 从指定的目录或者 tgz 文件中解析出 Chart 结构信息
  2. Helm 将要更新的 Release 的名称和 Chart 结构,Values 信息传递给 Tiller
  3. Tiller 生成 Release 并更新指定名称的 Release 的 History
  4. Tiller 将 Release 发送给 Kubernetes 用于更新 Release

Chart Rollback 过程:

  1. Helm 将要回滚的 Release 的名称传递给 Tiller
  2. Tiller 根据 Release 的名称查找 History
  3. Tiller 从 History 中获取上一个 Release
  4. Tiller 将上一个 Release 发送给 Kubernetes 用于替换当前 Release

语法

表达式
模版表达式:
模版表达式:, 表示去掉表达式输出结果前面和后面的空格。去掉前面空格可以这么写,去掉后面空格

待补充

实战

实战中可以将配置单独存放一个代码库,主要包含:

  • 镜像版本配置
  • 中间件配置
  • 外部依赖
  • 业务配置

参考

  1. Tutorials
    Learn Kubernetes Basics
    Configuring Redis using a ConfigMap
    使用 k8s 搭建 Redis 集群
    Exposing an External IP Address to Access an Application in a Cluster
    如何使用 k8s 搭建一个无状态服务
    StatefulSet Basics
    如何使用 k8s 搭建一个有状态服务
    AppArmor
    Using Source IP
    CICD
    https://www.linux.com/tutorials/set-cicd-pipeline-jenkins-pod-kubernetes-part-2/
    https://www.linux.com/tutorials/run-and-scale-distributed-crossword-puzzle-app-cicd-kubernetes-part-3/
    https://www.linux.com/tutorials/set-cicd-distributed-crossword-puzzle-app-kubernetes-part-4/
    Helm