k8s基础(一)-程序员宅基地

技术标签: 云原生  kubernetes  Docker  容器  

0、内容简介

  • part1: k8s 基础概念
  • part2: k8s 集群搭建
    • 通过kubeadmin
    • 基于二进制包
  • part3:k8s核心技术
    • pod
    • 控制器
    • 存储
    • service
    • 调度器
    • 安全机制 RBAC
    • 包管理工具
    • helm
  • part4:统一日志管理
  • part5:性能监控平台
  • part6:高可用k8集群
  • part7:集群部署项目

一、K8 introduction

1.1 k8 功能

  • 自动装箱(自动化部署)
  • 自愈
    • 失败重启
    • 检查到服务ready时才对外提供服务
  • 水平扩展
  • 服务发现
  • 滚动更新
  • 版本回退
  • 密码配置管理
  • 存储编排
    • 存储自动挂载,对于有状态应用实现数据持久化 十分重要。存储可以来自于网络(Ceph NFS,etc)或者本地
  • 批处理
    • 一次性任务,定时任务;满足批量数据处理和分析

1.2 k8 组件

在这里插入图片描述

  • Master Node
    • API server : 集群统一API 入口
    • Scheduler:节点调度,选择 WorkNode 后部署
    • controller-manager: 处理集群中常规后台任务,一个资源对应一个控制器
    • etcd
    • 比如,我想在这个K8上新建一个订单服务的实例,我向 API server发起一个请求,Scheduler会去调度 新建实例这个任务,创建动作,以及创建后这个实例的管理由 controller-manager(CM) 来搞定。(如此理解?)
  • Worker Node
    • kubelet : 就是个 Agent,管理Node上的节点
    • KubeProxy :网络代理,做 LB 等

1.3 核心概念

  • Pod:
    • K8的最小部署单元,是一组 容器(docker) 的集合
    • 同一个Pod中的容器是共享网络的
    • Pod是短生命的。比如服务器重新部署了,Pod会销毁并重建
  • controller
    • controller 创建Pod
    • controller确保Pod副本数量符合预期
    • controller确保所有Node运行同一个Pod(?)
    • Controller 可执行一次性或定时任务
  • service
    • 定义一组Pod访问规则

二、搭建

2.1 部署模式

  • 单master (自己本地玩)
    在这里插入图片描述
  • 多master(生产)
    在这里插入图片描述

2.2 kubeAdmin安装

1、准备好三台虚拟机(基于VMWare centos7)

  • 关闭防火墙
【临时关闭】
systemctl stop fire walld   
【永久关闭】
systemctl disable firewalld
  • 关闭 selinux
【永久关闭】
sed -i 's/enforcing/disabled/'  '/etc/selinux/config'
临时关闭
setenforce 0
  • 关闭swap
【临时关闭】
swapoff -a 
【永久关闭】
sed -ri 's/.*swap.*/#&/' /etc/fstab
  • 设置主机名
hostnamectl  set-hostname <hostname>
比如设置名字
k8master
k8node1
k8node2
  • 在master 设置 hosts
cat >> /etc/hosts<<EOF
192.168.12.151 k8node2
192.168.12.152 k8node1
192.168.12.153 k8master
EOF
  • 将ipv4的流量导入到 iptables的链
cat >/etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
EOF
  • 时间同步
yum install -y ntpdate 
ntpdate time.windows.com

2、每台机器安装 docker、kubeadmin、kubelet,建立起集群

第一步:先搞docker:
docker安装
注意还要把 docker.serivce 加入到开机启动:

systemctl enable docker.service

第二步:还是添加个阿里云的yum源【master work 都要搞】

cat  > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

第三步:再装kubeadmin 、kubeadmin 、kubectl 【master work 都要装】

yum install -y kubelet-1.18.0
yum install -y kubeadm-1.18.0
yum install -y kubectl-1.18.0
systemctl enable kubelet  
【设置了开机启动】

第四步:部署k8 master节点(在k8master节点上执行初始化动作)
这里的 192.168.12.153 是我本地虚拟机的 ip,即master

kubeadm init \
--apiserver-advertise-address=192.168.12.153 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16

等到第四步执行完,这个过程会比较久,它会把master node上所需要的scheduler 、 apiserver 等N多东西拉取下来(如果不是阿里云的镜像,估计根本没法玩。。)等到出现下面的语句时就表示执行成功了

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.12.153:6443 --token b4ee7o.2d8puhdflaonjq38 \
    --discovery-token-ca-cert-hash sha256:16526f83d2ae995ab96544b4f355ec5e3cba4cacc334c67035afa27e0ea9088d

第五步: 上面一步的执行结果中已经说明了下一步的动作。

