kubernetes 带状态程序部署-以mysql为例

背景

k8s 在部署带状态的程序相对来说比较麻烦,一个高可用的程序,应该可以在每一个node上跑,所以在程序的开发阶段就应该要考虑到部署阶段带来的问题,可以降低程序容器化

  1. 配置信息尽量写入DB,那么程序起来的时候直接从DB加载,无论从提高部署效率或者运营的角度来说,入库都是最好的选择,更新配置之后,replace pod就ok
  2. 无法入库的大文件配置,通过k8s的pv pvc来处理,参考
  3. 小文件配置,build docker的时候写入容器

k8s 支持的persistent volumes

目前支持的持久卷类型如下:(前面几项目前的网络环境难以实现)

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • FC (Fibre Channel)**
  • FlexVolume
  • Flocker
  • NFS
  • iSCSI
  • RBD (Ceph Block Device)
  • CephFS
  • Cinder (OpenStack block storage)
  • Glusterfs
  • VsphereVolume
  • Quobyte Volumes
  • HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
  • Portworx Volumes
  • ScaleIO Volumes
  • StorageOS

hostPath,也就是node的文件系统(貌似我最初接触docker挂在volume的时候就是这种方式,但是现在看来,在可用性真的弱)
cephfs和glusterfs都是linux生态上比较有名的分布式文件系统,使用上比nfs要复杂些,这里不展开。下面我使用的nfs,nfs相对于ceph和gluster,可用性略弱,搭建测试环境还是可以的。

https://kubernetes.io/docs/tasks/run-application/run-single-instance-stateful-application/

以mysql为例的带状态程序部署

由于这篇文章是部署完成之后写的,有一些时间数据可以能有差异,我当时使用的是default namespace,实际上namespace管理也很重要,最好在apply yaml的时候指定。

需要准备

  1. 一个nfs服务,每个节点都要安装nfs client
  2. 一个kubernetes 集群,带dashboard更佳(观察部署服务状态真的很方便)
  3. 外网环境!!
  4. kubectl operation

Step1: 准备pv pvc

我的k8s 环境如下

$kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
s01       Ready     master    7d        v1.10.3
s02       Ready         7d        v1.10.3
s03       Ready         7d        v1.10.3

mysql-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv01
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /opt/nfs_data/mysql
    server: 192.168.242.133

mysql-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

在对应的namespace apply一下配置,就可以看到下面状态
kubectl apply --namespace=targetNamespace -f *.yaml

$ kubectl get pv
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                    STORAGECLASS   REASON    AGE
mysql-pv01   20Gi       RWO            Recycle          Bound     default/mysql-pv-claim                            8h
$ kubectl get pvc
NAME             STATUS    VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound     mysql-pv01   20Gi       RWO                           8h

当你看到bound状态的时候,说明pv和pvc已经bind好,这样才可以进行下一步deployment
Note:关于pv和pvc是如何绑定的我最初看的官网的几个例子,但是都没发现有key相关的绑定,参考官方bind说明,大约就是说,容量大小和读取模式匹配就断匹配到了,我感觉bind算法说得也不是很清楚,可能要看代码才知道

Step2: deploy

mysql-deployment.yaml

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

apply 一下,等拉取镜像完成,容器创建完成后,可以看到,it may take a few minutes,

$ kubectl get deployment
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mysql     1         1         1            1           8h
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
mysql-648d67bf7c-r9ftr   1/1       Running   0          8h

到这步,mysql就基本部署完成了,pod已经起来,
$ kubectl exec -it mysql-648d67bf7c-r9ftr -- mysql -uroot -ppassword
到这一步,就可以看到非常熟悉的mysql console啦

Step3: expose

这里使用nodePort来暴露内部mysql的端口,这样在内网环境就可以访问到容器内的pod,由于这个是单点部署,需要知道mysql这个pod运行在哪个node,才能在内网环境下访问

 mysql-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: NodePort
  sessionAffinity: ClientIP
  selector:
    app: mysql
  ports:
    - port: 3306
      nodePort: 30010

mysql 这个pod运行在s02节点上,对应的IP:192.168.242.134,内网环境下可以直接通过s02节点的ip访问
mysql -h192.168.242.134 -P30010 -uroot -ppassword
接下来就可以看到mysql console了

以上步骤的最终效果

注意

以上部署是单点部署,只是为了跑通带状态程序的部署,在高可用性上非常弱
暴露的ip,要知道mysql运行在哪个node上,才能决定连接的ip,后续可以使用clusterIp方案。
安全问题,内网环境需要隔离

你可能感兴趣的:(DevOps,golang)