DevOps流水线开发运维平台

242 阅读10分钟

一、kubernetes

DevOps和无运维

抽象了数据中心的硬件基础设施,使得对外暴露的只是一个巨大的资源池,不用关注底层服务器。简化了应用的开发、部署,以及对开发和运维团队的管理。

  • Kubernetes使开发者可以自主部署应用,并且控制部署的频率,完全脱离运维团队的帮助;(NoOps)
  • Kubernetes同时能让运维团队监控整个系统,并且在硬件故障时重新调度应用

image.png

1.1 容器

容器的本质就是进程

  • Linux命名空间
    • 文件、进程、网络接口、主机名等
  • Linux控制组(cgroups)
    • 进程能使用的资源量(CPU、内存、网络宽带等)

创建进程后,先使用namespace技术进行资源隔离,然后再利用CGroups技术为容器创建资源限制的配置文件

1.2 Pod

核心概念,其它的对象都是在管理、暴露pod或者被pod使用

为何需要Pod?为何不直接使用使用容器?为何甚至同时需要运行多个容器

为什么需要pod.png

在kubernetes中,容器就相当于是一个进程(Linux线程),Pod就是进程组(Linux线程组)。

image.png

Pod,实际上是在扮演传统基础设施里“虚拟机”的角色;而容器,则是这个虚拟机里运行的用户程序。

凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的。这些属性的共同特征是,它们描述的是“机器”这个整体,而不是里面运行的“程序”

  • “机器”的网卡
  • “机器”的磁盘
  • “机器”的防火墙
  • “机器”运行在哪个服务器之上

YAML描述文件

pod.png

三大重要组成部分

  • metadata 包括名称、命名空间、标签和关于该容器的其它信息
  • spec 包含pod内容的实际说明,例如容器、卷和其它信息
  • status 包含运行中的pod的当前信息,例如pod所处的条件、每个容器的描述和状态,以及内部IP和其它基本信息

标签的用途是标识和分组对象,而注解用于提供对象来源、如何使用及其策略的额外信息

1.3 servcie

  1. 为什么需要服务

    • Pod的IP不是固定的
    • 一组Pod实例的负载均衡

    解决不断变化的pod IP地址的问题 当一个服务被创建时,它会得到一个静态的IP,在服务的生命周期中这个IP不会发生改变。客户端应该通过固定IP地址连接到服务,而不是直接连接pod。服务会确保其中一个pod接收连接,而不关心pod当前运行在哪里(以及它的IP地址是什么) 对外暴露一系列pod、稳定的IP地址以及端口

  2. 服务是如何实现的(使用场景)

  • clusterIP

image.png

kube-dns生成的 DNS记录格式: [serviceName].[namespace].svc.cluster.local

  • NodePort

service.png

service-nodeport.png

  • Headless Service

Headless 的作用就是绕过 Cluster IP 提供的负载均衡,由自己决定要访问哪个 Pod。 配了 Headless 后除了可以使用 IP 访问 Pod,还可以使用域名 [podName].[serviceName].[namespace].svc.cluster.local

默认NIFI节点: nifi-0.nifi-headless.gdc.svc.cluster.local:8080

  • ExternalName

把集群外部的服务引入到集群内部来,在集群内部直接使用。

image.png

apiVersion: v1
kind: Service
metadata:
  name: gdc-assets-iot-service
  namespace: middleware
spec:
  type: ExternalName
  externalName: gdc-assets-iot-service.gdc.svc.cluster.local

1.4 ingress

就是 Service 的“Service”。

k8s可以通过三种方式将集群内服务暴露到外网

  • NodePort
  • LoadBalancer
  • Ingress

为什么需要Ingress

  • Ingress在HTTP应用层操作,可以提供一些服务不能实现的功能,可以根据 http header, path 进行路由转发
  • Ingress 实际上就是 Kubernetes 对“反向代理”的抽象

Ingress.png

1.5 控制器/编排(工作负载)

  • Deployment(无状态应用) 7dfd64ad53741f3dda4a920de037ad3.jpg

deployment.jpg

YMAL描述

deployment-yaml.png

  • StatefulSet (有状态应用)
  • DaemonSet(守护进程)
  • Job(离线业务)

二、Helm

2.1 简介

核心思想:所有k8s资源对象都可以打包在一起进行安装、更新和删除。

可以将Helm看作Kubernetes下的apt-get/yum

官方文档:v3.helm.sh/zh/docs/

