Kubernetes集群的学习笔记(7)
Kubernetes的Dashboard 和 分级认证权限。
Dashboard的简介Dashboard算是k8s的一个管理的web界面。不做具体的操作,登录的时候使用的是K8S提供的用户名和密码。
Dashboard的部署只需要从github进行apply资源清单即可。
Dashboard的登录使用Token登录
获取系统中默认的admin的token,或者创建一个需要登录和管理的ServiceAccount,然后Binding到Role或者 ClusterRole,进行权限的控制
查看集群中自动创建的dashboard的secret, 系统部署完成之后自动创建了一个可管理全部集群的secret
~]$ kubectl get secret -n kube-system | grep dashboard
dashboard-admin-token-g85h7 kubernetes.io/service-account-token 3 109d
在这个secret中有Token相关的信息
~]$ kubectl describe secret dashboard-admin-token-g85h7 -n kube-system
其中的Token字段的内容就是可以用来登录的令牌。复制到dashboard中粘贴即可
使用config文件登录
创建ServiceAccount,Binding到role
获取Secret,然后查看他的token
制作config文件
使用config文件登录
Kubernetes的管理方式
命令
create , run ,expose , delete ,edit ….
命令式配置文件
create -f , delete -f , replace -f
声明式配置文件
apply -f , patch
一般不混合使用,1.2 使用的是替换,但是3是立刻修改,立刻生效,所以还是比较危险的。
Kubernetes集群的学习笔记(6)
K8S的认证部分, ServiceAccount以及RBAC 。
授权插件
Node
ABAC
RBAC
Webhook
常用的授权插件就是RBAC
基于角色的授权和访问控制基于角色的访问控制,就是将权限授予Role,而不是User。 将权限的控制授予Role, 将User分配到Role。默认的是拒绝全部, 无法也无需定义拒绝权限,定义的Permission是许可访问的权限。
角色,User Accouts OR Service Accounts.
许可, Permission分为两个部分:Operation 以及 Object.
角色以及角色绑定Role – RoleBinding
Role 和 RoleBinding 是建立和控制 NameSpace 级别的权限。
集群角色以及集群角色绑定ClusterRole – ClusterRoleBinding
Cluster 和 ClusterBinding 是建立和控制 Cluster 级别的权限。
NOTE: 特殊的情况,可以对名称空间级别的
特殊的绑定方式ClusterRole – RoleBinding
可以使用 RoleBinding 绑定 ClusterRole, 那么这种情况下,Role只是具有NameSpace的权限。解释一下:雷在同一个Cluster中有多个不同的NameSpace,我需要对每个NameSpace都授权相同的权限,这种场景下:
如果使用RoleBinding 去绑定一个Role,那么每一个NameSpace都需要建立各自的 RoleBinding,并且都要各自绑定到Role。
如果建立一个ClusterRole, 使用RoleBinding绑定到ClusterRole上面,那么我只需要定义一个即可在全部集群范围内生效这个权限。这样的就相当于批量的进行Role的授权。
相关命令命令不做过多的解释,所有的资源可以通过explain获取,主要是记录逻辑和思路。
~]$ kubectl create role testrole --verb=get,list,watch --resources=pods -o yaml
~]$ kubectl get role
~]$ kubectl describe role pods-reader
~]$ kubectl create rolebinding test-rolebinding --role=testrole --user=testuser -o yaml
~]$ kubectl explain rolebinding
~]$ kubectl config use-context USERNAME@kubernetes
~]$ kubectl create clusterrole test-clusterrole --verb=get,list,watch --resource=pods -o yaml
~]$ kubectl explain clusterrole
~]$ kubectl get clusterrole
~]$
其他补充在RBAC中可以存在三类组件:
user
group
service account
创建Pod的过程中可以指定一个值叫做ServiceAccountName,如果授权ServiceAccount高等级的权限,那么,Pod会以这个Account运行,那么Pod中的应用程序也会有ServiceAccount的权限。也就是提高了Pod应用程序的等级,使得Pod可以对K8S的相关资源进行管理和配置。
i3wm的简单配置
将自己的桌面环境迁移到了i3。Gnome好用是好用的,但是体量还是有点儿大了,吃资源有点多。
这个现在已经更新到 DWM 上面了, 对于这里面还有其他的工具是一直在用的, 比如 picom 等等。
安装i3-gaps安装的过程比较简单,pacman 就完事儿了。
pacman -Syyu
pacman -S i3-gaps
这里有两个可以选择,一个是i3-wm, 还有一个是i3-gaps, 我用了i3gaps, 好看一些。
pacman -S alacritty
pacman -S polybar
pacman -S compton (最新的软件改名了,叫picom,但是安装的方式不变的。)
pacman -S picom
pacman -S dmenu
pacman -S rofi
pacman -S feh
pacman -S variety
pacman -S unzip-natspec
#unzip-natspec貌似是在archlinuxcn里面的,可以处理zip解压的时候乱码的问题,不用考虑手动指定解压的-O了。
配置i3在已经有Gnome环境的条件下,i3 的配置还是比较轻松的。
I3的使用说明i3默认的操作是使用Windows/Super/Mod这个按键(或者随便怎么叫吧,后面都说Super,和Gnome的口径一致),简单列举一下频率较高的使用方式
先说重载配置文件,使用 Super + Shift + r
退出到DM,使用Super + Shift + e, DM就是你的登录界面。
i3提供了10个虚拟桌面,切换虚拟桌面方式是可以通过Super + 1 - 10 快速切换
在默认的Tiling排列模式中切换排列位置Vertical和Horizontal. 通过Super V 或者 Super H
调整容器布局:
使用Stacking – Super + s 所有的标签堆叠显示最上方提供标签进行切换
使用Tabbed – Super + w 标签页方式显示所有窗口
使用Toggle – Super + e 平铺窗口模式,可切换不同的布局方式
打开程序可以通过terminal开启,或者Super + d 使用dmenu开启(可将 dmenu 替换成 rofi)
关闭程序可以通过Super + Shift + q关闭,或者鼠标点击x,不是所有的窗口都有x
在窗口间移动可使用 Super + {jkl;}四个按键;或者使用Super + {up,down,left,right}的arrowkey
可将窗口变更为Floating, 使用Super + Shift + Space
Floating窗口调整位置可长按Super 使用鼠标拖动调整位置
全屏程序使用 Super + f
i3的自定义配置配置文件的位置配置文件的路径: $HOME/.config/i3/config,所有的配置在这个文件下修改
自定义界面的设置默认的i3启动的时候还是挺丑的,我有四个设置:
gaps inner 5 # 设置i3窗口间的空隙大小,单位是像素。
new_window 1pixel # 设置新的窗口的边界宽度,效果是不显示窗口的title。
new_float 1pixel # 新的浮动窗口的边界宽度,同上。
smart_borders on # 在只有一个窗口的情况下自动最大化当前的窗口,不处理窗口的Gap。
默认terminal程序更改设置默认使用 Super + Enter 打开alacritty
bindsym $mod+Return exec --no-startup-id alacritty
alacritty 是一个使用GPU进行渲染的terminal模拟器,它有自己的配置文件,我的配置文件路径在:$HOME/.config/alacritty/alacritty.conf
*NOTE: 关于Alacritty的问题目前已经解决的差不多了。 还有还有一个问题是关于ssh过去之后不能正确的识别终端类型的问题,解决方案在后面。
默认打开Firefox我的设置是Super + p
bindsym $mod+p exec --no-startup-id firefox
开机启动一些程序我的开机启动了 Compton, Variety, Remmina,Aria2c, Polybar, ibus-daemon,剩下的看自己喜欢什么就安装什么就OK了。
exec_always --no-startup-id compton --config /home/liarlee/.config/compton/compton.conf -b
exec_always --no-startup-id variety
exec_always --no-startup-id remmina
exec_always --no-startup-id aria2c --conf-path=/home/liarlee/.aria2/aria2.conf
exec_always --no-startup-id sh /home/liarlee/.config/polybar/polybar_startup.sh
exec_always --no-startup-id ibus-daemon -dr
截屏功能快捷键默认的i3不能用PrintScreen我觉得有点儿难受,所以自己添加了快捷键和保存位置
bindsym --release Print exec "scrot -b -m /home/liarlee/Pictures/Scort_ScreenShot/screenshot.png"
更新:
之前的这个方式可以作为截图的快捷方式,但是当你需要连续的截图的时候就会特别的难受,因为新截图会自动覆盖掉旧的截图。更新一下新的方式,写一个脚本,当我们按下PrintSc的时候触发这个脚本,就可以对文件重命名了。
也许脚本名称可以叫 - screenshot.sh
#!/bin/bash
snapdate=`date "+%Y%m%d_%H%M%S"`
gnome-screenshot -f /home/hayden/screenshot/Screenshot-$snapdate.png
更新i3的配置文件,添加快捷键的管理。
bindsym --release Print exec "/home/liarlee/Scripts/System/screenshot.sh"
这样再截图就会保存到指定的位置,并且用时间命名区分开不同的截图,不会覆盖了。
调节音量快捷键由于已经有了PulseAudio, 所以i3自动增加了笔记本Func-key的调整,但是如果没有功能键的话,还是要按照如下自定义的。我调整音量用的Super + F2/F3, 也可以改其他的
# Use pactl to adjust volume in PulseAudio.
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status
bindsym $mod+F3 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status
bindsym $mod+F2 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status
bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status
拼音输入法我在Gnome下使用的是Ibus-rime框架的小鹤双拼,Gnome下开箱即用,但是i3需要做一些简单的配置,更改一些环境变量。
在自己的家目录 : touch .xprofile
添加内容如下:
export GTK_IM_MODULE=ibus
export QT_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
使用source读取配置文件中的环境变量,使环境变量生效。尝试输出echo $XMODIFIER查看是否已经生效,输出空值的话ibus还是无法使用。
结合上面的i3配置文件,使用ibus-daemon -dr启动,不要XIM。如果你使用了-x启动,在浮动的输入法工具栏中会显示一个禁止的标志,说明拼音未正常工作。
配置Polybar我基本上使用的是默认的Bar配置文件,还比较方便。
复制一个配置文件的模板到家目录的文件夹下:
cp -p /usr/share/doc/ploybar/config .config/polybar/config
编辑一个启动脚本
touch polybar_startup.sh
写入如下内容
#!/bin/bash
## kill all old process of ploybar
killall -q polybar
while pgrep -u $UID -x polybar > /dev/null; do sleep 1; done
echo "---" | tee -a /tmp/polybar.log
polybar example & /tmp/polybar.log 2>&1 &
echo "Polybar launched"
结合上面的i3配置进行开机自动运行即可。我觉得默认的这个还行,可以日常使用了,不调整了,太费劲了。
目前还未解决的问题无法在terminal中输入中文目前中文的输入法还是有些问题,无法在alacritty中输入中文,可能和ibus的关系比较大,我尝试使用fctix完全没有任何问题,所有的地方都可以输入中文,所以选择什么方式输入中文,各有所好吧。但是,Gnome环境和i3的环境是会冲突的,所以同时安装ibus和fcitx要考虑一下。
Alacritty中无法输入中文的问题已经解决了!
那么解决的方法如下:
在/etc/profile文件中(或者.zshrc中),添加如下的环境变量
export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULES=ibus
之后 ,
source /etc/profile
source ~/.zshrc
重新启动alacritty就可以使用了。
我想root cause是 ...
Kubernetes集群的学习笔记(5)
K8S集群的存储卷笔记。
整体的存储卷调用结构:
在k8s的集群中,Pod声明自己需要存储卷资源,同时创建自己的PVC,PVC绑定到集群中已经注册的PV资源,例如 已经建立的NFS网络空间。PV资源通过存储系统的分配,直接提供给Pod来使用。
PVC属于名称空间级别,PV属于集群资源。
存储卷的类型
EmptyDir:只在Node上存在的存储卷,Pod删除的时候存储卷也会被移除,无法持久存储,叫做EmptyDir,做临时存储和缓存使用,可以使用Node的内存。
HostPath: Docker的存储卷类型,Node节点上的目录。
网络存储: SAN, NAS; 分布式存储(Glusterfs,Cephfs,rbd); 云存储(EBS, Azure Disk,特定的托管在云上的服务)
kubectl explain pod.spec.volumes
可以查看支持那些存储。
PVC对于用户来说,无法掌握所有的存储系统的知识和技能,因此,创建了PVC的逻辑层,在定义需要使用存储卷的Pod中只需定义需要的空间以及存储的类型,不需要详细的考虑后端存储的信息和配置。
PVC被定义在Pods的配置中,一个 PVC可以被多个Pod同时访问。
PV存储类: Gold Storage Class, Sliver Storage Class, Bronze Stroage Class.三个不同级别的存储类。存储类直接接受PVC的内容并对PVC定义的容量等信息进行分配。
PV与存储服务的提供者直接绑定且需要在存储服务提供方配置完成。PV与PVC具有一一对应的关系。
PersistentVolumegitRepo仓库的使用:
gitRepo存储卷建立在EmptyDir的基础上,在Pod内建立空目录,同步Git的内容到空目录,Pod运行的过程中不会更改存储卷上的内容。也就是说,git同步是pod建立的时候同步的数据,不会对git项目的数据进行更改。Pod更改了存储卷中的数据不会自动推送到Git上(可以使用Sidecar进行推送和配置)。
PV资源的定义---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs:
path: /data/volumes/v1
server: storage1.liarlee.com
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 20Gi
使用apply命令进行应用即可。
查看所有的PV使用: kubectl get pv , 其中显示了PV的名称,大小,访问模式,回收策略,状态,建立时间等。
PersistentVolumeClaim使用的过程中,在Pod中定义PVC;PVC和PV是一一对应的,但是PVC可以被多个Pod调用和挂载。一个PV会Binding一个PVC,PVC在Pod中被定义。
PVC以及PV的状态,未绑定的状态叫做Pending,绑定后叫做Bound。
PVC的定义---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc001
namespace: default
spec:
accessModes: ["ReadWriteMany"]
resource:
request:
storage: 6Gi
ConfigMap资源configmap是明文资源,secret是base64的编码资源,因此安全程度提高了。configmap相当于外挂的配置文件,当Pods启动的时候直接挂载Configmap读取自己需要的配置内容。
配置应用容器化的方式
自定义命令行参数
配置文件直接放入镜像中
通过环境变量进行配置
存储卷
Cloud Native应用通过环境变量直接配置
通过EntryPoint脚本预处理环境变量作为配置问文件中的信息
docker config命令行方式
Configmap的创建configmap为了将配置文件中镜像中解耦,configmap可以直接注入到容器中直接使用,注入的方式可以使用存储卷,或者使用EntryPoint来处理。
通过命令直接传递键值:
kubectl create configmap cm-nginx --from-literal=nginx_server_name=nginx.liarlee.com --from-literal=nginx_server_port=80
kubectl create configmap cm-nginx --from-file=./nginx.conf # 直接传递文件到ConfigMap
kubectl get cm cm-nginx -o yaml # 用YAML的格式查看ConfigMap
通过YAML文件:
---
apiVersion: v1
kind: ConfigMap
data:
nginx.conf................................
metadata:
name: cm-nginx
namespace: default
创建Pod时ConfigMap使用环境变量方式:
---
apiVersion: v1
kind: Pod
metadata:
name: pod-nginx
namespace: default
labels:
app: pods-nginx
tier: frontend
annotations:
liarlee.com/created-by: "cluster admin"
spec:
containers:
- name: pod-nginx
image: nginx:latest
ports:
- name: http
containerPort: 80
env:
- name: NGINX_SERVER_PORT
valueFrom:
configMapKeyRef:
name: cm-nginx
key: nginx_port
env:
- name: NGINX_SERVER_NAME
valueFrom:
configMapKeyRef:
name: cm-nginx
key: nginx_server_name
创建Pod的时候使用挂载卷的方式:
通过挂载的方式可以通过修改configmap的方式,同步修改容器内部的配置。
---
apiVersion: v1
kind: Pod
metadata:
name: pod-nginx
namespace: default
labels:
app: pods-nginx
tier: frontend
annotations:
liarlee.com/created-by: "cluster admin"
spec:
containers:
- name: pod-nginx
image: nginx:latest
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/conf.d/
readOnly: true
Volumes:
- name: nginxconf
configMap:
name: cm-nginx
创建Secret的类型kubectl create secret –help
docker-registry – 连接到Docker私有仓库的密钥
generic – 通用的服务密钥
tls – 创建证书
StatefulSet的建立和使用在一定程度上实现了有状态的管理,但是依旧需要写成管理脚本,注入到Pod中。
CoreOS – 提供了 Operator相关的功能用来完善有状态的应用的部署。
两类不同的Pod
Cattle
Pet
最早叫做PetSet, 后面改成StatefulSet。
StatefulSet一般用于管理以下特性的组件:
稳定且有唯一的网络标识符;必须保持Pod的名称和地址稳定持久有效;
稳定且持久的存储;
有序平滑(Graceful)的部署及扩展;启动的时候Pod1 - Pod8;
有序平滑(Graceful)的终止和删除;关闭的时候Pod8 - Pod1;
有序的滚动更新;有顺序的进行Pod的更新;
有三个主要的部分;
1. Headless Service
- 类似于Redis,提供一个headless的服务,来确保每一个请求直达后端的pod,可保持pod的接入点稳定且不发生变化。
2. StatefulSet Controller
- 需要一个控制器来进行Pod的管理和控制,保持Pod的生命周期,即使Pod被终止也需要在启动后保持和之前一样的Pod信息。
3. Volume Claim Template
- 由于有状态的服务不能同时使用同一个PV,所有的节点存储的数据各不相同,所以不能提供一个PVC&PV。因此提供了申请PV的模板,每个Pod提供一个独立的存储卷用来做独立存储。
对于StatefulSet来说,确保所有的Pod名称稳定有效不可变动。大多数有状态的副本都会使用持久存储,多个Pod能不能共用同一个存储? 不能,每个Pod必须使用不同的存储。
所以,需要定义PV,定义PVC模板,定义Pod,定义Stateful控制器,定义headless服务这几种。
定义StatefulSet的YAML文件---
apiVersion: v1
kind: Service
metadata:
name: sts-headless-svc
labels:
Service: sts-headless-svc
spec:
ports:
- port: 80
name: sts-headless-svc
clusterIP: None
selector:
service: sts-headless-svc
---
apiVersion: app/v1
kind: StatufulSet
metadata:
name: sts
spec:
serviceName: sts
replicas: 3
selector:
matchlabels:
service: sts-headless-svc
template:
metadata:
labels:
service: sts-headless-svc
spec:
containers:
- name: sts-container
image: ikubernetes/SOMEIMAGE'SNAME
ports:
...
Kubernetes集群的学习笔记(4)
K8S Service资源的笔记以及Ingress资源的笔记。
k8s的serviceservice的模型: userspace(kube-proxy), iptables, ipvs
Service的类型请求发送的过程:
Client –> Node’s IP:Node’s Port –> Cluster’s IP:ServicePort –> PodIP: ContainerPort
Service的类型:
ClusterIP是将提供服务的Pods统一建立一个集群内部的可访问接口,为集群内部的服务提供入口,PodsPort to ClusterIP:Port.
NodePort是将Node的端口映射出去的方式,每个节点各自对外提供一组IP:Port用来对外提供服务 - PodsPort to NodePort.
LoadBalancer使用LBaaS的方式对外提供服务,共有云环境可用,例如阿里云。
Externalname可将外部的服务引入到集群的内部,需要提供的字段是外部网络的真正的DNS服务的CNAME(FQDN)。
HeadlessService是不提供ClusterIP,可将ServiceName直接解析到PodsIP。
上面的每一个类型的服务都是顺序增强的,也就是说,基础的模式是 ClusterIP 。
HTTPS的处理和思路
启动一个Pod对HTTPS进行卸载和LB
如果需要对HTTPS进行配置,Kubernetes本身提供的Service不能提供7层协议的卸载(将HTTPS卸载为HTTP与后端做通信以及数据交换),那么可行的方案是,建立一个新的Pod,例如nginx,由nginx-pod进行HTTPS的代理和卸载操作,但是这样的话就会有如下的流程:
User Request –> LBaaS(LB) –> Service - NodePort(LB) –> Pod - nginx proxy(LB) –> BackendPods
PROBLEM: 在这种情况下,用户的请求需要进行两次负载的转换才可以到达Pod,开销太大。
将Nginx的Pod与Node的Net名称空间进行共享
使得Nginx的Pod直接工作在Node的网卡级别上。免去了K8S的Service中间的一次转发。为了避免单点的故障,可将DeamonSet将Pod运行在一部分节点上。
Ingress Controller可以用于处理和卸载HTTPS协议的负载均衡器Pod控制器。
K8S四个附件: DNS, DashBoard, Ingress Controller, heasper。
如上的那种NginxPod,衍生为Ingress Controller, 独立运行的应用程序组成,不属于Controller Manager。通常由4种选择:HAProxy,Nginx,Envoy,Traefik。微服务使用更多的是Envoy。
Ingress资源定义IngressController如何建立一个期望的前端(Nginx URL Rewrite),同时定义了期望的后端(Upstream servers),更新后端负载Pod的信息。
Ingress类型Ingress资源的定义格式使用NginxServer的方式进行配置IngressPod
apiVersion: Extensions/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: nginx.test.local
http:
paths:
- path:
backend:
serviceName: svc-nginx
servicePort: 80
k8s所有的NS删除的时候都进入Terminating状态
集群无法删除Namespace解决方式。
Namespace 无法删除 始终处于Teminating强制删除的方法,临时方案。
将名称空间的配置文件导出。kubectl get namespace testtest -o json > tmp.json
编辑这个临时文件。vim tmp.json
删除spec字段中的值。
"spec" : {
"finalizers" : [ # delete this line.
"kubernetes" # delete this line.
] # delete this line.
}
```
使用另一个terminal, 运行本地的proxy, 连接到API server。 kubectl proxy --port=8888
通过ApiServer进行删除 curl -k -H "Content-Type: application/json" -X PUT --data-binary @tmp.json http://127.0.0.1:8001/api/v1/namespaces/[NEEDTODELETENS]/finalize;
这里面http的调用路径在 : tmp.json的 api 字段中。
运行结果返回NameSpace的相关信息应该就是删除了。
Namespace删除卡住的原因
Solution From Github: https://github.com/kubernetes/kubernetes/issues/60807
是某些服务的问题导致了无法删除掉相关的NS
kubectl get apiservice | grep False
kubectl api-resources –verbs=list –namespaced -o name | xargs -n 1 kubectl get -n [NEEDTODELETENS]
kubectl delete apiservice v1alpha3.kubevirt.io
其实是这个apiservice影响的,他的状态不正常导致的NS删除的时候卡住,删除这个apiservice就可以了。
Linux_Cobbler搭建本地YUM源同步k8s阿里云
昨天晚上尝试使用阿里云的时候出现问题 ,阿里云的k8s源安装的时候报错,无法正常通过yum安装。内网正好放了一台Cobbler,所以直接从Cobbler同步阿里的repo过来放到内网,防止这个事情再次发生。
Cobbler是什么
Cobbler是一个免费开源系统安装部署软件,用于自动化网络安装操作系统。 Cobbler 集成了 DNS, DHCP,软件包更新, 带外管理以及配置管理, 方便操作系统安装自动化。Cobbler 可以支持PXE启动, 操作系统重新安装, 以及虚拟化客户机创建,包括Xen, KVM or VMware. Cobbler透过koan程序以支持虚拟化客户机安装。Cobbler 可以支持管理复杂网路环境,如创建在链路聚合以太网的桥接环境。 FROM Wikipedia
Cobbler Repo的建立k8s的源,Cobbler直接建立的同步不可以是因为k8s的目录结构和一般软件源的结构不同。(开始以为阿里云会一直保持带有Pool文件夹的那个结构, 今天早上看到结构已经和普通的yumrepo一样了,记录一下出现这种问题怎么办好了。)其实解决的方案就是手动同步,使用Cobbler进行源的发布。其实也就是httpd发布出去。
建立阿里云的源[root@cobbler /]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[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
[root@cobbler /]# mv kubernetes.repo /etc/yum.repos.d/kubernetes.repo
[root@cobbler /]# yum clean all
[root@cobbler /]# yum makecache
[root@cobbler /]# yum repolist
# 在repolist中记录repoid
手动同步源[root@cobbler /]# reposync -n --repoid=kubernetes -p /var/www/cobbler/repo_mirror/ --allow-path-traversal
手动将已经同步好的目录创建为repo[root@cobbler /]# createrepo /var/www/cobbler/repo_mirror/kubernetes/
最后编辑一下自己的kubernetes.repo源文件,只指向本地的源就可以了。
Kubernetes集群的学习笔记(3)
k8s笔记YAML格式定义资源。
通过YAML定义PodsapiVersionkubectl api-versions查看所有可用的组名apiVersion:[Group/Version]
Kind 资源类别Metadata 元数据
name: uniq Key
namespace
labels Key-Value
annotations
SelfLink: 资源引用的链接API格式:/api/group/verison/namespaces/namespace/type/name
Speckubectl explain pods.spec可使用命令查看:定义用户期望的目标状态。
Status自动维护即可 ,不需要更改。
简单的YAML实例apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
version: v1
spec:
containers:
- name: app
image: nginx
- name: php-fpm
image: php-fpm
对Pods进行标签操作
查看标签kubectl get pods –show-labelskubectl get pods -l LABEL_NAME –show-labels
增加标签kubectl label pods pod-demo KEY VALUE
修改标签kubectl label pods pod-demo KEY VALUE –overwirte
指定selector选择标签 - 等值关系, 集合关系的标签选择器。kubectl get pods -l release=stablekubectl get pods -l release!=stablekubectl get pods -l “release in (v1, v2, v3)”kubectl get pods -l “release notin (v1, v2, v3)”
许多资源支持内嵌字段,matchLabels(直接给定键值) , matchExporession(基于给出的表达式进行选择)。常用的操作符号,In ; Notin ; Exists;NotExists;
Pod的生命周期
初始化容器init c(初始化主容器的执行环境),可以有多个,串行执行,直到最后一个init c执行结束。
main c在所有的初始化完成之后开始启动,在容器的运行时间与main c的执行时间基本一致;main c刚刚启动之后,可以手动执行Poststart;结束之前可以进行Prestop;
在Pod运行的过程中,提供Pod的Liveness probe; 提供Pod的Readiness probe。
常见的Pod状态:
Pending: 挂起,调度尚未完成;
Running: 运行状态;
Failed: 失败;
Succeeded: 成功;
Unknown: kubelet失去联络或者无法获取Pod信息时;
创建Pod的阶段:
创建提交请求给API server,目标状态保存到etcd;
API Server 请求 Schduler 进行Pod的调度;
API取得Pod的调度结果后,将信息记录到etcd;
Node节点获取到API server上的Pod状态更新后,开始按照调度的信息进行Pod的建立。
Pod生命周期中的重要行为:
初始化容器: init container ;
容器探测: liveness ,readiness;
容器的重启策略: restartPolicyAlways, OnFailure, Never; 三种策略中默认的设置时Always.
Pod的终止过程:
发送term信号, 默认等待30s,如果30s还未终止就强制终止。
存活检测可通过三种类型进行探测: ExecAction, TCPSocketAction, HTTPGetAction;
K8S将loop-lvm改为direct-lvm说明
对k8s集群进行存储驱动的调整,从loop-lvm 切换到direct-lvm。
k8s的几种不同的存储驱动
AUFS - 这是一个经过时间检验的存储驱动
DeviceMapper - Redhat系默认的驱动,有loop和direct两种不同配置
Btrfs - 我…. 这个文件系统的快照真的是贼好用,但是性能什么的….我倒觉得都一般
ZFS - 还没用过
VFS - 还没用过
Overlay2 - 简单的接触了一下,docker目前推荐的存储驱动
关于存储驱动选择的相关博客及文章
Docker引擎 - 选择存储驱动Docker五种存储驱动原理及应用场景和性能测试对比Docker系统八:Docker的存储驱动
Loop-lvm这是docker默认安装之后的选择,因为这样可以out-of-box,但是据说稳定性不佳,我没遇到稳定性的问题,但是遇到了IO高导致的整个虚拟机运行缓慢。Loop-LVM其实使用了linux中的使用loop设备我之前安装的一套k8s默认是使用overlay2的存储,可能是内核的版本过低导致无法使用其他的存储驱动,所以我觉得默认使用了loop-lvm。
loop-lvm的工作模式是,默认在/var/lib/docker/devicemapper/devicemapper/目录下生成data&metadata两个稀疏文件(我目前还不知道什么叫做稀疏文件),并将两个文件挂载为loop设备做为块设备来使用。按照这个说法的话确实如果直接对裸设备的想能和稳定性都应该更强。所以下面可以动手啦~
Direct-lvm这里直接放一个官方文档的链接好了。Device-Mapper-driver
切换loop-lvm到direct-lvm想要切换的原因其实是已经安装好的这个k8s的master节点在跑了很久之后,总是被zabbix监控到报警,硬盘负载高;cpu进程数高。cpu的进程数量高可以理解,毕竟监控了如此多的容器。硬盘负载高这个报警在系统中发现是/dev/loop2这个设备。对应去查找 docker info中的信息,发现这是k8s的存储所使用的。进而搜索到了关于loop-lvm&direct-lvm的相关问题,发现使用loop设备的方式应该实在性能上有影响的,k8s不推荐生产环境使用,所以考虑切换过来,今后毕竟还是要长期使用的。值得注意的是:切换一定会导致之前的容器无法使用。而且目前来看关键的数据是不能恢复的,所以最好是在之前已经做好了计划。
自动托管配置自动托管的配置主要是两部分,首先是建立一个空的LVM,不需要挂载,只要系统识别到即可。之后是更改配置文件及重启docker服务。
在虚拟机中加入一块新的硬盘,fdisk中识别为/dev/sdb;
关闭docker。systemctl stop docker.
在配置文件中加入如下的配置,注意格式不要错,不要丢下末尾的逗号:{
"storage-driver": "devicemapper", # 告诉docker应用使用的存储驱动
"storage-opts": [
"dm.directlvm_device=/dev/sdb", # 指定使用的块设备,不需要格式化,不需要分区。在这里指定了设备docker会自动完成创建LVM等等操作。
"dm.thinp_percent=95", # 指定Thinpool占用的百分比
"dm.thinp_metapercent=1", # 指定Thinpool Meta数据使用的百分比
"dm.thinp_autoextend_threshold=80", # 指定自动扩容的阈值
"dm.thinp_autoextend_percent=20", # 指定自动扩容的比例
"dm.directlvm_device_force=false" # 是否强制格式化设备,默认是false。如果使用dockerd启动的时候出现了提供需要强行格式化设备的提示,就改为True。
]
}
重新启动docker服务。如果正常启动可通过docker info 查看是否已经切换过来。
如果没有能成功启动,尝试重启虚拟机;尝试使用dockerd命令直接启动,根据dockerd的日志信息进行相应的修改。
常见错误有:Sep 23 18:38:03 k8s-master dockerd: time="2019-09-23T18:38:03.931876136+08:00" level=warning msg="[graphdriver] WARNING: the devicemapper storage-driver is deprecated, and will be removed in a future release"
# 存储驱动将会在未来的版本被移除的警告。这不会导致docker无法运行。
Sep 23 18:25:52 localhost dockerd: Error starting daemon: error initializing graphdriver: /dev/sdb is already part of a volume group "docker": must remove this device from any volume group or provide a different device
# 这个问题说明 docker 认为你的/dev/sdb上已经被创建了LVM,你需要手动指定,自动托管不会对这个设备进行操作。这会导致docker无法启动。
# 首先你需要把/dev/sdb这个设备从LVM里面移除,lvdelete,pvdelete,vgdelete, 将设备还原为默认的状态,之后重启docker,将设备的所有操作控制都交给docker来做,就不会有这个错误了。
总结在更换之后目前性能稳定,IO的负载也下来了。总体来看还是不错的。不过随着kubernetes的发展,我觉得这种问题应该会越来越少。还是推荐在安装的时候直接调整,不然数据的随时确实带来了一些麻烦。
RabbitMQ_SysV风格管理脚本模板
需要自己写一个RabbitMQ的SysV脚本,所以找了一个模板,如果需要的时候可以改改就用了。
SysV脚本#!/bin/sh
#
# rabbitmq-server RabbitMQ broker
#
# chkconfig: - 80 05
# description: Enable AMQP service provided by RabbitMQ
#
### BEGIN INIT INFO
# Provides: rabbitmq-server
# Required-Start: $remote_fs $network
# Required-Stop: $remote_fs $network
# Description: RabbitMQ broker
# Short-Description: Enable AMQP service provided by RabbitMQ broker
### END INIT INFO
# Source function library.
. /etc/init.d/functions
# 一些加注释的位置是需要修改的参数
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/data/erlang/bin # 更改PATH指向Erlang的路径
NAME=rabbitmq-server # 服务的名称,可以和脚本名称一致
DAEMON=/data/rabbitmq_server-3.6.13/sbin/${NAME} # 启动为守护进程的命令所在绝对路径
CONTROL=/data/rabbitmq_server-3.6.13/sbin/rabbitmqctl # 制定rabbitmqctl程序的所在位置, 绝对路径
DESC=rabbitmq-server # 目标服务
USER=root # 运行时的用户, 线上服务都使用了root用户
export HOME=/data/rabbitmq_server-3.6.13/ # 指定RabbitMQ的HOME目录,默认是在安装目录下;也有可能是在运行RabbitMQ用户的家目录下
ROTATE_SUFFIX=
# INIT_LOG_DIR=/usr/local/rabbitmq/var/rabbitmq
INIT_LOG_DIR=/data/rabbitmq_server-3.6.13/var/log/rabbitmq # 指出log的目录
# PID_FILE=/var/run/rabbitmq/pid
PDI_FILE=/data/rabbitmq_server-3.6.13/var/lib/rabbitmq/mnesia/rabbit@ean-online-dubbo-zk-rmq-server-209.pid # 指出当前RabbitMQ的PID文件所在目录
START_PROG="daemon"
LOCK_FILE=/var/lock/subsys/$NAME
test -x $DAEMON || exit 0
test -x $CONTROL || exit 0
RETVAL=0
set -e
[ -f /etc/default/${NAME} ] && . /etc/default/${NAME}
[ -f /etc/sysconfig/${NAME} ] && . /etc/sysconfig/${NAME}
ensure_pid_dir () {
PID_DIR=`dirname ${PID_FILE}`
if [ ! -d ${PID_DIR} ] ; then
mkdir -p ${PID_DIR}
chown -R ${USER}:${USER} ${PID_DIR}
chmod 755 ${PID_DIR}
fi
}
remove_pid () {
rm -f ${PID_FILE}
rmdir `dirname ${PID_FILE}` || :
}
start_rabbitmq () {
status_rabbitmq quiet
if [ $RETVAL = 0 ] ; then
echo RabbitMQ is currently running
else
RETVAL=0
# RABBIT_NOFILES_LIMIT from /etc/sysconfig/rabbitmq-server is not handled
# automatically
if [ "$RABBITMQ_NOFILES_LIMIT" ]; then
ulimit -n $RABBITMQ_NOFILES_LIMIT
fi
ensure_pid_dir
set +e
RABBITMQ_PID_FILE=$PID_FILE $START_PROG $DAEMON \
> "${INIT_LOG_DIR}/startup_log" \
2> "${INIT_LOG_DIR}/startup_err" \
0<&- &
$CONTROL wait $PID_FILE >/dev/null 2>&1
RETVAL=$?
set -e
case "$RETVAL" in
0)
echo SUCCESS
if [ -n "$LOCK_FILE" ] ; then
touch $LOCK_FILE
fi
;;
*)
remove_pid
echo FAILED - check ${INIT_LOG_DIR}/startup_\{log, _err\}
RETVAL=1
;;
esac
fi
}
stop_rabbitmq () {
status_rabbitmq quiet
if [ $RETVAL = 0 ] ; then
set +e
$CONTROL stop ${PID_FILE} > ${INIT_LOG_DIR}/shutdown_log 2> ${INIT_LOG_DIR}/shutdown_err
RETVAL=$?
set -e
if [ $RETVAL = 0 ] ; then
remove_pid
if [ -n "$LOCK_FILE" ] ; then
rm -f $LOCK_FILE
fi
else
echo FAILED - check ${INIT_LOG_DIR}/shutdown_log, _err
fi
else
echo RabbitMQ is not running
RETVAL=0
fi
}
status_rabbitmq() {
set +e
if [ "$1" != "quiet" ] ; then
$CONTROL status 2>&1
else
$CONTROL status > /dev/null 2>&1
fi
if [ $? != 0 ] ; then
RETVAL=3
fi
set -e
}
rotate_logs_rabbitmq() {
set +e
$CONTROL rotate_logs ${ROTATE_SUFFIX}
if [ $? != 0 ] ; then
RETVAL=1
fi
set -e
}
restart_running_rabbitmq () {
status_rabbitmq quiet
if [ $RETVAL = 0 ] ; then
restart_rabbitmq
else
echo RabbitMQ is not runnning
RETVAL=0
fi
}
restart_rabbitmq() {
stop_rabbitmq
start_rabbitmq
}
case "$1" in
start)
echo -n "Starting $DESC: "
start_rabbitmq
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
stop_rabbitmq
echo "$NAME."
;;
status)
status_rabbitmq
;;
rotate-logs)
echo -n "Rotating log files for $DESC: "
rotate_logs_rabbitmq
;;
force-reload|reload|restart)
echo -n "Restarting $DESC: "
restart_rabbitmq
echo "$NAME."
;;
try-restart)
echo -n "Restarting $DESC: "
restart_running_rabbitmq
echo "$NAME."
;;
*)
echo "Usage: $0 {start|stop|status|rotate-logs|restart|condrestart|try-restart|reload|force-reload}" >&2
...