翼flink任务流程

翼flink特点

​ 翼flink是基于flink进行二次开发的应用平台,将flink繁琐的交互方式简化为只通过用户书写sql命令、上传udf包即可完成。翼flink目前基于云原生体系进行任务调度,使用k8s application的方式进行任务生成,减去了繁琐的集群管理步骤。

​ 因此,本文的重点将介绍翼flink是如何在k8s application中将一个flink sql或用户自定义jar包生成任务的过程,在此过程中将涉及java、scala源码linux操作

云原生基础环境

  1. 我们要提供一个docker,在这里省略安装过程。

  2. 在这里,我们需要搭建一个K8S环境用于提供flink任务的运行时环境。在这里推荐使用kubeadm或者一些脚本工具搭建https://gitlab.ctyuncdn.cn/liuxy28/kube-minite/-/tree/x86_64。具体过程在这里省略,可以参考上述链接中的文档进行操作。

  3. 需要注意的是,我们需要在相应用户的目录下提供一个kubeconfig文件,如下图所示,通过该文件,StreamPark才能顺利地调用K8S客户端提交任务,该config的内容为与K8S的ApiServer进行连接时需要使用的信息。

    在这里插入图片描述

  4. 安装flink官方客户端,在这里我们使用flink官方1.14-scala2.12的客户端进行安装,如下所示

    wget https://archive.apache.org/dist/flink/flink-1.14.3/flink-1.14.3-bin-scala_2.12.tgz
    tar zxvf ./flink-1.14.3-bin-scala_2.12.tgz
    

Flink流程(对比项)

​ 和翼flink-StreamPark相比,传统的flink界面的功能性较少,并且对于k8s application模式必须要经过大数据开发工程师将代码进行打包、制作镜像、上传后才能成功的启动flink任务。其流程如下:

  1. 将flink代码打包成jar包

  2. 制作独特的任务镜像

  3. 将镜像推送至镜像仓供flink进行拉取,生成任务

  4. 通过flink脚本生成任务

    ./bin/flink run-application \
    --target kubernetes-application \
    -Dkubernetes.cluster-id=flink-cluster  \
    # 指定容器启动的镜像(与之前提交的保持一致)
    -Dkubernetes.container.image=registry.cn.hangzhou.aliyuncs.com/dockerxiahu/flink:1.15.1-app-test-05 \
    -Dkubernetes.jobmanager.replicas=1 \
    # 指定容器运行的命名空间
    -Dkubernetes.namespace=flink \
    -Dkubernetes.jobmanager.service-account=flink-service-account \
    -Dkubernetes.taskmanager.cpu=1 \
    -Dtaskmanager.memory.process.size=4096mb \
    -Dkubernetes.jobmanager.cpu=1 \
    -Djobmanager.memory.process.size=4096mb \
    -Dkubernetes.rest-service.exposed.type=NodePort \
    -Dclassloader.resolve-order=parent-first \
    # yaml 模板,为解决hosts映射,后续可以通过编排此yaml文件,实现动态替换启动jar包和配置文件
    -Dkubernetes.pod-template-file=/opt/flink-1.14.2/flink-templeta.yaml \
    # Main方法
    -c com.clb.hadoop.hub.flink.realtime.launch.FlinkConsumeKafkaToHdfs \
    # 启动Jar包和启动配置文件的绝对路径(容器内部,不是宿主机)
    local:///opt/flink/lib/flink-realtime-1.0-SNAPSHOT.jar /opt/flink/usrlib/flink-realtime-hdfs.properties
    

​ 通过如上几个步骤,才能顺利地将一个flink任务成功的执行。

翼flink-StreamPark流程

​ 将用户的sql、UDF包快捷便利地上传,快速的仅仅通过翼flink-StreamPark端启动用户的flinksql任务,将以上几个步骤一键式的完成便是翼flink-StreamPark的主要工作。关于翼flink-StreamPark的使用在这里将不再过多介绍。如下,将对翼flink-StreamPark的代码进行介绍。

任务初始化构建

