Kubernetes入门
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 ofkube-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 | minikube version |
- 创建部署单元(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
访问
- 使用 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/ - 查看日志
1
2# 所有应用发送给STDOUT的信息都会成为Pod容器的日志
kubectl logs $POD_NAME - 使用 exec 命令访问 Pod
1
2
3
4# 查看Pod内的环境变量
kubectl exec $POD_NAME env
# 在Pod中一个容器内启动一个bash会话,相当于登入了该容器
kubectl exec -ti $POD_NAME bash
Service
- 创建 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 - 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 - 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 - 删除 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 即修改 Deployment 中的 Pod 数。
- 扩展 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 - 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 - 缩小(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
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 - 验证更新
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 - 回滚(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 过程:
- Helm 从指定的目录或者 tgz 文件中解析出 Chart 结构信息
- Helm 将指定的 Chart 结构和 Values 信息通过 gRPC 传递给 Tiller
- Tiller 根据 Chart 和 Values 生成一个 Release
- Tiller 将 Release 发送给 Kubernetes 用于生成 Release
Chart Update 过程:
- Helm 从指定的目录或者 tgz 文件中解析出 Chart 结构信息
- Helm 将要更新的 Release 的名称和 Chart 结构,Values 信息传递给 Tiller
- Tiller 生成 Release 并更新指定名称的 Release 的 History
- Tiller 将 Release 发送给 Kubernetes 用于更新 Release
Chart Rollback 过程:
- Helm 将要回滚的 Release 的名称传递给 Tiller
- Tiller 根据 Release 的名称查找 History
- Tiller 从 History 中获取上一个 Release
- Tiller 将上一个 Release 发送给 Kubernetes 用于替换当前 Release
语法
表达式
模版表达式:
模版表达式:, 表示去掉表达式输出结果前面和后面的空格。去掉前面空格可以这么写,去掉后面空格
待补充
实战
实战中可以将配置单独存放一个代码库,主要包含:
- 镜像版本配置
- 中间件配置
- 外部依赖
- 业务配置
参考
- 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