Kubernetes基础
一.k3s环境搭建
- 这里安装的是k3s,目的是简化繁琐的环境搭建快速上手使用
1. 每个机器都要运行(root)
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
2. 安装docker
sudo apt-get update
# 安装一些必须的包,这些包让 apt 可以通过 HTTPS 来使用一个仓库
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
# 添加 Docker 的官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 设置 Docker 稳定版仓库:你可以使用 Docker 提供的脚本来设置仓库,或者手动添加
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install docker-ce
sudo systemctl start docker
sudo systemctl enable docker # 开机自启
二.使用
1.Pod
- pod包含一个或者多个容器的容器组,是kubernetes中创建和管理的最小对象
1. pod是k8s中最小的调度单元,k8s直接管理pod而不是容器
2. 同一个pod容器总是被自动安排到集群的同一节点(物理机或虚拟机)上,并且一起调度
3. pod可以理解为运行特定应用的"逻辑主机",这些容器共享存储,网络和配置声明(如资源限制)
4. 每个pod有唯一的IP地址,IP地址分配给pod,在同一个pod内,所有容器共享一个IP地址和端口空间,pod内的容器可以使用localhost互相通信
kubectl run my_nginx --image=nginx:1.22
# -------- ------------------
# 名字 容器镜像
kubectl get pod #查看容器
kubectl logs -f my_nginx #查看指定容器日志
kubectl describe(单词意思:简述) pod my_nginx #查看容器的创建信息
kubectl get pod -owide #现实详细的pod信息
curl ip #可以访问ip
kubectl exec -it my_nginx -- /bin/bash #和容器进行交互
kubectl rum my-busybox --image=busybox -it --rm #一次性任务,退出pod时自动退出
kubectl delete pod my_nginx #删除pod
2.Deployment(部署) 和ReplilcaSet(副本集)
- ReplicaSet(副本集,是Pod的集合):它可以设置运行pod的数量,确保任何时间都有指定数量的Pod副本在运行,通常我们不直接使用ReplicaSet而是在Deployment中声明。
- Deployment(部署):Deployment是对ReplicaSet和pod更高级的抽象,它使pod拥有多副本,自愈,扩缩容,滚动升级能力
# 创建一个deployment, 指定副本的数量为3, 镜像为nginx:1.22
kubectl create deployment nginx-deploy --image=nginx:1.22 --replicas=3
kubectl get deploy
kubectl get pod
kubectl get replicaSet
# 你可以删除几个pod来测试一下,当你有pod下线,马上就有新的pod上线,使用保持pod数量和你设置的--replicas一致
# deployment缩放功能(手动缩放)
kubectl get replicaSet --watch #这个命令可以观察容器的缩放功能
kubectl scale deploy nginx-deploy --replicas=5 # 修改副本容器数量为5(此时容器会产生缩放)
# 自动缩放
# 创建容器pod最少数量为3 最大数量为10 cpu维持在75以下
kubectl autoscale deployment/nginx-auto --min=3 --max=10 --cpu-percent=75
# 自动缩放通过泽佳和减少副本的数量,保持所有的pod的平均cpu利用率不超过75%
# 自动缩放需要声明pod的资源限制,同时使用Metrice Server服务(k3s默认已经安装)
# 滚动更新
# 更新镜像,指定副本集,更新镜像版本
kubectl set image deploy/nginx-deploy nginx=nginx1.23
# 观察副本集
kubectl get rs[reploy缩写] --watch
# 会创建新的副本集,新的更新一个,旧的下线一个
# 版本回滚
# 可以查看副本集的版本
kubectl rollout history deploy/nginx-deploy
# 查看详情可以加上版本号
kubectl rollout history deploy/nginx-deploy --revision=1
# 进行回滚,加上版本号
kubectl rollout undo deploy/nginx-deploy --to-revision=1
3. Service服务
- Service将运行在一组Pods上的应用程序公开为网络服务的抽象方法, Service为一组Pod提供相同的DNS名,并且在它们之间负载均衡,k8s为Pod分配了IP地址,但IP地址可能会发生变化集群内可以使用Service的名称访问服务,而不需要担心Pod的IP发生变化。
- k8s service 定义了一种抽象,逻辑上的一组可以互相替换掉pod,通常称为微服务Service对应的Pod集合通常是通过选择运算符来确定的,比如一个Service里面有3个nginx副本,这些副本可以互换,我们不需要关心调用了哪个nginx,也不用去关注Pod的运行状态,只需要调用这个服务即可。
# --name=服务名称, --port=服务端口 --target-port=容器端口
kubectl expose deploy/nginx-deploy --name=nginx-service --port=8080 --target-port=80
# 查看服务
kubectl get service
# 通过查看到的ip + port 访问服务
curl ip:port
# 创建一次性pod,--rm表示退出时自动删除该容器
kubectl run test -it --image=nginx:1.22 --rm -- bash
# 通过service+port访问
curl nginx-service:8080
# 查看service信息,service 在Endpoints上的机器进行负载均衡
kubectl describe service nginx-service
# 可以进去修改其中一个pod,然后再多次访问service来测试负载均衡
kubectl exec -it [pod-name] -- bash
- 想要外部的机器能访问到service,需要给service定义类型。
ServiceType取值:
- ClusterIP:将服务公开在集群内部,k8s会给服务分配一个集群内部的IP,集群内的所有主机都可以通过这个Cluster-IP访问服务,集群内部的Pod可以通过service名称访问服务。
- NodePort: 通过每个节点的主机IP和静态端口(NodePort)暴露服务,集群的外部主机可以使用节点IP和NodePort访问服务。
- ExternalName:将集群外部的网络引入集群内部。
- LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。
# 通过以下命令,可以让外部端口,访问到内部的nginx-deploy上,名字是nginx-outside,对外端口是新生成的,需要查看节点信息来对对照
kubectl expose deploy/nginx-deploy --name=nginx-outside --type=NodePort --port=8081 --target-port=80
[root@k8s-master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 20h
nginx-service ClusterIP 10.43.7.249 <none> 8080/TCP 18h
nginx-outside NodePort 10.43.110.179 <none> 8081:31997/TCP 11s
# 这时候其他节点ip也能访问到该服务,是公布到所有节点上的,node-ip+31997就可以访问了

4.Namespace(命名空间)
- 命名空间是一种资源隔离机制,将同一资源划分为相互隔离的组,命名空间可以在多个用户之间划分集群资源。
# k8s默认会创建4个命名空间
[root@k8s-master ~]# kubectl get namespace
NAME STATUS AGE
default Active 21h
kube-system Active 21h
kube-public Active 21h
kube-node-lease Active 21h
# default: 默认,不可删除,未指定命名空间的对象都会分配到这里
# kube-system: 系统对象(控制平面和Node组件)所使用的命名空间
# kube-public:自动创建的公共命名空间,所有用户(未经过身份验证的用户)都可以读取,通常我们约定,将整个集群中公用的可见和可读的资源放在这个空间中
# kube-node-lease: (租约Lease) 对象使用的命名空间,每个节点都有一个关联的lease对象,lease是一个轻量级的资源,lease通过发送心跳,检测集群中的每个节点是否发生故障
kubectl get lease -A #查看lease对象
kubectl create ns develop # 创建新的命名空间
kubectl run nginx --image=nginx:1.22 -n=develop # 指定命名空间创建pod
kubectl get pod -n=develop # 查看指定命名空间下的pod
# 如果不指定命名空间,查询到的pod都是default
kubectl get pod # 默认default
kubectl config set-context ${kubectl config current-context} --namespace=devlop # 修改默认查询的命名空间
kubectl get pod # 这个时候就是查询的devlop命名空间下的内容了
# 删除命名空间(会清空所有命名空间下的内容,除非无法自动删除某些对象,那么这个命名空间就无法自动删除,通常是因为对象处于错误状态或者其他,删除掉这些对象就可以继续删除命名空间了)
kubectl delete ns develop
5.声明式对象配置
k8s中管理对象,有两种方式:
- 命令行指令:就是上面内容我们一直在玩的东西。
- 声明式配置:k8s使用yaml文件来描述k8s对象,声明式配置好比申请列表,学习难度大且配置困难,麻烦好处是操作留痕,适合操作复杂的对象,多用于生产。
常用命令缩写
namespace ns
nodes no
pods po
services svc
deployment deploy
replicasets rs
statefulsets sts
# yaml规范
* 缩进代表上下级关系
* 缩进只允许使用空格,通常两个字符
* : 键值对,后面必须有空格
* - 列表,后面必须有空格
* [] 数组
* # 注释
* | 多行文本块
* --- 表示文档的开始,多用于分割多个资源对象
group:
name: group-1
members:
- name: "Luo"
UID: 1001
- name: "JIU"
UID: 1002
# comments
word:
["I don't care money", "R U OK"]
test: |
line
new line
3rd line
---
group:
name: group-2
members:
- name: "Luo"
UID: 1001
- name: "JIU"
UID: 1002
# comments
word:
["I don't care money", "R U OK"]
test: |
line
new line
3rd line
在创建k8s对象所对应的yaml文件中,需要配置的字段如下:
* apiVersion: k8s API的版本
* kind: 对象类别,比如Pod,Deployment,Service,ReplicaSet
* metadata: 描述对象的元数据,包括一个name字符串,UID和可选的namespace
* spec: 对象的配置
使用yaml定义一个Pod
# 官方文档地址
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/
simple-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.22
ports:
- containerPort: 80
kubectl apply -f simple-pod.yaml #是配置文件生效
kubectl get pod
kubectl delete -f simple-pod.yaml #删除pod
6. 标签
- 标签(Labels)是附加到对象(比如Pod)上的键值对,用于补充对象的描述信息,标签能是用户能够以松散的方式管理对象的映射,而无需客户端存储这些映射,由于一个集群中可能管理程前上万个容器,我们可以使用标签高效的进行选择和操作容器集合。
# 键的格式:
* 前缀(可选)/名称(必须)
# 有效名称和值
* 必须为63个字符或者更少(可以为空)
* 如果不为空,必须以字母数字字符([a-z0-9A-Z])开头和结尾
* 包含破折号'-',下划线'_',点'.'和字母或数字
abel-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: label-demo
# 标签
labels:
environment: production
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.22
ports:
- containerPort: 80
kubectl apply -f label-pod.yaml
kubectl get pod --show-labels #查看容器的标签
# 可以使用-l来过滤标签,多个标签用逗号分割
kubectl get pod -l "app=nginx,environment=production"
选择器:标签选择器可以识别一组对象,标签不支持唯一性,标签选择器最常见的用法就是为Service选择一组Pod作为后端。
my-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
# 选择自己的选择器
app: nginx
ports:
# 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
- port: 80
targetPort: 80
# 可选字段
# 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767)
kubectl apply -f my-service.yaml
kubectl describe svc/my-service #查看service详情
Name: my-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.43.58.138
IPs: 10.43.58.138
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30007/TCP
Endpoints: 10.42.1.11:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# 你能看到Endpoints: 10.42.1.11:80,我们用以下命令查看pod机器
kubectl get pod -l "app=nginx" -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
lable-demo 1/1 Running 0 18m 10.42.1.11 k8s-woker1 <none> <none>
# 你会发现机器就是我们刚才启动的机器,选择器给你选择的Pod节点作为你服务的Pod
7.容器与镜像
- 容器运行时接口(CRI),Kubelet运行在每个节点(Node)上,用于管理和维护Pod和容器的状态,容器运行时接口(CRI)是Kubelet和容器运行时之间通信的主要协议,它将Kubelet与容器运行时解耦,理论上,实现了CRI接口的容器引擎,都可以作为k8s的容器运行时(Docker没有实现(CRI)接口,k8s使用dockershim来兼容docker,自V1.24版本其,Dockershim已从k8s项目中移除),crictl是一个兼容了CRI的容器运行时命令,他的用法和docker命令一样,可以用来检查和调试底层的运行时容器。
crictl ps
crictl images
# crictl和docker的操作很像,但是没有太多命令
# 在一些局域网的环境下,没发从互联网拉取镜像,可以手动的导出,导入镜像
# crictl没有命令导出导入镜像功能
# 需要使用ctr命令导入,导出镜像,他是containerd的命令行接口
# 我们只需要学会导入导出镜像即可,其他功能太难用了
# [导入]
docker images
docker pull alpine:3.15
docker save alpine:3.15 > alpine-3.15.tar
ls
scp alpine-3.15.tar root@ip:~
# 开始导入镜像
# k8s中,所有的镜像都位于(k8s.io)这个命名空间当中的,-n表示导入命名空间,最后还要指定上平台(linux/amd64)
ctr -n k8s.io images import alpine-3.15.tar --platform linux/amd64
# [导出]
ctr -n k8s.io iamges export alpine.tar docker.io/library/alpine:3.15 --platform linux/amd64
# =------= =--------= =---------------------------= =--------------------=
# 命名空间 导出位置 镜像位置 指定平台(arm64等)
# 导入镜像需要在每台机器上都导入,一般是在Google镜像下载不下来的时候这样干
三.实战
1. 金丝雀发布
流程描述:
1. 首先发布v1版本
2. 然后上线一部分v2版本
3. 继续扩大v2版本数量
4.v1版本全部下线
部署第一个版本
发布v1版本的应用,镜像使用nginx:1.22,数量为3
* 创建Namespace
* 创建Deployment
* 创建外部访问的Service
- 部署第一个版本
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-v1
namespace: dev
labels:
app: nginx-deployment-v1
spec:
replicas: 3
selector:
matchLabels: # 跟template.metadata.labels一致
app: nginx
template:
metadata:
labels:
app: nginx # 也就是和这行一致
spec:
containers:
- name: nginx
image: nginx:1.22
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: canary-demo
namespace: dev
spec:
type: NodePort
selector: # 更Deployment中的selector一致
app: nginx
ports:
# By default and for convenience, the `targetPort` is set to the same value as the `port` field.
- port: 80
targetPort: 80
# Optional field
# By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
nodePort: 30008
部署deploy-v1
[root@k8s-master ~]# kubectl apply -f deploy-v1.yaml
namespace/dev created
deployment.apps/nginx-deployment-v1 created
service/canary-demo created
# 可以看到创建了三个对象
# 查看指定命名空间下的所有对象
[root@k8s-master ~]# kubectl get all -n=dev
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-v1-645549fcf7-6vp4g 1/1 Running 0 111s
pod/nginx-deployment-v1-645549fcf7-dn4m8 1/1 Running 0 111s
pod/nginx-deployment-v1-645549fcf7-sg9vh 1/1 Running 0 111s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/canary-demo NodePort 10.43.134.77 <none> 80:30008/TCP 111s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment-v1 3/3 3 3 111s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-v1-645549fcf7 3 3 3 111s
- 创建Canary Deployment
发布新版本的应用,镜像使用docker/getting-staeted,数量为1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-canary # 修改名称
namespace: dev
labels:
app: nginx-deployment-canary # 修改标签
spec:
replicas: 1
selector:
matchLabels: # 跟template.metadata.labels一致
app: nginx
template:
metadata:
labels:
app: nginx
track: canary # 用于区别的新标签,便于单独查找
spec:
containers:
- name: new-nginx # 修改容器名称
image: docker/getting-started # 新镜像
ports:
- containerPort: 80
# 因为标签里面都有app: nginx,所以新部署的容器会被Selector自动加入到服务里面
[root@k8s-master ~]# kubectl apply -f deploy-canary.yaml
deployment.apps/nginx-deployment-canary created
[root@k8s-master ~]# kubectl get all -n=dev
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-v1-645549fcf7-6vp4g 1/1 Running 0 8m19s
pod/nginx-deployment-v1-645549fcf7-dn4m8 1/1 Running 0 8m19s
pod/nginx-deployment-v1-645549fcf7-sg9vh 1/1 Running 0 8m19s
pod/nginx-deployment-canary-74577469b5-w2vtp 1/1 Running 0 58s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/canary-demo NodePort 10.43.134.77 <none> 80:30008/TCP 8m19s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment-v1 3/3 3 3 8m19s
deployment.apps/nginx-deployment-canary 1/1 1 1 58s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-v1-645549fcf7 3 3 3 8m19s
replicaset.apps/nginx-deployment-canary-74577469b5 1 1 1 58s
[root@k8s-master ~]# kubectl describe service canary-demo -n=dev
Name: canary-demo
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.43.134.77
IPs: 10.43.134.77
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30008/TCP
Endpoints: 10.42.0.43:80,10.42.1.12:80,10.42.2.11:80 + 1 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# 注意Endpoints后面有一个+ 1 more...说明有一个新的pod加入到Service当中了
# 你可以尝试多访问几次该Service,负载均衡会让你访问到新上线的服务
curl 10.43.134.77:80
# 当你使用了一段时间,发现没什么问题,就可以把节点数量调整为3
kubectl scale deploy nginx-deployment-canary --replicas=3 -n=dev
# 然后开始慢慢下线nginx-deployment-v1中的内容(这里调整为了0)
kubectl scale deploy nginx-deployment-v1 --replicas=0 -n=dev
# 局限性
按照 Kubernetes 默认支持的这种方式进行金丝雀发布,有一定的局限性:
> 不能根据用户注册时间、地区等请求中的内容属性进行流量分配
> 同一个用户如果多次调用该 Service,有可能第一次请求到了旧版本的 Pod,第二次请求到了新版本的 Pod
# 在 Kubernetes 中不能解决上述局限性的原因是:Kubernetes Service 只在 TCP 层面解决负载均衡的问题,并不对请求响应的消息内容做任何解析和识别,如果想要更完善地实现金丝雀发布,可以考虑Istio灰度发布,Istio是服务网格技术。
2. 运行有状态的应用
以MySQL数据库为例,在kubernetes集群中运行一个有状态的应用,该部分比较难,部署数据库几乎覆盖了kubernetes中常见的对象和概念
* 配置文件--ConfigMap
* 保存密码--Secret
* 数据存储--持久卷(PV)和持久卷声明(PVC)
* 动态创建卷--存储类(StorageClass)
* 部署多个实例--StatefulSet
* 数据库访问--Headless Service
* 主从复制--初始化容器和sidecar
* 数据库调试--port-forward
* 部署Mysql集群--helm
- 创建mysql文件夹,用来单独操作
mkdir mysql
# 配置环境变量
* 使用MySQL镜像创建Pod,需要使用环境变量设置MySQL的初始密码。
* 环境变量配置示例(可以在docker hub中查看MySQL镜像的用法,配置文件见664行[mysql-pod.yaml])
# 挂载卷
* 将数据存储在容器中,一旦容器被删除,数据也会被删除。
* 将数据存储到卷(Volume)中,删除容器时,卷不会被删除。
# hostPath卷: hostPath卷将主机节点上的文件或目录挂载到Pod中(配置见681行)
mysql-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
spec:
containers:
- name: mysql
image: mysql:5.7
env: #环境变量,用于配置容器内应用程序的环境
- name: MYSQL_ROOT_PASSWORD #环境变量名称,MySQL初始化时的root用户密码
value: "123456" #环境变量值,设置root用户的密码为"123456"
ports: #定义容器的端口
- containerPort: 3306 #暴露的端口号,此处为MySQL默认的3306端口
volumeMounts: #挂载卷
- mountPath: /var/lib/mysql #定义卷的挂载点,即容器内的目录
name: data-volume
volumes: #定义Pod内的卷
- name: data-volume
hostPath:
path: /home/mysql/data #主机上的目录路径
type: DirectoryOrCreate #如果路径不存在,则创建目录
挂载卷的主要目的是将主机上的目录映射到容器内的目录,以实现数据持久化。具体效果如下:
主机路径:/home/mysql/data
容器路径:/var/lib/mysql
当Pod启动时,主机上的/home/mysql/data目录会被挂载到容器内的/var/lib/mysql目录,
这意味着在容器内对/var/lib/mysql目录的任何读写操作都会直接作用于主机上的/home/mysql/data目录
kubectl apply -f mysql-pod.yaml
kubectl get pod -owide
- ConfigMap与Secret
- 在Docker中,我们一般通过绑定挂载的方式将配置文件挂载到容器里,在Kubernetes集群中,容器可能被调度到任意节点,配置文件需要能在集群任意节点上访问、分发和更新。
ConfigMap
* ConfigMap 用来在键值对数据库(etcd)中保存非加密数据。一般用来保存配置文件。
* ConfigMap 可以用作环境变量、命令行参数或者存储卷。
* ConfigMap 将环境配置信息与 容器镜像 解耦,便于配置的修改。
* ConfigMap 在设计上不是用来保存大量数据的。
* 在 ConfigMap 中保存的数据不可超过 1 MiB。
mysql-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
volumeMounts:
- mountPath: /var/lib/mysql
name: data-volume
- mountPath: /etc/mysql/conf.d #最后将conf-volume挂在到/etc/mysql/conf.d(参考mysql官方文档)
name: conf-volume #指定要挂载的名字
readOnly: true #将配置文件设置为只读
volumes:
- name: conf-volume #conf-volume
configMap: #需要在这里引入configMap
name: mysql-config
- name: data-volume
hostPath:
# directory location on host
path: /home/mysql/data
# this field is optional
type: DirectoryOrCreate
---
apiVersion: v1 #创建configMap
kind: ConfigMap
metadata:
name: mysql-config
data:
mysql.cnf: |
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init-connect='SET NAMES utf8mb4'
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[root@k8s-master mysql]# kubectl apply -f mysql-pod.yaml
pod/mysql-pod created
configmap/mysql-config created
#可以看见创建了两个,一个是ConfigMap,一个是pod
[root@k8s-master mysql]# kubectl describe cm mysql-config #查看cm(缩写,configMap)信息
Name: mysql-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
mysql.cnf:
----
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init-connect='SET NAMES utf8mb4'
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
BinaryData
====
Events: <none>
[root@k8s-master mysql]# kubectl exec -it mysql-pod -- bash # 进入mysql
bash-4.2# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.44 MySQL Community Server (GPL)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
# 进入数据库后,可以查看其字符集
mysql> show variables like '%char%'
# 可以看到都是utf-8开头,有两个是系统字符集,无法更改
# 使用edit命令修改mysql-config配置文件
kubectl edit cm mysql-config
# 随便在里面加入一行注释
# eg: this is a msg
# 查看mysql-pod配置文件
kubectl exec -it mysql-pod -- bash
cat /etc/mysql/conf.d/mysql.cnf
# 可以看到多了一行注释,说明配置文件已经自动更新了
Secret:
Secret 用于保存机密数据的对象。一般由于保存密码、令牌或密钥等, 当修改secret后环境变量不会自动更新,需要手动更新
* data字段用来存储 base64 编码数据。
* stringData存储未编码的字符串。
* Secret 意味着你不需要在应用程序代码中包含机密数据,减少机密数据(如密码)泄露的风险。
* Secret 可以用作环境变量、命令行参数或者存储卷文件。
[备注]: 给数据加密成base64命令
echo your-passwd | base64
mysql-pod.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-password
type: Opaque
data:
PASSWORD: MTIzNDU2Cg== #BASE64编码(echo 123456 | base64)
---
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD # 密码是环境变量设置的,指定我们上面创建的Secret
valueFrom:
secretKeyRef:
name: mysql-password # 名字为mysql-password,对应上面834行的Secret名称
key: PASSWORD
optional: false # 此值为默认值;表示Secret已经创建了,可以直接使用我们创建的
volumeMounts:
- mountPath: /var/lib/mysql
name: data-volume
- mountPath: /etc/mysql/conf.d
name: conf-volume
readOnly: true
volumes:
- name: conf-volume
configMap:
name: mysql-config
- name: data-volume
hostPath:
# directory location on host
path: /home/mysql/data
# this field is optional
type: DirectoryOrCreate
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
mysql.cnf: |
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init-connect='SET NAMES utf8mb4'
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[root@k8s-master mysql]# kubectl apply -f mysql-pod.yaml
secret/mysql-password created
pod/mysql-pod created
configmap/mysql-config created
# 可以很明显看到多创建了一个secret
[root@k8s-master mysql]# kubectl describe secret/mysql-password #查看Secret
Name: mysql-password
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
PASSWORD: 7 bytes
# 可以看到加密数据: [PASSWORD: 7 bytes] 是不显示的
# [注意]: 当Secret被修改后,环境变量不会自动更新,需要重启pod
卷(Volume)
# 将数据存储在容器中,一旦容器被删除,数据也会被删除, 卷是'独立于容器之外'的一块存储区域,通过挂载(Mount)的方式供Pod中的容器使用
# 使用场景
* 卷可以在多个容器之间共享数据。
* 卷可以将容器数据存储在外部存储或云存储上。
* 卷更容易备份或迁移。
# k8s中常见的卷类型:
* 临时卷(Ephemeral Volume):与 Pod 一起创建和删除,生命周期与 Pod 相同
emptyDir - 作为缓存或存储日志
configMap 、secret、downwardAPI - 给Pod注入数据(注意这里configMap 、secret是卷的类型,并不是configMap 、secret对象)
* 持久卷(Persistent Volume):删除Pod后,持久卷不会被删除
本地存储 - hostPath、 local
网络存储 - NFS
分布式存储 - Ceph(cephfs文件存储、rbd块存储)
* 投射卷(Projected Volumes):projected 卷可以将多个卷映射到同一个目录上
[补充]: 一个集群中可以有多种存储,比如local,Nfs,Ceph,Cloud Storage,每一种存储单独对应一个存储类(Storage Class),存储类是存储和集群沟通的桥梁,
通过存储类,我们可以创建不同的持久卷,这些持久卷可以是预先创建好的,也可以是Pod请求动态创建的
- 临时卷(Ephemeral Volume),可以缩写为(EV),临时卷,顾名思义用来存储临时数据
* 与 Pod 一起创建和删除,生命周期与 Pod 相同
* emptyDir - 初始内容为空的本地临时目录
* configMap - 为Pod注入配置文件
* secret - 为Pod注入加密数据
[注意]: configMap和secret是卷的类型,他们会引用configMap和secret对象,创建一个临时卷,再将临时卷挂载到Pod中
apiVersion: v1
kind: Pod
metadata:
name: redis-pod
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {} #设置为emptyDir卷
其他类型也一样的格式写法
# 可以用以下命令查看临时卷
kubectl get ev
- 持久卷(PV)与持久卷声明(PVC)
* 持久卷(Persistent Volume):删除Pod后,卷不会被删除
> 本地存储
* hostPath - 节点主机上的目录或文件
(仅供单节点测试使用;多节点集群请用 local 卷代替)
* local - 节点上挂载的本地存储设备(不支持动态创建卷)
> 网络存储
* NFS - 网络文件系统 (NFS)
> 分布式存储
* Ceph(cephfs文件存储、rbd块存储)
* 持久卷(PersistentVolume,PV): 是集群中的一块存储, 可以理解为一块虚拟硬盘
持久卷可以由管理员事先创建, 或者使用存储类(Storage Class)根据用户请求来动态创建, 持久卷属于集群的公共资源,并不属于某个namespace
> 创建持久卷(PV)是服务端的行为,通常集群管理员会提前创建一些常用规格的持久卷以备使用。
hostPath仅供单节点测试使用,当Pod被重新创建时,可能会被调度到与原先不同的节点上,导致新的Pod没有数据。
多节点集群使用本地存储,可以使用local卷, 创建local类型的持久卷,需要先创建存储类(StorageClass)
local卷不支持动态创建,必须手动创建持久卷(PV)
创建local类型的持久卷,必须设置nodeAffinity(节点亲和性)
调度器使用nodeAffinity信息来将使用local卷的 Pod 调度到持久卷所在的节点上,不会出现Pod被调度到别的节点上的情况
* 持久卷声明(PersistentVolumeClaim,PVC): 表达的是用户对存储的请求
PVC声明好比申请单,它更贴近云服务的使用场景,使用资源先申请,便于统计和计费, Pod 将 PVC 声明当做存储卷来使用,
PVC 可以请求指定容量的存储空间和访问模式 。PVC对象是带有namespace的
剩下内容待更新...

浙公网安备 33010602011771号