​ 任务的初始化在翼flink-StreamPark端一般要求将我们的sql打包成k8s环境能够运行的镜像,整体流程的起点为sql,终点为生成k8s任务镜像并上传至镜像仓供后续调用。详细代码请见,以下将对各个步骤分步讲解org/apache/streampark/flink/packer/pipeline/impl/FlinkK8sApplicationBuildPipeline.scala

  1. 在StreamPark本机环境中构建工作空间环境,这里主要就是新建一个目录,用于存储用户数据,简单地通过目录进行隔离。在这里不再详解

        // Step-1: init build workspace of flink job
        // the sub workspace dir like: APP_WORKSPACE/k8s-clusterId@k8s-namespace/
        val buildWorkspace =
          execStep(1) {
            val buildWorkspace = s"${request.workspace}/${request.clusterId}@${request.k8sNamespace}"
            LfsOperator.mkCleanDirs(buildWorkspace)
            logInfo(s"recreate building workspace: $buildWorkspace")
            buildWorkspace
          }.getOrElse(throw getError.exception)
    
  2. 将用户的k8s Podtemplate导出至翼flink-StreamPark端的相应存储目录

    ​ 在这里,先对k8s template进行介绍,一般情况下flink原生k8s调度系统将会提供一个默认的k8s资源文件来运行我们的任务,如果不指定podtemplate的话将使用默认的pod启动任务。拓展地,Flink 允许用户通过模板文件定义 JobManager 和 TaskManager pod。 这允许直接支持 Flink Kubernetes 配置选项不支持的高级功能。 使用 kubernetes.pod-template-file 指定包含 pod 定义的本地文件。 它将用于初始化 JobManager 和 TaskManager。

    ​ 在StreamPark端,同样地可以指定podTemplate,而在这一步主要仍是将podTemplate导出至本地,供后续使用。

        // Step-2: export k8s pod template files
        val podTemplatePaths = request.flinkPodTemplate match {
          case podTemplate if podTemplate.isEmpty =>
            skipStep(2)
            Map[String, String]()
          case podTemplate =>
            execStep(2) {
              val podTemplateFiles = PodTemplateTool.preparePodTemplateFiles(buildWorkspace, podTemplate).tmplFiles
              logInfo(s"export flink podTemplates: ${podTemplateFiles.values.mkString(",")}")
              podTemplateFiles
            }.getOrElse(throw getError.exception)
        }
    
  3. 打包生成任务的运行时jar包

    ​ 在这里,是一个复杂的过程,打包运行时jar包主要将如下一些要素打包成一个fatjar(所有依赖打包在一起,防止依赖缺失,直接通过java -jar即可调用)

    • 必要的基础组件(如logback、json解析组件)
    • 用户的作业依赖(UDF)
    • 翼flink-StreamPark自研的Sql语句翻译器(SqlClient.scala所在的包,主要将用户的sql动态的输入进任务中,直接翻译成算子任务,免去了sql语句仍需要打包成flink Jar包的繁琐操作)

    ​ 最终地,将生成能够动态解析用户sql的flink运行jar包,如下本jar包的入口信息(MANIFEST.MF),可见其标记了入口的主类,如此Flink加载此jar包时候将优先使用sqlclient作为flink任务的入口。

    Manifest-Version: 1.0
    Implementation-Title: StreamPark : Flink Shims 1.14
    Implementation-Version: 2.0.0
    Specification-Vendor: Apache Software Foundation
    Specification-Title: StreamPark : Flink Shims 1.14
    Build-Jdk-Spec: 1.8
    Created-By: Maven JAR Plugin 3.2.2
    Specification-Version: 2.0
    Implementation-Vendor: Apache Software Foundation
    Main-Class: org.apache.streampark.flink.cli.SqlClient
    
  4. 任务镜像的生成

    ​ 目前而言,任务的镜像主要作用为将上述第3步的运行时jar包加入到镜像目录中,详细地请看如下的dockerfile,主要使用flink官方提供的基础镜像基础上将用户的jar包添加到/usr/local/flink/usrlib目录下。之后此镜像将作为我们任务的运行时镜像,目前阶段通过镜像仓保存。

    FROM apache/flink:1.14.3-scala_2.12
    RUN mkdir -p $FLINK_HOME/usrlib
    COPY lib $FLINK_HOME/lib/
    COPY streampark-flinkjob_test-local.jar $FLINK_HOME/usrlib/streampark-flinkjob_test-local.jar
    

​ 对于翼flink而言,最终的任务执行端将是上述jar包中的org.apache.streampark.flink.cli.SqlClient类的主函数。
在这里插入图片描述

  1. 任务镜像的推送

    ​ 镜像的推送主要地将通过翼flink-StreamPark所在的宿主机上的docker将上一步生成的镜像推送到目标镜像仓,在这里相关的镜像仓的设定应该提前设定好,并且需要注意的,该任务镜像包含了用户自定义的UDF可能存在一定的隐私性,最好能够提供一个私有的镜像仓(如自建harbor)。当镜像推送成功后,云原生底座才能进行调用

    ​ 一般地,在翼flink-StreamPark启动前,应该在其相应的数据库中初始化相应的docker信息,如下所示。
    在这里插入图片描述

  2. Ingress的生成(可选)

任务启动

StreamPark的实现