配置:
 mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

第六步:部署work node节点,将其 join到集群中来 【注意:要在work node执行

kubeadm join 192.168.12.153:6443 --token b4ee7o.2d8puhdflaonjq38 \
    --discovery-token-ca-cert-hash sha256:16526f83d2ae995ab96544b4f355ec5e3cba4cacc334c67035afa27e0ea9088d

这里的token是24H后失效,但可以重新生成:

kubeadm token create --print-join-command

做到这里,看看 此时状态–> NotReady

[root@k8master ~]# kubectl get nodes
NAME       STATUS     ROLES    AGE   VERSION
k8master   NotReady   master   9h    v1.18.0
k8node1    NotReady   <none>   54s   v1.18.0
k8node2    NotReady   <none>   39s   v1.18.0

第七步:部署CNI网络插件,否则没法联网 【在master上执行】

 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

不过这个地址要翻墙,有点麻烦。可以先下载下来【点此查看】,然后执行

kubectl apply -f kube-flannel.yml 

第八步:查看此时 pod 的状态

[root@k8master ~]# kubectl get pods -n kube-system
NAME                               READY   STATUS    RESTARTS   AGE
coredns-7ff77c879f-px8zm           1/1     Running   0          10h
coredns-7ff77c879f-tqtjt           1/1     Running   0          10h
etcd-k8master                      1/1     Running   1          10h
kube-apiserver-k8master            1/1     Running   1          10h
kube-controller-manager-k8master   1/1     Running   1          10h
kube-flannel-ds-hzks4              1/1     Running   0          83m
kube-flannel-ds-kcpk9              1/1     Running   0          83m
kube-flannel-ds-mflpz              1/1     Running   0          83m
kube-proxy-rggn5                   1/1     Running   1          10h
kube-proxy-rz5b4                   1/1     Running   0          106m
kube-proxy-w5rfq                   1/1     Running   0          106m
kube-scheduler-k8master            1/1     Running   1          10h

第九步:安装一个Nginx 来做个测试(主要看网络有没问题)

 kubectl create deployment nginx --image=nginx
获取到镜像可能需要时间,可以 不断 执行下面命令查看状态
kubectl get pod 
 kubectl expose deployment nginx --port=80 --type=NodePort
 【查看Pod状态,注意这里是 逗号】
 kubectl get pod,svc
[root@k8master ~]# kubectl get pod,svc
NAME                        READY   STATUS    RESTARTS   AGE
pod/nginx-f89759699-pchp4   1/1     Running   0          20m

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP        10h
service/nginx        NodePort    10.1.114.75   <none>        80:31787/TCP   16m

通过浏览器访问:
http://192.168.12.151:31787/
OR:
http://192.168.12.152:31787/
由于K8做了LB,任意一个Work Node 的节点都可以访问到 Nginx的欢迎页面。

2.3 二进制包安装

TODO

2.4 最低资源要求

单节点集群:一个控制节点和一个工作节点,是个玩具。
最小的生产环境集群:至少三个节点,包括一个控制节点和两个工作节点,提供一定程度的高可用性和容错性。
建议的生产环境集群:至少三个控制节点(master)和三个worker node,可根据需求和负载进行扩展

三、核心技术

3.1 kubectl

基本格式: kubectl [command] [type] [name] [flags]

  • command: 操作指令, create get describe delete
  • type: 资源类型,case-intensive,可以单数、复数、缩略形式
[root@k8master ~]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-pchp4   1/1     Running   0          51m

  • flags : 可选参数

帮助命令:

  • kubectl help 【Kubectl 的命令 特别多,需要的时候直接查阅 帮助文档即可】
  • kubectl get --help 【看 get 的细致命令】

查看 健康检查:

  • kubectl get cs

3.2 资源编排

yml文件格式:

  • 使用空格,而不是 tab缩进
  • 使用 ---表示一个新yml 的开始
  • 缩进表示了层级关系, 缩进不正会没法玩 跟python 有点类似

yml文件我们基本不从0开始写,而是生成一个模板,然后自己改改。

  • 第一种:使用kubectl create 生成yml (create 并没有真正部署好)
kubectl create deployment web --image=nginx -o yaml --dry-run  > myyaml.yaml

这里创建一个 资源名为web的部署,但是并不真正执行,而只是 产生一个 yaml, --dry-run 表示 尝试运行;生成的yaml 内容输出到 一个文件

[root@k8master ~]# cat myyaml.yaml
# 版本
apiVersion: apps/v1
# 资源类型
kind: Deployment
# 资源元数据
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
# 资源规格
spec:
   # 副本数量
  replicas: 1
# 标签选择器
  selector:
    matchLabels:
      app: web
  strategy: {}
