kubernetes之PV及PVC案例

kubernetes之PV及PVC案例

概念

默认情况下容器中的磁盘文件是非持久化的,对于运行在容器中的应用来说面临两个问题,第一:当容器挂掉kubelet将重启启动它时,文件将会丢失;第二:当Pod中同时运行多个容器,容器之间需要共享文件时,Kubernetes的Volume解决了这两个问题

官方文档
https://kubernetes.io/zh/docs/concepts/storage/

PersistentVolume(PV)是集群中已由管理员配置的一段网络存储,集群中的存储资源就像一个node节点是一个集群资源,PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期, 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统,PV是由管理员添加的的一个存储的描述,是一个全局资源即不隶属于任何namespace,包含存储的类型,存储的大小和访问模式等,它的生命周期独立于Pod,例如当使用它的Pod销毁时对PV没有影响。

PersistentVolumeClaim(PVC)是用户存储的请求,它类似于pod,Pod消耗节点资源,PVC消耗存储资源, 就像pod可以请求特定级别的资源(CPU和内存),PVC是namespace中的资源,可以设置特定的空间大小和访问模式。

kubernetes 从1.0版本开始支持PersistentVolume和PersistentVolumeClaim。

PV是对底层网络存储的抽象,即将网络存储定义为一种存储资源,将一个整体的存储资源拆分成多份后给不同的业务使用。

PVC是对PV资源的申请调用,就像POD消费node节点资源一样,pod是通过PVC将数据保存至PV,PV在保存至存储。

PersistentVolume参数

# kubectl explain PersistentVolume

Capacity: #当前PV空间大小,kubectl explain PersistentVolume.spec.capacity

accessModes :访问模式,#kubectl explain PersistentVolume.spec.accessModes
    ReadWriteOnce – PV只能被单个节点以读写权限挂载,RWO
    ReadOnlyMany – PV以可以被多个节点挂载但是权限是只读的,ROX
    ReadWriteMany – PV可以被多个节点是读写方式挂载使用,RWX

persistentVolumeReclaimPolicy #删除机制即删除存储卷时候,已经创建好的存储卷由以下删除操作:
#kubectl explain PersistentVolume.spec.persistentVolumeReclaimPolicy
    Retain – 删除PV后保持原装,最后需要管理员手动删除
    Recycle – 空间回收,及删除存储卷上的所有数据(包括目录和隐藏文件),目前仅支持NFS和hostPath
    Delete – 自动删除存储卷

volumeMode #卷类型,kubectl explain PersistentVolume.spec.volumeMode
    定义存储卷使用的文件系统是块设备还是文件系统,默认为文件系统

mountOptions #附加的挂载选项列表,实现更精细的权限控制
    ro #等

官方提供的基于各后端存储创建的PV支持的访问模式
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options

PersistentVolume参数

#kubectl explain PersistentVolumeClaim.

accessModes :PVC 访问模式,#kubectl explain PersistentVolumeClaim.spec.volumeMode
    ReadWriteOnce – PVC只能被单个节点以读写权限挂载,RWO
    ReadOnlyMany – PVC以可以被多个节点挂载但是权限是只读的,ROX
    ReadWriteMany – PVC可以被多个节点是读写方式挂载使用,RWX

resources: #定义PVC创建存储卷的空间大小

selector: #标签选择器,选择要绑定的PV
    matchLabels #匹配标签名称
    matchExpressions #基于正则表达式匹配

volumeName #要绑定的PV名称

volumeMode #卷类型
    定义PVC使用的文件系统是块设备还是文件系统,默认为文件系统

运行java应用Jenkins

基于java命令,运行java war包或jar包,本次以jenkins.war 包部署方式为例,且要求jenkins的数据保存至外部存储(NFS或者PVC),其他java应用看实际需求是否需要将数据保存至外部存储

下载Jenkins War包

https://www.jenkins.io/download/

root@master1:/opt/data/dockerfile/web/jevon/jenkins# ls
Dockerfile  jenkins-2.222.1.war

镜像目录文件

root@master1:/opt/data/dockerfile/web/jevon/jenkins# tree
.
├── build-command.sh
├── Dockerfile
├── jenkins-2.222.1.war
└── run_jenkins.sh

0 directories, 4 files

Dockerfile

root@master1:/opt/data/dockerfile/web/jevon/jenkins# cat Dockerfile 
FROM harbor.linux.com/webimages/jdk-base:v8.212

MAINTAINER Jevonwei jevonran@163.com

RUN mkdir /apps/jenkins -p
ADD jenkins-2.222.1.war /apps/jenkings/
ADD run_jenkins.sh /usr/bin/

