Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pipeline strawman example #1

Merged
merged 1 commit into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 127 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,127 @@
# build-pipeline
A library of build pipelines
# Pipeline CRD

This repo contains the API definition of the Pipeline CRD and an on cluster implementation of that API.
The goal of the Pipeline CRD is to provide k8s-style resources that allow the
declaration of CI/CD-style pipelines, which can be backed by any arbitrary impelmentation.

Features the Pipeline CRD will support include:

* Conditional, parallel and distributed execution
* Interaction with CI/CD resources such as source code, artifacts, resutls, deployments and clusters

The goal of the Pipeline CRD is to fit into and cooperate with
[the knative ecosystem](https://github.com/knative/docs#welcome-knative), specifically:

* [The Build CRD](https://github.com/knative/docs/blob/master/build/builds.md)
* [The Eventing APIs](https://github.com/knative/eventing/tree/master/docs/spec)

_See [examples](./examples) for some examples of how this is intended to work._

![Overview of the 5 CRDs](./crds.png)

The CRDs involved are:

* [Task](#task)
* [Pipeline](#pipeline)
* [PipelineParams](#pipelineparams)
* [TaskRun](#taskrun)
* [PipelineRun](#pipelinerun)

High level details of this design:

* [Pipelines](#pipelines) do not know what will trigger them, they can be
triggered by events or by manually creating [PipelineRuns](#pipelinerun)
* [Tasks](#tasks) can exist and be invoked completely independently of
[pipelines](#pipelines); they are highly cohesive and loosely coupled
* Test results are a first class concept, being able to navigate test results
easily is powerful (e.g. see failures easily, dig into logs, e.g. like
[the Jenkins test analyzer plugin](https://wiki.jenkins.io/display/JENKINS/Test+Results+Analyzer+Plugin))
* [Tasks](#tasks) can depend on artifacts, output and parameters created by other tasks.

## Task

`Task` is a CRD that knows how to instantiate a [Knative Build](https://github.com/knative/build),
either from a series of `steps` (i.e. [Builders](https://github.com/knative/docs/blob/master/build/builder-contract.md))
or from a [`BuildTemplate`](https://github.com/knative/docs/blob/master/build/build-templates.md).
It takes Knative Build and adds inputs and outputs. Where these inputs and outputs are provided
from is not known to a task, so they can be provided by a Pipeline or by a user invoking a Task directly.

`Tasks` are basically [knative BuildTemplates](https://github.com/knative/build-templates)
with additional input types and clearly defined outputs.

## Pipeline

`Pipeline` describes a graph of [Tasks](#task) to execute. It defines the DAG
and expresses how all inputs (including [PipelineParams](#pipelineparams) and outputs
from previous `Tasks`) feed into each `Task`. It allows for fan in and fan out, and
ordering can be expressed explicitly using `prev` and `next`, or it can be inferred
from a `Task’s` inputs.

Dependencies between parameters or inputs/outputs are expressed as references to k8s objects.

## PipelineParams

`PipelineParams` contains parameters for a [Pipeline](#pipeline). One `Pipeline`
can be invoked with many different instances of `PipelineParams`, which can allow
for scenarios such as running against PRs and against a user’s personal setup.
`PipelineParams` can control:

* What **sources** the `Pipeline` runs against
* Which **serviceAccount** to use (provided to all tasks)
* What **artifact** stores are used (e.g. Docker registries)
* Where **results** are stored (e.g. in GCS)

## TaskRun

Creating a `TaskRun` will invoke a [Task](#task), running all of the steps until completion
or failure. Creating a `TaskRun` will require satisfying all of the input requirements of the
`Task`.

`TaskRuns` are basically [knative Builds](https://github.com/knative/build) with inputs and
outputs, and in the future we may want to transition `Builds` to become `Tasks`.

`TaskRuns` can be created directly by a user or by a [PipelineRun](#pipelinerun).

### TaskRun Status

Once a `TaskRun` has been created, it will start excuting its steps
sequentially. The `conditions` field will be updated as the `TaskRun`
executes:

* The `Started` condition will be added when the first step starts.
* The `Completed` condition will be added when the last step completes,
or after a non-zero exit code from a step.
* The `Successful` condition will be added after the `Completed`
condition and will indicate if the run succeeded or failed.

When the `TaskRun` has completed, the `steps` field will indicate
the exit code of all steps that completed.

## PipelineRun

Creating a `PipelineRun` executes the pipeline, creating [TaskRuns](#taskrun) for each task
in the pipeline.

`PipelineRuns` tie together a [Pipeline](#pipeline) and a [PipelineParam](#pipelineparam).
A `PipelineRun` could be created:

* By a user manually
* In response to an event (e.g. in response to a Github event, possibly processed via
[knative eventing](https://github.com/knative/eventing))

### PipelineRun Status

Once a `PipelineRun` has been created, it will start excuting the DAG
of its Tasks by creating a [`TaskRun`](#taskrun) for each of them. The
`conditions` field will be updated as the `PipelineRun`
executes:

* The `Started` condition will be added when the first `TaskRun` is created.
* The `Completed` condition will be added when the last `TaskRun`
completes (or fails).
* The `Successful` condition will be added after the `Completed`
condition and will indicate if the `PipelineRun` succeeded or failed.

When the `PipelineRun` has completed, the `taskRuns` field will contain
references to all `TaskRuns` which were executed and their next and
previous `TaskRuns`.
Binary file added crds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Examples

This directory contains examples of [the Pipeline strawman CRDs](../README.md) in action.

## Example Tasks

* Example [Tasks](../../README.md#task) are in:
* [build_task.yaml](build_task.yaml)
* [deploy_tasks.yaml](deploy_tasks.yaml)
* [test_tasks.yaml](test_tasks.yaml)

Here are the Task Types that are defined.

1. `build-push`: This task as the name suggests build an image via [kaniko](https://github.com/GoogleContainerTools/kaniko) and pushes it to registry.
2. `make`: Runs make target.
3. `integration-test-in-docker`: This is a new task that is used in the sample pipelines to test an app in using `docker build` command to build an image with has the integration test code.
This task then calls `docker run` which will run the test code. This follows the steps we have for [kritis integration test](https://github.com/grafeas/kritis/blob/4f83f99ca58751c28c0ec40016ed0bba5867d70f/Makefile#L152)
4. `deploy-with-helm`: This task deploys a kubernetes app with helm.
5. `deploy-with-kubectl`: This task deploys with kubectl apply -f <filename>

### Example Runs

The [runs](./runs/) dir contains an example [TaskRun](../README.md#taskrun) and an example [PipelineRun](../README.md#pipelinerun).

[run-kritis-test.yaml](./invocations/run-kritis-test.yaml) shows an example of how to manually run kritis unit test off your development branch.

[kritis-pipeline-run.yaml](./invocations/kritis-pipeline-run.yaml) shows an example of what it would look like to invoke the [kritis example pipeline](#example-pipelines) manually and have it fail on the second task (building and pushing the image).

## Example Pipelines

Finally, we have 2 example [Pipelines](../README.md#pipeline) in [./pipelines](./pipelines)

1. [Kritis](./pipelines/kritis.yaml): This exmaple demonstrates how to configure a pipeline which runs unit test, build an image, deploys it to test and then run integration tests. (This is the pipeline for [kritis](https://github.com/grafeas/kritis).)

![Pipeline Configuration](./pipelines/kritis-pipeline.png)

2. [Guestbook](./pipelines/guestbook.yaml): This is pipeline which is based on example application in [Kubernetes example Repo](https://github.com/kubernetes/examples/tree/master/guestbook)
This pipeline demonstartes how to integrate frontend [guestbook app code](https://github.com/kubernetes/examples/tree/master/guestbook-go) with backed [redis-docker image](https://github.com/GoogleCloudPlatform/redis-docker/tree/master/4) provided by GCP.

![Pipeline Configuration](./pipelines/guestbook-pipeline.png)
25 changes: 25 additions & 0 deletions examples/build_task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: pipeline.knative.dev/v1beta1
kind: Task
metadata:
name: build-push
namespace: default
spec:
inputs:
sources:
- name: workspace
params:
- name: pathToDockerFile
type: string
outputs:
artifacts:
- name: builtImage
type: image
storeKey: registry
buildSpec:
template:
name: kaniko
arguments:
- name: DOCKERFILE
value: ${pathToDockerFile}
- name: REGISTRY
value: ${registry}
47 changes: 47 additions & 0 deletions examples/deploy_tasks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apiVersion: pipeline.knative.dev/v1beta1
kind: Task
metadata:
name: deploy-with-helm
namespace: default
spec:
inputs:
sources:
- name: workspace
params:
- name: pathToHelmCharts
type: string
- name: helmArgs
type: string
- name: image
type: string
cluster:
- name: clusterName
buildSpec:
steps:
- name: deploy
image: kubernetes-helm
args: ['deploy', '--path=${pathToHelmChart}', '--set image=${image}', '${helmArgs}']

---
apiVersion: pipeline.knative.dev/v1beta1
kind: Task
metadata:
name: deploy-with-kubectl
namespace: default
spec:
inputs:
sources:
- name: workspace
type: string
params:
- name: kubectlArgs
type: string
- name: pathToFiles
type: string
cluster:
- name: targetCluster
buildSpec:
steps:
- name: runKubectl
image: k8s-kubectl
args: ['--use-context', '${targetCluster}', '--namespace', '${targetCluster.namespace}', 'apply', '-c', '${pathToFiles}', '${kubectlArgs}']
45 changes: 45 additions & 0 deletions examples/invocations/kritis-pipeline-run.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
apiVersion: pipeline.knative.dev/v1beta1
kind: PipelineRun
metadata:
name: kritis-pipeline-run-12321312984
namespace: default
spec:
pipelineRef:
name: kritis-pipeline
pipelineParamsRef:
name: pipelineparams-sample
trigger:
triggerRef:
type: manual
# The status section will be filled in by the PipelineRun controller once it
# has started invoking the PipelineRun.
status:
taskRuns:
- taskRef:
name: unit-test-kritis-12321312984
nextTasks:
- taskRef:
name: push-kritis-12321312984
prevTasks: []
- taskRef:
name: push-kritis-12321312984
nextTasks: []
prevTasks:
- taskRef:
name: unit-test-kritis-12321312984
conditions:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment here, this will be auto filed by the controller?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya the whole status section will be filled out by the controller - ill add a comment

- type: Started
status: True
lastTransitionTime: 1534204248
reason: manualTrigger
message: "Pipeline has been triggered manually"
- type: Completed
status: True
lastTransitionTime: 1535000000
reason: done
message: "Pipeline execution has finished"
- type: Successful
status: False
lastTransitionTime: 1535000000
reason: taskFailure
message: "TaskRun `push-kritis-12321312984` had non-zero exit code"
59 changes: 59 additions & 0 deletions examples/invocations/run-kritis-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
apiVersion: pipeline.knative.dev/v1beta1
kind: TaskRun
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: unit-test-kritis-feature-x
spec:
taskRef:
name: make
trigger:
triggerRef:
type: manual
inputs:
sources:
- name: 'kritis'
type: 'github'
url: 'github.com/grafeas/kritis'
branch: 'featureX'
commit: 'HEAD'
params:
- name: 'makeTarget'
type: 'string'
value: 'test'
results:
runs:
- name: 'runsBucket'
type: 'gcs'
url: 'gcs://somebucket/results/runs'
logs:
- name: 'logBucket'
type: 'gcs'
url: 'gcs://somebucket/results/logs'
tests:
- name: 'testBucket'
type: 'gcs'
url: 'gcs://somebucket/results/tests'
# The status section will be filled in by the TaskRun controller once it
# has started invoking the TaskRun.
status:
steps:
- name: make
logsURL: 'gcs://somebucket/results/tests/unit-test-kritis-feature-x/make'
exitCode: 0
conditions:
- type: Started
status: True
lastTransitionTime: 1534204250
reason: pipelineRun
message: "Task has been triggered by a Pipeline run"
- type: Completed
status: True
lastTransitionTime: 1534250000
reason: done
message: "Pipeline execution has finished"
- type: Successful
status: True
lastTransitionTime: 1534250000
reason: zeroExitCode
message: "All steps completed with an exit code of 0"
Loading