美文网首页云原生
十四 中间件容器化及Helm

十四 中间件容器化及Helm

作者: 負笈在线 | 来源:发表于2022-05-19 09:00 被阅读0次

    (一) 容器化中间件

    1.如何部署应用到K8S


    当我们需要部署应用时后,考虑是否需要部署到K8S时一般需要考虑上图的几个因素。
    1.我们部署应用的架构是怎么样的:比如你要部署redis集群到K8S,就要了解redis集群架构是怎么样的;redis需要怎么样的配置,配置文件怎么加载(环境变量or配置文件),一些云原生的配置文件可以通过加载环境变量,例如rabbitMQ;程序监控端口是什么(redis6379,rabbit5672,15672),启动命令(./redis-server 配置文件 ).
    2.镜像谁来做:如果是公司自己的程序,那就自己做。如果是一个中间件,别人开发的,那么镜像在官方都是有的,不需要自己做,官方做的比自己做的好。
    3.找合适的部署方式:是否有状态的(倾向无状态应用deployment,中间件很多需要存储挂载PVC),配置分离:一般都是需要把配置文件分离,一些中间件可以通过环境变量加载的,就直接填环境变量,否则配置需要分离出来做成configmap,然后挂载在容器中;
    4.然后这个程序如何被使用:什么协议,内部使用还是外部使用,比如redsi使用TCP协议,例如rabbitMQ使用web客户端访问监控端使用http协议,如果是一个TCP协议的内部访问,使用svc名称就可以访问,外部访问的话一般用NODEPORT暴露出去。如果是http协议可以用ingress外部代理出去使用。

    2.部署一个单实例到K8S

    1)找到官方镜像:https://hub.docker.com/
    2)确认需要的配置:环境变量或配置文件
    3)选择部署方式:Deployment或其他的
    4)配置访问:TCP或HTTP

    2.1.部署rabbitMQ到K8S

    首先在官网网站找到rabbitMQ的镜像,搜索选择合适的镜像下载同步到公司的镜像仓库。



    确认配置文件:rabbitMQ是可以通过环境变量方式经行配置 然后确认部署方式:由于rabbitMQ是单实例,所以可以用deployment部署,消息队列一般要保存数据做持久化,所以也要挂载PVC(挂载目录/var/lib/rabbitmq)。 写deployment,pvc部署文件,可以官网找模板自己改:

    [root@k8s-master01 ~]# vim rabbitMQ-deployment.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: rabbitmq
      namespace: public-service
    spec:
      ports:
      - name: web
        port: 5672
        protocol: TCP
        targetPort: 5672
      - name: http
        port: 15672
        protocol: TCP
        targetPort: 15672
      selector:
        app: rabbitmq
      sessionAffinity: None
      type: NodePort
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations: {}
      labels:
        app: rabbitmq
      name: rabbitmq
      namespace: public-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: rabbitmq
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: rabbitmq
        spec:
          affinity: {}
          containers:
          - env:
            - name: TZ
              value: Asia/Shanghai
            - name: LANG
              value: C.UTF-8
            - name: RABBITMQ_DEFAULT_USER   #通过环境变量配置默认管理员用户密码
              value: user
            - name: RABBITMQ_DEFAULT_PASS
              value: password
            image: rabbitmq:3.8.17-management
            imagePullPolicy: IfNotPresent
            lifecycle: {}
            livenessProbe:
              failureThreshold: 2
              initialDelaySeconds: 30
              periodSeconds: 10
              successThreshold: 1
              tcpSocket:
                port: 5672
              timeoutSeconds: 2
            name: rabbitmq
            ports:
            - containerPort: 5672
              name: web
              protocol: TCP
            readinessProbe:
              failureThreshold: 2
              initialDelaySeconds: 30
              periodSeconds: 10
              successThreshold: 1
              tcpSocket:
                port: 5672
              timeoutSeconds: 2
            resources:
              limits:
                cpu: 1000m
                memory: 1024Mi
              requests:
                cpu: 250m
                memory: 500Mi
          restartPolicy: Always
    
    [root@k8s-master01 ~]# kubectl create ns public-service  #单独创建一个命名空间
    
    [root@k8s-master01 ~]# kubectl create -f rabbitMQ-deployment.yaml
    [root@k8s-master01 ~]# kubectl get pod -n public-service 
    NAME                        READY   STATUS    RESTARTS   AGE
    rabbitmq-77b5d5b747-6nl55   1/1     Running   3          2d
    
    [root@k8s-master01 ~]# kubectl get svc -n public-service 
    NAME       TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                          AGE
    rabbitmq   NodePort   10.108.113.166           5672:31142/TCP,15672:31317/TCP   2d1h
    

    然后通过NodePort暴露一个端口访问,通过暴露的端口访问(用http)
    http://192.168.0.236:32424/#/


    3.传统架构和K8S管理中间件的区别

    3.1.区别

    传统架构: 如下图,比较复杂



    k8s架构: 一句话总结功能就是可以很方便管理一些比较复杂的应用,比如MySQL集群、Redis集群等,可以一键式创建集群、扩容、备份等。常用的两种包管理工具是Operator和Helm。 helm:倾向于无状态应用的部署,比如公司的服务、某些不需要持久化数据的中间件、不需要实现额外功能的服务,比如备份、回滚等(比较容易)。 Operator:管理更为复杂的有状态服务,比如MySQL集群、Redis集群、Rook等。并且可以利用Operator实现扩容、备份、回滚等功能.(功能需要写代码实现,比较复杂)



    3.2.中间件到底要不要部署在K8s

    非生产环境:使用K8s管理比较推荐
    非生产环境的中间件推荐所有都装在K8S中,一般测试环境不用考虑性能,稳定性,数据不需要持久化(mysql除外),也可以用动态存储rook。
    生产环境:需要考虑性能、持久化、稳定性等问题。
    mysql对磁盘IO要求比较高,一般可以考虑用云厂商的数据库。 生产环境需要考虑的比较多,一般结合项目需求,

    (二) Operator

    1.Operator部署redis集群

    Operator常用的模板:https://github.com/operator-framework/awesome-operators
    Redis Cluster Operator: https://github.com/ucloud/redis-cluster-operator


    首先要先创建一些自定义的资源,K8S有很多kind,Operator可以管理这些创建的自定义kind
    1.1.创建Operator-redis
    # git clone https://github.com/ucloud/redis-cluster-operator.git
    # cd  redis-cluster-operator/
    # kubectl create -f deploy/crds/redis.kun_distributedredisclusters_crd.yaml
    # kubectl create -f deploy/crds/redis.kun_redisclusterbackups_crd.yaml
    # kubectl create ns redis-cluster  #通过集群的方式创建,如果需要创建另一个集群,再创建一个redis-cluster2,同样执行下面4条命令即可
    # kubectl create -f deploy/service_account.yaml -n redis-cluster
    # kubectl create -f deploy/namespace/role.yaml -n redis-cluster
    # kubectl create -f deploy/namespace/role_binding.yaml -n redis-cluster
    # kubectl create -f deploy/namespace/operator.yaml -n redis-cluster
    

    查看operator-redis:

    [root@k8s-master01 redis-cluster-operator]# kubectl get pod -n redis-cluster 
    NAME                                      READY   STATUS    RESTARTS   AGE
    redis-cluster-operator-675ccbc697-gz6fw   1/1     Running   0          23s
    
    1.2.创建redis集群

    此文件可以定义集群的规模

    [root@k8s-master01 redis-cluster-operator]# vim deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml
    apiVersion: redis.kun/v1alpha1
    kind: DistributedRedisCluster
    metadata:
      annotations:
        # if your operator run as cluster-scoped, add this annotations
        redis.kun/scope: cluster-scoped
      name: example-distributedrediscluster
    spec:
      # Add fields here
      masterSize: 3   #master节点数
      clusterReplicas: 1   #每个主节点有几个从节点
      image: redis:5.0.4-alpine   #使用的镜像版本
    

    创建:

    [root@k8s-master01 redis-cluster-operator]# kubectl create -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml  -n redis-cluster
    

    【可选】提示:如果集群规模不大,资源少,可以自定义资源,把请求的资源降低</pre>

    # kubectl create -f deploy/example/custom-resources.yaml -n redis-cluster</pre>
    
    1.3.扩容Redis集群

    扩容Redis集群

    # grep "master" deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml
             masterSize: 4
    # kubectl replace -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml -n redis-cluster
    
    1.4.卸载集群
    # kubectl delete -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml -n redis-cluster
    # kubectl delete -f deploy/cluster/operator.yaml -n redis-cluster
    # kubectl delete -f deploy/cluster/cluster_role_binding.yaml -n redis-cluster
    # kubectl delete -f deploy/cluster/cluster_role.yaml -n redis-cluster
    # kubectl delete -f deploy/service_account.yaml -n redis-cluster
    # kubectl delete -f deploy/crds/redis.kun_redisclusterbackups_crd.yaml -n redis-cluster
    # kubectl delete -f deploy/crds/redis.kun_distributedredisclusters_crd.yaml -n redis-cluster
    

    (三) Helm

    1.使用Helm创建Kafka、Zookeeper集群

    首先安装heml,并添加仓库
    a.下载安装包:https://github.com/helm/helm/releases
    b.解压:tar -zxvf helm-v3.0.0-linux-amd64.tar.gz
    c.复制到二进制目录:mv linux-amd64/helm /usr/local/bin/helm

    [root@k8s-master01 bin]# which helm  #查看
    /usr/local/bin/helm
    

    d.添加bitnami和官方helm仓库:

    [root@k8s-master01 ~]# helm repo add bitnami https://charts.bitnami.com/bitnami
    [root@k8s-master01 ~]# helm repo add stable https://charts.helm.sh/stable
    

    e.基础命令:
    下载一个包:helm pull
    创建一个包:helm create
    安装一个包:helm install
    查看:helm list
    查看安装参数:helm get values
    更新:helm upgrade
    删除:helm delete
    f.安装方式一:先下载后安装

    [root@k8s-master01 ~]# helm pull bitnami/zookeeper
    [root@k8s-master01 ~]# tar xf zookeeper-7.5.1.tgz #解压
    [root@k8s-master01 ~]# cd zookeeper && vim values.yaml #修改values.yaml相应配置:副本数、auth、持久化
    image:镜像地址
    replicaCount: 3  #副本数
    persistence: 设置持久化,storageClass: sc-pvc名称
    helm install -n public-service zookeeper . #安装
    

    g.安装方式二:直接安装kafka
    通过命名方式直接设置环境变量参数

    [root@k8s-master01 zookeeper]# helm install kafka bitnami/kafka --set zookeeper.enabled=false --set replicaCount=3 --set externalZookeeper.servers=zookeeper --set persistence.enabled=false -n public-service
    
    [root@k8s-master01 zookeeper]# kubectl get pod -n public-service  #2个集群都启动完成
    NAME          READY   STATUS    RESTARTS   AGE
    kafka-0       1/1     Running   0          4m11s
    kafka-1       1/1     Running   0          4m11s
    kafka-2       1/1     Running   0          4m11s
    zookeeper-0   1/1     Running   0          23m
    zookeeper-1   1/1     Running   0          23m
    zookeeper-2   1/1     Running   0          23m
    
    [root@k8s-master01 ~]# kubectl get svc -n public-service  #查看SVC
    NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    kafka                ClusterIP   10.104.163.22            9092/TCP                     17m
    kafka-headless       ClusterIP   None                     9092/TCP,9093/TCP            17m
    zookeeper            ClusterIP   10.105.133.146           2181/TCP,2888/TCP,3888/TCP   37m
    zookeeper-headless   ClusterIP   None                     2181/TCP,2888/TCP,3888/TCP   37m
    

    2.Kafka验证

    先起一个kafka客户端验证
    kafka客户端:

    # kubectl run kafka-client –restart=’Never’ –image docker.io/bitnami/kafka:2.8.0-debian-10-r30 –namespace public-service –command — sleep infinity
    
    [root@k8s-master01 zookeeper]# kubectl get pod -n public-service | grep client
    kafka-client 1/1 Running 0 39s
    

    模拟生产者

    [root@k8s-master01 zookeeper]# kubectl exec --tty -i kafka-client --namespace public-service -- bash  #进入kafka
    I have no name!@kafka-client:/$ kafka-console-producer.sh \
    >             --broker-list kafka-0.kafka-headless.public-service.svc.cluster.local:9092,kafka-1.kafka-headless.public-service.svc.cluster.local:9092,kafka-2.kafka-headless.public-service.svc.cluster.local:9092 \
    >             --topic test
    >1
    >test 2
    >xiaofei 1
    >xiaofei2^H 
    >wo123
    

    模拟消费者

    [root@k8s-master01 ~]#  kubectl exec --tty -i kafka-client --namespace public-service -- bash
    I have no name!@kafka-client:/$         kafka-console-consumer.sh \
    >             --bootstrap-server kafka.public-service.svc.cluster.local:9092 \
    >             --topic test \
    >             --from-beginning
    
    1
    test 2
    xiaofei 1
    xiaofei 
    wo123
    

    集群能正常消费,无异常

    3.Kafka更新删除

    更新和安装差不多,用heml upgrade更新

    3.1.Kafka更新:

    命令方式:

    [root@k8s-master01 ~]# helm upgrade kafka bitnami/kafka --set zookeeper.enabled=false --set replicaCount=5 --set externalZookeeper.servers=zookeeper --set persistence.enabled=false -n public-service #副本数改成5</pre>
    

    yaml文件方式:

    [root@k8s-master01 ~]# [root@k8s-master01 ~]# vim zookeeper/values.yaml
    [root@k8s-master01 ~]# helm upgrade -n public-service zookeeper . 
    
    3.2.Kafka删除:
    [root@k8s-master01 ~]# helm list -A   #查看helm数
    NAME        NAMESPACE       REVISION    UPDATED                                 STATUS      CHART           APP VERSION
    kafka       public-service  1           2021-12-16 18:21:58.629211542 +0800 CST deployed    kafka-14.7.1    2.8.1      
    zookeeper   public-service  1           2021-12-16 18:02:36.300204363 +0800 CST deployed    zookeeper-7.5.1 3.7.0
    [root@k8s-master01 ~]# helm delete -n publice-service fafka zookeeper  #删除即可
    

    4.Helm的目录层级

    创建一个Chart:helm create helm-test

    ├── charts # 依赖文件
    ├── Chart.yaml # 当前chart的基本信息
        apiVersion:Chart的apiVersion,目前默认都是v2
        name:Chart的名称
        type:图表的类型[可选]
        version:Chart自己的版本号
        appVersion:Chart内应用的版本号[可选]
        description:Chart描述信息[可选]
    ├── templates # 模板位置
    │   ├── deployment.yaml
    │   ├── _helpers.tpl # 自定义的模板或者函数
    │   ├── ingress.yaml
    │   ├── NOTES.txt #Chart安装完毕后的提醒信息
    │   ├── serviceaccount.yaml
    │   ├── service.yaml
    │   └── tests # 测试文件
    │       └── test-connection.yaml
    └── values.yaml #配置全局变量或者一些参数
    

    主要是values.yaml,定义全局变量,可以自定义参数,然后templates模板文件可以引用上面的变量,需要自己定义。
    渲染配置文件,并不生成方式:会生成内置模板的yaml,包含sa,svc,deployment等自定义yaml。

    [root@k8s-master01 helm-test]# helm install helm-test . --dry-run
    NAME: helm-test
    LAST DEPLOYED: Fri Dec 17 11:47:39 2021
    NAMESPACE: default
    STATUS: pending-install
    REVISION: 1
    HOOKS:
    ---
    # Source: helm-test/templates/tests/test-connection.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: "helm-test-test-connection"
      labels:
        helm.sh/chart: helm-test-0.1.0
        app.kubernetes.io/name: helm-test
        app.kubernetes.io/instance: helm-test
        app.kubernetes.io/version: "1.16.0"
        app.kubernetes.io/managed-by: Helm
      annotations:
        "helm.sh/hook": test
    spec:
      containers:
        - name: wget
          image: busybox
          command: ['wget']
          args: ['helm-test:80']
      restartPolicy: Never
    MANIFEST:
    ---
    # Source: helm-test/templates/serviceaccount.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: helm-test
      labels:
        helm.sh/chart: helm-test-0.1.0
        app.kubernetes.io/name: helm-test
        app.kubernetes.io/instance: helm-test
        app.kubernetes.io/version: "1.16.0"
        app.kubernetes.io/managed-by: Helm
    ---
    # Source: helm-test/templates/service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: helm-test
      labels:
        helm.sh/chart: helm-test-0.1.0
        app.kubernetes.io/name: helm-test
        app.kubernetes.io/instance: helm-test
        app.kubernetes.io/version: "1.16.0"
        app.kubernetes.io/managed-by: Helm
    spec:
      type: ClusterIP
      ports:
        - port: 80
          targetPort: http
          protocol: TCP
          name: http
      selector:
        app.kubernetes.io/name: helm-test
        app.kubernetes.io/instance: helm-test
    ---
    # Source: helm-test/templates/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helm-test
      labels:
        helm.sh/chart: helm-test-0.1.0
        app.kubernetes.io/name: helm-test
        app.kubernetes.io/instance: helm-test
        app.kubernetes.io/version: "1.16.0"
        app.kubernetes.io/managed-by: Helm
    spec:
      replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/name: helm-test
          app.kubernetes.io/instance: helm-test
      template:
        metadata:
          labels:
            app.kubernetes.io/name: helm-test
            app.kubernetes.io/instance: helm-test
        spec:
          serviceAccountName: helm-test
          securityContext:
            {}
          containers:
            - name: helm-test
              securityContext:
                {}
              image: "nginx:1.16.0"
              imagePullPolicy: IfNotPresent
              ports:
                - name: http
                  containerPort: 80
                  protocol: TCP
              livenessProbe:
                httpGet:
                  path: /
                  port: http
              readinessProbe:
                httpGet:
                  path: /
                  port: http
              resources:
                {}
    
    NOTES:
    1. Get the application URL by running these commands:
      export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=helm-test,app.kubernetes.io/instance=helm-test" -o jsonpath="{.items[0].metadata.name}")
      export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
      echo "Visit http://127.0.0.1:8080 to use your application"
      kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
    

    5.Helm的内置变量

    heml有些变量是没有在values中设置的,叫内置变量,如下常见内置变量:
    Release.Name: 实例的名称,helm install指定的名字
    Release.Namespace: 应用实例的命名空间
    Release.IsUpgrade: 如果当前对实例的操作是更新或者回滚,这个变量的值就会被置为true
    Release.IsInstall: 如果当前对实例的操作是安装,则这边变量被置为true
    Release.Revision: 此次修订的版本号,从1开始,每次升级回滚都会增加1
    Chart: Chart.yaml文件中的内容,可以使用Chart.Version表示应用版本,Chart.Name表示Chart的名称

    相关文章

      网友评论

        本文标题:十四 中间件容器化及Helm

        本文链接:https://www.haomeiwen.com/subject/ahtuurtx.html