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))
}
}