Cristian Marius Tiutiu, Bikram Gupta, and Anish Singh Walia
This blueprint will show you how to implement a CI/CD solution using free and popular open-source implementations that run on Kubernetes clusters natively.
DigitalOcean Marketplace provides pre-configured 1-Click apps to deploy to your DigitalOcean Kubernetes (DOKS) cluster quickly. You will use 1-Click apps to provision each software component for your cluster.
You will learn to use Tekton to build a CI/CD pipeline that continuously fetches code changes from a Git repository and builds a Docker image for your custom application. Then, Tekton will push the Docker image to a remote registry and notify Argo CD to deploy it to your Kubernetes cluster. This guide will also teach you how to use Knative Eventing to trigger the CI/CD pipeline each time code is automatically pushed to your application’s GitHub repository. All these steps run automatically.
This tutorial uses the following tools:
After completing this blueprint, you will have a fully functional CI/CD pipeline that continuously builds and deploys code changes for your custom applications using Kubernetes.
Following diagram shows the complete setup:
In the tutorial, you will learn:
To complete this tutorial, you will need:
kubectl
and doctl
.Next, this tutorial provides a quick introduction to each software component. The main purpose is to give you a basic understanding of each component and how it’s being used.
Kaniko is a tool to build container images directly from a Dockerfile inside a container or Kubernetes cluster. It means you can build and push docker images to a remote registry directly from your Kubernetes cluster. What is nice about this setup is you can have a full CI system running completely in your Kubernetes cluster.
Under the hood, Kaniko doesn’t depend on a Docker daemon and executes each command within a Dockerfile completely in userspace. This enables building container images in environments that can’t easily or securely run a Docker daemon, such as a standard Kubernetes cluster. Kaniko is meant to be run as an image: gcr.io/kaniko-project/executor
.
Please visit the official project page for more information and details about Kaniko.
In this blueprint, you will use Kaniko to build Docker images for your custom applications from the Kubernetes cluster itself.
Continuous integration (or CI) is the process of automating the integration of small code changes from multiple contributors into a single software project. To achieve CI a central repository is used (e.g. Git), where each developer (or contributor) pushes code changes. Then, a CI tool (e.g., Tekton) detects changes and starts the CI automation.
In general, each CI automation consists of several steps:
Tekton is a cloud-native solution for building CI/CD systems on top of Kubernetes clusters. It is specifically engineered to run on Kubernetes and empowers developers to create CI pipelines using reusable blocks called Tasks. Other important components are Tekton CLI and Catalog (collection of reusable Tasks), which make Tekton a complete ecosystem.
In this guide, Tekton implements the CI part via the Pipeline
resource (and associated components, such as: Tasks
, Triggers
, etc).
Tekton is modular and very well organized. This tutorial relies on the following Tekton components to implement the CI part:
A Tekton Task
is a collection of Steps
that you define and arrange in a specific execution order as part of your continuous integration flow. Steps are the basic unit of execution in Tekton, which performs real actions such as building code, creating a Docker image, pushing to the Docker registry, etc. To add steps to a Task, you define a steps
field containing a list of desired Steps. The order in which the Steps appear in this list is the order in which they will be executed.
Tekton creates a Kubernetes Pod in your cluster for each task to run the steps. Then, each step runs in a docker container thus it must reference a docker image. The container you choose depends on what your step does. For example:
Alpine Linux
image.Google’s Kaniko
image.bitnami/kubectl
image.Task definitions are composed of (most important are highlighted):
A typical Tekton Task
definition looks like below:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kaniko-example
spec:
params:
- name: IMAGE
description: Name (reference) of the image to build.
- name: DOCKERFILE
description: Path to the Dockerfile to build.
default: ./Dockerfile
results:
- name: IMAGE_DIGEST
description: Digest of the image just built.
- name: IMAGE_URL
description: URL of the image just built.
steps:
- name: build-and-push
workingDir: $(workspaces.source.path)
image: $(params.BUILDER_IMAGE)
...
Explanation for the above configuration:
spec.params
: defines the list of input parameters for a Task.spec.results
: defines a list of string values that this Task emits. Emitting results allows passing values between tasks. In other words, a result is an output value created by one Task, and can be used as an input value for the second Tasks (and so on).spec.steps
: defines the list of steps to execute. Steps represent the basic unit of execution, and define the logic of Tasks.Important Note:
Task resources are deprecated starting with v1beta1
version of Tekton APIs. Users are encouraged to use the new features as the deprecation note explains.
By design, Tekton will not run your Tasks when created. To launch a Task into execution, you need to create a separate TaskRun resource. A TaskRun is what instantiates your Task and begins the execution of steps. A TaskRun executes the Steps in the Task in the specified order until all Steps have been executed successfully or a failure occurs. Also, a TaskRun allows passing input parameters and specifying resources and workspaces for your custom Task.
What’s important to remember is that tasks are reusable building blocks that can be shared and referenced across pipelines. This design aspect makes Tekton unique. To help users even more, the Tekton project offers a collection of reusable tasks via the Tekton Catalog project.
The below picture illustrates the Task
and TaskRun
concepts:
Please visit the official documentation page for more information and details about Tekton Tasks.
A Tekton Pipeline organizes your Tekton tasks and orchestrates the CI flow. A Pipeline specifies one or more Tasks in the desired order of execution. You can embed tasks in a pipeline directly or reference them from external manifest files. Using references, you create task definitions in separate manifest files and reuse them across pipelines. This method is encouraged because it avoids code or configuration duplication and promotes code reuse
(or configuration reuse). Thus, tasks act as objects (with inputs and outputs) that can be reused (and instantiated) across your pipelines. You can create dedicated pipelines to test, build, and deploy your application code.
Pipeline definitions are composed of (most important are highlighted):
Typical Tekton Pipeline
definition looks like below:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: kaniko-pipeline
spec:
params:
- name: git-url
- name: git-revision
- name: image-name
- name: path-to-image-context
- name: path-to-dockerfile
workspaces:
- name: git-source
tasks:
- name: fetch-from-git
taskRef:
name: git-clone
params:
- name: url
value: $(params.git-url)
- name: revision
value: $(params.git-revision)
workspaces:
- name: output
workspace: git-source
- name: build-image
taskRef:
name: kaniko
params:
- name: IMAGE
value: $(params.image-name)
- name: CONTEXT
value: $(params.path-to-image-context)
- name: DOCKERFILE
value: $(params.path-to-dockerfile)
workspaces:
- name: source
workspace: git-source
Explanation for the above configuration:
spec.params
: defines the list of input parameters for the Pipeline.spec.workspaces
: defines a list of workspaces to be used by each Task inside the Pipeline. Workspaces are used to share data (or artifacts) between tasks.spec.tasks
: defines the list of tasks to be executed in order as part of the Pipeline. Tasks can be embedded in the Pipeline YAML definition, or referenced using the taskRef
field.Tip:
The Tekton Catalog (or Hub) provides a ready-to-use collection of task definitions for common-use scenarios, such as cloning a git repository, building a docker image via kaniko, etc. You can install them in your Kubernetes cluster via tkn
CLI or kubectl
. Then, you can reference each task in your custom pipeline using the taskRef
field (you can see such an example in the example pipeline definition to follow).
By design, Tekton will not run your Pipelines when created. To launch a Pipeline into execution, you must create a PipelineRun resource. A PipelineRun lets you instantiate and execute a Tekton Pipeline in your Kubernetes cluster. A PipelineRun executes the Tasks in the Pipeline in the specified order until all Tasks have been executed successfully or a failure occurs.
Important Notes:
v1beta1
version of Tekton APIs (hence, not used in this tutorial as well). As the deprecation note explains, users are encouraged to use the new features.The picture below illustrates the Pipelines and Tasks composition:
Please visit the official documentation page for more information and details about Tekton Pipelines.
You need a mechanism to tell Tekton how to react and trigger your CI pipeline in response to external events emitted by various sources, such as GitHub. This is accomplished via another Tekton component called Triggers (needs to be installed separately). Tekton triggers allow you to detect and extract information from events from various sources and execute TaskRuns and PipelineRuns based on that information. It can also pass information extracted from events directly to TaskRuns and PipelineRuns.
The following resources are required to trigger a Tekton pipeline using GitHub webhooks automatically:
Triggers
.EventListener
detects an event. A Trigger
specifies a TriggerTemplate
and a TriggerBinding
.TaskRun
or PipelineRun
to execute when your EventListener
detects an event.TriggerTemplate
.Optionally, you can also create an Interceptor to filter events, perform webhook verification (using secrets), or other processing before the Trigger actions are executed.
The following diagram illustrates how Tekton EventListeners and Triggers work:
In this blueprint, you will use Tekton EventListeners and Triggers to respond to GitHub push events and trigger the CI/CD pipeline to build and deploy your custom application.
Please visit the official project page for more information and details about Tekton EventListener and Triggers.
Tekton Catalog is a collection of reusable tasks you can use in your pipelines. The main idea is to promote the modular design of Tekton and abstract implementation details for common situations. For example, in most of the pipelines you will want to use git clone tasks, application image build tasks, push to remote registry tasks, etc.
The following listing contains a few interesting tasks to start with:
In this blueprint you will use Tekton catalog to install commonly used tasks, such as git-clone, kaniko and argocd-sync-and-wait.
Please visit the Tekton Catalog GitHub project page to learn more.
Tekton Dashboard is a web-based interface for Tekton Pipelines and Tekton triggers resources. It allows you to manage and view Tekton resource creation, execution, and completion.
Tekton Dashboard supports:
In this blueprint, you will use the Tekton dashboard to interact with pipeline runs and visualize results (such as logs) for each task from the CI/CD flow.
Please visit the Tekton Dashboard GitHub project page to learn more.
Argo CD is a popular open-source implementation for doing GitOps continuous delivery (CD) on top of Kubernetes. Your applications, definitions, configurations, and environments should be declarative and version-controlled. Also, application deployment and lifecycle management should be automated, auditable, and easily understood. All this can be done using Argo.
Argo CD adheres to the same GitOps patterns and principles, thus maintaining your cluster state using a declarative approach. Synchronization happens via a Git repository, where your Kubernetes manifests are stored. Kubernetes manifests can be specified in several ways:
Why Argo and not Tekton for the CD part?
While you can also accomplish the CD part using Tekton, Argo is more specialized for this task. Every CI system can indeed be used to perform deployments as well, but it implies more steps and logic to accomplish the same thing. Traditionally, you would use all kinds of scripts and glue logic to create the CD part inside a CI system (take Jenkins as an example). Soon, you will notice that it’s unnatural, hence a dedicated CD solution is more appropriate.
Other important aspects to consider:
Argo CD helps you implement GitOps and keep your Kubernetes manifests (even those used in this guide) synced with a Git repository—no need to go back and apply everything by hand on every change. GitOps also allows you to keep track of changes easily and, most important, forbids manual intervention in your cluster (via other members in the team using kubectl
, for example).
Next, the most important aspect is a setup where a specialized system takes care of the CD part and doesn’t interfere, or it’s not dependent on the CI part. If the CI system goes down for some reason, it shouldn’t affect the CD part and vice-versa. On the other hand, a system or a component that does multiple things at once can be prone to failure in accomplishing both. So, it’s best to follow the single responsibility principle in general and let Tekton take care of the CI part and Argo handle CD (as well as GitOps).
Argo CD is using the Application core concept to manage applications deployment and lifecycle. Inside an Argo CD application manifest, you define the Git repository hosting your application definitions and the corresponding Kubernetes cluster used to deploy your applications. In other words, an Argo CD application defines the relationship between a source repository and a Kubernetes cluster. It’s a concise and scalable design where you can associate multiple sources (Git repositories) and corresponding Kubernetes clusters.
A major benefit of using applications is that you don’t need to deploy Argo to each cluster individually. You can use a dedicated cluster for Argo and simultaneously deploy applications to all clusters from a single place. This way, you avoid Argo CD downtime or loss in case other environments have issues or get decommissioned.
You can group similar applications into a Project. Projects permit logical grouping of applications and associated roles/permissions when working with multiple teams. Each new application belongs to the default
project when not specified. The default
project is created automatically, and it doesn’t have any restrictions. The default project can be modified but not deleted.
Note:
All examples used in this tutorial use the default
Argo CD project.
Please visit the official documentation website to read more about Argo CD core concepts.
In this blueprint, you will learn how to continuously use Argo CD to deploy code changes for your custom applications.
Knative is an open-source solution for deploying serverless applications using Kubernetes as the underlying platform. In addition to application development, developers may also have infrastructure tasks such as maintaining Kubernetes manifests for application deployment, rolling back to a previous revision, traffic routing, scaling up or down workloads to meet load demand, etc.
Knative reduces the boilerplate needed for spinning up workloads in Kubernetes, such as creating deployments, services, ingress objects, etc. Knative also helps you implement best practices in production systems (e.g., blue-green, canary deployments), application observability (logs and metrics), and support for event-driven applications.
Knative has two main components:
In this blueprint you will learn how to use the Knative Serving component to deploy and publicly expose serverless web application - the 2048 game, via Services (not to be confused with Kubernetes Services).
For each application you want to run and expose publicly via Knative, you need to create a Knative Service CRD. A Knative Service represents the basic execution unit for the Knative Serving component. Going further, a Knative Service resource abstracts all the details needed to run and expose your application, such as creating Kubernetes deployments (including autoscaling), services, ingress configurations, etc.
Knative can automatically scale down your applications to zero when not in use or idle (for example, when no HTTP traffic is present), which makes your applications serverless.
Knative Serving features include:
Other important Knative Serving resources worth mentioning are:
You can read more about the available Knative Serving resources on the official documentation page.
The Knative Eventing component is used in this blueprint to connect GitHub events with Tekton Pipelines to automatically trigger the CI flow. The Tekton CI pipeline rebuilds the application image whenever a git push event is triggered by the GitHub repository hosting the application source code.
Knative Eventing helps address common tasks for cloud-native development, such as:
Event-driven architectures allow loose coupling between components in the system. This has a tremendous advantage, meaning that new functionality can be added easily without interfering or breaking other components. Event-based architectures use a message broker such as Apache Kafka or RabbitMQ (or an in-memory
one - not recommended for production systems). Using brokers abstracts the details of event routing from the event producer and consumer. In other words, applications need not to worry how a message (or event) travels from point A to B. The broker takes care of all the details and correctly routes each message (or event) from the source to the destination (or multiple destinations). Brokers also offer support for complex deliveries, such as responding to events, message filtering, delivery guarantees, etc.
Knative eventing provides support for the following delivery mechanisms:
1:1
scenarios, where an event source sends messages to a single subscriber (such as a Knative Service or a Kubernetes Service).1:n
fanout scenarios, where an event source can send messages to 1 or more subscribers via channels. Channels can be in-memory (volatile), or persistent if using Kafka.In this blueprint, you will learn how to use Knative Eventing to listen for GitHub events and trigger the Tekton CI/CD pipeline that builds and deploys your custom application.
For more information about Knative and other features, please visit the official documentation website. Knative Tips is also a very good documentation source and practical examples for Knative in general.
Cert-Manager is an open-source certificate management tool that works with Kubernetes. It supports all the required operations for obtaining, renewing, and using SSL/TLS certificates. Cert-Manager can talk with various certificate authorities (CAs), like Let’s Encrypt, HashiCorp Vault, and Venafi. It can also automatically issue valid certificates for you and renew them before they expire.
SSL/TLS certificates secure your connections and data by verifying the identity of hosts/sites and encrypting your data. Cert-Manager manages them by integrating with your Kubernetes cluster’s Ingress Controller, the main entry point for your backend services. Then, you can provide identity information to users by presenting them with a valid SSL/TLS certificate whenever they visit your website(s).
This blueprint configures Knative Serving to work with Cert-Manager and enables the automatic creation and renewal of TLS certificates for each Knative Service. The Knative component providing the auto TLS integration is called net-certmanager, and it’s a separate project developed by Knative.
Cert-Manager relies on several CRDs to fetch TLS certificates for your domain, such as:
namespaced
certificate issuer, allowing you to use different CAs
in each namespace
.Issuer
, but it doesn’t belong to a namespace, hence can be used to issue
certificates in any namespace
.namespaced
resource that references an Issuer
or ClusterIssuer
for issuing certificates.In this blueprint, you will a cluster based issuer (ClusterIssuer
) resource to enable TLS termination for your Knative services. Next, net-certmanager
manages TLS certificates automatically for you via the ClusterIssuer
resource.
For more information about Cert-Manager and its features, please visit the official documentation website.
Next, you will prepare the sample application repository used in this tutorial, as well as the DigitalOcean Docker Registry used for storing application images. You will also create a dedicated Kubernetes namespace to keep everything clean and well-organized.
Before continuing with the tutorial, perform the following steps:
To test the Tekton CI/CD flow presented in this blueprint, you need to fork the kubernetes-sample-apps repository first. Also, create a GitHub Personal Access Token (PAT) with the appropriate permissions, as explained here. The PAT is needed to allow the GitHubSource CRD to manage webhooks for you automatically. Store the PAT credentials somewhere safe because you will need them later.
You need a DigitalOcean Container Registry to store the sample application images. For detailed steps to create one, follow the quickstart guide. A free plan is adequate to complete this guide.
Alternatively, you can run the following command to provision a new registry:
doctl registry create <YOUR_DOCKER_REGISTRY_NAME_HERE> \
--region <YOUR_DOCKER_REGISTRY_REGION_HERE> \
--subscription-tier starter
The command includes the following flags:
--region
: Specifies the region name to provide the registry. You can list all the available regions via the doctl registry options available-regions
command.--subscription-tier
: Specifies the subscription tier to use. You can list all the available tiers via the doctl registry options subscription-tiers
command. The example above uses the starter
tier, which is free.Then, run the following command to verify that the registry was created successfully. Make sure to replace the <>
placeholders accordingly in the following command:
doctl registry get <YOUR_DOCKER_REGISTRY_NAME_HERE>
The output looks similar to the following:
OutputName Endpoint Region slug
tekton-ci registry.digitalocean.com/tekton-ci nyc3
In this guide, the registry is named tekton-ci
and provisioned in the nyc3
region.
Finally, you must configure your DOKS cluster to pull images from your private registry. DigitalOcean provides an easy way of accomplishing this task using the control panel. First, navigate to the Settings tab of your container registry. Then, click the Edit button from the DigitalOcean Kubernetes Integration section. Finally, select the appropriate checkbox and press the Save button.
It’s generally a best practice to have a dedicated namespace when provisioning new resources in your Kubernetes cluster to keep everything organized. A dedicated namespace also lets you easily clean up everything later on.
This tutorial uses the doks-ci-cd
namespace. Run the following command to create it:
kubectl create ns doks-ci-cd
Then, check if the namespace is successfully created:
kubectl get ns doks-ci-cd
The output looks similar to:
NAME STATUS AGE
doks-ci-cd Active 13m
Clone the container-blueprints
repo using the following command:
git clone https://github.com/digitalocean/container-blueprints.git
Then, change the directory to your local copy using the following command:
cd container-blueprints
Next, you will install each software component required by this guide using the DigitalOcean Marketplace collection of 1-click apps for Kubernetes.
Cert-Manager is available as a 1-Click Kubernetes application from the DigitalOcean Marketplace. To install Cert-Manager, navigate to your cluster’s Marketplace tab and search for the app. Then, click the Install App button and follow the instructions.
After the installation finishes, you should see the new application listed in the Marketplace tab of your Kubernetes cluster. The output looks similar to:
Finally, check if the installation was successful by following the Getting started after deploying Cert-Manager section from the Cert-Manager 1-Click app documentation page.
Next, you will provision Tekton Pipelines on your Kubernetes cluster from DigitalOcean Marketplace.
Tekton installation is divided into two parts:
Tekton Pipelines is available as a 1-Click Kubernetes application from the DigitalOcean Marketplace. On the other hand, you will install Tekton Triggers using kubectl
.
To install Tekton Pipelines, navigate to the Marketplace tab of your cluster and search for the app. Then, click on the Install App button from the right side and follow the instructions:
After the installation, you should see the new application listed in your Kubernetes cluster’s Marketplace tab. The output looks similar to:
Finally, check if the installation was successful by following the Getting started after deploying Tekton Pipelines section from the Tekton Pipelines 1-Click app documentation page.
Next, you will provision Tekton Triggers on your Kubernetes cluster.
Tekton Triggers is not available as a 1-Click application, so you will install it using kubectl
as recommended in the official installation page. Run the following commands to install Tekton Triggers and dependencies. The latest stable version available at this time of writing is v0.20.1:
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/previous/v0.20.1/release.yaml
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/previous/v0.20.1/interceptors.yaml
Note:
Tekton Triggers require Tekton Pipelines to be installed first as a dependency, as described in the Provision Tekton Pipelines section. By default, it uses the tekton-pipelines
namespace to create the required resources.
Next, check if Tekton Triggers was installed successfully:
kubectl get pods --namespace tekton-pipelines -l app.kubernetes.io/part-of=tekton-triggers
The output looks similar to:
OutputNAME READY STATUS RESTARTS AGE
tekton-triggers-controller-75b9b7b77d-5nk76 1/1 Running 0 2m
tekton-triggers-core-interceptors-7769dc7cbc-8hjkn 1/1 Running 0 2m
tekton-triggers-webhook-79c866dc85-xz64m 1/1 Running 0 2m
All tekton-triggers
pods should be running and healthy. You can also list the installed Tekton components and corresponding version using the Tekton CLI:
tkn version
The output looks similar to:
OutputClient version: 0.24.0
Pipeline version: v0.29.0
Triggers version: v0.19.1
Next, you will provision the Tekton Dashboard on your Kubernetes cluster using kubectl
.
Tekton Dashboard is not available as a 1-Click application yet, so you will install it using kubectl
as recommended in the official installation page. Run the following commands to install Tekton Dahsboard and dependencies. The latest stable version available at this time of writing is v0.28.0:
kubectl apply -f https://storage.googleapis.com/tekton-releases/dashboard/previous/v0.28.0/tekton-dashboard-release.yaml
Note: Tekton Dashboard requires Tekton Pipelines to be installed first as a dependency, as described in the Provision Tekton Pipelines section. By default, it uses the tekton-pipelines
namespace to create required resources.
Next, check if the Tekton Dashboard installation was successful:
kubectl get pods --namespace tekton-pipelines -l app.kubernetes.io/part-of=tekton-dashboard
The output looks similar to:
OutputNAME READY STATUS RESTARTS AGE
tekton-dashboard-56fcdc6756-p848r 1/1 Running 0 5m
All tekton-dashboard
pods should be running and healthy. You can also list installed Tekton components and corresponding version using Tekton CLI:
tkn version
The output looks similar to:
OutputClient version: 0.24.0
Pipeline version: v0.29.0
Triggers version: v0.20.1
Dashboard version: v0.28.0
The Tekton Dashboard can be accessed by port-forwarding the associated Kubernetes service. First, check the associated service:
kubectl get svc --namespace tekton-pipelines -l app.kubernetes.io/part-of=tekton-dashboard
The output looks similar to the following:
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
tekton-dashboard ClusterIP 10.245.127.170 <none> 9097/TCP 23s
Notice that the Kubernetes service is named tekton-dashboard
and listening on port 9097
.
Now, port-forward the tekton-dashboard
service:
kubectl port-forward svc/tekton-dashboard -n tekton-pipelines 9097:9097
Finally, open a web browser and navigate to localhost:9097
. You should see the welcome page:
You can explore each section from the left menu, and see what options are available. Next, you will install the Argo CD 1-Click app from DigitalOcean marketplace.
Argo CD is available as a 1-Click Kubernetes application from the DigitalOcean Marketplace. To install Argo CD, navigate to the Marketplace tab of your cluster and search for the app. Then, click on the Install App button, and follow the instructions:
After the installation finishes, you should see the new application listed in the Marketplace tab of your Kubernetes cluster. The output looks similar to:
Finally, check if the installation was successful by following the Getting started after deploying Argo CD section from the Argo CD 1-click app documentation page.
Next, you will install the Knative 1-Click app from the DigitalOcean Marketplace.
Knative is available to install as a 1-Click Kubernetes application from the DigitalOcean Marketplace. To install Knative, navigate to the Marketplace tab of your cluster and search for the app. Then, click on the Install App button and follow the instructions:
After the installation finishes, you should see the new application listed in the Marketplace tab of your Kubernetes cluster. The output looks similar to:
Finally, check if the installation was successful by following the Getting started after deploying Knative section from the Knative 1-click app documentation page.
Note: The Knative 1-Click app installs both the Knative Serving and Eventing components in your DOKS cluster, via the Knative Operator.
Next, you will configure each component of Knative to work in conjunction with Tekton Pipelines and trigger the CI automation on GitHub events such as push
. You will also publicly expose and enable TLS termination for your Knative services.
In this step, you will learn how to prepare a domain you own to work with Knative Services. Then, you will learn how to configure Knative Serving to use your custom domain and enable automatic TLS termination for all Knative services. It’s generally a best practice to enable TLS termination for all application endpoints exposed publicly.
In this section, you will configure DNS within your DigitalOcean account using a domain that you own. Then, you will create a wildcard record to match a specific subdomain under your root domain and map it to your Knative load balancer. DigitalOcean is not a domain name registrar. You need to buy a domain name first from providers such as Google or GoDaddy.
First, run the following command to register your domain with DigitalOcean, replacing the <>
placeholders:
doctl compute domain create "<YOUR_DOMAIN_NAME_HERE>"
The output looks similar to the following:
OutputDomain TTL
starter-kit.online 0
In this example, we use the domain starter-kit.online
.
Note: Ensure that your domain registrar is configured to point to DigitalOcean name servers. For more information, see here.
Next, you will add a wildcard record of type A
for the Kubernetes namespace doks-ci-cd
. First, you need to identify the load balancer external IP created by Knative:
kubectl get svc -n knative-serving
The output looks similar to the following:
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
activator-service ClusterIP 10.245.219.95 <none> 9090/TCP,8008/TCP,80/TCP,81/TCP 4h30m
autoscaler ClusterIP 10.245.42.109 <none> 9090/TCP,8008/TCP,8080/TCP 4h30m
autoscaler-bucket-00-of-01 ClusterIP 10.245.236.8 <none> 8080/TCP 4h30m
autoscaler-hpa ClusterIP 10.245.230.149 <none> 9090/TCP,8008/TCP 4h30m
controller ClusterIP 10.245.13.134 <none> 9090/TCP,8008/TCP 4h30m
domainmapping-webhook ClusterIP 10.245.113.122 <none> 9090/TCP,8008/TCP,443/TCP 4h30m
kourier LoadBalancer 10.245.23.78 159.65.208.64 80:31060/TCP,443:31014/TCP 4h30m
Then, add the wildcard record, which maps your subdomain to the Knative load balancer. Knative Services are namespace scoped and use the following pattern: *.<k8s_namespace>.<your_root_domain>
. The doks-ci-cd
Kubernetes namespace and the EXTERNAL-IP
column value for the kourier
service are used for this blueprint. You can also change the TTL
value as per your requirement, making sure to replace the <>
placeholders accordingly:
doctl compute domain records create "<YOUR_DOMAIN_NAME_HERE>" \
--record-name "*.doks-ci-cd" \
--record-data "<YOUR_KOURIER_LOAD_BALANCER_EXTERNAL_IP_ADDRESS_HERE>" \
--record-type "A" \
--record-ttl "30"
Note: The DNS record must not contain the root domain value - it will be appended automatically by DigitalOcean. For example, if the root domain name is starter-kit.online
, and the Kourier LoadBalancer
has an external IP
value of 143.198.242.190
, then the above command becomes:
doctl compute domain records create "starter-kit.online" \
--record-name "*.doks-ci-cd" \
--record-data "143.198.242.190" \
--record-type "A" \
--record-ttl "30"
Finally, you can check the records created for the starter-kit.online
domain:
doctl compute domain records list starter-kit.online
The output looks similar to:
OutputID Type Name Data Priority Port TTL Weight
274640149 SOA @ 1800 0 0 1800 0
274640150 NS @ ns1.digitalocean.com 0 0 1800 0
274640151 NS @ ns2.digitalocean.com 0 0 1800 0
274640152 NS @ ns3.digitalocean.com 0 0 1800 0
309782452 A *.doks-ci-cd 143.198.242.190 0 0 3600 0
Knative enables TLS termination automatically for your existing or new services and automatically fetches or renewes TLS certificates from Let’s Encrypt. This feature is provided via Cert-Manager and a special component (or adapter) named net-certmanager. You can also configure Knative to use a custom domain you own and let users access your services via your domain.
The following steps configure Knative Serving with your domain and enable the auto-TLS feature:
ClusterIssuer
resource to issue certificates from Let’s Encrypt.net-cert-manager
controller to act as a bridge (or adapter) between Cert-Manager and Knative Serving to issue certificates automatically.Knative Operator
to:
ClusterIssuer
resource to issue/renew certificates for each service automatically.auto TLS
feature via a special flag called auto-ts.
First, you need to create a ClusterIssuer CRD for Cert-Manager. This blueprint provides a ready-to-use manifest, which you can install using kubectl
:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: kn-letsencrypt-http01-issuer
spec:
acme:
privateKeySecretRef:
name: kn-letsencrypt
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- http01:
ingress:
class: kourier
The manifest has the following keys:
spec.acme.privateKeySecretRef.name
- Specifies the unique name given to the private key of the TLS certificate.spec.acme.server
- Specifies the Let’s Encrypt server endpoint used to issue certificates.spec.acme.solvers
- Specifies the ACME client challenge type and what ingress class to use. The above configuration uses the HTTP-01 challenge and Knative Kourier ingress controller.Apply the Knative ClusterIssuer manifest using kubectl
:
kubectl apply -f https://github.com/digitalocean/container-blueprints/blob/main/DOKS-CI-CD/assets/manifests/knative-serving/resources/kn-cluster-issuer.yaml
Check the ClusterIssuer state:
kubectl get clusterissuer kn-letsencrypt-http01-issuer
The output looks similar to:
OutputNAME READY AGE
kn-letsencrypt-http01-issuer True 22h
The READY
column should show True
. Now, that the ClusterIssuer resource is functional, you need to tell Knative Serving how to use it and issue certificates automatically for your Knative Services. This feature is called auto TLS. To use this feature, you need to install an additional component called net-certmanager.
You can install net-certmanager
using kubectl
:
kubectl apply -f https://github.com/knative/net-certmanager/releases/download/knative-v1.4.0/release.yaml
Alternatively, you can use the Knative Operator. The Knative Operator is already installed in your DOKS cluster via the DigitalOcean Knative 1-Click app, which you deployed previously. The following YAML manifest shows you how to instruct Knative Operator to install the additional net-certmanager
component, as part of the KnativeServing
component configuration:
apiVersion: operator.knative.dev/v1alpha1
kind: KnativeServing
metadata:
name: knative-serving
namespace: knative-serving
spec:
additionalManifests:
- URL: https://github.com/knative/net-certmanager/releases/download/knative-v1.4.0/release.yaml
You don’t have to apply the above manifest by hand, because everything is handled via Kustomize in this repository, including enabling the auto TLS feature for Knative Services.
Kustomize
uses the kustomization manifest to take the original KnativeServing configuration from the DigitalOcean Marketplace GitHub repository and apply a set of patches for each needed feature. This way, you don’t have to modify the original file or keep a modified copy of it somewhere. Kustomize lets you use the original file as a base, and apply a set of patches on the fly.
The patch files are listed below:
net-certmananger
component via Knative Operator.ClusterIssuer
resource created earlier to automatically issue TLS certificates from Let’s Encrypt.auto TLS
feature for Knative Services, via the auto-tls
flag.Follow the steps to apply all required changes for the Knative Serving component via Kustomize:
Edit domain-config to point to your own domain name (replace the starter-kit.online
key with your domain), using a text editor of your choice (preferably with YAML
linting support). For example, you can use Visual Studio Code:
code https://github.com/digitalocean/container-blueprints/blob/main/DOKS-CI-CD/assets/manifests/knative-serving/patches/domain-config.yaml
Apply kustomizations
using kubectl
:
kubectl apply -k DOKS-CI-CD/assets/manifests/knative-serving
Finally, you can test your whole setup by deploying the sample hello-world
Knative Service provided in the DigitalOcean Marketplace repo to test the whole setup:
kubectl apply \
-n doks-ci-cd \
-f https://raw.githubusercontent.com/digitalocean/marketplace-kubernetes/master/stacks/knative/assets/manifests/serving-example.yaml
After a few moments, a new service should show up. List all Knative Services using the Knative CLI (kn
):
kn service list -n doks-ci-cd
The output looks similar to:
NAME URL LATEST AGE CONDITIONS READY
hello https://hello.doks-ci-cd.starter-kit.online hello-world 31m 3 OK / 3 True
The hello-world
service endpoint should be in a healthy state with the READY
column set to True
. Also, the service endpoint should be HTTPS enabled as shown in the URL
column value, and use your custom domain name. You can also open a web browser and navigate to the service endpoint - a Hello World!
message should be displayed.
Note:
spec.acme.server
field to point to Let’s Encrypt staging server by editing the kn-cluster-issuer file and then run kubectl apply -f
. This is because the Let’s Encrypt production server has a quota limit set which can be very easily reached, and you will not be able to issue certificates for the whole day.By default, Knative will configure all services with a public endpoint, if a valid domain is configured. If you do not want to expose a Knative service because of some security implications publicly, or if it’s not ready yet to be consumed by users, you can use the Knative Private Services feature.
To make a Knative service private, you need to add a special label named networking.knative.dev/visibility: cluster-local
to any Knative service manifest. For example:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: hello
labels:
networking.knative.dev/visibility: cluster-local
spec:
template:
metadata:
# Revision name
# Must follow the convention {service-name}-{revision-name}
name: hello-world
spec:
containers:
- image: gcr.io/knative-samples/helloworld-go
ports:
- containerPort: 8080
env:
- name: TARGET
value: "World"
After applying the above manifest in the doks-ci-cd
namespace, Knative will create a private service:
kn service list -n doks-ci-cd
The output looks similar to:
OutputNAME URL LATEST AGE CONDITIONS READY
hello http://hello.doks-ci-cd.svc.cluster.local hello-world 17m 3 OK / 3 True
In the output above, you will notice that the hello-world
service endpoint is using the internal domain of the cluster - svc.cluster.local
. Also, only HTTP is enabled for the service in question.
Next, you will configure Knative Eventing to listen for GitHub events and trigger the sample Tekton CI/CD pipeline used in this tutorial.
Knative has a very powerful eventing system built in. Tekton also has some primitives built in to react on external events, such as the EventListener. Tekton EventListeners know how to filter events as well, via Interceptors. This tutorial shows you another way of processing events and triggering Tekton pipelines by using Knative Eventing.
Before continuing, it’s important to understand some Knative Eventing concepts used in this guide:
GitHubSources
, you can also filter and react on specific events such as push
events. It can also manage webhooks for you automatically via the GitHub API using the PAT you created previously.This guide uses a simple delivery mechanism, where GitHubSource filters and fires the Tekton CI/CD pipeline EventListener on push events. The GitHubSource component is available via the eventing-github Knative project. The official version doesn’t support Kubernetes v1.22 and up at this time of writing (there is a open PR to address this issue). This repository provides a functional github-eventing-v1.4.0 manifest that you can use.
Install github-eventing
in your cluster by apply the github-eventing-v1.4.0
manifest using kubectl
:
kubectl apply -f https://github.com/digitalocean/container-blueprints/blob/main/DOKS-CI-CD/assets/manifests/knative-eventing/github-eventing-v1.4.0.yaml
The command also creates a dedicated knative-sources
namespaces for github-eventing
.
Now, check if all github-eventing
pods are up and running:
kubectl get pods -n knative-sources
The output looks similar to:
OutputNAME READY STATUS RESTARTS AGE
github-controller-manager-0 1/1 Running 0 21h
github-webhook-6cdcfc69ff-2q4sn 1/1 Running 0 21h
The github-controller
and github-webhook
pods should be in a Running
state. The github-controller
pod is responsible with reconciling your GitHubSource
CRDs. The github-webhook
pod manages webhooks for your GitHub repository, as defined by the GitHubSource CRD.
Each time you create a GitHubSource resource, a corresponding Knative Service is also created. The Knative Service exposes a public endpoint and gets registered as a webhook in your GitHub repository by the github-eventing
component. Then, each time a GitHub event is fired, the Knative Service created by your GitHubSource resource is triggered and notifies the Tekton EventListener. This approach has other benefits, such as letting Knative Serving to take care of creating endpoints for your webhooks and automatically provide TLS support.
The following diagram illustrates the setup used in this guide and all involved components.
You can also replace the simple delivery mechanism with a complex delivery that uses channels or brokers. Then, you can have multiple subscribers responding to all kinds of events. For example, you can have a dedicated setup where, based on the type of event that gets fired, a different Tekton Pipeline is triggered. For example:
main
(or development
) branch, another subscriber gets notified and triggers a dedicated CI/CD pipeline.A typical GitHubSource CRD definition looks like the following:
apiVersion: sources.knative.dev/v1alpha1
kind: GitHubSource
metadata:
name: sample-app-github-source
spec:
eventTypes:
- push
ownerAndRepository: github-repo-owner/sample-app-repo
accessToken:
secretKeyRef:
name: github-pat
key: accessToken
secretToken:
secretKeyRef:
name: github-pat
key: secretToken
sink:
uri: http://el-tekton-event-listener.doks-ci-cd.svc.cluster.local:8080
The manifest has the following keys:
spec.eventTypes
: Specifies what type of events you’re interested in, for example push
.spec.ownerAndRepository
: Specifies the GitHub repository (and owner) for the application source code.spec.accessToken
(spec.secretToken
): Specifies the GitHub personal access token name and value.spec.sink
: Specifies a destination for events, such as a Kubernetes service URI, or a Knative Service.Next, you will configure and test the Tekton CI/CD pipeline for the sample application (2048 game). You will also learn how to automatically trigger the pipeline on GitHub events when pushing commits, using Knative GitHubSource and Tekton EventListeners.
In this part of the tutorial, you will set up a Tekton CI/CD Pipeline that builds a Docker image for your custom application using Kaniko and publishes it to a remote Docker registry. Then, the Tekton pipeline will trigger Argo CD to create and deploy the application to your Kubernetes cluster.
At a high-level overview, you use the following steps:
Next, to set up the CI/CD Pipeline workflow:
Finally, to configure the CI/CD pipeline to trigger Git events:
GitHubSource
resource that triggers your Tekton pipeline by registering the required webhook with your GitHub application repository.EventListener
that triggers and processes incoming events from the GitHubSource
.TriggerTemplate
that instantiates a Pipeline
resource (and associated Tasks
) each time the EventListener
is triggered.TriggerBinding
resource to populate the TriggerTemplate
input parameters with data extracted from the GitHub event.The following diagram below illustrates the CI/CD process implemented using Tekton and Argo:
This blueprint provides all the necessary manifests to create resources, such as Tekton CRDs and Knative CRDs, in your Kubernetes cluster via Kustomize. You will find everything inside the tekton folder, including the kustomization manifest. You can look at each and see how it’s being used.
The following shows how the tekton
kustomization folder is structured:
OutputDOKS-CI-CD/assets/manifests/tekton/
├── configs
│ ├── argocd
│ │ ├── auth.env
│ │ └── server.env
│ ├── docker
│ │ ├── config.json
│ │ └── registry.yaml
│ └── github
│ ├── githubsource.yaml
│ └── pat.env
├── eventing
│ ├── tekton-ci-cd-channel-subscribers.yaml
│ ├── tekton-ci-cd-channel.yaml
│ └── tekton-ci-cd-github-source.yaml
├── pipelines
│ └── tekton-argocd-build-deploy.yaml
├── tasks
│ └── argocd-task-create-app.yaml
├── triggers
│ ├── rbac.yaml
│ ├── tekton-argocd-build-deploy-event-listener.yaml
│ ├── tekton-argocd-build-deploy-trigger-binding.yaml
│ └── tekton-argocd-build-deploy-trigger-template.yaml
└── kustomization.yaml
The DOKS-CI-CD/assets/manifests/tekton/
folder structure is explained below:
configs
: Contains configuration files for the secret and configmap generators used in the kustomization file. This folder is further broken into:
argocd
: Contains ArgoCD configurations and secrets.docker
- contains the registry configuration file used to push images to the DigitalOcean Docker registry.github
: Contains your PAT (Personal Access Token) credentials.eventing
: Contains all manifest files required to configure Knative Eventing to trigger the Tekton CI/CD pipeline. The following manifests are present here:
tekton-ci-cd-github-source.yaml
: Configures the GitHubSource
CRD used in this tutorial (in-depth explanations can be found inside).tekton-ci-cd-channel-subscribers.yaml
: This is optional and not being used by the kustomization from this tutorial. Provided as an example for how to use Knative Eventing subscriptions feature.tekton-ci-cd-channel.yaml
- This is optional and not being used by the kustomization from this tutorial. Provided as an example for how to use Knative Eventing channels feature.pipelines
: Contains configuration files for the Tekton CI/CD Pipeline used in this tutorial. Following manifests are present here:
tekton-argocd-build-deploy.yaml
: Contains the definition for the CI/CD pipeline (in-depth explanations can be found inside).tasks
: Contains configuration files for custom Tekton Tasks used in this tutorial. Following manifests are present here:
argocd-task-create-app.yaml
: Defines the Argo CD task for creating new applications.triggers
: Contains configuration files for the Tekton Triggers used in this tutorial. The following manifests are present here:
rbac.yaml
- defines the service account and required role bindings used by the Tekton EventListener from this tutorial. This is required by the EventListener to instantiate resources, such as the Tekton CI/CD pipeline.tekton-argocd-build-deploy-event-listener.yaml
- contains the definition for the Tekton EventListener used in this tutorial (in-depth explanations can be found inside).tekton-argocd-build-deploy-trigger-binding.yaml
: Contains the definition for the Tekton TriggerBinding used this tutorial (in-depth explanations can be found inside).tekton-argocd-build-deploy-trigger-template.yaml
: Contains the definition for the Tekton TriggerTemplate used in this tutorial (in-depth explanations can be found inside).kustomization.yaml
: This is the main kustomization file (in-depth explanations can be found inside).Note: The configs
folder used by Kustomize contains sensitive data. Use a .gitignore
file to exclude committing those files in your Git repository.
Steps to follow to create all required resources in your Kubernetes cluster, via Kustomize:
DOKS-CI-CD/assets/manifests/tekton/configs
subfolder, making sure to replace the <>
placeholders accordingly. For example, you can use VS Code:code DOKS-CI-CD/assets/manifests/tekton/configs/argocd/auth.env
code DOKS-CI-CD/assets/manifests/tekton/configs/docker/config.json
code DOKS-CI-CD/assets/manifests/tekton/configs/github/pat.env
Tips: To obtain the Argo CD admin password, use the following command:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
read/write
credentials, you can use the following command and write results directly in the config.json
file:doctl registry docker-config --read-write <YOUR_DOCKER_REGISTRY_NAME_HERE> > DOKS-CI-CD/assets/manifests/tekton/configs/docker/config.json
configs/GitHub/GitHub source.yaml
file and replace the <>
placeholders accordingly, then save the changes. For example, you can use VS Code:code DOKS-CI-CD/assets/manifests/tekton/configs/github/githubsource.yaml
configs/docker/registry.yaml
file and replace the <>
placeholders accordingly, then save changes. For example, you can use VS Code:code DOKS-CI-CD/assets/manifests/tekton/configs/docker/registry.yaml
-k
flag):kubectl apply -k DOKS-CI-CD/assets/manifests/tekton
After Kustomize
finishes, you should have all required resources created in your cluster in the doks-ci-cd
namespace.
First, check the eventing resources state (the GitHubSource):
kubectl get githubsources -n doks-ci-cd
The output looks similar to (READY
column should display True
, and SINK
should point to the EventListener
service URI
):
OutputNAME READY REASON SINK AGE
tekton-ci-cd-github-source True http://el-tekton-argocd-build-deploy-event-listener.doks-ci-cd.svc.cluster.local:8080 36s
The above output shows you that the EventListener of your Tekton CI/CD pipeline is connected (via the SINK column value) to the GitHubSource CRD to receive GitHub events.
Next, check associated Knative Services:
kn services list -n doks-ci-cd
The output looks similar to:
OutputNAME URL LATEST READY
hello https://hello.doks-ci-cd.starter-kit.online hello-world True
tekton-ci-cd-github-source-7cgcw https://tekton-ci-cd-github-source-7cgcw.doks-ci-cd.starter-kit.online tekton-ci-cd-github-source-7cgcw-00001 True
You should see a tekton-ci-cd-github-source-xxxx
service running, and in the READY
state. This service is responsible for receiving events from GitHub. The tekton-ci-cd-github-source-xxxx
service URL should be also registered as a webhook in your forked repo. Navigate to the Settings of your forked GitHub repository and check the Webhooks section. A new webhook should be listed with a green check mark:
It points to the same URL as displayed in the Knative services listing. On the other hand, you can also inspect the events being sent by GitHub (including response status).
Finally, check important Tekton resources status, such as pipelines, triggers, and event listeners:
tkn pipeline list -n doks-ci-cd
tkn pipelinerun list -n doks-ci-cd
tkn triggertemplate list -n doks-ci-cd
tkn eventlistener list -n doks-ci-cd
Tip: For troubleshooting, you can inspect each resource events and logs, via the corresponding subcommand as shown below:
describe
subcommand:tkn pipeline describe tekton-argocd-build-deploy-pipeline -n doks-ci-cd
tkn pipelinerun describe <tekton-argocd-build-deploy-pipeline-run-zt6pt-r-r7wgw> -n doks-ci-cd
logs
subcommand:tkn pipeline logs tekton-argocd-build-deploy-pipeline -n doks-ci-cd
tkn pipelinerun logs tekton-argocd-build-deploy-pipeline-run-zt6pt-r-r7wgw -n doks-ci-cd
Next, you will test the CI/CD pipeline flow by pushing some changes to the tekton-sample-app
repository prepared in the Forking the Sample Application Repo step. Then, you will access the Tekton dashboard and watch a live demonstration of how the pipeline triggers automatically and execution of steps.
You will begin testing the CI/CD flow by changing the knative-service
resource from the application repo to point to your container registry.
First, clone the git repository prepared in the Fork the Sample Application Repo step (make sure to replace the <>
placeholders accordingly):
git clone git@github.com:<YOUR_GITHUB_USER_NAME_HERE>/kubernetes-sample-apps.git
Then, change the directory to your local clone:
cd kubernetes-sample-apps
Next, edit the game-2048-example/knative-service.yaml manifest file to point to your Docker registry. For example you can use VS Code (make sure to replace the <>
placeholders accordingly):
code game-2048-example/knative-service.yaml
Save and commit knative-service.yaml
file changes to your GitHub repository. Next, port-forward the tekton dashboard
service:
kubectl port-forward svc/tekton-dashboard -n tekton-pipelines 9097:9097
Now, launch your Web browser and access localhost:9097. Then, navigate to PipelineRuns - you should see your Tekton CI/CD pipeline running:
If you click on it, you should see each Task execution status and logs:
Note: Initially, you may get a failed pipeline run as well. When the webhook is created for the first time, GitHub sends a specific payload to test your GitHubSource endpoint to check if it’s alive. The payload content is invalid for the Tekton pipeline and causes the pipeline to fail.
You can access your application endpoint and play the game. First, list all Knative routes from the doks-ci-cd
namespace:
kn route list -n doks-ci-cd
The output looks similar to:
OutputNAME URL READY
game-2048 https://game-2048.doks-ci-cd.starter-kit.online True
hello https://hello.doks-ci-cd.starter-kit.online True
tekton-ci-cd-github-source-7cgcw https://tekton-ci-cd-github-source-7cgcw.doks-ci-cd.starter-kit.online True
A new entry should be present named game-2048
, and in a READY
state with HTTPS enabled in the URI field. Open a Web browser and paste the link shown in the URL
column. The 2048 game should start successfully:
If everything looks like the above, then you created and tested your first Tekton CI/CD pipeline successfully.
In this guide, you learned how to combine software components (such as Knative, Tekton and Argo) to create a simple CI/CD pipeline running entirely on Kubernetes. You also learned how to configure and use Knative Serving and Eventing to do useful work for you and ease application development on Kubernetes. Then, by using Knative Eventing and Tekton EventListeners, you enabled automatic CI/CD flow triggering each time a change is pushed to the application GitHub repository. Finally, Argo CD closes the loop and deploys your custom application on Kubernetes as a Knative service.
Argo CD is a GitOps tool that can keep both application and Kubernetes-specific configuration in sync with dedicated GitHub repositories. You can use a dedicated repository for automatically configuring your DOKS cluster with all the steps used in this guide. From a practical point of view, you can fork the container-blueprints repository and tell Argo CD to sync all Kubernetes configuration manifests with your cluster. This way, you don’t need to redo all steps by hand again and let Argo handle it automatically, as well as future upgrades for all software components used in this guide.
You can also let Argo CD manage Helm releases as well majority of DigitalOcean Marketplace 1-Click apps use Helm to deploy software components.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
hi, im getting this error when running your knative event sourcing
error: error parsing https://github.com/digitalocean/container-blueprints/blob/main/DOKS-CI-CD/assets/manifests/knative-eventing/github-eventing-v1.4.0.yaml: error converting YAML to JSON: yaml: line 229: mapping values are not allowed in this context