​ 目前地,对于flink任务启动,主要是用K8s Application模式对任务进行启动。主要地,其步骤和本文中介绍的手动启动相似,主要则是通过flink官方原生java任务客户端。对于StreamPark中的代码,唯一做的事就是把用户的相关信息解析成flink支持的参数,与K8S交互部分完全使用flink端原生的方法

​ 最终地与手动启动类似,通过参数进行控制。

与K8S交互

​ StreamPark中,主要调用相关依赖org.apache.flink.kubernetes.KubernetesClusterDescriptordeployApplicationCluster方法启动flink任务,所有的和云原生底座的交互将在这里进行。详情参见org.apache.streampark.flink.client.impl.KubernetesNativeApplicationSubmit。对于StreamPark端所做的工作主要为通过flink源码中通过命令行模式执行的客户端org.apache.flink.client.cli.CliFrontend转化为自动执行。

​ 所有的一切和k8s操作相关的代码请看org.apache.flink.kubernetes.kubeclient.Fabric8FlinkKubeClient中,其中所有和k8s操作的细节都有介绍。由于本文作者关于K8S的操作技术不是很熟练。后续将对此加强解读。

在这里插入图片描述

​ 对于翼flink-StreamPark而言主要是调用此方法启动一个K8s的Deployment资源,并调用一些PodTemplate进行初始化,这里给出一个样例文件如下,此为StreamPark端调用原生flink-kubernetes依赖生成的结果。其底层调用的是fabric系列的k8s操作sdk进行操作。

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2023-04-03T08:54:11Z"
  generation: 1
  labels:
    app: ceshiaa
    component: jobmanager
    type: flink-native-kubernetes
  name: ceshiaa
  namespace: flink-dev
  resourceVersion: "41858779"
  uid: 1d5e5467-f430-4e28-91ef-d03146b52854
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: ceshiaa
      component: jobmanager
      type: flink-native-kubernetes
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: ceshiaa
        component: jobmanager
        type: flink-native-kubernetes
    spec:
      containers:
      - args:
        - bash
        - -c
        - kubernetes-jobmanager.sh kubernetes-application
        command:
        - /docker-entrypoint.sh
        env:
        - name: _POD_IP_ADDRESS
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.podIP
        image: lvlin241/streamparkflinkjob-flink-dev-ceshiaa
        imagePullPolicy: Always
        name: flink-main-container
        ports:
        - containerPort: 8081
          name: rest
          protocol: TCP
        - containerPort: 6123
          name: jobmanager-rpc
          protocol: TCP
        - containerPort: 6124
          name: blobserver
          protocol: TCP
        resources:
          limits:
            cpu: "1"
            memory: 4Gi
          requests:
            cpu: "1"
            memory: 4Gi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /opt/flink/conf
          name: flink-config-volume
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: default
      serviceAccountName: default
      terminationGracePeriodSeconds: 30
      volumes:
      - configMap:
          defaultMode: 420
          items:
          - key: logback-console.xml
            path: logback-console.xml
          - key: log4j-console.properties
            path: log4j-console.properties
          - key: flink-conf.yaml
            path: flink-conf.yaml
          name: flink-config-ceshiaa
        name: flink-config-volume

​ 其中,关于flink任务的K8S配置项,请参考org.apache.flink.kubernetes.configuration.KubernetesConfigOptions中的设定,详情可查看官方文档https://nightlies.apache.org/flink/flink-docs-release-1.13/zh/docs/deployment/config/#kubernetes。对于StreamPark唯一能做的就是修改这些参数的值,将K8s信息传递给flink进相应的资源生成。

UI&任务日志查询

​ 启动flink任务日志后,允许通过界面查询日志。由于目前模式均为K8S Application模式部署。flink web ui默认通过nodeport方式获取。一般地当任务成功启动后,相应的web ui将提供出来,但目前翼flink-StreamPark暂不支持该功能。

​ 对于任务日志,翼flink-StreamPark则是通过访问底层云底座的deployment资源获得,详细代码请见org.apache.streampark.flink.kubernetes.helper.KubernetesDeploymentHelper,其方法如下所示:

  def watchDeploymentLog(nameSpace: String, jobName: String, jobId: String): String = {
    tryWithResource(KubernetesRetriever.newK8sClient()) { client =>
      val path = KubernetesDeploymentHelper.getJobLog(jobId)
      val file = new File(path)
      val log = client.apps.deployments.inNamespace(nameSpace).withName(jobName).getLog
      Files.asCharSink(file, Charsets.UTF_8).write(log)
      path
    }
  }

​ 之后,StreamPark端将会把查询到的日志保存在其工作目录下,并以该任务的job_id作为标识进行保存,保存至fl一般地,将会把用户日志保存在安装目录下的temp目录中,提供持久化存储,供后续使用。

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值