<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>serverless on Digi Hunch</title><link>https://static.digihunch.com/tag/serverless/</link><description>Recent content in serverless on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 23 Apr 2025 13:37:45 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/serverless/index.xml" rel="self" type="application/rss+xml"/><item><title>AWS serverless services and developer tools</title><link>https://static.digihunch.com/2022/11/aws-serverless-services-and-developer-tools/</link><pubDate>Wed, 09 Nov 2022 12:19:00 -0400</pubDate><guid>https://static.digihunch.com/2022/11/aws-serverless-services-and-developer-tools/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-server-less-devtools.webp" alt="Featured image of post AWS serverless services and developer tools" /&gt;&lt;p class="wp-block-paragraph"&gt;As &lt;a href="https://static.digihunch.com/2022/10/computing-from-paas-to-serverless/"&gt;discussed&lt;/a&gt;, serverless simply means cloud services that delegate autoscaling management to cloud platform. In my mind, the word &amp;#8220;serverless&amp;#8221; translates into &amp;#8220;managed autoscaling&amp;#8221;. As long as a service&amp;#8217;s capacity is managed automatically, we can consider it as serverless. Given that capacity scaling accounts for a good amount of work in IT operation, moving to serverless significantly reduces operation overhead. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Unlike containers, the serverless ecosystem lacks standard. Since &lt;a href="https://serverlessland.com/"&gt;AWS&lt;/a&gt; is leading the charge in this field, let&amp;#8217;s take a look at its offerings.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Lambda Function&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda functions have triggers. We can configure a trigger from an AWS service, or even a non-AWS service which supports AWS event bridge, to invoke Lambda function. Based on the trigger (e.g. SQS, S3, DynamoDB), you then specify event source mapping. For example, if trigger is SQS, you need to specify the queue name, batch size and batch window in event source mapping. If trigger is S3, the event source mapping needs to specify bucket, S3 action, etc. Event source mappings vary significantly among trigger types.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Depending on the trigger, a Lambda function may be invoked in one of the two ways:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-cyan-bluish-gray-background-color has-background"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-sync.html" target="_blank" rel="noreferrer noopener"&gt;Synchronous&lt;/a&gt; invocation&lt;/th&gt;&lt;th&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#async-overview" target="_blank" rel="noreferrer noopener"&gt;Asynchronous&lt;/a&gt; invocation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Summary&lt;/td&gt;&lt;td&gt;Requestor fires request and waits until it receives response before closing connection.&lt;/td&gt;&lt;td&gt;Lambda places triggering event in a queue and immediately returns a success code (202). Then a separate process reads events off the queue and sends them to your Lambda function. When the function returns a success response or exits without throwing an error, Lambda sends a record of the invocation to an EventBridge event bus.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pros&lt;/td&gt;&lt;td&gt;Requestor get invocation result as soon as function run is complete&lt;/td&gt;&lt;td&gt;The queue decouples the request and invocation.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cons&lt;/td&gt;&lt;td&gt;When load is high the function requires higher capacity for concurrency&lt;/td&gt;&lt;td&gt;Involves more parties at play and can be quite complex to troubleshoot.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/operatorguide/invocation-modes.html" target="_blank" rel="noreferrer noopener"&gt;Here&lt;/a&gt; is a chart with the triggers that support each invocation mode. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Real-life applications often need to include libraries and dependencies that requires language-specific steps. For example, NodeJS applications need &lt;a href="https://aws.amazon.com/blogs/compute/optimizing-node-js-dependencies-in-aws-lambda/"&gt;bundling&lt;/a&gt; (often using Webpack or esbuild). We can use &lt;a href="https://aws.amazon.com/blogs/compute/using-lambda-layers-to-simplify-your-development-process/"&gt;Lambda layers&lt;/a&gt; to simplify the management. The additional libraries often need to be packaged in S3 bucket or as container image.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda functions are subject to &lt;a href="https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/"&gt;cold start&lt;/a&gt; to &lt;a href="https://betterprogramming.pub/lets-stop-talking-about-serverless-cold-starts-38e4c1fda963"&gt;cope with&lt;/a&gt;. When a lot of invocations occur about the same time, the order of executions might be different than the order of upstream events that invokes the function. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-api-gateway"&gt;API Gateway&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS API Gateway is an &lt;a href="https://microservices.io/patterns/apigateway.html"&gt;API gateway&lt;/a&gt; implementation for REST and WebSocket APIs. It couples with &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html"&gt;Lambda&lt;/a&gt; in the classic &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/serverless-multi-tier-architectures-api-gateway-lambda/welcome.html"&gt;multi-tier serverless&lt;/a&gt; architecture pattern. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this classic pattern Lambda function often need to work with a database (e.g. DynamoDB etc), to perform &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD operations&lt;/a&gt; and other custom business logics. The CRUD operations are so commonplace that it makes sense to use mapping template to configure CRUD operation instead of writing similar set of functions for each new data model. API Gateway supports such a &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/models-mappings.html"&gt;mapping template&lt;/a&gt; called &lt;a href="https://velocity.apache.org/engine/devel/vtl-reference.html"&gt;Velocity Template Language&lt;/a&gt; (VTL), a technology from Apache &lt;a href="https://velocity.apache.org/"&gt;Velocity&lt;/a&gt; Project.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;API Gateway integrate with many other AWS services. Here are the available integration types:&lt;/p&gt;&#10;&lt;table id="tablepress-20" class="tablepress tablepress-id-20 tbody-has-connected-cells"&gt;&#10;&lt;thead&gt;&#10;&lt;tr class="row-1"&gt;&#10;&#9;&lt;th class="column-1"&gt;Integration Type&lt;/th&gt;&lt;th class="column-2"&gt;Description&lt;/th&gt;&lt;th class="column-3"&gt;Integration Mode&lt;/th&gt;&lt;th class="column-4"&gt;How it works&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody class="row-striping row-hover"&gt;&#10;&lt;tr class="row-2"&gt;&#10;&#9;&lt;td rowspan="2" class="column-1"&gt;AWS integration&lt;/td&gt;&lt;td rowspan="2" class="column-2"&gt;connects gateway to an AWS service action as the end point.&lt;/td&gt;&lt;td class="column-3"&gt;AWS_PROXY&lt;/td&gt;&lt;td class="column-4"&gt;this mode only supports only one action with one service: the function invoking action for Lambda service. Therefore it is available only for Lambda integration and no other AWS services. For that reason, it is also known as Lambda proxy integration. This mode is recommended for Lambda integration and is the default mode for LambdaIntegrationOption CDK construct. It connects a method (PUT, GET, etc) to a Lambda function and pass along the request on the way in, and the response on the way out. You do not set integration request or integration response. Even if you do, there’s no effect. This “pass-along” mode is easier to understand and configure. &lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-3"&gt;&#10;&#9;&lt;td class="column-3"&gt;AWS&lt;/td&gt;&lt;td class="column-4"&gt;this mode connects an API method to a broad range of supported AWS service action. Function invoking for Lambda service is a common example but not the only service action supported in this mode. When used in Lambda integration, it is also referred to as “Lambda custom integration”, or “normal (request/response mapping) integration”. This mode is good for advanced use cases (e.g. header modification) but involves more management effort. You have to control the mapping between method request and integration request, and between integration response and method response. &lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-4"&gt;&#10;&#9;&lt;td rowspan="2" class="column-1"&gt;HTTP integration&lt;/td&gt;&lt;td rowspan="2" class="column-2"&gt;for generic HTTP service endpoint&lt;/td&gt;&lt;td class="column-3"&gt;HTTP_PROXY&lt;/td&gt;&lt;td class="column-4"&gt;the pass-along mode for upstream HTTP endpoint&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-5"&gt;&#10;&#9;&lt;td class="column-3"&gt;HTTP&lt;/td&gt;&lt;td class="column-4"&gt;the request/response mapping mode for upstream HTTP endpoint&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-6"&gt;&#10;&#9;&lt;td class="column-1"&gt;MOCK integration &lt;/td&gt;&lt;td class="column-2"&gt;the API gateway itself serves as the endpoint.&lt;/td&gt;&lt;td class="column-3"&gt;MOCK&lt;/td&gt;&lt;td class="column-4"&gt;the API gateway itself acts endpoint without an upstream. One example use case is to return CORS-related headers upon a pre-flight OPTIONS query.&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;!-- #tablepress-20 from cache --&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The table above is a summary of API Gateway integration types as covered &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-integration-types.html"&gt;here&lt;/a&gt;. In the AWS context, proxy mode suggests that the request is not being morphed (transformed). In non-proxy mode, request or response may be modified on their ways in or out.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For API gateway to invoke lambda function, synchronous invocation is used by default. You can also configure API gateway to invoke Lambda function &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-integration-async.html" target="_blank" rel="noreferrer noopener"&gt;asynchronously&lt;/a&gt; by using headers.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As with other API gateway implementations, AWS API Gateway can also connects to an authorizer (either another Lambda function or Cognito service) in order to authorize the incoming request.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;AppSync&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a previous post, I discussed &lt;a href="https://static.digihunch.com/2022/10/graphql-and-grpc/"&gt;GraphQL&lt;/a&gt; as a modern and efficient alternative to REST API. &lt;a href="https://aws.amazon.com/appsync/"&gt;AppSync&lt;/a&gt; to GraphQL is the same as API Gateway to REST API. One of the advantages that GraphQL has over REST API is more information in the response. Oftentimes, we use a proxy that supports GraphQL in front of REST API service. AppSync can act as such proxy. I think of it as a managed &lt;a href="https://www.apollographql.com/docs/intro/platform"&gt;Apollo&lt;/a&gt; since they play the the role in the architecture. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another benefit of GraphQL is the support of subscription, obviating WebSocket configuration. AppSync supports pub/sub API for real-time experience. Client application can get near real-time update as the data on the server is changed.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can configure AppSync to connect to different data sources to formulate GraphQL response. The data source can be an HTTP endpoint, a Lambda function, a database (Relational or DynamoDB), or OpenSearch. &lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="408" src="https://static.digihunch.com/wp-content/uploads/2022/12/appsync-1024x408.png" alt="" class="wp-image-7653" srcset="https://static.digihunch.com/wp-content/uploads/2022/12/appsync-1024x408.png 1024w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-300x119.png 300w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-768x306.png 768w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-1536x612.png 1536w, https://static.digihunch.com/wp-content/uploads/2022/12/appsync-2048x816.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;figcaption class="wp-element-caption"&gt;App Sync&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Between data source and the request, AppSync uses resolver to convert GraphQL payload to the underlying protocols and executes if the caller is authorized to invoke it. Resolvers are comprised of request and response mapping templates, which contain transformation and execution logic. AppSync also uses VTL as the mapping template for resolvers.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Messaging Services&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Messaging services have three patterns: queues, pub/sub, and event buses. In AWS, the corresponding services are SQS, SNS and EventBridge. Here is a good &lt;a href="https://aws.amazon.com/blogs/compute/choosing-between-messaging-services-for-serverless-applications/"&gt;post&lt;/a&gt; about how to choose among them.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Queues are temporary storage to decouple the source and destination systems. The expectation is that the actions in response to the message can be delayed. If that is not the case and the response needs to be immediate, that is by definition an event-driven pattern. A common solution is to have the AWS service invoke Lambda function. If that is not supported, we can use SNS as an intermediary. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SNS is for simple event-driven pattern. In a more complicated event-driven architecture, we often need an event bus to route events in certain ways. We also need to support various &lt;a href="https://aws.amazon.com/eventbridge/integrations/"&gt;event sources&lt;/a&gt; by different software providers. Moreover, we want the capability to register our own event schema. These are the scenarios where EventBridge can help.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Developer tools&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In application development with serverless stack, the line between application and infrastructure is somewhat blurred. Developers often find themselves making repeated configuration on cloud resources while writing application code. For example, to test Python code (application), developer has to upload the code to S3, create Lambda function referencing the code, etc. This would require too much work with AWS CLI, or CloudFormation. The AWS &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html"&gt;SAM&lt;/a&gt; (AWS Serverless Application Model) is a better utility for serverless development workflow.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SAM comes with its own CLI and developers can feed it with template that interacts with a number of serverless &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-resources-and-properties.html"&gt;resources&lt;/a&gt; (e.g. API, SimpleTable, Function, etc). I view SAM as one layer of abstraction on top of CloudFormation that handles some resources in serverless stack. It saves developers from re-writing resources in CloudFormation templates and keeping them consistent, which would have been tedious. Once you deployed your application using SAM, it will appear as a Lambda Application in the console.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SAM templates are also declarative. It is simple but limited in feature. AWS CDK is also a powerful utility that works with general purpose programming language for IaC and interacts with all AWS resources. It is very powerful for building serverless applications. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;AWS Amplify&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We have CDK, SAM and CloudFormation but we still have to ensure integration between those resources and our applications. For example, when creating a S3 buckets, they have to get the endpoint and reference it in the application code. So is Cognito. As a result, developers still have to spend time on resource integration. They still can&amp;#8217;t focus on business logic. We need a tool that can make opinionated configuration of cloud resources and automatically reference them from the application code. This is the purpose of AWS Amplify.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amplify not only help application developers create backend resources with opinionated configurations. It also provides libraries for the application to use and connect to those resources seamlessly. Developers will need to include Amplify libraries in the application code. To create cloud resources, they can use Amplify &lt;a href="https://docs.amplify.aws/cli/"&gt;CLI&lt;/a&gt; or &lt;a href="https://docs.amplify.aws/console/uibuilder/figmatocode/#step-1-set-up-figma-file"&gt;Studio&lt;/a&gt; (a web portal from AWS console). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amplify natively supports a number of serverless resources such as API (using API gateway or AppSync), Storage (S3 and CloudFront), Lambda function, Cognito, etc. Developer may use Amplify CLI command to create such supported resources. Amplify will prompt some guiding questions in order to configure them correctly. In addition to the natively supported resources, developers can also create custom resources. They have to declare those custom resources with CloudFormation or CDK. I came across &lt;a href="https://github.com/aws-samples/amazon-location-samples/tree/main/maplibre-js-react-iot-asset-tracking"&gt;this&lt;/a&gt; project as a good illustration of how Amplify works. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Amplify Studio can save developers from using Amplify CLI commands. It also can integrate with &lt;a href="https://en.wikipedia.org/wiki/Figma_(software)"&gt;Figma&lt;/a&gt;, providing developers with a framework for &lt;a href="https://aws.amazon.com/blogs/mobile/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/"&gt;frontend development.&lt;/a&gt; However, in my experience, it is still &lt;a href="https://github.com/aws-amplify/amplify-ui/issues"&gt;glitchy&lt;/a&gt;. For now I stick to Amplify CLI.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amplify also supports &lt;a href="https://docs.aws.amazon.com/amplify/latest/userguide/getting-started.html"&gt;hosting&lt;/a&gt; capability, providing users with opinionated and customizable CI/CD pipeline configuration.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;How about &amp;#8220;clientless&amp;#8221;&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda function can also run client-side logics. System administrators have to create lots of client-side scripting. While Lambda functions can encapsulate those logics, we&amp;#8217;d still need a script orchestrator to invoke those functions. AWS &lt;a href="https://aws.amazon.com/step-functions/"&gt;Step Function&lt;/a&gt; comes to rescue. It was even regarded as the &lt;a href="https://itnext.io/why-step-functions-is-the-best-aws-service-you-are-not-using-4f3c133d7d0d"&gt;most under-utilized service&lt;/a&gt;. As the author states, a state machine (as design pattern) is simply a flow of actions with decision making logics.&amp;nbsp;AWS Step function helps you groom the logic flow of existing actions with &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html" target="_blank" rel="noreferrer noopener"&gt;Amazon States Language&lt;/a&gt;. There are standard and express workflows. Each step is a state. A state can be of several different types, such as Choice, Task, Succeed, Fail, End, Map, Wait, Parallel. The task can be a Lambda function, and even AWS API calls. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS Step function integrate with Lambda functions. It is typically used for patterns with long process and the need to orchestrate the execution of several Lambda functions. For specific use cases, look at these &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/create-sample-projects.html" target="_blank" rel="noreferrer noopener"&gt;sample projects&lt;/a&gt;. For example, a network professional needs to run a lot of connectivity testing, reusing the same Python script but run it from different subnets. We need to create a Lambda function for commands like &amp;#8220;nc -vz&amp;#8221; then &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc-endpoints.html"&gt;invoke the lambda function from VPC&lt;/a&gt;, multiple times from different VPCs. We should use step function to drive this. It works like a Makefile on Linux, without requiring your own computer to run.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS Step function also integrates with &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/connect-supported-services.html" target="_blank" rel="noreferrer noopener"&gt;other AWS services&lt;/a&gt;, such as SNS, SQS, Dynamo, Batch, Glue, EMR, EKS, API gateway, event bridge.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Whenever we need to create a script, involving custom actions, or AWS API calls, we should consider using AWS step function to organize the actions. The benefits are: it saves you a laptop or bastion host (&amp;#8220;client-less&amp;#8221;), many ways to invoke them (not just cron&amp;#8221;). &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this post, we started with some serverless services in AWS. For server-side application, we can use API Gateway to invoke Lambda function. For client-side, we can use step function to invoke Lambda function. We then discussed some tools to speed up application development in serverless pattern. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS categorizes both Amplify and AppSync under Front-end Mobile. Amplify does not represent any computing resources in AWS cloud. It is a library and CLI tools to enhance developer experience. AppSync on the other hand is a cloud computing resource acting as GraphQL API for mobile or web application. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/10/computing-from-paas-to-serverless/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Computing services: from PaaS to Serverless&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/11/key-mapping-on-external-pc-keyboard-on-macbook/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Key mapping for external PC keyboard on Mac&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Computing services: from PaaS to Serverless</title><link>https://static.digihunch.com/2022/10/computing-from-paas-to-serverless/</link><pubDate>Fri, 21 Oct 2022 19:31:00 -0400</pubDate><guid>https://static.digihunch.com/2022/10/computing-from-paas-to-serverless/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-computing-paas-serverless.webp" alt="Featured image of post Computing services: from PaaS to Serverless" /&gt;&lt;p class="wp-block-paragraph"&gt;Silicon Valley startups in mid-2000s likely do not run their own IT operations (i.e. renting their own data centre spaces, purchasing their own rack-mounted servers). Since the &lt;a href="https://web.archive.org/web/20070101134207/http://www.amazon.com/aws/"&gt;launch of EC2&lt;/a&gt;, AWS has been renting extra computing capacity to those startups, in the IaaS model. The leased infrastructure requires maintenance work, and AWS realized that many of these customers cannot afford specialized database admins, network admins, storage admins, or even server admins. As a result, they created a handful of managed services aiming to cut out admin overhead and let their customer focus on coding. This is how Platform-as-a-service (PaaS) came about. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s take a look at what are exactly operation activities.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-ops-activities"&gt;Ops activities&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;IT operation team manages server provisioning, installation of operating system, tuning performance, configuring auto scaling and load balancing, configure networking and storage systems, etc. Networking can be so complex that many infrastructure teams have a dedicated &lt;a href="https://en.wikipedia.org/wiki/Network_operations_center"&gt;Network Operation Center&lt;/a&gt; (NOC), who along with security team, manages key aspects of networking, such as segmentation, router configuration, load balancing, firewall configuration.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For client-server application, the client-side code will make outgoing connections, utilizing the TCP/IP stack on the host through an ephemeral port. The server-side code has to be wrapped as a service. A daemon ensures the process running this service stays up and listens to a TCP port in order to respond to request by invoking the functions. Application team usually assumes these activities.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If database is involved, then the patching, upgrade, replication, data protection are all Ops problems. If storage is involved, then Ops has to manage mass data accumulated over years, the integration between storage and database and applications, performance, replication, etc. Some larger organizations have full-time database administrator and storage administrators.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Then comes container. Containers have their benefits but it increases the operation overhead by an order of magnitude. Running container application at scale warrants its own platform, most likely a Kubernetes platform, to address all of the problems above again at the cluster level. Some organization created platform team to manage container and VM platforms.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is the Ops, that turns functional code into a running business. It is also the Ops, that becomes a pain point as a startup scales. With IaaS and PaaS models, AWS managed to convince many small businesses to delegate their IT operations to AWS. This is the humble start of cloud computing.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-elastic-beanstalk"&gt;Elastic Beanstalk&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;At first, I wasn&amp;#8217;t too impressed with Elastic Beanstalk, since it abstracts away too many details. However, I later realized that it has been surprisingly popular in the developer community, especially with individual developers and SMBs. It simplifies deployment to the point that their users don&amp;#8217;t need to know other AWS services, allowing them to focus on coding application logic.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You configure Applications and Environments (one application may have multiple environments). In the Environment layer, you can specify code platform (e.g. Python 3.8 on 64bit Amazon Linux 2, Java, Go, PHP, Ruby) and even container platform (Docker on EC2 or ECS). Behind the scene, Elastic Beanstalk configures EC2 instances, Elastic Load Balancers, etc on the selected VPC and integrate with logging and monitoring services. In the console, Elastic Beanstalk exposes a list of configurations options (e.g. AMI, instance type). This centralized configuration page is dummied down for those who don&amp;#8217;t want to deal with Ops. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The downside of Elastic Beanstalk is it takes away a lot of flexibility. Many developers find Elastic Beanstalk limit their choices of deployment, as their applications scale. Elastic Beanstalk does not suit for applications that demand extensive operation efforts. Its niche market is individual developers and SMB. Few enterprise applications run on Elastic Beanstalk.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-containerization-with-ecs-and-eks"&gt;Containerization with ECS and EKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When we containerize an application, we build container images. Then we run these images with container runtimes, is a core feature of container platform. Container platform also provides orchestration engine since we frequently take containers up and down. In addition, container platform provides mechanisms for container networking and storage.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS has a couple options for container platform. ECS (Elastic Container Service) came out earlier. It organizes a group of EC2 instances as a cluster. You can manage autoscaling, &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/networking-networkmode.html"&gt;networking&lt;/a&gt;, and &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/storage.html"&gt;persistent storage&lt;/a&gt; (EFS, FSx etc) on ECS. EKS (Elastic Kubernetes Service) is the managed Kubernetes service by AWS. Just like AKS, it provides a managed control plane along with computing nodes.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I see ECS as a proprietary and simplified container platform, and Kubernetes as an open-source standard for full-fledged container platform with an entire ecosystem. EKS includes an upstream-certified Kubernetes distribution with a set of tools specific to AWS. Since Kubernetes is the de-facto standard container platform, I prefer EKS by default, unless I can justify the use of ECS. In fact, ECS and Kubernetes have many concepts in common. For example, a &amp;#8220;Task&amp;#8221; in ECS is equivalent to a Pod in Kubernetes. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Whether it is ECS or EKS, right-sizing the computing node group is always challenging especially when the application traffic load is irregular. AWS Fargate is a technology that provides on-demand, right-sized compute capacities. It works with ECS and EKS. When integrated with EKS, we delegate the node management (e.g. scaling) to Fargate and forget about sizing the node pool.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Using ECS and Fargate involves quite a bit of configurations. To simplify that, we can use App Runner, which builds ECS cluster and uses Fargate to execute the container behind the scenes. App Runner helps client in a way similar to Elastic Beanstalk, but concentrate on Container workload.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-serverless-with-lambda-and-api-gateway"&gt;Serverless with Lambda and API Gateway&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The services above have their limitations when it comes to scaling capability. First, they cannot scale to zero. You still pay for idling resources. Also, it is not easy to find the optimal autoscaling setting. Lambda and API Gateway together solves these challenges. AWS refers to it as serverless, which has since become a buzzword. To understand what it is, let&amp;#8217;s examine two concepts:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Function as a Service&lt;/strong&gt;: service with the ability to execute code on demand. Users only pay for code execution time and do not care where the underlying runtime is&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Backend as a Service&lt;/strong&gt;: service with the ability to listen to a port and respond to web request&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lambda itself is a function as a service. Triggered by events, it only incurs a charge when it&amp;#8217;s invoked. It does not stay up and listening to a TCP port for incoming web request, as does a backend service. In order to act as a backend, Lambda needs to pair up with API gateway. In this configuration, API gateway listens to a web request, and it fires an event to trigger the execution of Lambda function. Lambda and API gateway together makes a backend as a service. In AWS, the coupling of API gateway and Lambda function ensures an idle service does not incur computing cost.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Since Lambda supports many types of events as trigger, it is also used in event-driven architecture, either standalone or from a VPC. Under the hood, Lambda runs code in a container (with a quick startup time relative to a VM).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Developers can release Lambda code by uploading zip package to S3 bucket, or just packaging code into container image. For deployment, apart from AWS console and CLI, one can leverage CloudFormation, SAM (serverless application model), or CDK.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Lambda vs Fargate&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both Lambda and Fargate are serverless capabilities, at least from a marketing perspective. Both can be used to back web service but there are differences. They provision computing resource at different granularity. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a web service, the execution duration of a Lambda function is the response duration to an API request, in terms of seconds. While the server is waiting for a request, there is no usage of the computing resource so you&amp;#8217;re not paying for waiting for a request. However, this also creates the delay of cold-start, especially when the code size is large. There are several ways to optimize the cold start (e.g. &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html"&gt;SnapStart&lt;/a&gt; for Java), but none of those can completely get rid of the cold-start delay with a once-after-a-while request. A light GET call could take 5 seconds with cold start. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the Fargate side, the resource provisioning is based on container lifecycle, instead of request lifecycle. As a result, you&amp;#8217;re still paying for wait time, and it is not per-request billing. Since the container remains up, your request is not going to experience the cold-start if it&amp;#8217;s been idle for a while. Although, Fargate saves you from the effort to right-sizing the computing nodes for container execution, it is not quite the idea of &amp;#8220;scale-to-zero when idle&amp;#8221; by itself. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Serverless Architecture&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the white paper &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/serverless-multi-tier-architectures-api-gateway-lambda/welcome.html"&gt;AWS Serverless Multi-Tier Architectures with Amazon API Gateway and AWS Lambda&lt;/a&gt;, AWS advocates the serverless architecture as a modern alternative to the traditional widely adopted three-tier architecture (presentation, logic and data tiers). In the three tier architecture, the scalability of three tier are managed separately. The modern serverless architecture that AWS whitepaper proposes uses API Gateway and Lambda function in place of Load Balancer and EC2 instances (e.g. in an Auto Scaling Group), as illustrated below:&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="432" height="345" src="https://static.digihunch.com/wp-content/uploads/2022/08/serverless.png" alt="" class="wp-image-7170"/&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both API Gateway and Lambda scale automatically to support the need of application workload. It assumes the role of logic tier in three-tier architecture but requires minimal maintenance work. For presentation tier, AWS has serverless alternatives such as CloudFront, S3. For data tier, AWS has serverless alternatives such as Amazon Aurora for relational database and DynamoDB for NoSQL. However, the &amp;#8220;no request, no pay&amp;#8221; model for Lambda does not apply to the data tier in serverless architecture.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Whilst this paradigm benefits small shop IT who wants to minimize infrastructure cost, it has downsides. There is no ability for infrastructure optimization. Since you do not manage where the code runs, client may have concerns over security (e.g. multi-tenant runtime). As business grows, keep using Lambda can result in technology lock-in. Also, a less used application usually requires warm-up time. A code start (downloading the code and preparing the environment behind the scene) can take 100ms to over a second.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;PaaS attempts to help startups simplify the &amp;#8220;grunt work&amp;#8221; of IT operation. Serverless takes it even further. The semantics of serverless computing is confusing and the &lt;a href="https://en.wikipedia.org/wiki/Serverless_computing"&gt;Wikipedia&lt;/a&gt; page acknowledges it as a misnomer. The nature of serverless model, is the cloud users delegate server capacity management to cloud platforms. The users don&amp;#8217;t need to manage servers, VMs, instances, containers, etc on their own. In a &lt;a href="https://static.digihunch.com/2022/04/knative-introduction-serving/"&gt;previous post&lt;/a&gt;, I discussed the ability to scale to zero, which is just one of the many enabling technologies of serverless. Also, &amp;#8220;no request, no pay&amp;#8221; is neither an inherent nature of serverless model. Serverless service may involve storage (e.g. data service, S3, Aurora serverless) which incurs storage cost. There is a &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/website-deployment-services/welcome.html"&gt;whitepaper&lt;/a&gt; on choosing the right AWS service to deploy your website or web application, with a decision tree. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS pioneered serverless with Lambda release in 2014 but competitor follows. In the Azure landscape, there is an entire suite of computing services from virtual machine to serverless (also with a &lt;a href="https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/compute-decision-tree"&gt;decision tree&lt;/a&gt; in documentation). Azure&amp;#8217;s counterpart for &lt;a href="https://azure.microsoft.com/en-ca/solutions/serverless/"&gt;serverless architecture&lt;/a&gt; is Azure Function (released in 2016 for GA) with API Management. As for GCP, the &lt;a href="https://cloud.google.com/serverless"&gt;serverless&lt;/a&gt; suite includes the event-driven Cloud Function (introduced in 2017) and Knative-based FaaS Cloud Run (introduced in 2019).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are &lt;a href="https://thenewstack.io/serverless-needs-standards-to-be-the-future-of-application-infrastructure"&gt;voices&lt;/a&gt; in advocacy of standardization of serverless model, and CNCF had since made minuscule efforts such as &lt;a href="https://cloudevents.io/?utm_source=thenewstack&amp;amp;utm_medium=website&amp;amp;utm_campaign=platform"&gt;CloudEvents&lt;/a&gt;. The status quo, unfortunately, is anything but standardized.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lastly, here is a table that summarizes the pros and cons of each computing service model.&lt;/p&gt;&#10;&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Computing Service Model&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Pro&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Con&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;EC2&lt;/td&gt;&lt;td&gt;&amp;#8211; Most straightforward and widespread legacy model&lt;br&gt;&amp;#8211; Legacy&lt;/td&gt;&lt;td&gt;&amp;#8211; Ops tasks can be heavy (e.g. patch and vulnerability management of OS)&lt;br&gt;&amp;#8211; Utilization can be low&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ECS&lt;/td&gt;&lt;td&gt;&amp;#8211; Container orchestration is managed&lt;br&gt;&amp;#8211; Convenient to scale&lt;br&gt;&amp;#8211; Well integrated with other AWS services&lt;/td&gt;&lt;td&gt;&amp;#8211; Limited advanced features&lt;br&gt;&amp;#8211; Vendor lock-in&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;EKS&lt;/td&gt;&lt;td&gt;&amp;#8211; Highly scalable and flexible&lt;br&gt;&amp;#8211; Advanced, platform-neutral deployment tools available (e.g. Helm, ArgoCD, etc)&lt;br&gt;&amp;#8211; Custom configurations (e.g. operators)&lt;/td&gt;&lt;td&gt;&amp;#8211; Significant operation overhead&lt;br&gt;&amp;#8211; Steep learning curve (especially for teams)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Lambda&lt;/td&gt;&lt;td&gt;&amp;#8211; automatically scale&lt;br&gt;&amp;#8211; low ops overhead&lt;br&gt;&amp;#8211; pay per use&lt;/td&gt;&lt;td&gt;&amp;#8211; limited choices of runtime&lt;br&gt;&amp;#8211; subject to latency due to cold start; yet warm start incurs cost&lt;br&gt;&amp;#8211; not suitable for long running tasks (batch processing jobs etc)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In summary, the Lambda-based serverless model is good for stateless server-side workload with short response time (&amp;lt;15s), tolerance of cold-start, no need for portability across platforms, and no complex package dependency. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/10/graphql-and-grpc/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;GraphQL and gRPC&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/11/aws-serverless-services-and-developer-tools/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;AWS serverless services and developer tools&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Knative Eventing Introduction</title><link>https://static.digihunch.com/2022/04/knative-introduction/</link><pubDate>Fri, 29 Apr 2022 10:16:00 -0400</pubDate><guid>https://static.digihunch.com/2022/04/knative-introduction/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-knative-eventing.webp" alt="Featured image of post Knative Eventing Introduction" /&gt;&lt;p class="wp-block-paragraph"&gt;In the previous &lt;a href="https://static.digihunch.com/2022/04/knative-introduction-serving/"&gt;post&lt;/a&gt;, I mentioned that Knative Serving and Knative Eventing should be seen as two different projects. The former is supposed to be widely used as a serving layer for microservices, whereas the latter has a narrower customer base. There are a dozen companies who need to build Platform as a Service, and will benefit from event-driven architecture. They are the niche customer for Knative Eventing. In this post, we go through two demos for Eventing.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-event-driven-architecture"&gt;Event Driven Architecture&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Before jumping into Knative eventing, let&amp;#8217;s first understand the value of event-driven architecture. As covered in Knative &lt;a href="https://www.cncf.io/online-programs/event-driven-architecture-with-knative-events/"&gt;presentation&lt;/a&gt; in 2020, a growing micro-service architecture involves lots of service-to-service communications that looks like a spider web in a diagram. Two services communicating with each other are tightly coupled: changing one requires a change of the other. Event-driven architecture evolves to decouple those interdependent services. Knative eventing tries to standardize the event data with Cloud Event and also proposes a framework to drive this architecture. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The documentation uses different words to express the same concepts. So let&amp;#8217;s take a note first: &lt;strong&gt;source&lt;/strong&gt; = &lt;strong&gt;producer&lt;/strong&gt; which emits events, and &lt;strong&gt;sink&lt;/strong&gt; = &lt;strong&gt;subscriber&lt;/strong&gt; = &lt;strong&gt;consumer&lt;/strong&gt; which is the destination of events. Knative Eventing supports two models of in even-driven architecture.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Brokers and Triggers provides an &amp;#8220;event mesh&amp;#8221;. Event producers delivers events to a Broker. Triggers then distribute them uniformly by consumers. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Broker is a &amp;#8220;hub&amp;#8221; for events. It is a central location to receive and send events for delivery. We can choose from the following broker types:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;MT (multi-tenant) channel-based broker (which a channel implementation, such as Kaka channel or an in-memory channel)&lt;/li&gt;&#10;&lt;li&gt;GCP broker&lt;/li&gt;&#10;&lt;li&gt;Apache Kafka broker&lt;/li&gt;&#10;&lt;li&gt;RabbitMQ broker&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Triggers represents a desire to subscribe to events from a specific broker. It can act as a filter&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter"&gt;&lt;img decoding="async" src="https://knative.dev/docs/eventing/channels/images/channel-workflow.png" alt="Sources send events to a Channel. The Channel fans out events to Subscriptions. The Subscriptions send events to Sinks."/&gt;&lt;figcaption class="wp-element-caption"&gt;channel-subscriber model&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Channels and Subscriptions provide a &amp;#8220;event pipe&amp;#8221; model which transforms and routes events between Channels using Subscriptions. This model makes more sense when events out of one system needs to be transformed and then routed to another process.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A channel can be either a generic channel object, or a custom channel implementation (such as Kafka channel or in-memory channel)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The subscription consists of a Subscription object, which specifies the Channel and the Sink (aka the Subscriber) to deliver events to. You can also specify some Sink-specific options, such as how to handle failures.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The key difference is Broker-Trigger model allows you to filter events, where as Channel-Subscription model allows you to transform events.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that a Knative Service can act as both a Source and a Sink for events, and for good reason. You may want to consume events from the Broker and send modified events back to the Broker, as you would in any pipeline use-case. Between these components, Knative Eventing uses&amp;nbsp;&lt;a href="https://github.com/cloudevents/spec/blob/v1.0.1/primer.md"&gt;CloudEvents&lt;/a&gt;&amp;nbsp;to send information back and forth. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-knative-eventing-lab"&gt;Knative Eventing Lab&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can create a lab cluster using Kind as per the &lt;a href="https://github.com/digihunch/real-quicK-cluster#kind"&gt;instruction &lt;/a&gt;in real-quicK-cluster. In &lt;a href="https://kind.sigs.k8s.io/docs/user/quick-start/#settings-for-docker-desktop"&gt;docker-desktop settings&lt;/a&gt;, I configured 6 CPU and 8GB memory as the lab involves a number of nodes. The creation takes a couple minutes. This Knative eventing lab has four paths one can take, based on different model and different implementations:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Lab A demonstrates the configuration of broker-trigger model using Kafka based broker.&lt;/li&gt;&#10;&lt;li&gt;Lab B demonstrates the configuration of channel-subscription model, using in-memory channel.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The two labs share some common steps. We first install Knative Eventing using the provided manifests:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.3.0/eventing-crds.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.3.0/eventing-core.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get pods -n knative-eventing&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The Pods should come to READY fairly quickly. In the mean time, we can configure the consumer as well using the manifests below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Namespace&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;apps&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Deployment&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;replicas&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;selector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;matchLabels&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;containers&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;image&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;gcr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;releases&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eventing&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cmd&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;event_display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;selector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ports&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TCP&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;port&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;targetPort&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;apps&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Deployment&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;replicas&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;selector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;matchLabels&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;containers&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;image&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;gcr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;releases&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eventing&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cmd&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;event_display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;selector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ports&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TCP&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;port&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;targetPort&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The consumers (aka sinks) will be able to process events at the validation step at the end.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-lab-a-install-kafka-and-configure-kafka-based-broker"&gt;Lab A &amp;#8211; Install Kafka and configure Kafka-based Broker&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This lab is for broker-trigger model. We first configure a &lt;a href="https://knative.dev/docs/eventing/broker/kafka-broker/"&gt;Kafka Broker&lt;/a&gt;, which requires a Kafka cluster. The document uses &lt;a href="https://strimzi.io/quickstarts/"&gt;Strimzi operator&lt;/a&gt; to quickly install Kafka cluster. Instead, here we use Helm to install the Kafka cluster:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install my-cluster-kafka bitnami/kafka -n kafka --create-namespace --set volumePermissions.enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true --set replicaCount&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;At the end of installation, the Helm notes indicate that the bootstrap server is &lt;em&gt;my-cluster-kafka.kafka.svc.cluster.local:9092&lt;/em&gt;. All Kafka pods should come ready in about 5 minutes. After cluster install, we need to install Kafka controller and the Broker-layer data plane which allow you to map a Kafka instance to Broker CRD later:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -f https://github.com/knative-sandbox/eventing-kafka-broker/releases/download/knative-v1.3.0/eventing-kafka-controller.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -f https://github.com/knative-sandbox/eventing-kafka-broker/releases/download/knative-v1.3.0/eventing-kafka-broker.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get pods -n knative-eventing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n knative-eventing edit cm kafka-broker-config&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;As the command above suggests, once data plane is installed, we edit the default broker config by updating the bootstrap.servers with the bootstrap server address noted above. We also need to make sure the replication factor is no greater than number of partitions, which should not be a problem in our lab as the replica count was set to 3. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now we can create a Broker in the same namespace with consumer:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apiVersion: eventing.knative.dev/v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kind: Broker&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;metadata:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; namespace: event-example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; annotations:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; eventing.knative.dev/broker.class: Kafka&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;spec:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; apiVersion: v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kind: ConfigMap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: kafka-broker-config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; namespace: knative-eventing&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once the manifest above is applied, we should see the status of broker (named default) to be READY. We can also validate broker creation with kn CLI command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $ kubectl -n event-example get broker default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME URL AGE READY REASON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default http://kafka-broker-ingress.knative-eventing.svc.cluster.local/event-example/default 19m True&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kn broker list -n event-example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME URL AGE CONDITIONS READY REASON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default http://kafka-broker-ingress.knative-eventing.svc.cluster.local/event-example/default 19m &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; OK / &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; True&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then we create Triggers that connects both to the broker with filters, and to the consumers by referencing service name. The manifest to create triggers is provided below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eventing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Trigger&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;broker&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;attributes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;greeting&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;subscriber&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eventing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Trigger&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;broker&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;attributes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sendoff&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;subscriber&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can confirm the setups above by monitoring the resources (like we did for broker), or use knative CLI:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kn trigger list -n event-example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME BROKER SINK AGE CONDITIONS READY REASON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;goodbye-display default service:goodbye-display 3m24s &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; OK / &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; True&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-display default service:hello-display 3m24s &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; OK / &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; True&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can go to the validation step to send event and validate result.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-lab-b-install-in-memory-channel-and-configure-channel"&gt;Lab B &amp;#8211; Install in-memory channel and configure Channel&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This lab is for channel-subscription model. we first install an in-memory channel:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.3.0/in-memory-channel.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then we can map this channel to a Channel resource in Eventing. We can do so by applying the manifest below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;messaging&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Channel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;messaging&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Channel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The creation of Channel resources can be verified as below&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kn -n event-example channel list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME TYPE URL AGE READY REASON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;demo-channel-1 InMemoryChannel http://demo-channel-1-kn-channel.event-example.svc.cluster.local 6m34s True&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;demo-channel-2 InMemoryChannel http://demo-channel-2-kn-channel.event-example.svc.cluster.local 6m34s True&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we need to create Subscription which connects Channels to Consumers. Subscriptions can be created with the manifest below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;messaging&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Subscription&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;subscription&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;messaging&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Channel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;subscriber&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;messaging&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Subscription&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;subscription&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;messaging&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;knative&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Channel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;subscriber&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;goodbye&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can confirm subscription:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kn -n event-example subscription list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME CHANNEL SUBSCRIBER REPLY DEAD LETTER SINK READY REASON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;demo-subscription-1 Channel:demo-channel-1 service:hello-display True&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;demo-subscription-2 Channel:demo-channel-2 service:goodbye-display True&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can go to validation step.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-validation"&gt;Validation&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For validation, we need to first configure an event source. The source in our lab is a throw-away Pod with curl utility. I use my favourite &lt;a href="https://github.com/nicolaka/netshoot"&gt;nicolaka netshoot&lt;/a&gt; to fire off the events using. To launch the Pod and get to command shell:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl run tmp-shell -n event-example --rm -i --tty --image nicolaka/netshoot -- /bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you don&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t see a command prompt, try pressing enter.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-5.1# &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can POST message to the corresponding endpoint URL to fire events. The endpoint is different for each lab:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-white-background-color has-background"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Lab&lt;/th&gt;&lt;th&gt;URL&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;A (Kafka-based broker)&lt;/td&gt;&lt;td&gt;http://kafka-broker-ingress.knative-eventing.svc.cluster.local/event-example/default&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B (channel)&lt;/td&gt;&lt;td&gt;http://demo-channel-1-kn-channel.event-example.svc.cluster.local&lt;br&gt;http://demo-channel-2-kn-channel.event-example.svc.cluster.local&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With the correct URL, we can build a payload for POST method. Below is three curl commands with different payload POST to the same endpoint (taking lab A as an example):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;display:grid;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# curl -v &amp;#34;http://broker-ingress.knative-eventing.svc.cluster.local/event-example/default&amp;#34; \&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-X POST &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Id: say-hello&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Specversion: 1.0&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Type: greeting&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Source: not-sendoff&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex; background-color:#3c3d38"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex; background-color:#3c3d38"&gt;&lt;span&gt;-d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;msg&amp;#34;:&amp;#34;Hello Knative!&amp;#34;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# curl -v &amp;#34;http://broker-ingress.knative-eventing.svc.cluster.local/event-example/default&amp;#34; \&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-X POST &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Id: say-goodbye&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Specversion: 1.0&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Type: not-greeting&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Source: sendoff&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex; background-color:#3c3d38"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex; background-color:#3c3d38"&gt;&lt;span&gt;-d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;msg&amp;#34;:&amp;#34;Goodbye Knative!&amp;#34;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# curl -v &amp;#34;http://broker-ingress.knative-eventing.svc.cluster.local/event-example/default&amp;#34; \&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-X POST &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Id: say-hello-goodbye&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Specversion: 1.0&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Type: greeting&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Ce-Source: sendoff&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex; background-color:#3c3d38"&gt;&lt;span&gt;-H &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex; background-color:#3c3d38"&gt;&lt;span&gt;-d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;msg&amp;#34;:&amp;#34;Hello Knative! Goodbye Knative!&amp;#34;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;All the requests should receive 202 return code. As highlighted above, we specified type and source for each event fired to the broker. On the consumer side, we can simply check the pod log to verify the events received. Below is an example of events received as a result of the events sent above (take broker-trigger model as example):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl -n event-example logs -l app&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hello-display --tail&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2022/03/09 17:05:59 Failed to read tracing config, using the no-op default: empty json tracing config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;☁️ cloudevents.Event&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Context Attributes,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; specversion: 1.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type: greeting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: not-sendoff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: say-hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datacontenttype: application/json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Extensions,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; knativearrivaltime: 2022-03-09T17:14:19.196589801Z&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Data,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Hello Knative!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;☁️ cloudevents.Event&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Context Attributes,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; specversion: 1.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type: greeting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: sendoff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: say-hello-goodbye&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datacontenttype: application/json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Extensions,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; knativearrivaltime: 2022-03-09T17:14:42.977803608Z&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Data,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Hello Knative! Goodbye Knative!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl -n event-example logs -l app&lt;span style="color:#f92672"&gt;=&lt;/span&gt;goodbye-display --tail&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2022/03/09 17:05:58 Failed to read tracing config, using the no-op default: empty json tracing config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;☁️ cloudevents.Event&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Context Attributes,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; specversion: 1.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type: not-greeting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: sendoff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: say-goodbye&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datacontenttype: application/json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Extensions,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; knativearrivaltime: 2022-03-09T17:14:27.430702588Z&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Data,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Goodbye Knative!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;☁️ cloudevents.Event&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Context Attributes,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; specversion: 1.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type: greeting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: sendoff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: say-hello-goodbye&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datacontenttype: application/json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Extensions,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; knativearrivaltime: 2022-03-09T17:14:42.977803608Z&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Data,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Hello Knative! Goodbye Knative!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This is the gist of Knative evening. Note that the format of HTTP payload when we fire off events needs to conform to &lt;a href="https://cloud.google.com/eventarc/docs/cloudevents"&gt;CloudEvents format&lt;/a&gt;. The container image (&lt;a href="https://github.com/knative/eventing/tree/main/cmd/event_display"&gt;event_display&lt;/a&gt;) used in the container is also created for the purpose of processing events received and display them in stdout.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Persistent storage allows for stateful applications on Kubernetes. It also enables architectural patterns that requires persistent storage. Knative eventing is a framework that enables event driven architecture. It supports many &lt;a href="https://knative.dev/docs/eventing/channels/channels-crds/"&gt;messaging channels&lt;/a&gt; (including &lt;a href="https://nats.io/"&gt;NATs&lt;/a&gt;, a cloud-native messaging system) and &lt;a href="https://knative.dev/docs/eventing/broker/"&gt;broker&lt;/a&gt; types (MT channel based, GCP, RabbitMQ). &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/04/knative-introduction-serving/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Knative Serving Introduction&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/05/fsx-ontap-enterprise-storage-on-aws/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;FSx ONTAP – Enterprise storage on AWS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Knative Serving Introduction</title><link>https://static.digihunch.com/2022/04/knative-introduction-serving/</link><pubDate>Sun, 17 Apr 2022 11:33:00 -0400</pubDate><guid>https://static.digihunch.com/2022/04/knative-introduction-serving/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-knative-serving.webp" alt="Featured image of post Knative Serving Introduction" /&gt;&lt;h2 class="wp-block-heading" id="h-background"&gt;Background&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As per &lt;a href="https://www.ibm.com/cloud/learn/knative"&gt;IBM&lt;/a&gt;&amp;#8216;s definition, Knative enables serverless workloads to run on Kubernetes clusters, and makes building and orchestrating containers with Kubernetes faster and easier. It has drawn a lot of attention recently. It released version 1.0 in November 2021, and was accepted as a &lt;a href="https://www.cncf.io/blog/2022/03/02/knative-accepted-as-a-cncf-incubating-project/"&gt;CNCF incubating&lt;/a&gt; project in March 2022. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Glories aside, the value it delivers is the ability to go serverless on a Kubernetes platform. Originally, &lt;a href="https://cloud.google.com/knative"&gt;Knative&lt;/a&gt; was built with three components: build, serving and eventing. The &lt;a href="https://github.com/knative/build"&gt;build&lt;/a&gt; component was deprecated in favour of the &lt;a href="https://tekton.dev/"&gt;Tekton&lt;/a&gt; project. Tekton is cloud native CI/CD pipeline. It connects to source code repo and build artifacts. It can also deploy applications with pipeline as code. Tekton&amp;#8217;s documentation includes a quality tutorial &lt;a href="https://tekton.dev/docs/getting-started/"&gt;here&lt;/a&gt; linked to interactive terminal. On the other hand, we&amp;#8217;ll focus on Knative Serving in this post, and Knative Eventing in the &lt;a href="https://static.digihunch.com/2022/04/knative-introduction/"&gt;next&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://knative.dev/docs/"&gt;Knative&lt;/a&gt; can be seen as a serverless framework with a number of open-source technologies as building blocks, such as Istio for ingress gateway, Kafka or Google Pub/Sub as event-streaming engine, and Prometheus for observability to name a few. Despite of using the same CLI tool (named &lt;a href="https://knative.dev/docs/install/"&gt;kn&lt;/a&gt;), Knative Serving and Eventing are considered separate capabilities using different groups of CRDs. They are installed separately, using their respective &lt;a href="https://knative.dev/docs/install/yaml-install/"&gt;YAML&lt;/a&gt; files, or &lt;a href="https://knative.dev/docs/install/operator/knative-with-operators/"&gt;operator&lt;/a&gt;. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-serving-vs-eventing"&gt;Serving vs Eventing ?&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After reading the article &amp;#8220;&lt;a href="https://ahmet.im/blog/knative-positioning/"&gt;Did we market Knative wrong&lt;/a&gt;&amp;#8221; from Ahmet Balkan, my impression is the two are not related. They could have been two separate projects without sharing a common name. As the author puts, these two shared some core logics. But beyond that, they don&amp;#8217;t have anything in common. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Serving is lightweight and requires Istio. It provides the capability to scale from N to 0 when the system is idle, and from 0 to N when requests come in. It is the missing serving layer for running microservices on Kubernetes and Ahmet position it as the first thing that people installed after creating a cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The target user of Eventing is much smaller. Eventing is for event-driven architecture and is more complex than Serving. Ahmet admits that they over-estimated how many people on the planet want to build a Heroku-like PaaS layer on top of Knative. There are a couple of dozen companies who would work through the complexity and build their own Kubernetes-based internal PaaS or even public-facing FaaS using Knative. They are the niche audience of Knative Eventing. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For most platform builders who just need to run micro-service, Knative Serving is all they need.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-a-demo-on-serving"&gt;A Demo on Serving&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The definition of term &amp;#8220;serverless&amp;#8221; is very loose. Instead, Knative documentation promotes the ability to &lt;a href="https://knative.dev/docs/getting-started/first-autoscale/#watch-your-knative-service-scale-to-zero"&gt;scale to zero&lt;/a&gt; and refer to it as &amp;#8220;some people call this Serverless&amp;#8221;. This suggests that &amp;#8220;the ability to scale to zero&amp;#8221; should be the better term to describe this capability. To deploy it, we need the Service object with apiVersion serving.knative.dev/v1. Below is a guide for a quick hands-on, with some steps modified from the Knative Serving &lt;a href="https://knative.dev/docs/getting-started/first-service/"&gt;tutorial&lt;/a&gt; and installation &lt;a href="https://knative.dev/docs/install/yaml-install/serving/install-serving-with-yaml/"&gt;guide&lt;/a&gt;, with optional steps (extensions, DNS) skipped.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Follow the first part of &lt;a href="https://static.digihunch.com/2021/11/istio-ingress-egress/"&gt;this post&lt;/a&gt; or &lt;a href="https://github.com/digihunch/real-quicK-cluster#minikube"&gt;this guide&lt;/a&gt; in real-quicK-cluster project, to install minikube with metal LB and configure istio (using istioctl as per instruction). Then Knative serving can be installed with two YAML manifests:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.2.0/serving-crds.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.2.0/serving-core.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then we can install Knative istio controller to integrate them so we can see the knative gateways:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.2.0/net-istio.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl -n knative-serving get gateway&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can install the dummy service, either &lt;a href="https://knative.dev/docs/getting-started/first-service/#knative-service-hello-world"&gt;using kn CLI tool or using YAML manifest&lt;/a&gt;. The manifest is given below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;serving.knative.dev/v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;hello&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;default&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;template&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;hello-world&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;annotations&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoscaling.knative.dev/class&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;kpa.autoscaling.knative.dev&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoscaling.knative.dev/metric&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;rps&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoscaling.knative.dev/target&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;50&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoscaling.knative.dev/min-scale&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoscaling.knative.dev/max-scale&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;containerConcurrency&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;containers&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;TARGET&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;value&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;World&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;gcr.io/knative-samples/helloworld-go&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;user-container&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;containerPort&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;protocol&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;TCP&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can notice that in the annotations there are some settings to overwrite the default configuration. They are explained in the &lt;a href="https://knative.dev/docs/serving/autoscaling/#additional-resources"&gt;autoscaling&lt;/a&gt; section of the Knative serving documentation. Here we use request per second (rps) as metric, and have 50 as target. The scale range is between 3 and 10 replicas. Once the resource is created, we can validate it with one of the two commands:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get services.serving.knative.dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kn service describe hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The creation of knative service also created a number of Kubernetes resources, such as deployment and services:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get svc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span style="color:#f92672"&gt;(&lt;/span&gt;S&lt;span style="color:#f92672"&gt;)&lt;/span&gt; AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello ExternalName &amp;lt;none&amp;gt; knative-local-gateway.istio-system.svc.cluster.local 80/TCP 52s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world ClusterIP 10.110.127.231 &amp;lt;none&amp;gt; 80/TCP 108s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-private ClusterIP 10.111.27.73 &amp;lt;none&amp;gt; 80/TCP,9090/TCP,9091/TCP,8022/TCP,8012/TCP 108s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubernetes ClusterIP 10.96.0.1 &amp;lt;none&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get deploy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME READY UP-TO-DATE AVAILABLE AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/1 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 71s&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Before testing, let&amp;#8217;s mock the DNS entry to resolve to the Istio ingress service IP like below in /etc/hosts:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;192.168.64.16 hello.default.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can confirm that the service returns the expected result (after a brief pause): &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ curl hello.default.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hello World!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Wait for a short period without curl or connection from browser, the service should scale down to zero:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get deploy -l serving.knative.dev/service&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hello -w&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME READY UP-TO-DATE AVAILABLE AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/0 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 78s&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From a separate terminal, emulate HTTP request with &lt;a href="https://github.com/rakyll/hey"&gt;hey&lt;/a&gt; command, so the service receives more than 50 rps per pod:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ hey -n &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; -c &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; -z 20s -m GET http://hello.default.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can watch the deployment get scaled up to 10. Once the hey command completes its task, the deployment will scale back down:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get deploy -l serving.knative.dev/service&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hello -w&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME READY UP-TO-DATE AVAILABLE AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/0 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 78s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/1 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 3m54s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/1 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 3m54s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/1 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 3m54s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/1 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 3m54s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/1 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 4m2s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/10 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 4m4s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/10 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 4m4s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/10 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 4m4s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 4m5s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 2/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 4m9s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 3/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; 4m10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 4/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; 4m10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 7/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; 4m10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 9/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 4m10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 10/10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 4m11s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 10/5 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 5m18s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 10/5 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 5m18s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 5/5 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 5m18s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 5/2 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 5m20s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 5/2 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 5m20s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 2/2 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 5m20s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 2/1 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 5m22s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 2/1 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 5m22s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/1 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 5m22s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/0 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 5m52s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 1/0 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 5m52s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world-deployment 0/0 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 5m52s&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Autoscaling in Knative serving is backed by KPA (&lt;a href="https://knative.dev/docs/serving/autoscaling/"&gt;Knative Pod Autoscaler&lt;/a&gt;, used in the example above) or HPA. Also note that the trigger to scale up and down is client connection (RPS). This is different than KEDA. KEDA also supports the capability to scale to zero. However, with KEDA, it is an event that scales a deployment up from zero. In Knative serving, it is the connection to the Service itself that wakes up the service. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-cost-of-scale-to-zero"&gt;Cost of scale-to-zero&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As discussed, both KEDA and Knative serving supports the ability to scale to zero and wake up from zero. The trigger to wake up from zero is different. With KEDA, workload wakes up by an event. With Knative Serving, workload has to wake up upon receiving a connection to the service. In the design to solve this problem, &lt;a href="https://knative.dev/docs/serving/"&gt;Knative&lt;/a&gt; has four sub-components :&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Activator &amp;#8211; When a service is scaled to zero, its request are routed to the&amp;nbsp;&lt;em&gt;activator&lt;/em&gt;&amp;nbsp;which waits for a Pod to become ready (wake up) and proxies the traffic while editing the underlying&amp;nbsp;&lt;code&gt;Endpoints&lt;/code&gt;&amp;nbsp;to route the traffic directly to the Pod(s)&lt;/li&gt;&#10;&lt;li&gt;Autoscaler &amp;#8211; KPA&lt;/li&gt;&#10;&lt;li&gt;Controller &amp;#8211; The main component responsible for watching API objects for Knative CRDs (KService, Configuration, Route, Revision) and manage their lifecycle, create the underlying Kubernetes resources and garbage-collect old objects.&lt;/li&gt;&#10;&lt;li&gt;Webhook &amp;#8211; a Kubernetes Admission Webhook acting both as validating admission controller and mutating admission controller.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The key player is activator, which receives requests when a service is scaled to zero. The wake-up process is summarized as follows:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;After receiving request, activator will buffer (hold onto) the request&lt;/li&gt;&#10;&lt;li&gt;Then, it will look at request’s hostname to find which KService it is for.&lt;/li&gt;&#10;&lt;li&gt;Then, it will scale up the Kubernetes Deployment and wait for a Pod to become ready.&lt;/li&gt;&#10;&lt;li&gt;In the meanwhile, it updates Kubernetes Service to point to Pod IP addresses (so that activator gets out of the network path if the KService is awake).&lt;/li&gt;&#10;&lt;li&gt;Finally, activator proxies the request to the started pod&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;So the &amp;#8220;plumbing&amp;#8221; of the service connection managed by the Activator pod is the cost of scale to zero. This is also called &lt;a href="https://knative.dev/docs/serving/load-balancing/"&gt;Load Balancing&lt;/a&gt;, and the behaviour can be tweaked using two parameters: activator capacity and target burst capacity:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://knative.dev/docs/serving/load-balancing/target-burst-capacity/"&gt;Target burst capacity&lt;/a&gt;: once the target deploy has one more more Pod, service requests may still route via activator or bypassing the activator. Target burst capacity determines at what point service request should start to bypass activator. &lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://knative.dev/docs/serving/load-balancing/activator-capacity/"&gt;Activator capacity&lt;/a&gt;: determines how many requests can activator hold on to. Considering the service-to-service connection also routes via Service CRD, there can be a lot of connections via Activator so its capacity needs to be adjusted.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The additional overhead of managing and optimizing the &amp;#8220;Load Balancer&amp;#8221; is also part of operational cost for the ability to scale to zero.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In comparison, KEDA now has an &lt;a href="https://github.com/kedacore/http-add-on"&gt;HTTP add-on&lt;/a&gt; still at beta but allows connection-based wake-up. The &lt;a href="https://github.com/kedacore/http-add-on/blob/main/docs/design.md"&gt;design&lt;/a&gt; is a little different. As discussed in this &lt;a href="https://static.digihunch.com/2022/03/autoscaling-in-kubernetes-from-metric-based-to-event-driven/"&gt;previous &lt;/a&gt;post.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Knative consists of two disparate components: Serving and Eventing. Serving uses KPA to provide scaling based on service request, and the ability to scale to zero. It is often compared with KEDA, a single-purpose lightweight tool for autoscaling. &lt;a href="https://github.com/kedacore/http-add-on/blob/main/docs/faq.md#how-is-this-project-similar-or-different-from-knative"&gt;Here&lt;/a&gt; is a blurb on their difference by KEDA. The takeaways is that KEDA is more focused on scalability, whereas Knative serving covers more aspects. For example, the Service object of Knative also supports &lt;a href="https://knative.dev/docs/getting-started/first-traffic-split/"&gt;Traffic Splitting&lt;/a&gt;. Knative serving can integrate with istio.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/04/kubernetes-operator/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Operator&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/04/knative-introduction/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Knative Eventing Introduction&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Virtualization 3 of 4 – Containers</title><link>https://static.digihunch.com/2020/08/virtualization-3-of-3-containers/</link><pubDate>Tue, 18 Aug 2020 20:44:35 -0400</pubDate><guid>https://static.digihunch.com/2020/08/virtualization-3-of-3-containers/</guid><description>&lt;p class="wp-block-paragraph"&gt;In broad terms, virtualization of computing resource is about isolation of resources at different levels. We have covered hypervisor-based virtualization in the &lt;a href="https://static.digihunch.com/2020/07/overview-of-virtualization/"&gt;other&lt;/a&gt; post. In this article, we continue to dive into OS level virtualization.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Remember again that the gist of virtualization is isolation of resource. To support OS level virtualization, the OS must have its own capability to isolate computing resource. There are many implementations of &lt;a href="https://en.wikipedia.org/wiki/OS-level_virtualization"&gt;OS level virtualization&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Linux Kernel provides low-level mechanisms some two kernel features(namespaces, cgroups and chroot) for building various lightweight tools that can virtualize the system environment. Docker is such framework that builds on chroot namespaces and cgroups.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-chroot"&gt;Chroot&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Traditionally, root directory (/) is the top directory shared amongst all processes in the OS. There was a chroot() system call that allows each process to have its own idea of root directory. A chroot is an operation that changes the apparent root directory(/) for the current running process and their children. A program that is run in such a modified environment cannot access files and commands outside that environmental directory tree. This modified environment is called a &lt;strong&gt;chroot jail&lt;/strong&gt;. By separating a process using chroot() we ensure security by restricting the process from accessing outside its environment (breaking the jail). This short &lt;a href="https://www.youtube.com/watch?v=2wSJREC7RV8"&gt;video&lt;/a&gt; is a great lab.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although chroot() has a basic idea of isolation, it simply modifies pathname lookups for a process and its children (by prepending the new root path to any name starting with /). Relative paths can still refer any locations outside of the new root. So chroot() does not intend to defend against intentional tampering by privileged users.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-namespace-isolation"&gt;Namespace Isolation&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Namespaces are fundamentally the mechanisms to abstract, isolate, and limit the visibility that a group of processes has over various system entities such as process trees, network interfaces, user IDs and file system mounts. So there are several categories of namespaces:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Mount namespaces &amp;#8211; traditionally, there is one global mount namespace seen by all processes. The mount namespaces confine the set of filesystem mount points visible within a process namespace, enabling one process group in a mount namespace to have an exclusive view of the filesystem list, compared to another process.&lt;/li&gt;&lt;li&gt;UTS namespaces &amp;#8211; allows isolation of hostname per namespace. Each namespace can have its own hostname on the network&lt;/li&gt;&lt;li&gt;User namespaces &amp;#8211; allow a process to use unique user and group IDs&lt;/li&gt;&lt;li&gt;Cgroup namespaces &amp;#8211; processes inside a &lt;a href="https://man7.org/linux/man-pages/man7/cgroup_namespaces.7.html"&gt;cgroup namespace&lt;/a&gt; are only able to view paths relative to their namespace root.&lt;/li&gt;&lt;li&gt;IPC namespaces &amp;#8211; isolates the System V inter-process communication between namespaces, as well as POSIX message queues within each namespace. POSIX message queue allow process to exchange data in the form of messsages.&lt;/li&gt;&lt;li&gt;PID namespaces &amp;#8211; traditionally, *nix kernels spawn the init process with PID 1 during system boot, which in turn starts other user-mode process and is considered the root of the process tree (all the other processes start below this process in the tree). The PID namespace allows a process to spin off a new tree of processes under it with its own root process (PID=1). PID namespaces isolate process ID numbers, and allow duplication of PID numbers across different PID namespaces. The process IDs only needs to be unique within a PID namespace, and are assigned sequentially starting with PID 1. PID namespaces are used in containers.&lt;/li&gt;&lt;li&gt;Network namespaces &amp;#8211; traditionally, all processes in the entire OS share a single set of network interfaces and routing table entries. The routing table entries can be modified at operating system level. With network namespace, this assumption is no longer valid. Network namespace provides abstraction and virtualization of network protocol and interfaces. Each network namespace will have its own network device instances that can be configured with individual network addresses. Other network services, such as routing table, port number, are isolated as well.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Namespaces are created with the &amp;#8220;&lt;em&gt;unshare&lt;/em&gt;&amp;#8221; command or syscall, or as new flags in a &lt;em&gt;&lt;a href="https://man7.org/linux/man-pages/man2/clone.2.html"&gt;clone&lt;/a&gt;()&lt;/em&gt; syscall. The flags are listed here in the &lt;a href="https://man7.org/linux/man-pages/man7/namespaces.7.html"&gt;man&lt;/a&gt; page for namespace. Note that the &lt;em&gt;clone()&lt;/em&gt; syscall is a more generic implementation of &lt;em&gt;fork()&lt;/em&gt; syscall.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-cgroup"&gt;Cgroup&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;cgroups is a Linux kernel feature that limits, accounts for, and isolates the resource usage (CPU, memory, disk I/O, network, etc) of a collection of processes (not to be confused with process group, which has its own meaning). Cgroup has two versions. The control groups functionality (version 1) was merged into Linux kernel mainline in version 2.6.24, released in 2008, and version 2 in kernel 4.5 (March 2016), with significant changes to the interface and internal functionality.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Using cgroups, you can allocate resources such as CPU time, network and memory. Similiar to the process model in Linux, where each process is a child to a parent and relatively descends from the init process thus forming a single-tree like structure, cgroups are hierarchical, where child cgroups inherit the attributes of the parent, but what makes it different is that multiple cgroup hierarchies can exist within a single system, with each having distinct resource prerogatives.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Applying cgroups on namespaces results in isolation of processes into containers within a system, where resources are managed distinctly. Each container is a lightweight virtual machine, all of which run as individual entities and are oblivious of other entities within the same system.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-container-implementation"&gt;Container Implementation&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Above we covered some kernel features that enables container technology. There are many ways to use these technologies to implement the isolation. We call them container runtime. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/LXC"&gt;LXC&lt;/a&gt; is a user space interface for those Linux kernel containment features. It allows for running isolated containers on a control host using a single kernel. Users can launch a system init for each containers, also referred to as virtual environment (as opposed to virtual machines). The author of this &lt;a href="https://www.upguard.com/blog/docker-vs-lxc"&gt;article&lt;/a&gt; regard LXC as a suprcharged chroot on Linux. LXC has rest API tool called LXD. LXC was targeting sysadmin&amp;#8217;s use cases (not developer) to isolate users&amp;#8217; own private workloads from one another. In early days Docker was built on LXC. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Docker&amp;#8217;s target market is developers, and it moved beyond LXC with its own execution environment called &lt;em&gt;&lt;strong&gt;libcontainer&lt;/strong&gt;&lt;/em&gt;. With the initial success of Docker, a large community (Docker, CoreOS, Google, etc) emerged around the idea of using containers as the standard unit of software delivery. They started the Open Container Initiative (OCI) to define industry standards around container runtime (runtime spec) and image format (image spec). Docker &lt;a href="https://opencontainers.org/faq/#what-has-docker-done-to-help-create-this-foundation"&gt;donated&lt;/a&gt; the &lt;a href="https://github.com/docker-archive/libcontainer"&gt;libcontainer&lt;/a&gt; codebase to run independently under OCI, as &lt;a href="https://github.com/opencontainers/runc"&gt;runc&lt;/a&gt;. Docker implements isolation using the following technologies:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Namespace: to isolate process ID, networking, mount points, IPC, host and domain name;&lt;/li&gt;&lt;li&gt;Cgroups: to isolate the usage of CPU and memory between containers&lt;/li&gt;&lt;li&gt;UnionFS: isolate file system&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another container runtime technology is &lt;a href="https://en.wikipedia.org/wiki/OpenVZ"&gt;OpenVZ&lt;/a&gt;, which includes an extension of the Linux kernel. It uses container for entire operating systems (not just application and processes). All OpenVZ containers have to share the same Linux kernel version as host. The &lt;a href="https://wiki.aquasec.com/display/containers/Docker+Alternatives+-+Rkt%2C+LXD%2C+OpenVZ%2C+Linux+VServer%2C+Windows+Containers"&gt;adoption&lt;/a&gt; of OpenVZ is not high.&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Framework&lt;/td&gt;&lt;td&gt;Runtime implementation&lt;/td&gt;&lt;td&gt;Management tool&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LXC&lt;/td&gt;&lt;td&gt;libvert&lt;br&gt;LXC&lt;/td&gt;&lt;td&gt;LXD (rest API)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OCI&lt;/td&gt;&lt;td&gt;Docker&amp;#8217;s runc&lt;br&gt;CoreOS&amp;#8217;s rtk&lt;/td&gt;&lt;td&gt;docker engine (daemon and cli)&lt;br&gt;rtk cli&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption&gt;container runtimes&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Docker is now widely adopted for application hosting in production environment. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-container-and-cloud"&gt;Container and Cloud&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Public cloud vendors also has &lt;a href="https://logz.io/blog/aws-eks-vs-ecs-vs-fargate-understand-differences/"&gt;managed services&lt;/a&gt; around Docker. Here are some examples:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Managed Container&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Image Registry&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Managed Orchestration&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AWS&lt;/td&gt;&lt;td&gt;Elastic Container Service&lt;/td&gt;&lt;td&gt;Elastic Container Registry&lt;/td&gt;&lt;td&gt;Elastic Kubernetes Services&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Azure&lt;/td&gt;&lt;td&gt;Container Instances&lt;/td&gt;&lt;td&gt;Container Registry&lt;/td&gt;&lt;td&gt;Azure Kubernetes Service&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GCP&lt;/td&gt;&lt;td&gt;CloudRun&lt;/td&gt;&lt;td&gt;Container Registry&lt;/td&gt;&lt;td&gt;Google Kubernetes Engine&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Digital Ocean&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;td&gt;Container Registry&lt;/td&gt;&lt;td&gt;Kubernetes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption&gt;Container services from public cloud&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Cloud service was originally developed with VM as a unit of computing resource to service. OS level virtualization allows container to be a unit of computing resource. All these new technologies breed the serverless architecture and cloud-native deployment model. This has significant impact on the creation and delivery of software services. The &lt;a href="https://landscape.cncf.io/"&gt;cloud native landscape&lt;/a&gt; page illustrates more tools around containers.&lt;br&gt;&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/08/cloud-storage-overview/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cloud storage overview&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/08/virtualization-4-of-4-networking/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 4 of 4 – Networking&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>