k8s的核心概念,有了核心概念整个骨架就完整了,应付无状态程序已经够了,但还不够丰满。应用程序分成两种,无状态和有状态的。一般的前端和后端程序都是无状态的,而数据库是有状态的,它需要把数据存储起来,这样即使断电,数据也不会丢失。要创建有状态的程序,还需要引入另外一些k8s概念。它们虽然不是核心,但也很重要,共有三个,持久卷,网络和参数配置。
我们通过搭建MySQL来熟悉这些k8s概念。容器本身是无状态的,一旦出现问题它会被随时销毁,它存储的数据也就丢失了。MySQL需要一个能保存数据的持久层,在容器被销毁之后仍然存在,k8s叫它持久卷。
1 验证mysql镜像
#docker pull mysql:5.7
#docker run --name test-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=bigdata -d mysql:5.7
其中用户root密码bigdata
其中容器名字test-mysql
其中-p将容器3306映射到本机3306
其中-d后台运行
其中容器镜像mysql:5.7
#docker logs test-mysql查看日志
#docker ps 查看容器状态
#docker inspect test-mysql找到容器IP地址
# docker exec -it test-mysql /bin/bash进入容器
root@291c775dc19b:/# mysql -uroot -pbigdata
#docker stop test-mysql停止容器
容器IP地址
Navicat客户端连接数据库。
2 基于k8s安装mysql无状态
在k8s上安装MySQL分成三个部分,创建部署文件,创建服务文件和安装测试。
2.1 mysql_deployment.yaml
其中template之上是部署配置。
其中template向下是Pod配置。
其中containers向下是Pod里面的容器配置。
其中env是环境变量,这里通过环境变量来设置数据库的用户名和口令。
其中MySQL的端口是3306。
apiVersion: apps/v1
kind: Deployment # 类型是部署
metadata:
name: mysql-deployment # 对象的名字
spec:
selector:
matchLabels:
app: mysql #用来绑定label是“mysql”的Pod
strategy:
type: Recreate
template: # 开始定义Pod
metadata:
labels:
app: mysql #Pod的Label,用来标识Pod
spec:
containers: # 开始定义Pod里面的容器
- image: mysql:5.7
name: mysql-con
imagePullPolicy: IfNotPresent
env: # 定义环境变量
- name: MYSQL_ROOT_PASSWORD # 环境变量名
value: root # 环境变量值
- name: MYSQL_USER
value: dbuser
- name: MYSQL_PASSWORD
value: dbuser
args: ["--default-authentication-plugin=mysql_native_password"]
ports:
- containerPort: 3306 # mysql端口
name: mysql
2.2 mysql_service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-service
labels:
app: mysql
spec:
type: NodePort
selector:
app: mysql
ports:
- protocol : TCP
nodePort: 30306
port: 3306
targetPort: 3306
2.3 安装测试
#kubectl create -f mysql_deployment.yaml
#kubectl create -f mysql_service.yaml
Service中主要涉及三种Port:
(1)port 这里的port表示service暴露在clusterIP上的端口,clusterIP:Port 是提供给集群内部访问kubernetes服务的入口。
(2)targetPort
也是containerPort,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。
(3)nodePort
nodeIP:nodePort 是提供给从集群外部访问kubernetes服务的入口。
总的来说,port和nodePort都是service的端口,前者暴露给从集群内访问服务,后者暴露给从集群外访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端具体pod的targetPort,从而进入到pod上的容器内。
注意ClusterIP这个只能在k8s集群内部寻址。
注意NodePort这种方法可以在每个Node上开放一个对外端口,每一个指向这个端口的请求都被转发给一个服务。它的好处是你可以指定一个固定的端口(端口的取值范围只能是30000–32767),这样在笔记本上访问MySQL时就不用更换端口了。 如果你不指定,系统会随机分配一个。它的缺点是每个端口只能有一个服务,而且端口取值受限制,因此不适合生产环境。
通过navicat创建数据库mytest。
#kubectl delete -f mysql_service.yaml删除服务
#kubectl delete -f mysql_deployment.yaml删除部署
#kubectl apply -f mysql_deployment.yaml重新部署
#kubectl apply -f mysql_service.yaml重新服务
发现mysql数据库已经丢失。
3 基于k8s安装mysql有状态
3.1 卷和持久卷和持久卷声明
(1)卷(volume)
卷是k8s的存储概念,它依附于Pod,不能单独存在。但它不是在容器层。因此如果容器被重新启动,卷仍然在。但如果Pod重新启动,卷就丢失了。如果一个Pod里有多个容器,那么这些容器共享Pod的卷。你可以把卷看成是一个目录,里面可以存储各种文件。k8s支持各种类型的卷,例如本地文件系统和各种云存储。
(2)持久卷(PersistentVolume)
是对卷的一个封装,目的是为了更好地管理卷。它的生命周期不需要与Pod绑定,它可以独立于Pod存在。
(3)持久卷声明(PersistentVolumeClaim)
是对持久卷资源的一个申请,你可以申请特定的存储容量的大小和访问模式,例如读写模式或只读模式。k8s会根据持久卷申请分配适合的持久卷,如果没有合适的,系统会自动创建一个。持久卷申请是对持久卷的一个抽象,就像编程里的接口(Interface),它可以有不同的具体实现(持久卷)。
(4)动态持久卷
在这种情况下,你只需创建持久卷声明(不需要单独创建持久卷),然后把持久卷声明与部署绑定。系统会按照持久卷声明自动创建持久卷。下面是持久卷申请配置文件。其中“storage:1Gi”,是指申请的空间大小是1G。
3.2 mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: mysql
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi #持久卷的容量是 1 GB
3.3 mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.7
name: mysql-con
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD
value: root
- name: MYSQL_USER
value: dbuser
- name: MYSQL_PASSWORD
value: dbuser
args: ["--default-authentication-plugin=mysql_native_password"]
ports:
- containerPort: 3306
name: mysql
#名为mysql-persistent-storage的卷挂载到容器的目录/var/lib/mysql中。
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage #数据卷的名字
persistentVolumeClaim:
claimName: mysql-pv-claim #持久卷声明的名字
通过把持久卷声明当做持久卷来使用,与Pod进行绑定。
3.4 mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-service
labels:
app: mysql
spec:
type: NodePort
selector:
app: mysql
ports:
- protocol : TCP
nodePort: 30306
port: 3306
targetPort: 3306
3.5 安装测试
#kubectl apply -f mysql-pvc.yaml
#kubectl apply -f mysql-deployment.yaml
#kubectl apply -f mysql-service.yaml
在navicat创建mytest数据库
#kubectl delete -f mysql-service.yaml
#kubectl delete -f mysql-deployment.yaml
然后再部署
#kubectl apply -f mysql-deployment.yaml
#kubectl apply -f mysql-service.yaml
发现数据库mytest数据库仍然存在。
3.6 删除pv
先删除svc,再删除deployment,最后删除pvc,自动会删除对应的pv。
#kubectl delete -f mysql-service.yaml
#kubectl delete -f mysql-deployment.yaml
#kubectl apply -f mysql-pvc.yaml