EXPOSE 8080

CMD ["/usr/bin/run_jenkins.sh"]

run_jenkins.sh

root@master1:/opt/data/dockerfile/web/jevon/jenkins# cat run_jenkins.sh 
#! /bin/bash
cd /apps/jenkins && java -server -Xms1024m -Xmx1024m -Xss512K -jar jenkins-2.222.1.war --webroot=/apps/jenkins/jenkins-data --httpPort=8080

root@master1:/opt/data/dockerfile/web/pub-images/jenkins# chmod a+x run_jenkins.sh

build-command.sh

root@master1:/opt/data/dockerfile/web/jevon/jenkins# cat build-command.sh 
#!/bin/bash
docker build -t harbor.linux.com/danran/jenkins:v2.222.1 .
sleep 1
docker push harbor.linux.com/danran/jenkins:v2.222.1

构建镜像

root@master1:/opt/data/dockerfile/web/jevon/jenkins# bash build-command.sh 
Sending build context to Docker daemon  66.29MB
Step 1/7 : FROM harbor.linux.com/webimages/jdk-base:v8.212
 ---> b2a21bae10f4
Step 2/7 : MAINTAINER Jevonwei jevonran@163.com
 ---> Running in b58233826de9
Removing intermediate container b58233826de9
 ---> 56998928e055
Step 3/7 : RUN mkdir /apps/jenkins -p
 ---> Running in 7d61ce262f02
Removing intermediate container 7d61ce262f02
 ---> f3ac8e57dde0
Step 4/7 : ADD jenkins-2.222.1.war /apps/jenkins/
 ---> 0ef8fb2eeb92
Step 5/7 : ADD run_jenkins.sh /usr/bin/
 ---> 29cb2aa6ca79
Step 6/7 : EXPOSE 8080
 ---> Running in 26d431e39c5a
Removing intermediate container 26d431e39c5a
 ---> 3a6a89c04f46
Step 7/7 : CMD ["/usr/bin/run_jenkins.sh"]
 ---> Running in 8f05103b2a30
Removing intermediate container 8f05103b2a30
 ---> 5e0134545cb2
Successfully built 5e0134545cb2
Successfully tagged harbor.linux.com/danran/jenkins:v2.222.1
The push refers to repository [harbor.linux.com/danran/jenkins]
a8612df0a8b6: Pushed 
b9bfd2cf304d: Pushed 
cc45b9ed58cf: Pushed 
9f96344cfb8b: Mounted from danran/tomcat-app1 
519b1d12005c: Mounted from danran/tomcat-app1 
1d12abb2850e: Mounted from danran/tomcat-app1 
23a3090b0538: Mounted from danran/nginx-web1 
45d27d00345a: Mounted from danran/nginx-web1 
6f12928590f2: Mounted from danran/nginx-web1 
25cbc4e383db: Mounted from danran/tomcat-app1 
9dd0e608b4ce: Mounted from danran/tomcat-app1 
6d161c41a7f7: Mounted from danran/nginx-web1 
034f282942cd: Mounted from danran/nginx-web1 
v2.222.1: digest: sha256:bec9583ffc5be0a4b142dba67b6f43bec319a0781012bb172d13b28d34b13e52 size: 3041
验证jenkins镜像
root@master1:~# docker run -it --rm -p 8081:8080 harbor.linux.com/danran/jenkins:v2.222.1

创建PV/PVC

需要两个PVC,一个保存jenkins的数据,一个保存.jenkins的数据

PV使用NFS存储挂载,请提前确保/data/k8sdata/danran NFS共享目录可挂载

root@master1:~# showmount -e 10.203.104.30
Export list for 10.203.104.30:
/data/k8sdata       *
PV

jenkins-persistentvolume.yaml

root@master1:/opt/data/yaml/danran/jenkins# cat jenkins-persistentvolume.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins-datadir-pv
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/jenkins-data
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins-root-datadir-pv
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/zookeeper-root-data

创建PV

root@master1:/opt/data/yaml/danran/jenkins# kubectl apply -f jenkins-persistentvolume.yaml 
persistentvolume/jenkins-datadir-pv created
persistentvolume/jenkins-root-datadir-pv created

验证PV

root@master1:/opt/data/yaml/danran/jenkins# kubectl get pv
NAME                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                            STORAGECLASS   REASON   AGE
jenkins-datadir-pv           20Gi       RWO            Retain           Available                                                            43s
jenkins-root-datadir-pv   20Gi       RWO            Retain           Available                                                            43
PVC

jenkins-persistentvolumeclaim.yaml

