tekton——from机制 源码解析

1,208 阅读3分钟

tekton的版本是基于0.9.2源码进行分析 taskRun中from例子

  tasks:
    - name: taskA
      resources:
        inputs:
          - from:
              - taskB
            name: tmp // ----------------------------------- 第2处
            resource: resouce-2
          - name: resouce-2 //------------------------------ 第3处
            resource: resouce-2
      taskRef:
        name: taskA
    - name: taskB
      resources:
        inputs:
          - name: resource-1
            resource: resource-1
        outputs: //----------------------------------------- 第1处 
          - name: tmp
            resource: resouce-2
      taskRef:
        name: taskB

如上 taskA from taskB 意味着taskB 任务构建之后需要有对应的输出, 此输出会当作taskA此任务的输入

即:

taskA from taskB: 表示taskB的输出当作taskA的输入

使用from会使用到pvc(因为taskB 会有output), 作为两个task之间传输的通道;

taskB 的输出 : 需要定义outputs.resource(如 第1处); 将需要传入到taskA 中的内容拷贝到 /workspace/output/outputs.resource.name/workspace/output/tmp 中(/workspace/output为固定目录);此步骤需要在定义显示的步骤进行拷贝; tekton会自动将此目录下的内容 拷贝到/pvc/taskName/outputs.resource.name中,其中/pvc为固定目录, 此步骤为tekton自动进行操作,无需手动进行添加步骤

taskA 的输入: 从上面的yaml上看, taskA有两个输入,分别为第2处的从taskB的输出中得到和第3处从resource中得到; 此处讲解第2处: 定义的inputs.resource, 其中name需要与上面taskB 中的outputs.resource.name保持一致; tekton会自动将/pvc/taskBtaskName/inputs.resource.name (/pvc为固定目录)拷贝到 /workspace/inputs.resource(/workspace为固定目录)同名下面的targetPath中

taskRun主流程

在此流程才会创建出pod, 也就是说TaskRun是最终执行的关键

如何添加默认步骤

/tektoncd/pipeline/pkg/reconciler/taskrun/taskrun.go # createPod()中添加每个task需要的默认步骤

/tektoncd/pipeline/pkg/reconciler/taskrun/resources/input_resources.go # AddInputResource 自动添加下载代码步骤 & 如果用到pvc默认添加创建文件夹 拷贝的步骤

/tektoncd/pipeline/pkg/reconciler/taskrun/resources/input_resources.go # AddOutputResources 自动添加拷贝代码到/pvc目录的步骤

AddInputResource代码片段讲解

// 循环遍历taskSpec.Inputs.Resources
for i := len(taskSpec.Inputs.Resources) - 1; i >= 0; i-- {
		input := taskSpec.Inputs.Resources[i]
		boundResource, err := getBoundResource(input.Name, taskRun.Spec.Inputs.Resources)
		if err != nil {
			return nil, xerrors.Errorf("failed to get bound resource: %w", err)
		}
  // 根据resourceName获取具体的resource定义, 包含类型等信息
		resource, ok := inputResources[boundResource.Name]
		if !ok || resource == nil {
			return nil, xerrors.Errorf("failed to Get Pipeline Resource for task %s with boundResource %v", taskName, boundResource)
		}
		var copyStepsFromPrevTasks []v1alpha1.Step
  // 拼接destination, 如果TargetPath不为空则dPath=/workspace/TargetPth; 如果为空dPath=/workspace/input.name
		dPath := destinationPath(input.Name, input.TargetPath)
		// if taskrun is fetching resource from previous task then execute copy step instead of fetching new copy
		// to the desired destination directory, as long as the resource exports output to be copied
		if allowedOutputResources[resource.GetType()] && taskRun.HasPipelineRunOwnerReference() {
			for _, path := range boundResource.Paths {
        // 添加拷贝step; 从pvc中拷贝对应目录下的内容对应的dPath目录中
				cpSteps := as.GetCopyFromStorageToSteps(boundResource.Name, path, dPath)
				if as.GetType() == v1alpha1.ArtifactStoragePVCType {
					mountPVC = true
					for _, s := range cpSteps {
						s.VolumeMounts = []corev1.VolumeMount{v1alpha1.GetPvcMount(pvcName)}
            //添加创建dPath的目录
						copyStepsFromPrevTasks = append(copyStepsFromPrevTasks,
							v1alpha1.CreateDirStep(images.BashNoopImage, boundResource.Name, dPath),
							s)
					}
				} else {
					// bucket 使用对象存储, 暂时为研究
					copyStepsFromPrevTasks = append(copyStepsFromPrevTasks, cpSteps...)
				}
			}
		}
		// source is copied from previous task so skip fetching download container definition
		if len(copyStepsFromPrevTasks) > 0 {
			taskSpec.Steps = append(copyStepsFromPrevTasks, taskSpec.Steps...)
			mountSecrets = true
		} else {
			// Allow the resource to mutate the task.
      // 根据resourceType类型添加对应的步骤, 例如如果是git, 则会调用/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1/git_resource.go # GetInputTaskModifier 添加对应的git下载代码的步骤
			modifier, err := resource.GetInputTaskModifier(taskSpec, dPath)
			if err != nil {
				return nil, err
			}
			v1alpha1.ApplyTaskModifier(taskSpec, modifier)
		}
	}

