From 54ca2909e657a37c996cbd7d9beb85eebf7f4d68 Mon Sep 17 00:00:00 2001 From: Christie Wilson Date: Thu, 23 Apr 2020 17:17:35 -0400 Subject: [PATCH] =?UTF-8?q?Update=20end=20to=20end=20example=20to=20use=20?= =?UTF-8?q?workspaces=20and=20results=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One thing that is confusing about Pipelines being beta and PipelineResources not being beta is that many of our examples still use PipelineResources. In an effort to provide more examples of the alternatives, this commit takes our very first pipeline example, which builds and pushes multiple images, then deploys services that use the new images, and updates it to use workspaces and results (and - copies of - catalog tasks) instead of PipelineResources. And as a bonus, now that we have results, the last deploy step will use the digest of the previously built image to ensure it actually deploys the right image! In the future, we should add final tasks to this pipeline that ensure the deployment is actually running; the pipelinerun can succeed even when the images specified are bogus. I removed the build-push kaniko taskrun example since we'd probably want to point folks at the kaniko task in the catalog instead. BONUS: uses volume claim templates as well!! 🎉 --- .../v1beta1/pipelineruns/pipelinerun.yaml | 348 +++++++++++------- .../v1beta1/taskruns/build-push-kaniko.yaml | 81 ---- 2 files changed, 207 insertions(+), 222 deletions(-) delete mode 100644 examples/v1beta1/taskruns/build-push-kaniko.yaml diff --git a/examples/v1beta1/pipelineruns/pipelinerun.yaml b/examples/v1beta1/pipelineruns/pipelinerun.yaml index d85624d64c5..d1e0225a6d0 100644 --- a/examples/v1beta1/pipelineruns/pipelinerun.yaml +++ b/examples/v1beta1/pipelineruns/pipelinerun.yaml @@ -1,18 +1,6 @@ ---- -apiVersion: tekton.dev/v1alpha1 -kind: PipelineResource -metadata: - name: skaffold-image-leeroy-app -spec: - type: image - params: - - name: url - value: gcr.io/christiewilson-catfactory/leeroy-app ---- # This demo modifies the cluster (deploys to it) you must use a service # account with permission to admin the cluster (or make your default user an admin # of the `default` namespace with default-cluster-admin. - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: @@ -26,82 +14,170 @@ roleRef: name: cluster-admin apiGroup: rbac.authorization.k8s.io --- -apiVersion: tekton.dev/v1alpha1 -kind: PipelineResource -metadata: - name: skaffold-image-leeroy-web-pipelinerun -spec: - type: image - params: - - name: url - value: gcr.io/christiewilson-catfactory/leeroy-web ---- -apiVersion: tekton.dev/v1alpha1 -kind: PipelineResource -metadata: - name: skaffold-git-pipelinerun -spec: - type: git - params: - - name: revision - value: v0.32.0 - - name: url - value: https://github.com/GoogleContainerTools/skaffold ---- apiVersion: tekton.dev/v1beta1 kind: Task metadata: name: unit-tests spec: - resources: - inputs: - - name: workspace - type: git - targetPath: go/src/github.com/GoogleContainerTools/skaffold + workspaces: + - name: source + mountPath: /workspace/source/go/src/github.com/GoogleContainerTools/skaffold steps: - name: run-tests image: golang env: - name: GOPATH value: /workspace/go - workingDir: $(resources.inputs.workspace.path) - command: - - echo - args: - - "pass" + workingDir: $(workspaces.source.path) + script: | + # The intention behind this example Task is to run unit test, however we + # currently do nothing to ensure that a unit test issue doesn't cause this example + # to fail unnecessarily. In the future we could re-introduce the unit tests (since + # we are now pinning the version of Skaffold we pull) or use Tekton Pipelines unit tests. + echo "pass" --- +# Copied from https://github.com/tektoncd/catalog/blob/v1beta1/git/git-clone.yaml +# With a few fixes being ported over in https://github.com/tektoncd/catalog/pull/290 +# Post #1839 we can refer to the remote Task in a registry or post #2298 in git directly apiVersion: tekton.dev/v1beta1 kind: Task metadata: - name: build-push + name: git-clone spec: + workspaces: + - name: output + description: The git repo will be cloned onto the volume backing this workspace params: - - name: pathToDockerFile - description: The path to the dockerfile to build - default: $(resources.inputs.docker-source.path)/Dockerfile - - name: pathToContext - description: The build context used by Kaniko (https://github.com/GoogleContainerTools/kaniko#kaniko-build-contexts) - default: $(resources.inputs.docker-source.path) - resources: - inputs: - - name: docker-source - type: git - outputs: - - name: builtImage - type: image + - name: url + description: git url to clone + type: string + - name: revision + description: git revision to checkout (branch, tag, sha, ref…) + type: string + default: master + - name: submodules + description: defines if the resource should initialize and fetch the submodules + type: string + default: "true" + - name: depth + description: performs a shallow clone where only the most recent commit(s) will be fetched + type: string + default: "1" + - name: sslVerify + description: defines if http.sslVerify should be set to true or false in the global git config + type: string + default: "true" + - name: subdirectory + description: subdirectory inside the "output" workspace to clone the git repo into + type: string + default: "" + - name: deleteExisting + description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there + type: string + default: "false" + results: + - name: commit + description: The precise commit SHA that was fetched by this Task + steps: + - name: clone + image: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.11.0 + script: | + CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)" + cleandir() { + # Delete any existing contents of the repo directory if it exists. + # + # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/" + # or the root of a mounted volume. + if [[ -d "$CHECKOUT_DIR" ]] ; then + # Delete non-hidden files and directories + rm -rf "$CHECKOUT_DIR"/* + # Delete files and directories starting with . but excluding .. + rm -rf "$CHECKOUT_DIR"/.[!.]* + # Delete files and directories starting with .. plus any other character + rm -rf "$CHECKOUT_DIR"/..?* + fi + } + if [[ "$(params.deleteExisting)" == "true" ]] ; then + cleandir + fi + /ko-app/git-init \ + -url "$(params.url)" \ + -revision "$(params.revision)" \ + -path "$CHECKOUT_DIR" \ + -sslVerify="$(params.sslVerify)" \ + -submodules="$(params.submodules)" \ + -depth="$(params.depth)" + cd "$CHECKOUT_DIR" + RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')" + EXIT_CODE="$?" + if [ "$EXIT_CODE" != 0 ] + then + exit $EXIT_CODE + fi + # Make sure we don't add a trailing newline to the result! + echo -n "$RESULT_SHA" > $(results.commit.path) +--- +# Copied from https://github.com/tektoncd/catalog/blob/v1beta1/kaniko/kaniko.yaml +# with a few fixes that will be port over in https://github.com/tektoncd/catalog/pull/291 +# Post #1839 we can refer to the remote Task in a registry or post #2298 in git directly +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: kaniko +spec: + workspaces: + - name: source + params: + - name: IMAGE + description: Name (reference) of the image to build. + - name: DOCKERFILE + description: Path to the Dockerfile to build. + default: ./Dockerfile + - name: CONTEXT + description: The build context used by Kaniko. + default: ./ + - name: EXTRA_ARGS + default: "" + - name: BUILDER_IMAGE + description: The image on which builds will run + default: gcr.io/kaniko-project/executor:latest + results: + - name: IMAGE_DIGEST + description: Digest of the image just built. steps: - name: build-and-push - image: gcr.io/kaniko-project/executor:v0.17.1 + workingDir: $(workspaces.source.path) + image: $(params.BUILDER_IMAGE) # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential + # https://github.com/tektoncd/pipeline/pull/706 env: - - name: "DOCKER_CONFIG" - value: "/tekton/home/.docker/" + - name: DOCKER_CONFIG + value: /tekton/home/.docker command: - /kaniko/executor + - $(params.EXTRA_ARGS) + - --dockerfile=$(params.DOCKERFILE) + - --context=$(workspaces.source.path)/$(params.CONTEXT) # The user does not need to care the workspace and the source. + - --destination=$(params.IMAGE) + - --oci-layout-path=$(workspaces.source.path)/$(params.CONTEXT)/image-digest + # kaniko assumes it is running as root, which means this example fails on platforms + # that default to run containers as random uid (like OpenShift). Adding this securityContext + # makes it explicit that it needs to run as root. + securityContext: + runAsUser: 0 + - name: write-digest + workingDir: $(workspaces.source.path) + image: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/imagedigestexporter:v0.11.1 + # output of imagedigestexport [{"name":"image","digest":"sha256:eed29..660"}] + command: ["/ko-app/imagedigestexporter"] args: - - --dockerfile=$(params.pathToDockerFile) - - --destination=$(resources.outputs.builtImage.url) - - --context=$(params.pathToContext) + - -images=[{"name":"$(params.IMAGE)","type":"image","url":"$(params.IMAGE)","digest":"","OutputImageDir":"$(workspaces.source.path)/$(params.CONTEXT)/image-digest"}] + - -terminationMessagePath=$(params.CONTEXT)/image-digested + - name: digest-to-results + workingDir: $(workspaces.source.path) + image: stedolan/jq + script: | + cat $(params.CONTEXT)/image-digested | jq '.[0].value' -rj | tee /tekton/results/IMAGE_DIGEST --- # This task deploys with kubectl apply -f apiVersion: tekton.dev/v1beta1 @@ -113,15 +189,13 @@ spec: - name: path description: Path to the manifest to apply - name: yqArg - description: Okay this is a hack, but I didn't feel right hard-codeing `-d1` down below + description: Okay this is a hack, but I didn't feel right hard-coding `-d1` down below - name: yamlPathToImage description: The path to the image to replace in the yaml manifest (arg to yq) - resources: - inputs: - - name: workspace - type: git - - name: image - type: image + - name: imageURL + description: The URL of the image to deploy + workspaces: + - name: source steps: - name: replace-image image: mikefarah/yq @@ -132,7 +206,7 @@ spec: - "$(params.yqArg)" - "$(params.path)" - "$(params.yamlPathToImage)" - - "$(resources.inputs.image.url)" + - "$(params.imageURL)" - name: run-kubectl image: lachlanevenson/k8s-kubectl command: ['kubectl'] @@ -143,100 +217,93 @@ spec: --- # This Pipeline Builds two microservice images(https://github.com/GoogleContainerTools/skaffold/tree/master/examples/microservices) # from the Skaffold repo (https://github.com/GoogleContainerTools/skaffold) and deploys them to the repo currently running Tekton Pipelines. - -# **Note** : It does this using the k8s `Deployment` in the skaffold repos's existing yaml -# files, so at the moment there is no guarantee that the image that are built and -# pushed are the ones that are deployed (that would require using the digest of -# the built image, see https://github.com/tektoncd/pipeline/issues/216). - apiVersion: tekton.dev/v1beta1 kind: Pipeline metadata: name: demo-pipeline spec: - resources: - - name: source-repo - type: git - - name: web-image - type: image - - name: app-image - type: image + params: + - name: image-registry + default: gcr.io/christiewilson-catfactory + workspaces: + - name: git-source tasks: + - name: fetch-from-git + taskRef: + name: git-clone + params: + - name: url + value: https://github.com/GoogleContainerTools/skaffold + - name: revision + value: v0.32.0 + workspaces: + - name: output + workspace: git-source - name: skaffold-unit-tests + runAfter: [fetch-from-git] taskRef: name: unit-tests - resources: - inputs: - - name: workspace - resource: source-repo + workspaces: + - name: source + workspace: git-source - name: build-skaffold-web runAfter: [skaffold-unit-tests] taskRef: - name: build-push + name: kaniko params: - - name: pathToDockerFile - value: Dockerfile - - name: pathToContext - value: $(resources.inputs.docker-source.path)/examples/microservices/leeroy-web - resources: - inputs: - - name: docker-source - resource: source-repo - outputs: - - name: builtImage - resource: web-image + - name: IMAGE + value: $(params.image-registry)/leeroy-web + - name: CONTEXT + value: examples/microservices/leeroy-web + - name: DOCKERFILE + value: $(workspaces.source.path)/examples/microservices/leeroy-web/Dockerfile + workspaces: + - name: source + workspace: git-source - name: build-skaffold-app runAfter: [skaffold-unit-tests] taskRef: - name: build-push + name: kaniko params: - - name: pathToDockerFile - value: Dockerfile - - name: pathToContext - value: $(resources.inputs.docker-source.path)/examples/microservices/leeroy-app - resources: - inputs: - - name: docker-source - resource: source-repo - outputs: - - name: builtImage - resource: app-image + - name: IMAGE + value: $(params.image-registry)/leeroy-app + - name: CONTEXT + value: examples/microservices/leeroy-app + - name: DOCKERFILE + value: $(workspaces.source.path)/examples/microservices/leeroy-app/Dockerfile + workspaces: + - name: source + workspace: git-source - name: deploy-app taskRef: name: demo-deploy-kubectl - resources: - inputs: - - name: workspace - resource: source-repo - - name: image - resource: app-image - from: - - build-skaffold-app params: + - name: imageURL + value: $(params.image-registry)/leeroy-app@$(tasks.build-skaffold-app.results.IMAGE_DIGEST) - name: path - value: $(resources.inputs.workspace.path)/examples/microservices/leeroy-app/kubernetes/deployment.yaml + value: $(workspaces.source.path)/examples/microservices/leeroy-app/kubernetes/deployment.yaml - name: yqArg value: "-d1" - name: yamlPathToImage value: "spec.template.spec.containers[0].image" + workspaces: + - name: source + workspace: git-source - name: deploy-web taskRef: name: demo-deploy-kubectl - resources: - inputs: - - name: workspace - resource: source-repo - - name: image - resource: web-image - from: - - build-skaffold-web params: + - name: imageURL + value: $(params.image-registry)/leeroy-web@$(tasks.build-skaffold-web.results.IMAGE_DIGEST) - name: path - value: $(resources.inputs.workspace.path)/examples/microservices/leeroy-web/kubernetes/deployment.yaml + value: $(workspaces.source.path)/examples/microservices/leeroy-web/kubernetes/deployment.yaml - name: yqArg value: "-d1" - name: yamlPathToImage value: "spec.template.spec.containers[0].image" + workspaces: + - name: source + workspace: git-source --- apiVersion: tekton.dev/v1beta1 kind: PipelineRun @@ -246,13 +313,12 @@ spec: pipelineRef: name: demo-pipeline serviceAccountName: 'default' - resources: - - name: source-repo - resourceRef: - name: skaffold-git-pipelinerun - - name: web-image - resourceRef: - name: skaffold-image-leeroy-web-pipelinerun - - name: app-image - resourceRef: - name: skaffold-image-leeroy-app + workspaces: + - name: git-source + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/examples/v1beta1/taskruns/build-push-kaniko.yaml b/examples/v1beta1/taskruns/build-push-kaniko.yaml deleted file mode 100644 index e12797dba67..00000000000 --- a/examples/v1beta1/taskruns/build-push-kaniko.yaml +++ /dev/null @@ -1,81 +0,0 @@ -apiVersion: tekton.dev/v1alpha1 -kind: PipelineResource -metadata: - name: skaffold-image-leeroy-web-build-push-kaniko -spec: - type: image - params: - - name: url - value: localhost:5000/leeroy-web ---- -apiVersion: tekton.dev/v1alpha1 -kind: PipelineResource -metadata: - name: skaffold-git-build-push-kaniko -spec: - type: git - params: - - name: revision - value: v0.32.0 - - name: url - value: https://github.com/GoogleContainerTools/skaffold ---- -# Builds an image via kaniko and pushes it to registry. -apiVersion: tekton.dev/v1beta1 -kind: Task -metadata: - name: build-push-kaniko -spec: - params: - - name: pathToDockerFile - description: The path to the dockerfile to build - default: /workspace/workspace/Dockerfile - - name: pathToContext - description: The build context used by Kaniko (https://github.com/GoogleContainerTools/kaniko#kaniko-build-contexts) - default: /workspace/workspace - resources: - inputs: - - name: workspace - type: git - outputs: - - name: builtImage - type: image - steps: - - name: build-and-push - image: gcr.io/kaniko-project/executor:v0.17.1 - # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential - env: - - name: "DOCKER_CONFIG" - value: "/tekton/home/.docker/" - args: - - --dockerfile=$(inputs.params.pathToDockerFile) - - --destination=$(outputs.resources.builtImage.url) - - --context=$(inputs.params.pathToContext) - - --oci-layout-path=$(inputs.resources.builtImage.path) - securityContext: - runAsUser: 0 - sidecars: - - image: registry - name: registry ---- -apiVersion: tekton.dev/v1beta1 -kind: TaskRun -metadata: - name: build-push-kaniko -spec: - taskRef: - name: build-push-kaniko - resources: - inputs: - - name: workspace - resourceRef: - name: skaffold-git-build-push-kaniko - outputs: - - name: builtImage - resourceRef: - name: skaffold-image-leeroy-web-build-push-kaniko - params: - - name: pathToDockerFile - value: Dockerfile - - name: pathToContext - value: /workspace/workspace/examples/microservices/leeroy-web