root@master1:/opt/data/yaml/danran/jenkins# cat jenkins-persistentvolumeclaim.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-datadir-pvc
  namespace: danran
spec:
  accessModes:
    - ReadWriteOnce
  volumeName: jenkins-datadir-pv
  resources: 
    requests:
      storage: 10Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-root-data-pvc
  namespace: danran
spec:
  accessModes:
    - ReadWriteOnce
  volumeName: jenkins-root-datadir-pv
  resources: 
    requests:
      storage: 10Gi

创建PVC

root@master1:/opt/data/yaml/danran/jenkins# kubectl apply -f jenkins-persistentvolumeclaim.yaml 
persistentvolumeclaim/jenkins-datadir-pvc created
persistentvolumeclaim/jenkins-root-data-pvc created

验证PVC

root@master1:/opt/data/yaml/danran/jenkins# kubectl get pv
NAME                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                            STORAGECLASS   REASON   AGE
jenkins-datadir-pv           20Gi       RWO            Retain           Bound    danran/jenkins-datadir-pvc                               6m13s
jenkins-root-datadir-pv   20Gi       RWO            Retain           Bound    danran/jenkins-root-data-pvc                             6m13s

root@master1:/opt/data/yaml/danran/jenkins# kubectl get pvc -n danran
NAME                      STATUS   VOLUME                    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
jenkins-datadir-pvc         Bound    jenkins-datadir-pv          20Gi       RWO                           2m28s
jenkins-root-data-pvc     Bound    jenkins-root-datadir-pv   20Gi       RWO                           2m28s

yaml文件

root@master1:/opt/data/yaml/danran/jenkins# cat jenkins.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: danran-jenkins
  name: danran-jenkins-deployment 
  namespace: danran
spec:
  replicas: 1
  selector:
    matchLabels:
      app: danran-jenkins
  template:
    metadata:
      labels:
        app: danran-jenkins
    spec:
      containers:
      - name: danran-jenkins-container
        image: harbor.linux.com/danran/jenkins:v2.222.1
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        volumeMounts:
          - mountPath: "/apps/jenkins/jenkins-data/"
            name: jenkins-datadir-danran
          - mountPath: "/root/.jenkins"
            name: jenkins-root-datadir
      volumes:
      - name: jenkins-datadir-danran
        persistentVolumeClaim:
          claimName: jenkins-datadir-pvc
      - name: jenkins-root-datadir
        persistentVolumeClaim:
          claimName: jenkins-root-data-pvc

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: danran-jenkins
  name: danran-nginx-service
  namespace: danran
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    nodePort: 38080
  selector:
    app: danran-jenkins

创建Pod

root@master1:/opt/data/yaml/danran/jenkins# kubectl apply -f jenkins.yaml 
deployment.apps/danran-jenkins-deployment created
service/danran-nginx-service created

验证Pod

root@master1:~# kubectl get pod -n danran
NAME                                                                                READY    STATUS    RESTARTS   AGE
danran-jenkins-deployment-788fd6d64f-n86cz             1/1          Running   0                 12s

web 登录测试

http://10.203.104.28:38080/

在pod中查看AdminPassword

[root@danran-jenkins-deployment-788fd6d64f-n86cz /]# cat /root/.jenkins/secrets/initialAdminPassword
30a2d1a3a59a4d3dbf9e3ab598cfd099

将AdminPassword填入web,登录

实战案例之Redis 服务

http://download.redis.io/releases/redis-4.0.14.tar.gz

构建redis镜像

镜像文件结构
root@master1:/opt/data/dockerfile/web/jevon/redis# tree
.
├── build-command.sh
├── Dockerfile
├── redis-4.0.14.tar.gz
├── redis.conf
└── run_redis.sh

0 directories, 5 files
Dockerfile
root@master1:/opt/data/dockerfile/web/jevon/redis# cat Dockerfile 
FROM harbor.linux.com/baseimages/centos-jevon-base:7.7.1908

MAINTAINER JevonWei "jevonran@163.com"

ADD redis-4.0.14.tar.gz /usr/local/src/
RUN ln -sv /usr/local/src/redis-4.0.14 /usr/local/redis && cd /usr/local/redis && make && cp src/redis-cli /usr/sbin/ && cp src/redis-server /usr/sbin/ && mkdir -pv /data/redis-data && mkdir -pv /var/log/redis/
ADD redis.conf /usr/local/redis/redis.conf
ADD run_redis.sh /usr/local/redis/run_redis.sh

EXPOSE 6379

CMD ["/usr/local/redis/run_redis.sh"]
编辑redis.conf
修改redis.conf配置文件的以下选项 
root@master1:/opt/data/dockerfile/web/jevon/redis# cat redis.conf
bind 0.0.0.0
save 900 1
save 5 1
save 300 10