image.png

Helm Client 是一个命令行下的客户端工具。主要用于 Kubernetes 应用程序 Chart 的创建、打包、发布以及创建和管理本地和远程的 Chart 仓库。

三个重要的概念

  • Chart: 代表一个 Helm 包。它包含了在 Kubernetes 集群中运行应用程序、工具或服务所需的所有 YAML 格式的资源定义文件。
  • Repository(仓库): 它是用来存放和共享 Helm Chart 的地方,类似于存放源码的 GitHub 的 Repository,以及存放镜像的 Docker 的 Repository。
  • Release:它是运行在 Kubernetes 集群中的 Chart 的实例。一个 Chart 通常可以在同一个集群中安装多次。每一次安装都会创建一个新的 Release。 每个 Release 包含多个 Kubernetes 资源,例如 Deployment、Pod、Service 等。

2.2 为什么要使用 Helm

  1. 传统的应用部署模式

image.png

每个服务由一个复杂的 Kubernetes YAML 格式的文件来定义并创建,可以看到如果靠传统的方式,去维护这些 YAML 格式文件,并在不同环境下使用不同的配置去创建应用,是一件非常复杂的工作

  1. 我们需要一种更好的方式,来维护和管理这些 YAML 文件

image.png

Helm 的模板文件基于text/template模板文件,提供了更加强大的模板渲染能力。Helm 可以将配置文件中的值渲染进模板文件中,最终生成一个可以部署的 Kubernetes YAML 格式的资源定义文件

  1. 部署一个应用可以简化为Chart模板(多个服务) + Chart配置 -> 应用

image.png

Chart 模板一个应用只用编写一次,可以重复使用。在部署时,可以指定不同的配置,从而将应用部署在不同的环境中,或者在同一环境中部署不同配置的应用。

  1. 查看release在k8s中创建出来的资源
  • helm get manifest catalog-server-service -n gdc

image.png

2.3 Chart包

文件含义
charts一个普通的空文件
Chart.yaml当前 chart 属性的配置信息
templates自己定义的 yaml 文件存于此
values.yaml定义 yaml 文件的全局配置

主要包含两类文件

  • n个模板文件
  • 1个配置文件

2.3.1 中间件包

CNCF:artifacthub.io/packages/he…

Promethues_chart.png

2.3.2 GDC通用包

image.png

未解决问题:range作用域内读取外部配置

2.3.3 配置说明

业务服务通用Helm安装包配置说明

三、SQL管理规范

文件存放目录及文件命名规范

sql语句规范

  • postgresql
  • mysql

四、jenkins流水线

3.1 运行系统

运行系统概述

image.png

项目类型

  • 自由风格类型项目
  • 流水线项目

3.2 pipeline

Pipeline 是Jenkins 2.X 的最核心的特性。让jenkins 可以实现持续交付管道的落地和实施

  1. Jenkins 1.x只能通过界面手动配置来配置描述过程,部署流水线完成任务
  2. Jenkins 2.x支持pipeline as code,可以通过代码来描述部署流水线

可以像管理其它源代码一样通过文件的形式来管理Jenkins任务,支持历史追溯、差异对比等。 更好的版本化、协作、重用

3.2.1 语法(Jenkinsfile)

基于Groovy语言实现的一种DSL(领域特定语言)。流水线通过Jenkins DSL编写代码来实现

git branch:'CIM_v2.4.5',url:'https://geek.******.com/scm/gdcc/gdc-install.git' 

# 
  1. 声明式
    • pipeline : 代表整条流水线,包含整条流水线的逻辑。

    • agent :节点,指定流水线的执行位置

    • stages :阶段集,流水线中多个stage的容器

    • stage : 阶段,代表流水线的阶段

    • steps :步骤,代表阶段中的一个或多个具体步骤的容器

    • post :构建后的操作

    • parameters :参数

    • triggers :触发器