# pod 模板
  template:
	# pod 元数据
    metadata:
      creationTimestamp: null
      labels:
        app: web
  # pod规格
    spec:
  # 容器配置
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}
  • 第二种:对已经部署好的,使用 kubectl get
    kubectl get deploy nginx -o=yaml > myyaml2.yaml
    不过,由于已经部署的资源对应的yaml内容会比较复杂,不是很推荐

3.3 pod

3.3.1 概述

  • Pod是一组容器的集合
  • K8不直接处理 容器,而是处理 Pod
  • Pod中的容器是共享网络的
  • Pod是短生命周期
  • Pod 是K8 创建和管理的最小单元
  • 如果熟悉K8的资源对象模型就知道,Pod是用户创建和部署的最小资源对象模型,也是K8上运行容器化应用的资源对象。其他资源对象都是用来支持Pod: 控制器对象管控Pod对象;Service或Ingress对象用来暴露Pod引用对象;Persistent资源对象为Pod提供存储。
  • 每一个Pod都有一个特殊的被称为“根容器”的pause 容器。Pause容器对应的镜像属于K8的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。(?)

3.3.2 为啥有Docker还要Pod

创建容器使用Docker,一个Docker对应一个容器,一个容器里只有一个进程(多进程似乎也能实现,但不好管理),一个容器运行一个程序

Pod 为方便管理,将多个容器放在一起。Pod是多进程设计

Pod存在是为了亲密性应用: 两个应用之间需要频繁调用。应用由于在同一网络中,调用性能更好、当然也更方便。

3.3.3 Pod实现机制

两个大机制:共享网络+共享存储

首先看第一点:
在这里插入图片描述

再看第二点:共享存储
就是 volume 数据卷的作用了

3.3.4 Pod 镜像拉取 重启策略 资源限制

1、镜像拉取
在这里插入图片描述

2、资源限制在这里插入图片描述
3、 重启策略在这里插入图片描述

3.3.5 health check

K8 的hc 是 容器对应用的hc,如此hc 有个问题:比如Java应用,已经堆溢出了,已不能提供服务,但是进程还在,容器不能准确获取状态。有一种更好的思路是通过检查应用状态来获取准确状态

在这里插入图片描述

3.3.6 调度策略

先看 这里: 这个Pod是怎么 在 k8node1 上创建的呢?

在这里插入图片描述

有哪些因素会影响调度呢?
1、资源限制

比如:

resources:
	requests:
			memory:'64Mi'
			cpu:'250m'

说明了宿主机必须满足剩余memory 64M,CPU 0.25C才会被调度到

2、标签选择器

比如yml 有这么一段描述:指定了Pod应该在 env_role=dev的Node上
在这里插入图片描述
下面简单描述一下 nodeSelector怎么对 env_role 起作用。Node1 Node2 属于dev ,Node3 Node4属于prod,可以调度Pod在 prod 环境中落地。这个场景对多环境的支持很有用。日常开发中常会切换dev qa staging等多个环境,但可能只要一套k8就将所有主机管理起来了。
在这里插入图片描述
那如何打标签呢?

[root@k8master ~]# kubectl label node k8node1 env_role=dev
node/k8node1 labeled
[root@k8master ~]# kubectl get nodes k8node1 --show-labels
NAME      STATUS   ROLES    AGE   VERSION   LABELS
k8node1   Ready    <none>   47h   v1.18.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,env_role=dev,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8node1,kubernetes.io/os=linux

默认已经打了很多标签了。env_role只是一个标签名,我们可以打自定义的标签,比如 kubectl label node k8node foo=bar

3、节点亲和性

nodeAffinity ,和nodeSelector 实现方式一致,使用labels 来影响调度。nodeAffinity 支持运算符操作,支持两种 亲和性(硬 、软)。常用operator: In NotIn Exists Gt Lt DoesnotExist

比如, 在nodeSelector 中,要求调度到env_role=dev 的节点,若有该label的节点不存在,将会一直等待。使用nodeAffinity(软),我们可以设定优先调度到 env_role=dev,若没有,调度到env_role=qa 也可以。

也有所谓的反亲和性,截图中使用的是 operator :In,如果是 NotIn DoesnotExist,就是反亲和。

p.s. 英语中的 affinity 表示一种亲密程度,也常见词,翻译成了汉语之后,总感觉有点过于高大上了,尽管它表达的是很简单的含义。
在这里插入图片描述

4、污点

NodeSelector NodeAffinity 都是Pod的属性,在调度的时候实现。

污点:不是Pod的属性,而是节点的属性,规定哪些节点不做普通分配调度。

使用场景:

  • 配置了某些特定硬件的Node
  • 专用节点
  • 基于 taint 驱逐

