kubernetes 基础干货
Posted wanglinjie122
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubernetes 基础干货相关的知识,希望对你有一定的参考价值。
1. 应用程序生命周期
#创建应用
kubectl create deployment web --image=nginx
#使用service 将pod暴露出去
kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web
#查看
kubectl get pods,svc
#访问应用
http://NodeIP:Port #端口随机生成,通过get svc获取
2. YAML 文件创建资源对象
kubectl create 创建一个资源
kubectl apply 从一个文件创建或者更新资源
标签重要性: 通过标签关联不同的资源
#查看service 关联的pod ip
kubectl get endpoints
apiVersion | API版本 |
---|---|
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本(实例)数量 |
selector | 标签选择器,与下面metadata.labels 保持一致 |
template | pod模板 |
spec | pod 的规格 |
containers | 容器配置 |
3. Deployment 介绍
Deployment 是最常用的k8s 工作负载控制器,是k8s 的一个抽象概念,用于更高级层次对象,部署和管理pod。
主要功能:
管理Pod 与ReplicaSet
具有上线部署、副本设定、滚动升级、回滚等功能
提供声明式更新,例如只更新一个新的image
应用场景: 网站 API 微服务
deployment 应用生命周期管理流程
应用程序——部署——升级——回滚——下线
当执行apply 部署应用时,deployment 向RS pod 扩容副本数量
回滚
kubectl rollout history deployment/web 查看历史版本
kubectl rollout undo deployment/web 回滚上一个版本
kubectl rollout undo deployment/web --to-revision=2 回滚历史指定版本
#回滚是重新部署某一次部署时的状态,即当时版本所有配置
4. Pod对象
Pod 是kubernetes 创建和管理的最小单元,一个pod 由一个容器或多个容器组成,这些容器共享存储、网络
POD的特点
一个pod 可以理解为一个应用实例,提供服务
Pod中容器始终部署一个Node上
Pod 中容器共享网络,存储资源
kubernetes直接管理pod,而不是容器
pod的主要用法:
运行单个容器:最常见的用法,在这种情况下,可以将pod看做是单个容器的抽象封装
运行多个容器: 封装多个紧密耦合且需要共享资源的应用程序
管理命令
创建pod:
kubectl apply -f pod.yaml
或者使用命令: kubectl run nginx --image=nginx
查看pod:
kubectl get pods
kubectl describe pod <pod名称> -n namesapce
查看日志:
kubectl logs <pod名称> -n namesapces
kubectl logs <pod名称> -n namespaces
进入终端
kubectl exec <pod名称> -n namespaces bash/sh
删除pod
kubectl delete pod <pod名称>
Pod 重启策略+健康检查
重启策略(restartPolicy)
* Always: 当容器终止退出后,总是重启容器,默认策略
* OnFailure: 当容器异常退出(退出状态码非0)时,才重启机器
* Never: 当容器终止退出,从不重启容器
健康检查有以下两种类型:
* livenessProbe(存活检查): 如果检查失败了,将杀死容器,根据pod的 restartPolicy 来操作
* readinessprobe(就绪检查): 如果检查失败,kubernetes会把pod 从service endpoints 剔除
支持以下三种检查方法:
httpGet: 发送HTTP请求,返回200-400范围状态码为成功
exec: 执行shell 命令返回状态码是0为成功
tcpSocket: 发起TCP Socket建立成功
环境变量
变量值得几种定义方式
* 自定义变量值
* 变量值从Pod 属性获取
* 变量值从Secret、ConfigMap 获取
kubernetes 调度
kubernetes 是基于list-watch机制控制的架构,实现组件间交互的解耦。
其他组件监控自己负责的资源,当这些资源发生变化时,kube-apiserver 会通知这些组件,这个过程类似发布与订阅
master: apiserver controller-manager scheduler
node: kube-proxy kubelet docker
创建一个pod的流程
1. kubelet 向apiserver发送一个创建pod 的请求
2. apiserver 接收到并向etcd 写入存储,写入成功后返回一个提示
3. scheduler 向apiserver查询未分配的pod资源,通过自身调度算法选择一个合适node 进行绑定(给这个pod打一个标记,标记分配到node1)
4. kubelet 向apiserver 查询分配到自己节点的pod,调用docker api(/var/run/docker.sock) 创建容器
5. kubelet 获取docker 创建容器的状态,并汇报给apiserver,apiserver 更新状态到etcd 存储
6. kubectl get pods 就能查看到pod状态
资源限制对调度的影响
apiVersion: v1
kind: Pod
metadata:
labels:
run: resources
name: resources
spec:
containers:
- image: nginx
name: web
resources:
#最小资源
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 1000Mi
#pod会根据Request 的值去查找有足够资源的Node来调度此Pod
limits 是最大可用资源,一般是requests的20% 左右,不太超出太多
limits 不能小于requests
reqeusts 只是一个预留机制,不是pod配置写多少,宿主机就会占多少资源
k8s 根据reqeusts来统计每个节点预分配资源,来判断下一个pod 能不能分配到这个节点
nodeSelector & nodeAffinity
nodeSelector: 用于将pod调度到匹配Label的Node上,如果没有匹配的标签会调度失败。
作用: 约束pod到特定节点运行
完全匹配节点标签
应用场景:
专用节点: 根据业务线将node分组管理
配置特殊硬件: 部分node 配有SSD硬盘 GPU
第一步 给节点打一个标签
kubectl label node k8s-node1 disktype=ssd
第二步 pod的yaml修改
root@k8s-master-01:~# cat resources1.yaml
apiVersion: v1
kind: Pod
metadata:
name: resources-ssh
spec:
nodeSelector:
disktype: "ssd"
containers:
- image: nginx
name: web
kubectl apply -f resources1.yaml
#然后查看是否跑到特定的节点上
kubectl get pod -o wide
nodeAffinity
节点亲和性类似于nodeSelector,可以根据节点上的标签来约束pod可以调度哪些节点
相比nodeSelector:
匹配有更多的逻辑组合,不只是字符串的完全相等,支持的操作
符有: In、Notln、Exists、DoesNotExist、Gt、Lt
调度氛围软策略和硬策略,而不是硬性要求
硬(required): 必须满足
软(preferred): 尝试满足,但不保证
# 硬性限制
cat resources1.yaml
apiVersion: v1
kind: Pod
metadata:
name: nodeaffinity-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type ### key的值
operator: In
values:
- gpu ### values的值
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
#软性限制
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 # 权重值,1-100,权重越大,调度到匹配节点的概率越大
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
Taint(污点)与Tolerations(污点容忍)
Taints: 避免Pod调度到特定Node 上
Tolerations: 允许pod调度到持有Taints的Node上
应用场景:
专用节点: 根据业务线将Node分组管理,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
配备特殊硬件: 部分Node 配有SSD硬盘、GPU,希望在默认情况下不调度该节点,只有配置看了污点容忍才允许配置
基于Taint的驱逐
Taint污点
格式
kubectl taint node [node] key=value:[effect]
# 例子
kubectl taint node k8s-node1 gpu=yes:NoSchedule
其中[effect]可取值:
NoSchedule: 一定不能被调度
PreferNoSchedule: 尽量不要调度,非必须配置容忍
NoExecute: 不仅不会调整,还会驱逐Node上已有的Pod
# 污点容忍是可以直接放宽条件写的,例如calico 不分key 与value,符合带有污点的是NoSchedule
tolerations:
- effect: NoSchedule
opeartor: Exists
nodeName
nodeName 指定节点名称,不经过调度器,并且给定节点上运行的kubelet 进程尝试执行该Pod,因此,如果nodeName在PodSpec中指定了,则它优先于上面的节点选择方法。
例子:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
service 介绍
将运行在一组pod上的应用程序公开为网络服务的抽象方法。
使用kubernetes,你无需修改应用程序即可使用不熟悉的服务发现机制,kubernetes 为pods提供自己的IP地址,并为一组Pod 提供相同的DNS 名,并且可以在它们之间进行负载均衡。
使用Pod IP就面临着ip 变化的情况,因为Pod 是非永久性资源,如果使用deployment 来运行你的应用程序,则它可以动态创建和销毁Pod,这样的话就会导致ip 随时变化。
# server 资源
kubernetes Service 是一种抽象的定义,Service 是不可变的,除非删除,这样的话可以有效的解决Pod IP变动的话问题,也可以有效的解耦这种关系。 即使有多个Pod,那么只需要连接一个可用的Service 即可解决负载问题。
定义Service
apiVersion: v1
kind: Service
metadata:
name: my-service #Service 的名字
spec:
selector:
app: MyApp # 指定关联Pod的标签
ports:
- protocol: TCP #协议
port: 80 # service 端口
targetPort: 9376 # 容器端口(应用程序监听端口)
type: ClusterIP #服务类型
Service 三种常用类型
##ClusterIP
ClusterIP 集群内部使用,只能在k8s 集群内
## NodePort
NodePort 对外暴露应用,通过每个节点上的IP和静态端口(NodePort)暴露服务。NodePort 服务会路由到自动创建的ClusterIP 服务。通过请求<节点IP>:<节点端口>,可以从集群的外部访问一个NodePort服务,端口范围30000-32767 在apiserver 里面可以修改端口范围。
NodePort 会在每台Node 上监听端口接收用户流量,
###LoadBalancer
LoadBalancer 对外暴露应用,适用公有云
Pod 对外暴露: 集群之内的其他应用
Service 代理模式
ipvs
在ipvs 模式下,kube-proxy 监视kubernetes 服务和端点,调用netlink 接口相应地创建IPVS规则,并定期将IPVS规则与kubernetes 服务和端点同步,该控制循环可确保IPVS状态与所需状态匹配。访问服务时,IPVS将流量定向到后端Pod之一。
IPVS 代理模式基于类似于iptables模式的netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。这意味着,与iptables 模式下的kube-proxy 相比,IPVS 模式下的kube-proxy 重定向通信延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS模式还支持更高的网络流量吞吐量。
IPVS 提供了更多选项来平衡后端Pod 的流量,这些是:
rr: 轮替
lc: 最少链接
dn: 目标地址哈希
sh: 源地址哈希
sed: 最短预期延迟
nq: 从不排队
iptables
kube-proxy 会监视kubernetes控制节点对Service 对象和Endpoints 对象的添加和移除。对每个Service,它会配置iptables 规则,从而捕获到达该Service 的clusterIP 和端口的请求,进而将请求重定向到Service的一组后端中的某个Pod上面。对于Endpoints对象,它也会配置iptables 规则,这个规则会选择一个后端组合。
DNS
coresDNS: 是一个DNS 服务器,kubernetes 默认采用,以Pod 部署在集群中,CoreDNS 服务监视kubernetes API,为每一个Service 创建DNS 记录用于域名解析
ClusterIP A 记录格式 <service-name>.<namespace-name>.svc.cluster.local
Ingress
ingress 公开了从集群外部到集群内服务的HTTP与HTTPS路由规则集合,而具体实现流量路由是有Ingress Controller 负责。
官网文档
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
需要先部署ingress-controlle 组件
https://github.com/kubernetes/ingress-nginx
创建ingress-nginx 规则
cat ingress-web.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: web.xingxing.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web # 关联service 的名称
port:
number: 80
## ingress 配置https
Ingress Controller 怎么工作的?
Ingress Controller 通过与kubernetes API 交互,动态的去感知集群中Ingress 规则变化,然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段Nginx 配置,应用到管理的Nginx 服务,然后热加载生效。 以此来达到Nginx 负载均衡器配置与动态更新的问题
网络存储卷 NFS
NFS卷: 提供对NFS挂载支持,可以自动将NFS共享路径挂载到Pod 中
# 安装nfs 插件 yum install nfs-utils -y
ConfigMap
ConfigMap 是一种API 对象,用来将非机密性的数据保存到键值对中。使用时,Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
ConfigMap 将你的环境配置信息和容器镜像解耦,便于应用配置的修改
例子
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# 类属性键;每一个键都映射到一个简单的值
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# 类文件键
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
#以环境变量方式使用的ConfigMap 数据不会被自动更新。更新这些数据需要重新启动Pod
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: demo
image: alpine
command: ["sleep", "3600"]
env:
# 定义环境变量
- name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
valueFrom:
configMapKeyRef:
name: game-demo # 这个值来自 ConfigMap
key: player_initial_lives # 需要取值的键
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
- name: config
configMap:
# 提供你想要挂载的 ConfigMap 的名字
name: game-demo
# 来自 ConfigMap 的一组键,将被创建为文件
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和SSH秘钥。
kubernetes Secret 默认情况下存储为base64-编码的、非加密的字符串。默认情况下,能够访问API 的任何人,或者能够访问kubernetes 下层数据存储(etcd)的任何人都可以明文方式读取这些数据。为了能够安全地使用Secret,可以配合使用RBAC 规则来限制。
kubernetes 安全框架
k8s 安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server 配置来启用插件。
1. Authentication(鉴权)
2. Authorization(授权)
3. Admission Control(准入控制)
客户端要访问k8s集群API Server,一般需要证书、Token 或者用户名+密码;如果Pod 访问,需要ServiceAccount
#k8s APIserver 提供三种客户端身份认证
https 证书认证: 基于CA证书签名的数字证书认证(kubeconfig)
http Token 认证: 通过一个Token 来识别用户(serviceaccount)
http Base认证: 用户名+密码的方式认证(已弃用)
RBAC(Role-Based Access Control,基于角色的访问控制:负责完成授权(Authorization))工作。
RBAC根据API 请求属性,决定允许还是拒绝。
比较常见的授权维度:
user: 用户
group: 用户分组
资源,例如pod、deployment
资源操作方法: get list create update patch watch delete
命名空间
API 组
准入控制(Admission Control )
Admission Control 实际上市一个准入控制器插件列表,发送到API Server 的请求都需要经过这个列表中的每个准入控制器插件的检查,检查不通过,则拒绝请求。
启用准入控制
kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger ...
关闭准入控制
kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...
查看插件哪些是默认启用的
kube-apiserver -h | grep enable-admission-plugins
基于角色的权限访问控制: RBAC
RBAC (Role-Based Access Control, 基于角色的访问控制)
是k8s 默认授权策略,并且是动态配置策略(修改即时生效)。
#主体(subject)
User 用户
Group 用户组
SeriveAccount 服务账号
#角色
Role 授权特定命名空间的访问权限
ClusterRole: 授权所有命名空间的访问权限
# 角色绑定
RoleBinding 将角色绑定到主体(subject) # 指定的命名空间中执行授权
ClusterRoleBinding 将集群角色绑定到主体 #在集群范围执行授权
etcd 集群备份恢复
#单实例备份
## 备份
ETCDCTL_API=3 etcdctl snapshot save snap.db --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key
## 恢复
#1. 先暂停kube-apiserver和etcd容器
mv /etc/kubernetes/manifests/ /etc/kubernetes/manifests.bak
mv /var/lib/etcd/ /var/lib/etcd.bak
#2. 恢复
ETCDCTL_API=3 etcdctl snapshot restore snap.db --data-dir=/var/lib/etcd
#3. 启动kube-apiserver 和etcd容器
mv /etc/kubernetes/manifests.bak /etc/kubernetes/manifests
####集群的备份,备份文件使用一个节点上的,
--endpoints=IP地址是主机自己的IP地址
#备份
ETCDCTL_API=3 etcdctl snapshot save snap.db --endpoints=https://$IP:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key
#集群恢复
1. 先暂停kube-apiserver 和etcd
###二进制
systemctl stop kube-apiserver
systemctl stop etcd
#kubeadm 与单集群一样
###在每个master 节点上进行恢复
先将刚在master 节点上备份的数据拷贝到其他节点上。确保恢复数据的一致性
--name k8s-master-01(etcd 配置文件写的名称,每个节点都不一样)
--initial-advertise-peer-urls=https://10.39.60.175:2380(在那个节点恢复写哪个节点IP)
--data-dir=/var/lib/etcd # etcd 数据读取的目录,需要和配置文件一致
ETCDCTL_API=3 etcdctl snapshot restore snap.db --name k8s-master-01 --initial-cluster="k8s-master-01=https://10.39.60.175:2380,k8s-master-03=https://10.39.60.157:2380,k8s-master-02=https://10.39.60.154:2380" --initial-cluster-token=etcd-cluster --initial-advertise-peer-urls=https://10.39.60.175:2380 --data-dir=/var/lib/etcd
### 启动kube-apiserver 和etcd容器
mv /etc/kubernetes/manifests.bak /etc/kubernetes/manifests ##kubeadm 方式
### 二进制方式
systemctl start etcd
systemctl start kube-apiserver
以上是关于kubernetes 基础干货的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点#kubernetes入门基础-pod的概念以及相关操作
#yyds干货盘点#kubernetes入门基础-Ingress的概念与使用
#yyds干货盘点#kubernetes入门基础-Service的概念以及相关操作