image.png

 - 部分:stages、steps、posts  (有点容器的意思,隔离)
 - 指令:是一个做任何一下事情的语句或代码块
     - 定义值 agent
     - 配置行为 triggers
     - 指定要完成的行为 state
 - 步骤:steps部分内部语句
 - 条件:when、conditions
  • 优点
    • 更结构化,贴近传统的Jenkins Web表单形式
    • 更强大的声明内容能力,高可读性
    • 可以通过Bule Ocean图形化界面自动生成
    • 段落可映射到常见的Jenkins概念,比如通知
    • 更友好的语法检查和错误识别
    • 提升流水线间的一致性
  • 缺点
    • 对迭代逻辑支持较弱(相比程序而言)
    • 仍在开发完善中(对于传统Jenkins中的部分功能缺乏支持)
    • 更严格的结构(更难实现自定义流水线代码)
    • 目前对于复杂的流水线和工作流难以胜任
  1. 脚本式
  • 优点
    • 更少的代码段落和若规范要求
    • 更强大的程序代码能力
    • 更像编写代码程序
    • 传统的流水线即代码模型,用户熟悉并向后兼容性
    • 更灵活的自定义代码操作
    • 能够构建更复杂的工作流和流水线
  • 缺点
    • 普遍要求更好的编程水平
    • 语法检查受限于Groovy语言及环境
    • 和传统的Jenkins模型有很大的差异
    • 与声明式流水线的实现相比,同一工作流会更复杂

3.2.2 实现

  • Pipeline Script

1f33dd48da8a951b69479fd3398323dc.png

  • Pipeline script from SCM

4df9c8e8587658292443013ba2723d89.png

流水线脚本默认名字【Jenkinsfile】

49fb4ab5df93fad0b04d7af90b113cdb.png

脚本实现

image.png