AddOutputResources代码片段讲解

for _, output := range taskSpec.Outputs.Resources {
		boundResource, err := getBoundResource(output.Name, taskRun.Spec.Outputs.Resources)
		if err != nil {
			return nil, xerrors.Errorf("failed to get bound resource: %w", err)
		}
		// 根据resource name 获取对应资源具体信息
		resource, ok := outputResources[boundResource.Name]
		if !ok || resource == nil {
			return nil, xerrors.Errorf("failed to get output pipeline Resource for task %q resource %v", taskName, boundResource)
		}

		var sourcePath string
  // 如果在output.resources中没有定义Targetpath, 则使用默认的前缀outputDir默认/workspace/output/
		if output.TargetPath == "" {
			sourcePath = filepath.Join(outputDir, boundResource.Name)
		} else {
			sourcePath = output.TargetPath
		}

		// Add containers to mkdir each output directory. This should run before the build steps themselves.
		mkdirSteps := []v1alpha1.Step{v1alpha1.CreateDirStep(images.BashNoopImage, boundResource.Name, sourcePath)}
		taskSpec.Steps = append(mkdirSteps, taskSpec.Steps...)
	// allowedOutputResources取值为git or storage
		if allowedOutputResources[resource.GetType()] && taskRun.HasPipelineRunOwnerReference() {
			var newSteps []v1alpha1.Step
			for _, dPath := range boundResource.Paths {
        // tektoncd/pipeline/pkg/apis/pipeline/v1alpha1/artifact_pvc.go # GetCopyToStorageFromSteps 将sourcePath中的内容拷贝到dPath中; 
        // 此处的dPath为对应的pvc目录
				newSteps = append(newSteps, as.GetCopyToStorageFromSteps(resource.GetName(), sourcePath, dPath)...)
			}
			taskSpec.Steps = append(taskSpec.Steps, newSteps...)
			taskSpec.Volumes = append(taskSpec.Volumes, as.GetSecretsVolumes()...)
		}

		// Allow the resource to mutate the task.
		modifier, err := resource.GetOutputTaskModifier(taskSpec, sourcePath)
		if err != nil {
			return nil, err
		}
		v1alpha1.ApplyTaskModifier(taskSpec, modifier)

		if as.GetType() == v1alpha1.ArtifactStoragePVCType {
			if pvcName == "" {
				return taskSpec, nil
			}

			// attach pvc volume only if it is not already attached
			for _, buildVol := range taskSpec.Volumes {
				if buildVol.Name == pvcName {
					return taskSpec, nil
				}
			}
			taskSpec.Volumes = append(taskSpec.Volumes, GetPVCVolume(pvcName))
		}
	}