dir /data/redis-data
requirepass danran
run_redis.sh
root@master1:/opt/data/dockerfile/web/jevon/redis# cat run_redis.sh 
#!/bin/bash

/usr/sbin/redis-server /usr/local/redis/redis.conf
tail -f /etc/hosts
build-command.sh
root@master1:/opt/data/dockerfile/web/jevon/redis# cat build-command.sh 
#!/bin/bash
TAG=$1
docker build -t harbor.linux.com/danran/redis:${TAG} .
sleep 1
docker push  harbor.linux.com/danran/redis:${TAG}
构建镜像
root@master1:/opt/data/dockerfile/web/jevon/redis# bash build-command.sh v1

运行redis服务

创建PV与PVC
PV

jenkins-persistentvolume.yaml

root@master1:/opt/data/yaml/danran/redis# cat redis-persistentvolume.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: redis-datadir-pv-1
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/redis-datadir

创建PV

root@master1:/opt/data/yaml/danran/redis# kubectl apply -f redis-persistentvolume.yaml 
persistentvolume/redis-datadir-pv created
PVC

redis-persistentvolumeclaim.yaml

root@master1:/opt/data/yaml/danran/redis# cat redis-persistentvolumeclaim.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis-datadir-pvc
  namespace: danran
spec:
  accessModes:
    - ReadWriteOnce
  volumeName: redis-datadir-pv-1
  resources: 
    requests:
      storage: 10Gi

创建PVC

root@master1:/opt/data/yaml/danran/redis# kubectl apply -f redis-persistentvolumeclaim.yaml 
persistentvolumeclaim/redis-datadir-pvc created
验证PV/PVC
root@master1:/opt/data/yaml/danran/redis# kubectl get pv
    NAME                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                            STORAGECLASS   REASON   AGE
redis-datadir-pv-1        20Gi       RWO            Retain           Bound    danran/redis-datadir-pvc                                 5m36s

root@master1:/opt/data/yaml/danran/redis# kubectl get pvc -n danran
NAME                            STATUS   VOLUME                    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
redis-datadir-pvc         Bound    redis-datadir-pv-1        20Gi       RWO                           11m
yaml文件
root@master1:/opt/data/yaml/danran/redis# cat redis.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: devops-redis
  name: deploy-devops-redis
  namespace: danran
spec:
  replicas: 1
  selector:
    matchLabels:
      app: devops-redis
  template:
    metadata:
      labels:
        app: devops-redis
    spec:
      containers:
      - name: redis-container
        image: harbor.linux.com/danran/redis:v1
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        volumeMounts:
          - mountPath: "/data/redis-data"
            name: redis-datadir
      volumes:
      - name: redis-datadir
        persistentVolumeClaim:
          claimName: redis-datadir-pvc

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: devops-redis
  name: srv-devops-redis
  namespace: danran
spec:
  type: NodePort
  ports:
  - name: http
    port: 6379
    targetPort: 6379
    nodePort: 36379
  selector:
    app: devops-redis
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
构建pod
root@master1:/opt/data/yaml/danran/redis# kubectl apply -f redis.yaml 
deployment.apps/deploy-devops-redis unchanged
service/srv-devops-redis created
查看srv-devops-redis service
root@master1:~# kubectl get svc -n danran
NAME                         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
danran-nginx-service         NodePort   172.28.129.39    <none>        80:38080/TCP                 3h25m
danran-nginx-spec            NodePort   172.28.111.204   <none>        80:40002/TCP,443:40043/TCP   3d14h
danran-tomcat-app1-service   NodePort   172.28.134.178   <none>        80:40004/TCP                 2d15h
srv-devops-redis             NodePort   172.28.158.139   <none>        6379:36379/TCP               5m26s
外部客户端访问redis
root@master1:~# redis-cli -h 10.203.104.26 -p 36379 -a danran

实战案例之MySQL 主从架构

https://kubernetes.io/zh/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
https://kubernetes.io/zh/docs/tasks/run-application/run-replicated-stateful-application/
https://www.kubernetes.org.cn/statefulset

基于StatefulSet实现

Pod调度运行时,如果应用不需要任何稳定的标示、有序的部署、删除和扩展,则应该使用一组无状态副本的控制器来部署应用,例如 Deployment 或 ReplicaSet更适合无状态服务需求,而StatefulSet适合管理所有有状态的服务,比如MySQL、MongoDB集群等。

基于StatefulSet 实现的MySQL 一主多从架构

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。

在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headlessservice,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。