pipeline {
    agent {
        kubernetes {
            inheritFrom "jenkins-slave"
            yaml '''
apiVersion: v1
kind: Pod
metadata:
  name: jenkins-slave
spec:
  containers:
  - name: jnlp
    image: *****-registry.cn-beijing.cr.aliyuncs.com/gdc/pipelinedata:v3
    imagePullPolicy: Always
    env:
    - name: "MYSQLHOST"
      value: 
    - name: "MYSQLUSER"
      value: root
    - name: "MYSQLPWD" 
      value: ******
    - name: "MYSQLPORT"
      value: 3306
    .....
    - name: "MQTT_HOST"
      value: 10.9.31.99
    - name: "MQTT_PORT"
      value: 1883
    volumeMounts:
    - mountPath: /root/.kube
      name: config-volume
    - mountPath: /home/release
      name: release-shared-db
  imagePullSecrets:
  - name: ******-aliyun-docker
  volumes:
  - configMap:
      name: ops-xa-te-kube
    name: config-volume
  - name: release-shared-db
    persistentVolumeClaim:
      claimName: release-shared-db 

'''
        }
    }
    // triggers{
    //     cron('H 02 * * *')
    // }
    options{
        //Disallow concurrent executions of the Pipeline. Can be useful for preventing simultaneous accesses to shared resources, etc.
        disableConcurrentBuilds()
    }
    environment {
        CREDENTIALSID = "shiyw-a"
        GITURL="https://geek.******.com/scm/gdcc/gdc-install.git"
        GITBRANCH="CIM_v2.4.20"
    }
    stages {
        stage('pull sql and script') {
            steps {
                container(name: 'jnlp'){
                    dir('/home/release/gdc-install'){
                        deleteDir()
                        git branch:env.GITBRANCH,credentialsId:env.CREDENTIALSID,url:env.GITURL
                    }
                }
            }
        }
        stage('uninstall gdc') {
                    steps {
                        container(name: 'jnlp'){

                            sh 'helm uninstall service-market-web -n ${NAMESPACE} || true'
                            sh 'helm uninstall service-market-server -n ${NAMESPACE} || true'
                            ......
                            sh 'sleep 1s'

                            sh 'helm list -n ${NAMESPACE}'
                        }
                    }
                }
                stage('uninstall middleware') {
                    steps {
                        container(name: 'jnlp'){
                            sh 'helm uninstall grafana -n ${NAMESPACE} || true'
                            sh 'helm uninstall prometheus -n ${NAMESPACE} || true'
                            sh 'helm uninstall elasticsearch -n ${NAMESPACE} || true'
                            sh 'helm uninstall nifi -n ${NAMESPACE} || true'
                            sh 'helm uninstall nifi-standalone -n ${NAMESPACE} || true'
                            sh 'helm uninstall dolphinscheduler3 -n ${NAMESPACE} || true'
                            sh 'helm uninstall minio -n ${NAMESPACE} || true'
                            sh 'helm uninstall zookeeper -n ${NAMESPACE} || true'
                            sh 'helm uninstall apollo-service -n ${NAMESPACE} || true'
                            sh 'helm uninstall apollo-portal -n ${NAMESPACE} || true'
                            sh 'helm uninstall emqx -n ${NAMESPACE} || true'
                            sh 'sleep 1s'
                            sh 'helm list -n ${NAMESPACE}'

                            // 批量清除gdc命名空间下的所有helm test
                            sh 'helm list -n ${NAMESPACE} | awk \'{print $1}\' | grep -v  NAME |xargs -I {} helm uninstall {} -n ${NAMESPACE}  || true'

                            // 批量清除gdc命名空间下的所有pvc
                            sh 'kubectl get pvc -n ${NAMESPACE} | awk \'{print $1}\' | grep -v  NAME |xargs kubectl delete pvc -n ${NAMESPACE}  || true'
                        }
                    }
                }
        stage('clean data') {
            steps {
                container(name: 'jnlp'){
                    sh """
                    cd /root/clean_data
                    pwd
                    echo "$TDENGINEHOST $TDENGINEHOSTNAME" >> /etc/hosts
                    cd TDengine-client-3.0.6.0
                    ./install_client.sh
                    cd /root/clean_data
                    bash delete_orientdb.sh

                    sh delete_kafka.sh || true
                    # redis-cli -h ${REDISHOST} -p ${REDISPORT} -a ${REDISPASSWORD} flushall
                    # sleep 30s
                    cat /var/log/clean.log
                    
                    """
                    dir('/home/release/gdc-install/tool'){
                        sh 'bash delete_tdengine.sh'
                    }
                      
                    
                    // sh 'redis-cli -h ${REDISHOST} -p ${REDISPORT} -a ${REDISPASSWORD} flushall'
                    sh 'redis-cli -h ${REDISHOST} -p ${REDISPORT} -a ${REDISPASSWORD} -n 0 flushdb'
                    sh 'redis-cli -h ${REDISHOST} -p ${REDISPORT} -a ${REDISPASSWORD} -n 1 flushdb'
                    sh 'redis-cli -h ${REDISHOST} -p ${REDISPORT} -a ${REDISPASSWORD} -n 2 flushdb'

                    sh 'psql -h ${PGHOST} -p ${PGPORT}  -U ${PGUSER} -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity  WHERE datname=\'kong\' AND pid<>pg_backend_pid();"'
                    sh 'dropdb -h ${PGHOST} -p ${PGPORT}  -U ${PGUSER}    "kong"  || true'
                    ......
                    sh 'psql -h ${PGHOST} -p ${PGPORT}  -U ${PGUSER} -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity  WHERE datname=\'dolphinscheduler\' AND pid<>pg_backend_pid();"'
                    sh 'dropdb -h ${PGHOST} -p ${PGPORT}  -U ${PGUSER}    "dolphinscheduler" || true'

                    
                    sh 'mysql -h${MYSQLHOST} -u${MYSQLUSER} -p${MYSQLPWD} -e "DROP DATABASE IF EXISTS apollo_config"'
                    ......
                }
                
            }
        }
        stage('initialize data') {
            
            steps {
                container(name: 'jnlp'){
                    dir('/home/release/gdc-install/sql/all'){
                        
                        sh 'mysql -h${MYSQLHOST} -u${MYSQLUSER} -p${MYSQLPWD} < middleware/apollo/apollo_config__mysql_ddl.sql'
                        sh 'mysql -h${MYSQLHOST} -u${MYSQLUSER} -p${MYSQLPWD} < middleware/apollo/apollo_config__mysql_dml.sql'
                        ......
                    }
                }
                
            }
        }
        stage('install middleware') {
            
            steps {
                container(name: 'jnlp'){
                    sh 'cd /home/release/gdc-install/helm/installCommand/0-secret && sh digitalcity-aliyun-docker.sh || true'
                    sh 'chmod +x /home/release/gdc-install/helm/installCommand/1-middleware'
                    sh 'cd /home/release/gdc-install/helm/installCommand/1-middleware && sh 1-helm-apollo-service.sh'
                    sh 'cd /home/release/gdc-install/helm/installCommand/1-middleware && sh 2-helm-apollo-portal.sh'
                    sh 'cd /home/release/gdc-install/helm/installCommand/5-check && bash gdc-pod-status-check.sh apollo-service Running'
                    sh 'cd /home/release/gdc-install/helm/installCommand/5-check && bash gdc-pod-status-check.sh apollo-portal Running'
                    sh 'sleep 2m'
                    sh 'cd /home/release/gdc-install/helm/installCommand/4-gdc && sh gdc-apollo-init-job.sh'   
                    
                    sh 'cd /home/release/gdc-install/helm/installCommand/1-middleware && sh 3-helm-zookeeper.sh'
                    sh """
                    cd /home/release/gdc-install/helm/installCommand/5-check
                    bash gdc-pod-status-check.sh zookeeper Running
                    """
                    dir('/home/release/gdc-install/helm/installCommand/1-middleware'){
                        sh 'sh 4-helm-minio.sh'
                        sh 'sh 5-helm-dolphin.sh'
                        sh 'sh 6-helm-nifi.sh'
                    }
                    sh """
                    cd /home/release/gdc-install/helm/installCommand/5-check
                    bash gdc-pod-status-check.sh nifi Running
                    """
                    dir('/home/release/gdc-install/helm/installCommand/1-middleware'){
                        sh 'sh 9-helm-elasticsearch.sh'
                        // sh 'sh 10-helm-prometheus.sh'
                        // sh 'sh 11-helm-grafana.sh'
                    }

                    sh 'cd /home/release/gdc-install/helm/installCommand/2-config && sh helm-kong-config.sh'
                    dir('/home/release/gdc-install/helm/installCommand/4-gdc'){
                        sh 'sh kong-cp.sh'
                        sh 'sleep 30s'
                        sh 'sh kong-dp.sh'
                        
                    }
                    dir('/home/release/gdc-install/helm/installCommand/1-middleware'){
                        sh 'sh 12-helm-emqx.sh'
                    }
                    sh 'helm list -n ${NAMESPACE}'
                }
            }
        }
        stage('check middleware pod status') {
            
            steps {
                container(name: 'jnlp'){
                    sh 'cd /home/release/gdc-install/helm/installCommand/5-check && bash gdc-pod-all-check.sh'
                }
            }
        }        
        stage('install gdc') {
            
            steps {
                container(name: 'jnlp'){
                    sh 'chmod +x /home/release/gdc-install/helm/installCommand/2-config'
                    sh 'chmod +x /home/release/gdc-install/helm/installCommand/3-pvc'
                    sh 'chmod +x /home/release/gdc-install/helm/installCommand/4-gdc'
                    
                    sh 'cd /home/release/gdc-install/helm/installCommand/2-config && sh helm-cim-web-config.sh'
                    sh 'cd /home/release/gdc-install/helm/installCommand/2-config && sh helm-gdc-common.sh'
                    sh 'cd /home/release/gdc-install/helm/installCommand/3-pvc && sh helm-object-services.sh'

                    dir('/home/release/gdc-install/helm/installCommand/4-gdc'){
                        sh 'sh platform-foundation.sh'
                        sh 'sh platform-api-definition.sh'
                        ......
                    }
                    sh 'sleep 2s'
                    sh 'helm list -n ${NAMESPACE}'
                }
            }
        }
        stage('check all pod status') {
            
            steps {
                container(name: 'jnlp'){
                    sh 'cd /home/release/gdc-install/helm/installCommand/5-check && bash gdc-pod-all-check.sh 30'
                    
                }
            }
        }        
        stage('metersphere') {
            steps{
                 script {
                    meterSphere method: 'testPlan', 
					mode: 'serial', 
					msAccessKey: '3XlCrXrJZB52PBpT',
					msEndpoint: 'http://10.0.68.20:31259/', 
					msSecretKey: 'K9TTRaQslcJqzN03', 
					openMode: 'auth', 
					projectId: '10950575-6ee8-46cb-9362-2ecbefede248', 
					rojectName: '',
					projectType: 'projectId', 
					resourcePoolId: '', 
					testCaseId: '', 
					testCaseName: '', 
					testPlanId: 'd40f4dc1-5e40-402a-95c2-fb6cd4a8cc6d',
					testPlanName: '', 
					workspaceId: '19740116-bf0a-11ed-ac16-fa163e3ecbeb'
                }
            }  
        }        
        
        

    }
}

3.2.3 多分支流水线

  1. Jenkinsfile 在项目的根目录
  2. 配置扫描 多分支流水线 触发器 ,扫描策略,若发现变化,就执行Jenkinsfile的脚本内容,若无变化就不执行;也可手动执行

7f8d6753bc19063bfe33fb1d99184903.png

gdc-verify-Multi.png

image.png

3.3 自由风格转换流水线

参考 blog.csdn.net/qq_15283475…