k8s基础(一)
文章目录0、内容简介一、K8 introduction1.1 k8 功能1.2 k8 组件1.3 核心概念二、搭建2.1 部署模式2.2 kubeAdmin安装2.3 二进制包安装三、0、内容简介part1: k8s 基础概念part2: k8s 集群搭建通过kubeadmin基于二进制包part3:k8s核心技术pod控制器存储service调度器安全机制 RBAC包管理工具helmpart4:
文章目录
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
更多推荐
所有评论(0)