演示:

[root@k8master ~]# kubectl describe node k8master  |grep taint -i
Taints:             node-role.kubernetes.io/master:NoSchedule

这里是master:NoSchedule;K8中的污点值的枚举(三个):

  • NoSchedule
  • PreferNoScedule : 尽量不被调度
  • NoExecute:表示不被调度而且将Pod驱逐到其他Node

如何打上污点呢?

kubectl taint node [node] key=value:污点枚举值
kubectl taint node [node] key=value:污点枚举值 -  

举个栗子:

// 创建 nginx 应用
[root@k8master ~]# kubectl create deployment web --image=nginx
deployment.apps/web created

//看此时pods
[root@k8master ~]# kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP           NODE      NOMINATED NODE   READINESS GATES
nginx-f89759699-pchp4   1/1     Running   0          2d11h   10.244.1.2   k8node1   <none>           <none>
web-5dcb957ccc-2gbcj    1/1     Running   0          40s     10.244.2.2   k8node2   <none>           <none>

// 再部署多一个nginx (名字叫  web)
kubectl create deployment web --image=nginx

// 再跟着扩容一个
 kubectl scale deployment web --replicas=2

// 此时再看 pod情况
[root@k8master ~]# kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP           NODE      NOMINATED NODE   READINESS GATES
nginx-f89759699-pchp4   1/1     Running   0          2d11h   10.244.1.2   k8node1   <none>           <none>
web-5dcb957ccc-2gbcj    1/1     Running   0          9m13s   10.244.2.2   k8node2   <none>           <none>
web-5dcb957ccc-8wnn4    1/1     Running   0          2m56s   10.244.1.3   k8node1   <none>           <none>

// 看到 Pod在Node上:
无论是 k8node1 k8node2都有分布。

// 删除当前的 Pods 
[root@k8master ~]# kubectl delete deployment nginx
[root@k8master ~]# kubectl delete deployment web

// 所有pod 已经删除完了
[root@k8master ~]# kubectl get pods -o wide
No resources found in default namespace.

// 给 k8node1 打上污点
[root@k8master ~]# kubectl taint node k8node1 env_role=dev:NoSchedule
node/k8node1 tainted
// 确认已经打上了污点
[root@k8master ~]# kubectl describe node k8node1  |grep -i taint
Taints:             env_role=dev:NoSchedule

// 创建并扩容
[root@k8master ~]# kubectl create deployment web --image=nginx
deployment.apps/web created
[root@k8master ~]# kubectl scale deployment web --replicas=2
deployment.apps/web scaled

// 可以看到  所有的容器都部署到了 k8node2 ,k8node1 由于已经打上了污点,因此不会被调度到
[root@k8master ~]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE     IP           NODE      NOMINATED NODE   READINESS GATES
web-5dcb957ccc-ph7kd   1/1     Running   0          116s    10.244.2.4   k8node2   <none>           <none>
web-5dcb957ccc-wtmcz   1/1     Running   0          2m14s   10.244.2.3   k8node2   <none>           <none>

// 再来删除污点  【注意最后的  横杠 - 】
[root@k8master ~]# kubectl taint node k8node1 env_role:NoSchedule-
node/k8node1 untainted
[root@k8master ~]# kubectl describe node k8node1 |grep taint -i
Taints:             <none>
5、污点容忍

在这里插入图片描述
污点容忍:
即使设置了污点值为 NoSchedule,这个Node依然可能被调度到。

3.4 controller

3.4.1 what’s controller

Pod是一种 抽象; Controller 是具体存在的。
controller:

  • 在集群上管理和运行容器的对象
  • Pod通过Controller 来运维:滚动升级、伸缩
  • Pod 和Controller的建立是 通过 label 【一个Pod可能有很多label ,那一个Pod可能被多个Controller 控制?】
  • Controller ,also named “工作负载(workload)”

3.4.2 Deployment Controller

  • 部署 无状态应用(web、微服务)
  • 管理Pod和 ReplicaSet (副本集?)
  • 提供 部署、滚动升级等功能

3.4.3 yaml & Deployment

第一步: 先生成一个测试用的模板 yml:

W0309 22:37:13.728646   40038 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client.

[root@k8master ~]# cat web.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

第二步:部署
由于是测试,不需要改了,然后从这个yaml 部署:

[root@k8master ~]# kubectl apply -f web.yml
deployment.apps/web created
[root@k8master ~]# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-5dcb957ccc-cfbw4   1/1     Running   0          13s

第三步: 暴露端口 (使用yml的方式)