StatefulSet 特点:
    -> 给每个pdo分配固定且唯一的网络标识符
    -> 给每个pod分配固定且持久化的外部存储
    -> 对pod进行有序的部署和扩展
    -> 对pod进有序的删除和终止
    -> 对pod进有序的自动滚动更新

StatefulSet的组成部分

Headless Service:用来定义Pod网络标识( DNS domain)。
StatefulSet:定义具体应用,有多少个Pod副本,并为每个Pod定义了一个域名。
volumeClaimTemplates: 存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应。

镜像准备

https://github.com/docker-library/ #github 下载地址

准备xtrabackup镜像
root@master1:~# docker pull registry.cn-hangzhou.aliyuncs.com/hxpdocker/xtrabackup:1.0
root@master1:~/package# docker tag registry.cn-hangzhou.aliyuncs.com/hxpdocker/xtrabackup:1.0 harbor.linux.com/danran/xtrabackup:1.0
root@master1:~/package# docker push harbor.linux.com/danran/xtrabackup:1.0
准备mysql 镜像
root@master1:~# docker pull mysql:5.7
root@master1:~/package# docker tag mysql:5.7.29 harbor.linux.com/danran/mysql:5.7.29
root@master1:~/package# docker push harbor.linux.com/danran/mysql:5.7.29

创建PV

创建五个PV,每个pod挂载一个pv

mysql-persistentvolume.yaml
root@master1:/opt/data/yaml/danran/mysql# cat mysql-persistentvolume.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-datadir-1
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/mysql-datadir-1
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-datadir-2
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/mysql-datadir-2
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-datadir-3
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/mysql-datadir-3
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-datadir-4
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/mysql-datadir-4
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-datadir-5
  namespace: danran
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 10.203.104.30
    path: /data/k8sdata/danran/mysql-datadir-5
创建PV
root@master1:/opt/data/yaml/danran/mysql# kubectl apply -f mysql-persistentvolume.yaml 
persistentvolume/mysql-datadir-1 created
persistentvolume/mysql-datadir-2 created
persistentvolume/mysql-datadir-3 created
persistentvolume/mysql-datadir-4 created
persistentvolume/mysql-datadir-5 created

root@master1:/opt/data/yaml/danran/mysql# kubectl get pv
NAME                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                            STORAGECLASS   REASON   AGE
mysql-datadir-1           20Gi       RWO            Retain           Available                                                            118s
mysql-datadir-2           20Gi       RWO            Retain           Available                                                            118s
mysql-datadir-3           20Gi       RWO            Retain           Available                                                            118s
mysql-datadir-4           20Gi       RWO            Retain           Available                                                            118s
mysql-datadir-5           20Gi       RWO            Retain           Available                                                            118s

部署Mysql

部署 MySQL 示例,包含一个 ConfigMap,两个 Services,与一个 StatefulSet。

文件结构
root@master1:/opt/data/yaml/danran/mysql# tree
.
├── mysql-configmap.yaml
├── mysql-persistentvolume.yaml
├── mysql-services.yaml
└── mysql-statefulset.yaml

0 directories, 4 files
ConfigMap
root@master1:/opt/data/yaml/danran/mysql# cat mysql-configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  labels:
    app: mysql
data:
  master.cnf: |
    # Apply this config only on the master.
    [mysqld]
    log-bin
    log_bin_trust_function_creators=1
    lower_case_table_names=1
  slave.cnf: |
    # Apply this config only on slaves.
    [mysqld]
    super-read-only
    log_bin_trust_function_creators=1
Services

以下 YAML 配置文件创建服务

root@master1:/opt/data/yaml/danran/mysql# cat mysql-services.yaml 
# Headless service for stable DNS entries of StatefulSet members.
apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  clusterIP: None
  selector:
    app: mysql
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
  name: mysql-read
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql
StatefulSet

拷贝https://kubernetes.io/zh/docs/tasks/run-application/run-replicated-stateful-application/的StatefulSet中的配置,并将image修改为harbor的镜像

创建pod
root@master1:/opt/data/yaml/danran/mysql# kubectl apply -f .
configmap/mysql created
service/mysql created
service/mysql-read created
statefulset.apps/mysql created
验证mysql pod
root@master1:/opt/data/yaml/danran/mysql# kubectl get pod -A | grep mysql
default                mysql-0                                                2/2     Running   0          115s
default                mysql-1                                                2/2     Running   1          87s
default                mysql-2                                                2/2     Running   1          59s
NFS中验证mysql数据

三个mysql 随机绑定了三个pv