// 生成暴露端口的yml
[root@k8master ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort --name=web1 -o yaml>web1.yml
// 看下web1.yml内容
[root@k8master ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
status:
  loadBalancer: {}

//应用yml暴露端口 
[root@k8master ~]# kubectl apply -f web1.yml
// 查看是否暴露成功
[root@k8master ~]# kubectl get pod,svc
NAME                       READY   STATUS    RESTARTS   AGE
pod/web-5dcb957ccc-cfbw4   1/1     Running   0          5m11s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP        2d23h
service/web1         NodePort    10.1.72.70    <none>        80:31800/TCP   63s
// 从浏览器访问
OK

小结一下就是:
生成拉起容器yml --> 部署(拉起容器) --> 生成暴露端口 yml --> apply

3.4.4 Rolling & Rolling back

roll : ngnix 1.14 --> 1.15
roll back: nginx :1.15--> 1.14

升级和回滚,不过回滚未必是从高版本–> 低版本,而是从当前版本–> 上一个版本。这里明白就好,不纠结。

k8可以使用yml 描述 升级和回滚的 行为:
(还是上一节生成的yml)

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
# 【这里改为  2】
  replicas: 2
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      # 【原本这里未指定版本因此使用了latest 版本,现在改为 1.14】
      - image: nginx:1.14      
        name: nginx
        resources: {}
status: {}

现在我们来升级一下 nginx 版本, nginx :1.15

// 通过 kubectl set image 来设定镜像版本

[root@k8master ~]# kubectl set image deployment web nginx=nginx:1.15
deployment.apps/web image updated

[root@k8master ~]# kubectl get pods -o wide
NAME                   READY   STATUS              RESTARTS   AGE     IP           NODE      NOMINATED NODE   READINESS GATES
web-65b7447c7-k5z87    0/1     Terminating         0          5m14s   10.244.1.5   k8node1   <none>           <none>
web-65b7447c7-wr9k8    1/1     Running             0          5m14s   10.244.2.6   k8node2   <none>           <none>
web-7d9697b7f8-6h4b6   0/1     ContainerCreating   0          2s      <none>       k8node2   <none>           <none>
web-7d9697b7f8-ln4bb   1/1     Running             0          36s     10.244.1.6   k8node1   <none>           <none>

// 看下 升级的状态
[root@k8master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out

看 升级的过程也挺有意思:先拉起一个容器,然后再销毁之前的容器。

如果此时我还是觉得之前的版本更好,想要还原回去;首先看下之前使用过哪些版本; 然后回滚到上一个版本(绝大多数场景下都是回滚到上一个版本)

// 看到目前只有过  2 个版本
[root@k8master ~]# kubectl rollout history deployment web
deployment.apps/web
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

[root@k8master ~]# kubectl rollout undo deployment web
deployment.apps/web rolled back

[root@k8master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out

// 回滚是个相当快的操作!!!
[root@k8master ~]# kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
web-65b7447c7-9gxlr   1/1     Running   0          30s
web-65b7447c7-q7qx2   1/1     Running   0          27s

// 还可以回滚到指定的版本【注意后面的 --to-revision=2】:
[root@k8master ~]# kubectl rollout undo deployment web --to-revision=2
deployment.apps/web rolled back

[root@k8master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out

[root@k8master ~]# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-7d9697b7f8-qls7t   1/1     Running   0          15s
web-7d9697b7f8-s8cvk   1/1     Running   0          17s

3.4.5 Scaling

弹性伸缩:

// 【将副本数修改为  5  个 (伸)】
[root@k8master ~]# kubectl scale deployment web --replicas=5
deployment.apps/web scaled
[root@k8master ~]# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-7d9697b7f8-5t8kp   1/1     Running   0          6s
web-7d9697b7f8-5ts25   1/1     Running   0          6s
web-7d9697b7f8-pmckl   1/1     Running   0          6s
web-7d9697b7f8-qls7t   1/1     Running   0          2m9s
web-7d9697b7f8-s8cvk   1/1     Running   0          2m11s

// 【将副本数 修改为  2 个(缩)】 (伸缩的过程极快)
[root@k8master ~]# kubectl scale deployment web --replicas=2
deployment.apps/web scaled
[root@k8master ~]#
[root@k8master ~]#
[root@k8master ~]# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-7d9697b7f8-pmckl   1/1     Running   0          102s
web-7d9697b7f8-qls7t   1/1     Running   0          3m45s

3.5 service

Service: 定义一组Pod的访问规则。

1、 为何需要service 这层抽象?

  • 防止Pod 失联
  • 定义一组Pod的访问规则(load balance)
    *在这里插入图片描述在这里插入图片描述

2、Service 和Pod 如何产生联系?
答曰:通过 labels & selector.
pod 具有 labels ;
serivce 有 selector:
serivce 使用 selector 来pick 哪些 pod 作为一组服务。

通过service实现服务注册和发现
在这里插入图片描述

3、常见service类型
先来看个例子:

kubectl expose --help

--type='': Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default is 'ClusterIP'.

这里看出来 service 的几种类型: clusterIP 、NodePort、LoadBalancer

  • clusterIP: 集群内部使用 【比如集群内部的POD之间的通信:集群中的前端POD调到后端POD ,再调到DB POD】
  • NodePort:对外提供服务 【内网部署应用,外网访问不到。如果要开放出去,可以在前面添加Nginx作反向代理】
  • LoadBalancer: 对外提供服务(但更多与公有云结合使用)

看下效果:

kubectl create deployment web --image=nginx --dry-run -o yaml > web.yaml
kubectl apply -f web.yaml
kubectl expose deployment web --port=80 --target-port=80 --dry-run -o yaml > service.yaml
// service中没有指定service 类型,则按 ClusterIP 处理
kubectl apply -f service.yaml

// 现在来看下pods,svc:
[root@k8master ~]# kubectl get pods,svc
NAME                       READY   STATUS    RESTARTS   AGE
pod/web-5dcb957ccc-mprzn   1/1     Running   0          10m
pod/web-5dcb957ccc-s4jg8   1/1     Running   0          10m

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP   4d8h
service/web          ClusterIP   10.1.143.33   <none>        80/TCP    2m38s

这里的 TYPE \ CLUSTER-IP 10.1.143.33 就是 前面说的用于集群内的service 类型,来测试下:
[root@k8master ~]# curl 10.1.143.33
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
.....

// 接着修改 service.yaml ; 增加了 service 类型为NodePort ;同时将 name 改为 web1(防止冲突)
[root@k8master ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web1
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  type: NodePort
status:
  loadBalancer: {}

// 再来看此时 pods svc

[root@k8master ~]# kubectl get pods,svc
NAME                       READY   STATUS    RESTARTS   AGE
pod/web-5dcb957ccc-mprzn   1/1     Running   0          17m
pod/web-5dcb957ccc-s4jg8   1/1     Running   0          17m

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP        4d8h
service/web          ClusterIP   10.1.143.33   <none>        80/TCP         10m
service/web1         NodePort    10.1.128.23   <none>        80:30762/TCP   87s

发现多出了一个service Type: NodePort,我们可从浏览器访问:
http://192.168.12.151:30762/ ,访问OK

3.6 Controller部署有状态应用(StatefulSet)

3.6.1 无状态与有状态

无状态:

  • 认为所有的POD都是一样的
  • 没有顺序要求
  • 不需要考虑在哪个Node执行
  • 随意进行伸缩

状态:

  • 不满足上述无状态的描述
  • 每个POD都独立,保持POD启动顺序和唯一性
    • 通过添加 唯一的网络状态、持久存储
    • 有序性

3.6.2 headless service

什么叫 无头 的?
其实说白了:ClusterIP=None的service,取而代之的是 域名,即:通过域名来操作。

比如说,正常情况下是 有头的 service。

[root@k8master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP        6d12h
web          ClusterIP   10.1.143.33   <none>        80/TCP         2d3h
web1         NodePort    10.1.128.23   <none>        80:30762/TCP   2d3h

3.6.3 部署Stateful 应用

1、准备个yml

[root@k8master ~]# cat sts.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    apps: nginx
spec:
  ports:
  - port: 80
    name: web
# 这里就是设置的无头的Service
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-statefulset
  namespace: default
spec:
  serviceName: nginx
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80

2、查看此时pods,svc

// 可以看到 : 有三个POD,每个都是唯一的名称
[root@k8master ~]# kubectl get pods,svc
NAME                      READY   STATUS    RESTARTS   AGE
pod/nginx-statefulset-0   1/1     Running   0          31s
pod/nginx-statefulset-1   1/1     Running   0          27s
pod/nginx-statefulset-2   1/1     Running   0          23s

// 【下面的 Service/Nginx 是无头的的service】
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.1.0.1     <none>        443/TCP   7d8h
service/nginx        ClusterIP   None         <none>        80/TCP    3m24s

前面提到: StatefulSet 的POD有唯一的网络标识,因此和Deployment相比,POD是有身份的。那域名怎么定义的呢?
答曰: 根据主机名,并根据一定规则生成域名

  • 每个POD有唯一主机名
  • 唯一域名:
    格式:
    主机名.service名称.名称空间.svc.cluster.local
    比如这个例子里第一个POD的域名:
ngnix-statefulset-0.nginx.default.svc.cluster.local

3.7 部署守护进程(daemonset)

特点:在每个Node节点上,运行同一个POD。新加入的Node,也加入这个POD。

这种部署方式十分常见:

  • 比如:在每个Node上都部署 日志收集工具

做个演示:
1、准备yml

[root@k8master ~]# cat ds.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: mydaemonset
  labels:
    app: filebeat
spec:
  selector:
    matchLabels:
       app: filebeat
  template:
    metadata:
      labels:
        app: filebeat
    spec:
      containers:
        - name: logs
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - name: varlog
              mountPath: /tmp/log
      volumes:
        - name: varlog
          hostPath:
            path: /var/log

2、查看

[root@k8master ~]# kubectl apply -f ds.yml
[root@k8master ~]# kubectl get pods -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
mydaemonset-cl847   1/1     Running   0          28s   10.244.2.16   k8node2   <none>           <none>
mydaemonset-vwk8v   1/1     Running   0          28s   10.244.1.17   k8node1   <none>           <none>

//  去看一下创建的 daemonset ,果然里面有很多的日志了
[root@k8master ~]# kubectl exec -it mydaemonset-cl847 bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@mydaemonset-cl847:/# ls /tmp/log/
anaconda           btmp           dmesg               maillog-20210307   rhsm              spooler-20210314      vmware-network.log
......

3.8 部署 Job(一次性的任务)

首先,创建yml

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
        - name: pi
          image: perl
          command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

然后启动任务:

[root@k8master ~]# kubectl create -f job.yml

若果本地没有镜像,首先要拉取镜像,会比较慢;过了一段时间后,注意这里的状态,是 Completed,表示已经完成了;还可以 kubectl logs PODNAME查看日志。

[root@k8master ~]# kubectl get pods
NAME       READY   STATUS      RESTARTS   AGE
pi-5x67j   0/1     Completed   0          3m4s

[root@k8master ~]# kubectl logs pi-5x67j
3.14159...

3.9 部署crobjob

[root@k8master ~]# cat cronjob.yml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox
              args:
                - /bin/sh
                - -c
                - date; echo hello from K8S cluster
          restartPolicy: OnFailure
[root@k8master ~]# kubectl apply -f cronjob.yml
//等待一段时间后;可见,这个cron job ,每分钟都会起一个容器,执行完之后,就销毁容器!!!
[root@k8master ~]# kubectl get pods
NAME                     READY   STATUS      RESTARTS   AGE
hello-1616077920-2vf94   0/1     Completed   0          2m39s
hello-1616077980-4tvdx   0/1     Completed   0          99s
hello-1616078040-4t2bt   0/1     Completed   0          39s

3.10 小结一下Controller

部署无状态: Deployment
部署有状态: StatefulSet
部署 Job: Job
部署CronJob: CronJob
部署守护进程: DaemontSet

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_30118563/article/details/114445652

智能推荐

储存环DCCT流强测量需要7位半表的说明_7位半数字电压表3706中文使用手册-程序员宅基地

文章浏览阅读358次。虽然仪表这两个指标都是同时提升的,但是我的感觉准确度是更重要的,对于一个恒定不变的电流或电压的测量,仪表的显示是以准确度相当的噪声变化得到测量结果,而不是以分辨率量级的变化。如果一个表,多配几个显示的管子显示,完全可以做出来8位半甚至9位半的超级仪表,但实际效果也许还不如一个5、6位半的表。_7位半数字电压表3706中文使用手册

Centos7 安装clang、LLVM_centos7 clang-程序员宅基地

文章浏览阅读1.9k次。其中 -DLLVM_ENABLE_RTTI=ON 这个选项需要重点说明一下。由于我的目的是为了研究bpf技术,所以不可避免的会涉及到编译安装bpftrace这个工具。在编译bpftrace工程的时候如果没有打开 LLVM 的RTTI,会导致编译失败。而这个编译选项默认是关闭的,所以这里必须明确打开这个功能。这个python版本要求至少3.6以上,不然会报如下错误。clang 13.0.1 安装成功。1、LLVM所有版本下载路径。2、这里安装版本13.0.1。我这个编译4个小时左右完成。_centos7 clang

期望薪资15k,不知vo和dto有何区别,能不能要?-程序员宅基地

文章浏览阅读300次。分享职场生活、职场攻略、程序员创业资源,为一线开发者提供优质内容有一位java求职者,三年工作经验,面试时问到VO和DTO有什么区别,他回答不出来,知识面挺广的,就是不够深入,薪资要1..._不喜欢dto

do_IRQ 函数细节-程序员宅基地

文章浏览阅读3.3k次。//// do_IRQ 函数执行完硬件 ISR 后退出时调用此函数。//void irq_exit(void){ account_system_vtime(current); trace_hardirq_exit(); sub_preempt_count(IRQ_EXIT_OFFSET); //_do_irq

python数据分析面试题目_一道经典的Python数据分析笔试题-程序员宅基地

文章浏览阅读252次。原标题:一道经典的Python数据分析笔试题最近无意看到一份关于数据分析的Python笔试题,做起来还是很有意思的,特意自己动手做了一下,和大家分享一下,希望大家也可以跟着练习。题目如下: 首先,模拟数据:importpandas aspdimportnumpy asnpdf = pd.DataFrame({ 'order_no':[ 'order_18213', 'order_16061', ..._将年龄列的缺失值用平均值填充,将性别列中的男,女分别替换为0、1

为什么自己新写的代码不能打断点_如何快速恢复被打断的思考-程序员宅基地

文章浏览阅读293次。此篇由下边的对话引出。三疯:最近工作中有什么困扰吗?万人迷:有一件。最近同时进行的工作种类有点多,而且杂。经常在苦思冥想一个开发问题或者热火朝天写代码的时候,突然来了另一件事情,新来的事情还得马上处理。这种被随时打断的感觉挺痛苦的,还不得不在内心抗拒的情况下转而处理插入的紧急事情。三疯:嗯……我有个做法你可以借鉴下。深度思考时被打断确实挺痛苦程序员在思考一个问题的时候,会持续深入的想很多东西。我的..._代码 不能断点

随便推点

蓝桥算法训练 乘法表,嵌套for循环_c语言for循环蓝桥杯-程序员宅基地

文章浏览阅读545次。问题描述输出九九乘法表。  输出格式输出格式见下面的样例。乘号用“*”表示。  样例输出下面给出输出的前几行:11=121=2 22=431=3 32=6 33=941=4 42=8 43=12 44=16首先对问题进行分析,其实可以发现这就是一个简单的嵌套循环,顾名思义就是在循环中在循环一次。分析完毕代码如下:#include<stdio.h>int main() { int i, j; for (int i = 1; i < 10; i++) { _c语言for循环蓝桥杯

配置Minecraft服务端文件-程序员宅基地

文章浏览阅读1.1w次,点赞5次,收藏11次。配置Minecraft服务端文件注:这是java版的服务端参数,参数介绍翻译自Mojang官方文档,地址:https://minecraft.gamepedia.com/Server.propertiesspawn-protection=16/* 通过将该值进行(x*2)+1的运算来决定出生点的保护半径。设置为0将不会禁用出生点保护。设置为0将会保护位于出生..._function-permission-level

TP6的服务在自定义composer包中如何使用_tp6 composer 详解 csdn-程序员宅基地

文章浏览阅读750次。这里的Service指的是注册到容器中的一系列可以调用的类或方法(函数)。看下是如何做到的,以下只对开发composer扩展包进行说明,写在项目目录中的可以参考官方的说明。3.新建src目录,并添加具体的服务文件:Test.php。2.扩展包添加composer.json文件。1.新建一个扩展包。_tp6 composer 详解 csdn

TM1650芯片使用经验_tm1650应用电路图-程序员宅基地

文章浏览阅读2w次,点赞12次,收藏53次。TM1650使用经验TM1650芯片功能TM1650芯片引脚TM1650通讯协议TM1650使用电路TM1650底层编程向TM1650发送指令编程TM1650芯片功能TM1650 是一种带键盘扫描接口的 LED(发光二极管显示器)驱动控制专用电路。内部集成有 MCU输入输出控制数字接口、数据锁存器、LED 驱动、键盘扫描、辉度调节等电路。TM1650 性能稳定、质量可靠、抗干扰能力强,可适用于..._tm1650应用电路图

neo4j 数组属性(属性值有多个)_neo4j 数组properties-程序员宅基地

文章浏览阅读3.6k次,点赞2次,收藏8次。1、多个属性值的设置语句match (m:公司{名称:["test3","test2"]}) return m2、多个属性的查询以及merge的使用OPTIONAL MATCH (n:公司) where "test3" in n.名称 WITH nwhere n is null merge (m:公司{名称:["test3","test2"]})return m(1)判断属性是否存在:直接用 "属性值 in 节点.属性名"的形式(2)merge和where不可以同时使用,._neo4j 数组properties

lxml.etree._ElementUnicodeResult 转为字符-程序员宅基地

文章浏览阅读3.6k次。lxml.etree._ElementUnicodeResult 转为字符在爬虫过程中,使用的是lxml的xpath查找对应的字段。address=each.xpath('.//address/text()')[0].strip()结果用address与一般的字符进行拼接时,总是出现UnicodeDecodeError: 'ascii' codec can't decode by..._lxml.etree._elementunicoderesult