root@ha1:~# ls /data/k8sdata/danran/mysql-datadir-1/
mysql
root@ha1:~# ls /data/k8sdata/danran/mysql-datadir-2/
mysql
root@ha1:~# ls /data/k8sdata/danran/mysql-datadir-3/
root@ha1:~# ls /data/k8sdata/danran/mysql-datadir-4/
root@ha1:~# ls /data/k8sdata/danran/mysql-datadir-5/
mysql

验证

在mysql-0 master中创建数据库danran

root@master1:~# kubectl exec -it mysql-0 bash
root@mysql-0:/# mysql
mysql> create database danran;
Query OK, 1 row affected (0.00 sec)

在mysql-1中查看新建的danran数据库是否存在

root@master1:~# kubectl exec -it mysql-1 bash
Defaulting container name to mysql.
Use 'kubectl describe pod/mysql-1 -n default' to see all of the containers in this pod.
root@mysql-1:/# mysql    
mysql> show databases;
+------------------------+
| Database               |
+------------------------+
| information_schema     |
| danran                 |
| mysql                  |
| performance_schema     |
| sys                    |
| xtrabackup_backupfiles |
+------------------------+ 
6 rows in set (0.00 sec)

k8s 示例之WordPress

https://cn.wordpress.org/
https://cn.wordpress.org/download/releases/

LNMP案例之基于Nginx+PHP实现WordPress博客站点,要求Nginx+PHP运行在同一个Pod的不同容器,MySQL运行与default的namespace并可以通过service name增删改查数据库

PHP代码通过NFS共享挂载到每个容器的的代码目录中

PHP镜像

官方PHP镜像

https://hub.docker.com/

 root@master1:~# docker pull php:5.6.40-fpm
root@master1:~# docker tag php:5.6.40-fpm harbor.linux.com/danran/php:5.6.40-fpm
root@master1:~# docker push harbor.linux.com/danran/php:5.6.40-fpm
准备PHP镜像
目录结构
root@master1:/opt/data/dockerfile/web/jevon/wordpress/php# tree
.
├── build-command.sh
├── Dockerfile
├── run_php.sh
└── www.conf

0 directories, 4 files
Dockerfile
root@master1:/opt/data/dockerfile/web/jevon/wordpress/php# cat Dockerfile 
#PHP Base Image
FROM harbor.linux.com/baseimages/centos-jevon-base:7.7.1908
MAINTAINER jevonran@163.com
RUN yum install -y https://mirrors.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm && yum install -y php56-php-fpm php56-php-mysql -y
ADD www.conf /opt/remi/php56/root/etc/php-fpm.d/www.conf
ADD run_php.sh /usr/local/bin/run_php.sh
EXPOSE 9000

CMD ["/usr/local/bin/run_php.sh]
run_php.sh
root@master1:/opt/data/dockerfile/web/jevon/wordpress/php# cat run_php.sh 
#!/bin/bash
/opt/remi/php56/root/usr/sbin/php-fpm
taif -f /etc/hosts

root@master1:/opt/data/dockerfile/web/jevon/wordpress/php# chmod +x run_php.sh
build-command.sh
root@master1:/opt/data/dockerfile/web/jevon/wordpress/php# cat build-command.sh 
#!/bin/bash
TAG=$1
docker build -t harbor.linux.com/danran/wordpress-php:${TAG} .
sleep 1
docker push  harbor.linux.com/danran/wordpress-php:${TAG}
构建镜像
root@master1:/opt/data/dockerfile/web/jevon/wordpress/php# bash build-command.sh v1

准备wordpress Nginx 基础镜像

目录结构
root@master1:/opt/data/dockerfile/web/pub-images/nginx-base-wordpress# tree
.
├── build-command.sh
├── Dockerfile
└── nginx-1.14.2.tar.gz

0 directories, 3 files
Dockerfile
root@master1:/opt/data/dockerfile/web/pub-images/nginx-base-wordpress# cat Dockerfile 
#Nginx Base Image
FROM harbor.linux.com/baseimages/centos-jevon-base:7.7.1908
MAINTAINER jevonran@163.com
RUN yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlibdevel openssl openssl-devel iproute net-tools iotop
ADD nginx-1.14.2.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.14.2 && ./configure --prefix=/apps/nginx && make && make install && ln -sv /apps/nginx/sbin/nginx /usr/sbin/nginx && rm -rf /usr/local/src/nginx-1.14.2.tar.gz
build-command.sh
root@master1:/opt/data/dockerfile/web/pub-images/nginx-base-wordpress# cat build-command.sh 
#!/bin/bash
docker build -t harbor.linux.com/webimages/nginx-base-wordpress:v1.14.2 .
sleep 1
docker push harbor.linux.com/webimages/nginx-base-wordpress:v1.14.2
构建镜像
root@master1:/opt/data/dockerfile/web/pub-images/nginx-base-wordpress# bash build-command.sh

准备wordpress PHP+Nginx镜像

目录结构
root@master1:/opt/data/dockerfile/web/jevon/wordpress/nginx# tree
.
├── build-command.sh
├── Dockerfile
├── index.html
├── nginx.conf
└── run_nginx.sh

0 directories, 5 files
Dockerfile
root@master1:/opt/data/dockerfile/web/jevon/wordpress/nginx# cat Dockerfile 
#Nginx Base Image
FROM harbor.linux.com/webimages/nginx-base-wordpress:v1.14.2

ADD nginx.conf /apps/nginx/conf/nginx.conf
ADD run_nginx.sh /apps/nginx/sbin/run_nginx.sh
RUN mkdir -pv /home/nginx/wordpress
RUN chown nginx:nginx /home/nginx/wordpress/ -R

EXPOSE 80 443
CMD ["/apps/nginx/sbin/run_nginx.sh"]
nginx.conf
root@master1:/opt/data/dockerfile/web/jevon/wordpress/nginx# cat nginx.conf 
user nginx nginx;
worker_processes auto;

events {
    worker_connections 1024;
    # multi_accept on;
}
http {
    sendfile on;      
    keepalive_timeout 65;
    client_max_body_size 10M;
    client_body_buffer_size 16K;
    client_body_temp_path /apps/nginx/tmp/ 1 2 2;
    
    include 	mime.types;
    default_type 	application/octet-stream;
    
    gzip on;
    
    server {
        listen 		80;
        server_name	localhost;

    # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;
        location / {
            root 	/home/nginx/wordpress;
            index	index.php index.html index.htm;
        }
    # pass PHP scripts to FastCGI server
    #
        location ~ .php$ {
            root 	/home/nginx/wordpress;
            fastcgi_index	index.php;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param	SCRIPT_FILENAME	$document_root$fastcgi_script_name;
            include 	fastcgi_params;

        }
       
        error_page	500 502 503 504 /50x.html;
        location = /50x.html {
            root	html;	
        }
   
    }
}
run_nginx.sh
root@master1:/opt/data/dockerfile/web/jevon/wordpress/nginx# cat run_nginx.sh 
#!/bin/bash
/apps/nginx/sbin/nginx
tail -f /etc/hosts
build-command.sh
root@master1:/opt/data/dockerfile/web/jevon/wordpress/nginx# cat build-command.sh 
#!/bin/bash
TAG=$1
docker build -t harbor.linux.com/danran/wordpress-nginx:${TAG} .
sleep 1
docker push  harbor.linux.com/danran/wordpress-nginx:${TAG}
构建nginx镜像
root@master1:/opt/data/dockerfile/web/jevon/wordpress/nginx# bash build-command.sh v1

运行WordPress站点

使用官方PHP镜像运行PHP环境,WordPress页面文件保存在后端存储NFS服务器

yaml
root@master1:/opt/data/yaml/danran/wordpress# cat wordpress.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: wordpress-app 
  name: wordpress-app-deployment
  namespace: danran
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress-app
  template:
    metadata:
      labels:
        app: wordpress-app
    spec:
      containers:
      - name: wordpress-app-nginx
        image: harbor.linux.com/danran/wordpress-nginx:v1
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 80
          protocol: TCP
          name: http
        - containerPort: 443
          protocol: TCP
          name: https
        volumeMounts:
          - name: wordpress
            mountPath: /home/nginx/wordpress
            readOnly: false

      - name: wordpress-app-php
        image: harbor.linux.com/danran/php:5.6.40-fpm
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 9000
          protocol: TCP
          name: http
        volumeMounts:
          - name: wordpress
            mountPath: /home/nginx/wordpress
            readOnly: false
      volumes:
      - name: wordpress
        nfs:
          server: 10.203.104.30
          path: /data/k8sdata/danran/wordpress
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: wordpress-app
  name: wordpress-app-spec
  namespace: danran
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30031
  - name: https
    port: 443
    protocol: TCP
    targetPort: 443
    nodePort: 30443
  selector:
    app: wordpress-app
运行wordpress
root@master1:/opt/data/yaml/danran/wordpress# kubectl apply -f wordpress.yaml 
deployment.apps/wordpress-app-deployment created
service/wordpress-app-spec created
验证pod
root@master1:~# kubectl get pods -n danran
NAME                                                                                     READY    STATUS    RESTARTS   AGE
wordpress-app-deployment-55bb954d5f-hmxn8              2/2          Running   0                  33s

在pod中确认nginx及php是否启用,确认nfs共享目录是否挂载

测试Nginx访问

在NFS 共享目录中创建一个index.html测试页,并将该共享目录的权限设置nginx的启动账号nginx可读,Pod中nginx的UID为2020

root@ha1:~# cd /data/k8sdata/danran/
root@ha1:/data/k8sdata/danran# chown 2020.2020 wordpress/ -R
root@ha1:/data/k8sdata/danran# cat wordpress/index.html 
Nginx Web Page

浏览器中访问Node节点的nginx暴露端口30031(http://10.203.104.27:30031/index.html)

测试PHP访问

在NFS 共享目录中创建一个PHP测试页,并将该测试页的权限设置nginx的启动账号nginx可读,Pod中nginx的UID为2020

root@ha1:/data/k8sdata/danran# cat wordpress/index.php
<?php
    phpinfo()
?>

root@ha1:/data/k8sdata/danran/wordpress# chown 2020.2020 index.php

浏览器中访问php测试页(http://10.203.104.27:30031/index.php)

将WordPress保存至NFS的共享目录

root@ha1:/data/k8sdata/danran/wordpress# ls
wordpress  wordpress-5.2.5.tar.gz
root@ha1:/data/k8sdata/danran/wordpress# tar zxvf wordpress-5.2.5.tar.gz


将wordpress解压后的数据移动到/data/k8sdata/danran/wordpress目录下
root@ha1:/data/k8sdata/danran/wordpress# mv wordpress/* .
root@ha1:/data/k8sdata/danran/wordpress# rmdir wordpress/
root@ha1:/data/k8sdata/danran/wordpress# ls
index.php    readme.html             wp-activate.php  wp-blog-header.php    wp-config-sample.php  wp-cron.php  wp-links-opml.php  wp-login.php  wp-settings.php  wp-trackback.php
license.txt  wordpress-5.2.5.tar.gz  wp-admin         wp-comments-post.php  wp-content            wp-includes  wp-load.php        wp-mail.php   wp-signup.php    xmlrpc.php

将该共享目录的权限设置nginx的启动账号nginx可读,Pod中nginx的UID为2020 
root@ha1:/data/k8sdata/danran/wordpress# chown 2020.2020 ./* -R
root@ha1:/data/k8sdata/danran/wordpress# ll

在浏览器访问http://10.203.104.27:30031/wp-admin/setup-config.php测试

HA中设置wordpress的负载均衡地址

root@ha1:~# cat /etc/haproxy/haproxy.cfg
listen danran-nginx-80
        bind 10.203.104.213:80
        mode tcp
        server master1 10.203.104.26:30031 check inter 3s fall 3 rise 5	
        server master2 10.203.104.27:30031 check inter 3s fall 3 rise 5	
        server master3 10.203.104.28:30031 check inter 3s fall 3 rise 5	

root@ha1:~# systemctl restart haproxy.service    

浏览器访问VIP地址测试(http://10.203.104.213/)

在本地hosts或DNS中添加VIP的主机名解析

10.203.104.213 www.linux.blog.com

测试主机访问wordpress(http://www.linux.blog.com/)

初始化WordPress站点

使用k8s中运行的mysql服务,作为mysql服务器,mysql服务器最好跟wordpress在同一NameSpace空间下

在mysql中创建wordpress数据库,并授权给wordpress用户
root@master1:~# kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
mysql-0                     2/2     Running   0          23h
mysql-1                     2/2     Running   1          23h
mysql-2                     2/2     Running   1          23h
 
root@master1:~# kubectl exec -it mysql-0 bash
Defaulting container name to mysql.
Use 'kubectl describe pod/mysql-0 -n default' to see all of the containers in this pod.
root@mysql-0:/# mysql
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 50586
Server version: 5.7.29-log MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

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> CREATE DATABASE wordpress;
Query OK, 1 row affected (0.01 sec)
mysql> GRANT ALL PRIVILEGES ON wordpress.* TO "wordpress"@"%" IDENTIFIED BY "wordpress";
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> exit
Bye
k8s中测试MySQL连接

web界面初始化

mysql所在的NameSpace为Default,mysql的mysql-services.yaml文件中写了连接数据库需使用mysql-0.mysql,故mysql的全域名为mysql-0.mysql.default.svc.danran.com

Database Host 添加Mysql的主机地址(如果mysql pod不在同一个namespace,那么就写对方services全称,以实现跨namespace的解析和访问)

验证k8s中mysql 数据

分别验证k8s中MySQL主库和从库是否数据

原文地址:https://www.cnblogs.com/JevonWei/p/13187031.html