Showing preview only (1,213K chars total). Download the full file or copy to clipboard to get everything.
Repository: mchmarny/dapr-demos
Branch: master
Commit: cc29106fb457
Files: 291
Total size: 1.1 MB
Directory structure:
gitextract_3z6jna8z/
├── .gitignore
├── LICENSE
├── README.md
├── apim-gateway/
│ ├── README.md
│ ├── apim/
│ │ ├── api.yaml
│ │ ├── policy-all.json
│ │ ├── policy-echo.json
│ │ ├── policy-message.json
│ │ └── policy-save.json
│ └── k8s/
│ ├── binding.yaml
│ ├── echo-service.yaml
│ ├── event-subscriber.yaml
│ ├── gateway.yaml
│ └── pubsub.yaml
├── autoscaling-on-queue/
│ ├── README.md
│ ├── deployment/
│ │ ├── kafka-client.yaml
│ │ ├── kafka-pubsub.yaml
│ │ ├── keda-2.0.0-beta.yaml
│ │ ├── producer.yaml
│ │ ├── subscriber-scaler.yaml
│ │ └── subscriber.yaml
│ ├── producer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── subscriber/
│ ├── Dockerfile
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── component-api/
│ ├── README.md
│ ├── config/
│ │ ├── email.yaml
│ │ ├── state.yaml
│ │ └── twitter.yaml
│ └── sample/
│ ├── email.json
│ └── twitter.json
├── cron-binding/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── config/
│ │ └── cron.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── component.yaml
│ │ └── deployment.yaml
│ └── main.go
├── dapr-aci/
│ ├── README.md
│ ├── components/
│ │ ├── pubsub.yaml
│ │ └── state.yaml
│ ├── deployment/
│ │ └── app.yaml
│ └── src/
│ ├── Dockerfile
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── dapr-api-on-aci/
│ ├── README.md
│ └── email.yaml
├── daprized-ingress/
│ ├── README.md
│ └── config/
│ ├── ingress-annotations.yaml
│ ├── ingress-config.yaml
│ ├── ingress.yaml
│ └── namespace.yml
├── fan-out/
│ ├── README.md
│ ├── grpc-echo-service/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── deployment.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── http-format-converter/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ ├── source-pubsub.yaml
│ │ │ └── target-binding.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── components.yaml
│ │ │ └── deployment.yaml
│ │ └── main.go
│ ├── queue-event-consumer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ └── source-pabusb.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── deployment.yaml
│ │ │ ├── target-kafka.yaml
│ │ │ └── target-redis.yaml
│ │ └── main.go
│ ├── queue-event-producer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ └── target-pabusb.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── deployment.yaml
│ │ │ ├── target-kafka.yaml
│ │ │ └── target-redis.yaml
│ │ └── main.go
│ ├── queue-format-converter/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ ├── kafka.yaml
│ │ │ ├── source-pabusb.yaml
│ │ │ └── target-pubsub.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── deployment.yaml
│ │ │ ├── target-kafka.yaml
│ │ │ └── target-redis.yaml
│ │ └── main.go
│ └── service-format-converter/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config/
│ │ └── source-pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── components.yaml
│ │ └── deployment.yaml
│ └── main.go
├── grpc-echo-service/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── deployment/
│ │ ├── app.yaml
│ │ └── space.yaml
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── grpc-event-subscriber/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── config/
│ │ └── pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── component.yaml
│ │ └── deployment.yaml
│ └── main.go
├── hardened/
│ ├── Makefile
│ ├── README.md
│ ├── config/
│ │ ├── pubsub.yaml
│ │ └── state.yaml
│ ├── deployment/
│ │ ├── hardened/
│ │ │ ├── app1.yaml
│ │ │ ├── app2.yaml
│ │ │ ├── app3.yaml
│ │ │ ├── pubsub.yaml
│ │ │ └── state.yaml
│ │ ├── namespace/
│ │ │ ├── ns.yaml
│ │ │ ├── role.yaml
│ │ │ └── trace.yaml
│ │ └── simple/
│ │ ├── app1.yaml
│ │ ├── app2.yaml
│ │ ├── app3.yaml
│ │ ├── pubsub.yaml
│ │ └── state.yaml
│ └── src/
│ ├── app1/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── app2/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── app3/
│ ├── Dockerfile
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── http-echo-service/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── deployment.yaml
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── http-event-subscriber/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── clooudevent.json
│ ├── config/
│ │ └── pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── component.yaml
│ │ └── deployment.yaml
│ └── main.go
├── order-cancellation/
│ ├── README.md
│ ├── demo/
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── component/
│ │ │ ├── audit-store.yaml
│ │ │ ├── email.yaml
│ │ │ ├── queue.yaml
│ │ │ └── workflow-store.yaml
│ │ ├── config/
│ │ │ └── order-cancel.json
│ │ ├── data/
│ │ │ ├── cancellation.json
│ │ │ ├── email.json
│ │ │ └── meta.json
│ │ └── deployment/
│ │ ├── auditor.yaml
│ │ ├── ingress.yaml
│ │ ├── space.yaml
│ │ ├── viewer.yaml
│ │ └── workflow.yaml
│ └── src/
│ ├── fn/
│ │ ├── .gitignore
│ │ ├── DaprAzFn.csproj
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── ReceiveEvent.cs
│ │ ├── config/
│ │ │ ├── meta.json
│ │ │ ├── pubsub.yaml
│ │ │ └── statestore.yaml
│ │ ├── host.json
│ │ └── local.settings.json
│ └── viewer/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config/
│ │ └── queue.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── resource/
│ ├── static/
│ │ ├── css/
│ │ │ └── app.css
│ │ └── js/
│ │ └── app.js
│ └── template/
│ ├── footer.html
│ ├── header.html
│ └── index.html
├── pipeline/
│ ├── README.md
│ ├── k8s/
│ │ ├── ingress.yaml
│ │ ├── process-pubsub.yaml
│ │ ├── processor.yaml
│ │ ├── provider.yaml
│ │ ├── scorer.yaml
│ │ ├── space.yaml
│ │ ├── state.yaml
│ │ ├── tweeter-pubsub.yaml
│ │ ├── twitter.yaml
│ │ └── viewer.yaml
│ ├── sentiment-scorer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── config/
│ │ │ └── secret.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── tweet-processor/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ ├── result-pubsub.yaml
│ │ │ └── source-pubsub.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── tweet-provider/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── config/
│ │ │ ├── pubsub.yaml
│ │ │ ├── secret.yaml
│ │ │ ├── state.yaml
│ │ │ └── twitter.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── tweet-viewer/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config/
│ │ └── source-pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── resource/
│ │ ├── static/
│ │ │ ├── css/
│ │ │ │ └── app.css
│ │ │ └── js/
│ │ │ └── app.js
│ │ └── template/
│ │ ├── footer.html
│ │ ├── header.html
│ │ └── index.html
│ └── tweet.json
├── setup/
│ ├── Makefile
│ ├── README.md
│ ├── aks/
│ │ ├── Makefile
│ │ └── README.md
│ ├── config/
│ │ ├── actor-dashboard.json
│ │ ├── fluentd-config.yaml
│ │ ├── fluentd.yaml
│ │ ├── ingress-annotations.yaml
│ │ ├── ingress-config.yaml
│ │ ├── ingress-template.yaml
│ │ ├── namespace-template.yml
│ │ ├── sidecar-dashboard.json
│ │ ├── system-services-dashboard.json
│ │ └── zipkin.yaml
│ ├── gke/
│ │ ├── Makefile
│ │ └── README.md
│ └── kubectl-install-dapr
└── state-change-handler/
├── Dockerfile
├── Makefile
├── README.md
├── config/
│ ├── pubsub.yaml
│ └── statechange.yaml
├── go.mod
├── go.sum
└── main.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# VS Code
Debug
# Test binary, built with `go test -c`
*.test
# Output
*.out
# mac
.DS_Store
# bin
bin
# vendored dependnacies
vendor
# certs
*.pem
# secrets
secrets.json
# certs
certs
setup/certs
# other
setup/config/ingress.yaml
setup/config/namespace.yml
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Mark Chmarny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Dapr demos
Collection of personal [Dapr](https://dapr.io) demos.
> Note, some of these demos require latest version of Dapr, Ingress gateway, Observability components, or cluster-local Redis and Mongo services. To create Kubernetes cluster with all these components on AKS, or quickly configure an existing cluster, consider the [Dapr Cluster Setup](./setup) utility.
* Bindings
* [Scheduling using cron](./cron-binding) - Using scheduler to execute service
* [Tweet stream](./pipeline/tweet-provider) - Subscribing to a Twitter even stream and publishing to a pub/sub topic
* [State change handler](./state-change-handler) - RethinkDB state changes streamed into topic
* Eventing
* [gRPC event subscriber](./grpc-event-subscriber) - Subscribing to topic and processing its events using gRPC service
* [HTTP event subscriber](./http-event-subscriber) - Subscribing to topic and processing its events using HTTP service
* Services
* [gRPC echo service](./grpc-echo-service) - gRPC service invocation example
* [HTTP echo service](./http-echo-service) - HTTP service invocation example
* [Sentiment Scorer](./pipeline/sentiment-scorer) - Sentiment scoring serving backed by Azure Cognitive Service
* Integrations
* [Components in ACI](./dapr-api-on-aci) - Dapr components as microservices on ACI without app
* [Component in Kubernetes](./component-api) - Dapr components as microservices on Kubernetes without app
* [Dapr Apps in ACI](./dapr-aci) - Deploying apps with Dapr sidecar and components on ACI
* [Dapr with APIM](./apim-gateway) - Dapr API using Azure API Management self-hosted gateway
* [Dapr API on Ingress](./daprized-ingress) - Expose Dapr API on Kubernetes Ingress Controller using NGINX
* [Dapr GitOps](https://github.com/mchmarny/git-ops) - GitHub Actions build pipeline for Dapr apps
* Solutions
* [Order cancellation](./order-cancellation) - multiple Dapr service integrations with observability
* [Pipeline](./pipeline) - Demos combining Twitter binding, Sentiment scoring, Multi Pub/Sub Processor, and WebSocket Viewer app
* [Fan-out](./fan-out) - Single message source "broadcasted" to multiple, configurable targets (e.g. Redis PubSub, HTTP, gRPC)
* [Hardened](./hardened) - Example of multi-microservice app with tightly controlled access to secrets, components, and full invoking service identity validation
* Templates
* [Dapr gRPC Service](https://github.com/mchmarny/dapr-grpc-service-template) - gRPC service template
* [Dapr HTTP Event Subscriber](https://github.com/mchmarny/dapr-http-event-subscriber-template) - Event subscriber HTTP service template
* [Dapr gRPC Event Subscriber](https://github.com/mchmarny/dapr-grpc-event-subscriber-template) - Event subscriber gRPC service template
* [dapr-http-cron-handler](https://github.com/mchmarny/dapr-http-cron-handler-template) - Scheduled service development template
## Disclaimer
This is my personal project and it does not represent my employer. While I do my best to ensure that everything works, I take no responsibility for issues caused by this code.
## License
This software is released under the [MIT](./LICENSE)
================================================
FILE: apim-gateway/README.md
================================================
# Dapr & Azure API Management Integration Demo
Dapr integration with [Azure API Management](https://azure.microsoft.com/en-us/services/api-management/) (APIM) using self-hosted gateway on Kubernetes.

In this demo we will walk through the configuration of API Management service and its self-hosted gateway on Kubernetes. To illustrate the Dapr integration we will also review three Dapr use-cases:
* Invocation of a specific Dapr service method
* Publishing content to a Pub/Sub topic
* Binding invocation with request content transformation
In addition, we will overview the use of APIM tracing to debug your configuration.
> While you can accomplish everything we show here in Azure portal, to make this demo easier to reliably reproduce, we will be using only the Azure CLI and APIs.
## Prerequisite
* [Azure account](https://azure.microsoft.com/en-us/free/)
* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
* [Kubernetes cluster with Dapr](https://github.com/dapr/docs/blob/v0.9.0/getting-started/environment-setup.md#installing-dapr-on-a-kubernetes-cluster)
* [Helm](https://helm.sh/docs/intro/install/)
## Terminology
You will see a few different APIs being used throughout this demo. At one point we are even going to use one API to manage another (API inception?). Here is short summary to help you keep all these APIs straight. Hope it helps:
* [Azure API](https://docs.microsoft.com/en-us/rest/api/apimanagement/) - this is the API provided by Azure to manage its service (yes, including the API Management Service)
* [API in APIM](https://docs.microsoft.com/en-us/azure/api-management/edit-api) - is the API which we will define in APIM service. Its operations will be used by the users
* [Dapr API](https://github.com/dapr/docs/tree/master/reference/api#dapr-api-reference) - are the RESTful HTTP APIs defined by Dapr which developers interact with building applications
## Setup
To make this demo easier to reproduce, start by exporting the name for your new Azure API Management (APIM) service.
> Note, the name of your API Management service instance has to be globally unique!
```shell
export APIM_SERVICE_NAME="dapr-apim-demo"
```
In addition also export the Azure [Subscription ID](https://docs.bitnami.com/azure/faq/administration/find-subscription-id/) and [Resource Group](https://docs.bitnami.com/azure/faq/administration/find-deployment-resourcegroup-id/) where you want to create that service.
```shell
export AZ_SUBSCRIPTION_ID="your-subscription-id"
export AZ_RESOURCE_GROUP="your-resource-group"
```
## Azure API Management
We will start by configuring the Azure API Management service.
### Service Creation
Create service instance:
> The `publisher-email` and `publisher-name` are only required to receive system notifications e-mails.
```shell
az apim create --name $APIM_SERVICE_NAME \
--subscription $AZ_SUBSCRIPTION_ID \
--resource-group $AZ_RESOURCE_GROUP \
--publisher-email "you@your-domain.com" \
--publisher-name "Your Name"
```
> Note, depending on the SKU and resource group configuration, this operation may take 15+ min. While this running, consider quick read on [API Management Concepts](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#-apis-and-operations)
### API Configuration
Each [API operation](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#-apis-and-operations) defined in APIM will map to one Dapr API. To define these mappings you will use OpenAPI format defined in [apim/api.yaml](./apim/api.yaml) file. You will need to update the OpenAPI file with the name of the APIM service created above:
```yaml
servers:
- url: http://<YOUR-APIM-SERVICE-NAME>.azure-api.net
- url: https://<YOUR-APIM-SERVICE-NAME>.azure-api.net
```
When finished, import that OpenAPI definition fle into APIM service instance:
```shell
az apim api import --path / \
--api-id dapr \
--subscription $AZ_SUBSCRIPTION_ID \
--resource-group $AZ_RESOURCE_GROUP \
--service-name $APIM_SERVICE_NAME \
--display-name "Demo Dapr Service API" \
--protocols http https \
--subscription-required true \
--specification-path apim/api.yaml \
--specification-format OpenApi
```
> Notice the `subscription-required` parameter is set to `true` which means that all invocations against the `dapr` API will need a subscription key. We cover how to obtain the subscription key later.
### Azure API Token
Export the Azure management API token to use through this demo.
```shell
export AZ_API_TOKEN=$(az account get-access-token --resource=https://management.azure.com --query accessToken --output tsv)
```
> If you receive an error later that your token expired, just re-run this command
### Policy Management
APIM [Policies](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#--policies) are sequentially executed on each request. We will start by defining "global" policy to throttle all operation invocations on our API, then add individual policies for each operation to add specific options.
#### Global Policy
APIM policies are defined inside of inbound, outbound, and backend elements. In our case to apply policy that will rate-limit all requests on all operations (before they are forwarded to Dapr API), we will place the global policy within the `inbound` section.
> Note, the rate limit quota we defined here is being shared across all the replicas of self-hosted gateway. In default configuration, where there are 2 replicas, this policy would actually be half of the permitted calls per minute.
```xml
<policies>
<inbound>
<rate-limit-by-key
calls="120"
renewal-period="60"
increment-condition="@(context.Response.StatusCode == 200)"
counter-key="@(context.Request.IpAddress)" />
</inbound>
...
</policies>
```
Apply that [policy](apim/policy-all.json) to all operations submit it to the Azure management API.
```shell
curl -i -X PUT \
-d @apim/policy-all.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/policies/policy?api-version=2019-12-01"
```
If everything goes well, the management API will return the created policy.
#### Echo Service Policy
The Dapr service invocation handles all the service discovery, so to invoke a specific method on any Dapr service users follow this API:
```http
POST/GET/PUT/DELETE /v1.0/invoke/<appId>/method/<method-name>
```
To enable users to invoke the `echo` method on Dapr service with ID of `echo-service` we will create a policy that inherits the global policy (`<base />`) first, to ensure only authorize service invocation are passed to the backend Dapr API. Then to "map" the invocation we set `dapr` as the "backend-id" and define the Dapr service and method attributes to specific service ID and method name.
```xml
<policies>
<inbound>
<base />
<set-backend-service
backend-id="dapr"
dapr-app-id="echo-service"
dapr-method="echo" />
</inbound>
...
</policies>
```
To apply [this policy](apim/policy-echo.json) to the `echo` operation on our API, submit it to the Azure management API:
```shell
curl -i -X PUT \
-d @apim/policy-echo.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/echo/policies/policy?api-version=2019-12-01"
```
If everything goes well, the management API will return the created policy. Additional information about Dapr Service Invocation in APIM are available [here](https://aka.ms/apim/dapr/invoke).
Also, since the external mapping of the API user invocations to Dapr is done in APIM policy, it can be easily re-mapped to any other version as the API implementation evolves over time.

#### Message Topic Policy
In addition to Dapr service invocation, APIM can also be used to publish to Dapr Pub/Sub API:
```http
POST /v1.0/publish/<pubsubname>/<topic>
```
To expose the `messages` topic configured in the `demo-events` component we will start by inheriting the global policy like before, and then set the publish policy to format the request that will be passed to the Dapr Pub/Sub API:
```xml
<policies>
<inbound>
<base />
<publish-to-dapr
topic="@("demo-events/messages")"
response-variable-name="pubsub-response"
>@(context.Request.Body.As<string>())</publish-to-dapr>
<return-response
response-variable-name="pubsub-response" />
</inbound>
...
</policies>
```
To apply [this policy](apim/policy-message.json) to the `message` operation on our API, submit it to the Azure management API:
```shell
curl -i -X PUT \
-d @apim/policy-message.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/message/policies/policy?api-version=2019-12-01"
```
If everything goes well, the management API will return the created policy. Additional information about Dapr Pub/Sub support in APIM are available [here](https://aka.ms/apim/dapr/pubsub).
#### Save Binding Policy
In our final case, we are going to overview exposing the Dapr binding API.
```http
POST/PUT /v1.0/bindings/<name>
```
In contrast to the previous policies, rather than just forwarding the original request content, we are going to create a brand new request based on the content of the original request and mapping it to the format expected by Dapr API. This capability comes handy when your API needs to stay the same while the backing service evolves API evolves over time. Consider the payload expected by Dapr binding API:
```json
{
"data": "",
"metadata": {
"": "",
"": ""
},
"operation": ""
}
```
The policy will first define a `key` variable that will be generated using system guid. Once defined, that variable can be used later on in the policy. To accommodate the binding format expected by Dapr, the policy will then set `operation` attribute in APIM `invoke-dapr-binding` policy, and set `metadata` items to:
* `source` which will be a static value indicating the record came from `APIM`
* `client-ip` which will be set to the client request IP
* `key` which will be set to the value of the variable defined above
Finally, for `data`, we simply use the original content of the client request.
```xml
<policies>
<inbound>
<base />
<set-variable name="key"
value="@{ return Guid.NewGuid().ToString(); }" />
<invoke-dapr-binding
name="demo-binding"
operation="create"
response-variable-name="binding-response">
<metadata>
<item key="source">APIM</item>
<item key="client-ip">@( context.Request.IpAddress )</item>
<item key="key">@( (string)context.Variables["key"] )</item>
</metadata>
<data>@( context.Request.Body.As<string>() )</data>
</invoke-dapr-binding>
<return-response response-variable-name="binding-response" />
</inbound>
...
</policies>
```
To apply [this policy](apim/policy-save.json) to the `save` operation on our API, submit it to the Azure management API:
```shell
curl -i -X PUT \
-d @apim/policy-save.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/save/policies/policy?api-version=2019-12-01"
```
> Note, the support in APIM for bindings is still rolling out across Azure regions. You can safely skip this section and just demo service invocation and topic publishing if you receive an error that `invoke-dapr-binding` is not recognize.
If everything goes well, the management API will return the created policy. Additional information about Dapr Binding support in APIM are available [here](https://aka.ms/apim/dapr/bind).
### Gateway Configuration
To create a self-hosted gateway which will be then deployed to the Kubernetes cluster, first, we need to create the `demo-apim-gateway` object in APIM:
```shell
curl -i -X PUT -d '{"properties": {"description": "Dapr Gateway","locationData": {"name": "Virtual"}}}' \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway?api-version=2019-12-01"
```
And then map that gateway to the previously created API:
```shell
curl -i -X PUT -d '{ "properties": { "provisioningState": "created" } }' \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway/apis/dapr?api-version=2019-12-01"
```
If everything goes well, the API returns JSON of the created objects.
## Kubernetes
Switching now to the Kubernetes cluster...
### Dependencies
To showcase the ability to expose Dapr pub/sub and binding APIs in APIM, we are going to need [Dapr components](https://github.com/dapr/docs/tree/master/concepts#components) configured on the cluster.
> Note, while Dapr supports some 75+ different components, to keep things simple in this demo we will use Redis as both pub/sub and binding backing service
Start with adding the Redis repo to your Helm charts:
```shell
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
```
And install Redis and wait for the deployment to complete:
> Note, for simplicity, we are deploying everything into the `default` namespace.
```shell
helm install redis bitnami/redis
kubectl rollout status statefulset.apps/redis-master
kubectl rollout status statefulset.apps/redis-slave
```
### Dapr Components
Dapr's modular design means that we can easily extend its functionality using [components](https://github.com/dapr/docs/tree/master/concepts#components). The specific implementation for these components which can be any number of the readily available Dapr building blocks is done in configuration. That means that it's also easy to swap or reconfigure them at runtime without the need to modify your code.

To create the binding component to point to the above created Redis cluster the configuration looks like this:
```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: demo-events
spec:
type: pubsub.redis
metadata:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
- name: allowedTopics
value: "messages"
```
Notice we are using the secret created by Redis for password so that our configuration doesn't include any secure information. We also specify that only the `messages` topic should be supported in this case.
To apply these component configurations run:
```shell
kubectl apply -f k8s/pubsub.yaml
kubectl apply -f k8s/binding.yaml
```
> Note, if you updated components after deploying the gateway you will need to restart the deployments.
```shell
kubectl rollout restart deployment/event-subscriber
kubectl rollout status deployment/event-subscriber
kubectl rollout restart deployment/demo-apim-gateway
kubectl rollout status deployment/demo-apim-gateway
```
To check if the components were registered correctly in Dapr, inspect the `daprd` logs in `demo-apim-gateway` pod for `demo-events` and `demo-binding`:
```shell
kubectl logs -l app=demo-apim-gateway -c daprd --tail=200
```
### Dapr Services
To deploy your application as a Dapr service all you need to do is augment your Kubernetes deployment template with few Dapr annotations.
```yaml
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "event-subscriber"
dapr.io/app-port: "8080"
```
> To learn more about Kubernetes sidecar configuration see [Dapr docs](https://github.com/dapr/docs/blob/master/concepts/configuration/README.md#kubernetes-sidecar-configuration).
For this demo we will use a pre-build Docker images of two applications: [gRPC Echo Service](https://github.com/mchmarny/dapr-demos/tree/master/grpc-echo-service) and [HTTP Event Subscriber Service](https://github.com/mchmarny/dapr-demos/tree/master/http-event-subscriber). The Kubernetes deployment files for both of these are located here:
* [k8s/echo-service.yaml](k8s/echo-service.yaml)
* [k8s/event-subscriber.yaml](k8s/event-subscriber.yaml)
Deploy both of these and check that it is ready:
```shell
kubectl apply -f k8s/echo-service.yaml
kubectl apply -f k8s/event-subscriber.yaml
kubectl get pods -l demo=dapr-apim -w
```
> Service is ready when its status is `Running` and the ready column is `2/2` (Dapr and our echo service containers both started)
```shell
NAME READY STATUS RESTARTS AGE
echo-service-668986b998-v2ssp 2/2 Running 0 10m
event-subscriber-7d68b67d9d-5v7bf 2/2 Running 0 10m
```
To make sure that the event subscriber connects to the Redis service you can query the service logs
```shell
kubectl logs -l app=event-subscriber -c daprd | grep demo-events
```
You should see entries containing:
```shell
app responded with subscriptions [{demo-events messages /messages map[]}]
app is subscribed to the following topics: [messages] through pubsub=demo-events
subscribing to topic=messages on pubsub=demo-events
```
### Self-hosted APIM Gateway
To connect the self-hosted gateway to APIM service, we will need to create a Kubernetes secret with the APIM gateway key. Start by getting the key which your gateway will use to connect to from APIM:
> Note, the maximum validity for access tokens is 30 days. Update the below `expiry` parameter to be withing 30 days from today
```shell
curl -i -X POST -d '{ "keyType": "primary", "expiry": "2020-10-10T00:00:01Z" }' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway/generateToken?api-version=2019-12-01"
```
Copy the content of `value` from the response and create a secret:
```shell
kubectl create secret generic demo-apim-gateway-token --type Opaque --from-literal value="GatewayKey paste-the-key-here"
```
> Make sure the secret includes the `GatewayKey` and a space ` ` as well as the value of your token (e.g. `GatewayKey a1b2c3...`)
Now, create a config map containing the APIM service endpoint that will be used to configure your self-hosted gateway:
```shell
kubectl create configmap demo-apim-gateway-env --from-literal \
"config.service.endpoint=https://${APIM_SERVICE_NAME}.management.azure-api.net/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}?api-version=2019-12-01"
```
And finally, deploy the gateway and check that it's ready:
```shell
kubectl apply -f k8s/gateway.yaml
kubectl get pods -l app=demo-apim-gateway
```
> Note, the self-hosted gateway is deployed with 2 replicas to ensure availability during upgrades.
Make sure both instances have status `Running` and container is ready `2/2` (gateway container + Dapr side-car).
```shell
NAME READY STATUS RESTARTS AGE
demo-apim-gateway-6dfb968f5c-cb4t7 2/2 Running 0 26s
demo-apim-gateway-6dfb968f5c-gxrrq 2/2 Running 0 26s
```
To check on the gateway logs:
```shell
kubectl logs -l app=demo-apim-gateway -c demo-apim-gateway
```
## Usage (API Test)
With APIM configured and self-hosted gateway deployed we are ready to test. Start by capturing the cluster load balancer ingress IP:
```shell
export GATEWAY_IP=$(kubectl get svc demo-apim-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
```
### API Subscription Key
All of the APIs we defined in this demo are protected with subscription key. To invoke them, we will first need a subscription key:
```shell
curl -i -H POST -d '{}' -H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/subscriptions/master/listSecrets?api-version=2019-12-01"
```
The response will include both the primary and secondary keys. Copy one of them and export so we can use it for the rest of the demo:
```shell
export AZ_API_SUB_KEY="your-api-subscription-key"
```
### Service Invocation
To invoke the backing gRPC service over Dapr API exposed by APIM run:
```shell
curl -i -X POST -d '{ "message": "hello" }' \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
-H "Ocp-Apim-Trace: true" \
"http://${GATEWAY_IP}/echo"
```
If everything is configured correctly, you should see the response from your backing Dapr service:
```json
{ "message": "hello" }
```
In addition, you can also check the `echo-service` logs:
```shell
kubectl logs -l app=echo-service -c service
```
### Message Publishing
To post a message to the Dapr Pub/Sub API exposed on APIM run:
```shell
curl -i -X POST \
-d '{ "content": "hello" }' \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
-H "Ocp-Apim-Trace: true" \
"http://${GATEWAY_IP}/message"
```
If everything is configured correctly, you will see `200` status code in the header, indicating the message was successfully delivered to the Dapr API.
You can also check the `event-subscriber` logs:
```shell
kubectl logs -l app=event-subscriber -c service
```
There should be an entry similar to this:
```shell
event - PubsubName:demo-events, Topic:messages, ID:24f0e6f0-ab29-4cd6-8617-6c6c36ac1171, Data: map[message:hello]
```
### Binding Invocation
To save a record into database using the Dapr binding API exposed by APIM run:
```shell
curl -i -X POST \
-d '{"city":"PDX","time":"1600171062","metric":"aqi","value": 457}' \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
-H "Ocp-Apim-Trace: true" \
"http://${GATEWAY_IP}/save"
```
If everything is configured correctly, you will see `200` status code in the header indicating the binding was successfully triggered on the Dapr API and our record successfully saved into the DB.
### Debugging
Notice in each one of our API invocations we have been including the `Ocp-Apim-Trace: true` header parameter. APIM provides an ability to trace requests across the policy execution chain which is helps in debugging your policy. The response of each one fo the above invocation includes the `Ocp-Apim-Trace-Location` header parameter. Just paste the value of that parameter into your browser to see the full trace stack in JSON. The trace can get pretty long so here are few Dapr-specific snippets:
```json
...
{
"source": "request-forwarder",
"timestamp": "2020-09-11T11:15:52.9405903Z",
"elapsed": "00:00:00.1382166",
"data": {
"message": "Request is being forwarded to the backend service. Timeout set to 300 seconds",
"request": {
"method": "POST",
"url": "http://localhost:3500/v1.0/publish/demo-events/messages"
}
}
},
{
"source": "publish-to-dapr",
"timestamp": "2020-09-11T11:15:53.1899121Z",
"elapsed": "00:00:00.3875400",
"data": {
"response": {
"status": {
"code": 200,
"reason": "OK"
},
"headers": [
{
"name": "Server",
"value": "fasthttp"
},
{
"name": "Date",
"value": "Fri, 11 Sep 2020 11:15:52 GMT"
},
{
"name": "Content-Length",
"value": "0"
},
{
"name": "Traceparent",
"value": "00-5b1f0bdfc2191742a4635a906359a7aa-196f5df2e977b00a-01"
}
]
}
}
}
...
```
## Summary
This demo illustrated how to setup the APIM service and deploy the self-hosted gateway into your cluster. Using this gateway you can mange access to any number of Dapr services hosted on Kubernetes. You can find out more about all the features of APIM (e.g. Discovery, Caching, Logging etc.) [here](https://azure.microsoft.com/en-us/services/api-management/).
## Cleanup
```shell
kubectl delete -f k8s/gateway.yaml
kubectl delete secret demo-apim-gateway-token
kubectl delete configmap demo-apim-gateway-env
kubectl delete -f k8s/echo-service.yaml
kubectl delete -f k8s/event-subscriber.yaml
kubectl delete -f k8s/pubsub.yaml
kubectl delete -f k8s/binding.yaml
az apim delete --name $APIM_SERVICE_NAME --no-wait --yes
```
================================================
FILE: apim-gateway/apim/api.yaml
================================================
openapi: 3.0.1
info:
title: dapr
version: '1.0'
servers:
- url: http://dapr-apim-demo.azure-api.net
- url: https://dapr-apim-demo.azure-api.net
paths:
/echo:
post:
summary: Echo Service
description: Invoke service using Dapr API
operationId: echo
requestBody:
content:
application/json:
example:
message: hello
responses:
'200':
description: ''
/message:
post:
summary: Message Topic
description: Post to topic using Dapr API
operationId: message
requestBody:
content:
application/json:
example:
content: hello
responses:
'200':
description: ''
/save:
post:
summary: DB Binding
description: DB binding using Dapr API
operationId: save
requestBody:
content:
application/json:
example:
city: PDX,
time: 1600171062
metric: aqi
value: 457
responses:
'200':
description: ''
================================================
FILE: apim-gateway/apim/policy-all.json
================================================
{
"properties": {
"format": "xml",
"value": "<policies><inbound><rate-limit-by-key calls=\"120\" renewal-period=\"60\" increment-condition=\"@(context.Response.StatusCode == 200)\" counter-key=\"@(context.Request.IpAddress)\" /></inbound><backend><forward-request /></backend><outbound /><on-error /></policies>"
}
}
================================================
FILE: apim-gateway/apim/policy-echo.json
================================================
{
"properties": {
"format": "xml",
"value": "<policies><inbound><base /><set-backend-service backend-id=\"dapr\" dapr-app-id=\"echo-service\" dapr-method=\"echo\" /></inbound><backend><base /></backend><outbound></outbound><on-error><base /></on-error></policies>"
}
}
================================================
FILE: apim-gateway/apim/policy-message.json
================================================
{
"properties": {
"format": "xml",
"value": "<policies><inbound><base /><publish-to-dapr topic=\"@("demo-events/messages")\" response-variable-name=\"pubsub-response\">@( context.Request.Body.As<string>() )</publish-to-dapr><return-response response-variable-name=\"pubsub-response\" /></inbound><backend /><outbound><base /></outbound><on-error><base /></on-error></policies>"
}
}
================================================
FILE: apim-gateway/apim/policy-save.json
================================================
{
"properties": {
"format": "xml",
"value": "<policies><inbound><base /><set-variable name=\"key\" value=\"@{ return Guid.NewGuid().ToString(); }\" /><invoke-dapr-binding name=\"demo-binding\" operation=\"create\" response-variable-name=\"binding-response\"><metadata><item key=\"source\">APIM</item><item key=\"client-ip\">@( context.Request.IpAddress )</item><item key=\"key\">@( (string)context.Variables[\"key\"] )</item></metadata><data>@( context.Request.Body.As<string>() )</data></invoke-dapr-binding><return-response response-variable-name=\"binding-response\" /></inbound><backend /><outbound><base /></outbound><on-error><base /></on-error></policies>"
}
}
================================================
FILE: apim-gateway/k8s/binding.yaml
================================================
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: demo-binding
spec:
type: bindings.redis
metadata:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
================================================
FILE: apim-gateway/k8s/echo-service.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-service
labels:
app: echo-service
demo: dapr-apim
spec:
replicas: 1
selector:
matchLabels:
app: echo-service
template:
metadata:
labels:
app: echo-service
demo: dapr-apim
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "echo-service"
dapr.io/app-protocol: "grpc"
dapr.io/app-port: "60002"
dapr.io/config: "tracing"
dapr.io/log-as-json: "true"
dapr.io/log-level: "debug"
spec:
containers:
- name: service
image: mchmarny/grpc-echo-service:v0.11.1
imagePullPolicy: Always
ports:
- containerPort: 60002
env:
- name: ADDRESS
value: ":60002"
================================================
FILE: apim-gateway/k8s/event-subscriber.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: event-subscriber
labels:
app: event-subscriber
demo: dapr-apim
spec:
selector:
matchLabels:
app: event-subscriber
template:
metadata:
labels:
app: event-subscriber
demo: dapr-apim
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "event-subscriber"
dapr.io/app-port: "8080"
dapr.io/config: "tracing"
dapr.io/log-as-json: "true"
dapr.io/log-level: "debug"
spec:
containers:
- name: service
image: mchmarny/http-event-subscriber:v0.11.1
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
- name: PUBSUB_NAME
value: "demo-events"
- name: TOPIC_NAME
value: "messages"
================================================
FILE: apim-gateway/k8s/gateway.yaml
================================================
# NOTE: Before deploying to a production environment, please review the documentation -> https://aka.ms/self-hosted-gateway-production
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-apim-gateway
spec:
replicas: 2
selector:
matchLabels:
app: demo-apim-gateway
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 25%
template:
metadata:
labels:
app: demo-apim-gateway
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "demo-apim-gateway"
dapr.io/config: "tracing"
dapr.io/log-as-json: "true"
dapr.io/log-level: "debug"
spec:
terminationGracePeriodSeconds: 60
containers:
- name: demo-apim-gateway
image: mcr.microsoft.com/azure-api-management/gateway:beta
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8081
readinessProbe:
httpGet:
path: /internal-status-0123456789abcdef
port: http
scheme: HTTP
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3
successThreshold: 1
env:
- name: config.service.auth
valueFrom:
secretKeyRef:
name: demo-apim-gateway-token
key: value
envFrom:
- configMapRef:
name: demo-apim-gateway-env
---
apiVersion: v1
kind: Service
metadata:
name: demo-apim-gateway
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8081
selector:
app: demo-apim-gateway
================================================
FILE: apim-gateway/k8s/pubsub.yaml
================================================
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: demo-events
spec:
type: pubsub.redis
metadata:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
- name: allowedTopics
value: "messages"
================================================
FILE: autoscaling-on-queue/README.md
================================================
# Autoscaling Dapr service based on queue depth
Dapr, with its modular building-block approach, along with the 10+ different Pub/Sub components, makes it easy to write message processing microservices. Since Dapr runs in VM, on bare-metal, in the Cloud, or even on the Edge... the autoscaling Dapr services is left to the hosting later.
In case of Kubernetes, Dapr integrates with [Keda](https://github.com/kedacore/keda), an event driven autoscaler for Kubernetes. In this demo I'll walk through the configuration of Dapr microservice to scale along with the back pressure on [Kafka](https://kafka.apache.org) queue that service processes.

## Setup
The autoscaling demo requires [Dapr](https://dapr.io). If you don't already have a Kubernetes cluster with Dapr installed you can use the included [setup](../setup) to configure all the dependencies.
### Keda
Start by install [Keda](https://github.com/kedacore/keda) into the cluster and wait for it become ready:
```shell
kubectl apply -f deployment/keda-2.0.0-beta.yaml
kubectl rollout status deployment.apps/keda-operator -n keda
```
### Kafka (optional)
Next, if you don't have access to Kafka you can use these instructions to install Kafka into the cluster:
```shell
helm repo add confluentinc https://confluentinc.github.io/cp-helm-charts/
helm repo update
kubectl create ns kafka
helm install kafka confluentinc/cp-helm-charts -n kafka \
--set cp-schema-registry.enabled=false \
--set cp-kafka-rest.enabled=false \
--set cp-kafka-connect.enabled=false \
--set dataLogDirStorageClass=default \
--set dataDirStorageClass=default \
--set storageClass=default
kubectl rollout status deployment.apps/kafka-cp-control-center -n kafka
kubectl rollout status deployment.apps/kafka-cp-ksql-server -n kafka
kubectl rollout status statefulset.apps/kafka-cp-kafka -n kafka
kubectl rollout status statefulset.apps/kafka-cp-zookeeper -n kafka
```
When done, also deploy Kafka client and wait until it's ready:
```shell
kubectl apply -n kafka -f deployment/kafka-client.yaml
kubectl wait -n kafka --for=condition=ready pod kafka-client --timeout=120s
```
Next, create the `metric` topic which we will use in this demo:
> The number of `partitions` is connected to the maximum number of replicas Keda will create.
```shell
kubectl -n kafka exec -it kafka-client -- kafka-topics \
--zookeeper kafka-cp-zookeeper-headless:2181 \
--topic metric \
--create \
--partitions 10 \
--replication-factor 3 \
--if-not-exists
```
## Deployment
To configure the autoscaling demo we will deploy two deployments: `subscriber` which will be used to process messages of the `metric` queue in Kafka, and the `producer`, which will be publishing messages. To make the `producer` compatible with any one of the Pub/Sub components supported by Dapr we will publish the events onto the Kafka queue using Dapr APIs.
### Subscriber
The `subscriber` service doesn't really do anything with the messages. To resemble real-life processing which may take some time to process messages, the `subscriber` allows for explicit processing time setting. The default value is `300ms`. We will go over how to modify that later.
To deploy the `subscriber` service, apply the [Kafka Dapr component](deployment/kafka-pubsub.yaml), the [message subscriber service](deployment/subscriber.yaml), and the [subscriber service Keda scaler](subscriber-scaler.yaml):
```shell
kubectl apply -f deployment/kafka-pubsub.yaml
kubectl apply -f deployment/subscriber.yaml
kubectl apply -f deployment/subscriber-scaler.yaml
```
When done, start watching for the number of replicas of the deployed `subscriber` service:
```shell
watch kubectl get pods -l app=autoscaling-subscriber
```
> Note, by default the subscriber service Keda scaler is set to scale to 0, so you will not see any pods yet. We will publish data on the `metric` topic with the `producer`.
### Producer
In a second terminal session, deploy the [producer service](deployment/producer.yaml) and wait for it to be ready:
```shell
kubectl apply -f deployment/producer.yaml
kubectl rollout status deployment/autoscaling-producer
```
## Demo
Back in the initial terminal now, some 20-30 seconds after the `producer` starts, you should see the number of `subscriber` pods being adjusted by Keda based on the number of the `metric` topic:
```shell
NAME READY STATUS RESTARTS AGE
autoscaling-subscriber-696ffb5c7b-64zqq 2/2 Running 0 31s
autoscaling-subscriber-696ffb5c7b-67f74 2/2 Running 0 15s
autoscaling-subscriber-696ffb5c7b-gpc2d 2/2 Running 0 7m42s
```
By default the `subscriber-scaler` is set to scale-to-zero and has the polling frequency of `15s`. You can adjust these values in [deployment/subscriber-scaler.yaml](deployment/subscriber-scaler.yaml):
```yaml
pollingInterval: 15
minReplicaCount: 0
maxReplicaCount: 10
cooldownPeriod: 30
```
To modify how long should the `subscriber` take to process each message adjust `PROCESS_DURATION` in [deployment/subscriber.yaml](deployment/subscriber.yaml) and re-apply it to the cluster:
```yaml
- name: PROCESS_DURATION
value: "300ms"
```
Finally, to adjust the number of messages published by the producer change the `producer` in [deployment/producer.yaml](./deployment/producer.yaml) and re-apply it to the cluster:
```yaml
- name: NUMBER_OF_PUBLISHERS
value: "1"
- name: PUBLISHERS_FREQ
value: "100ms"
```
The `NUMBER_OF_PUBLISHERS` setting is number of channels that are used to publish events (default: 1). And the `PUBLISHERS_FREQ` is the frequency with which each channel publishes events (default: 1s).
> There is a limit to the amount of messages a single container can produce. If you need to scale beyond that number, increase the number of `autoscaling-producer` replicas
```shell
kubectl scale -n kafka deployment/autoscaling-producer --replicas=10
```
### Updating Components
If you have changed already deployed Dapr component, make sure to reload the `subscriber` and `producer` deployments:
```shell
kubectl rollout restart deployment/autoscaling-subscriber
kubectl rollout status deployment/autoscaling-subscriber
kubectl rollout restart deployment/autoscaling-producer
kubectl rollout status deployment/autoscaling-producer
```
### Kafka Helpers
Get `metric` topic offsets for `autoscaling-subscriber` consumer group:
```shell
kubectl -n kafka exec -it kafka-client -- kafka-consumer-groups \
--bootstrap-server kafka-cp-kafka:9092 \
--describe \
--group autoscaling-subscriber
```
Purge the `metric` topic:
```shell
kubectl -n kafka exec -it kafka-client -- kafka-topics \
--zookeeper kafka-cp-zookeeper:2181 \
--alter \
--topic metric \
--config retention.ms=1000
sleep 15
kubectl -n kafka exec -it kafka-client -- kafka-topics \
--zookeeper kafka-cp-zookeeper:2181 \
--alter \
--topic metric \
--delete-config retention.ms
```
Delete `metric` topic
```shell
kubectl -n kafka exec -it kafka-client -- kafka-topics \
--zookeeper kafka-cp-zookeeper:2181 \
--delete \
--topic metric
```
## Cleanup
```shell
kubectl delete -f deployment/producer.yaml
kubectl delete -f deployment/kafka-pubsub.yaml
kubectl delete -f deployment/subscriber.yaml
kubectl delete -f deployment/subscriber-scaler.yaml
kubectl delete -f deployment/keda-2.0.0-beta.yaml
```
## Disclaimer
This is my personal project and it does not represent my employer. While I do my best to ensure that everything works, I take no responsibility for issues caused by this code.
## License
This software is released under the [MIT](../LICENSE)
================================================
FILE: autoscaling-on-queue/deployment/kafka-client.yaml
================================================
apiVersion: v1
kind: Pod
metadata:
name: kafka-client
spec:
containers:
- name: kafka-client
image: confluentinc/cp-enterprise-kafka:5.5.0
command:
- sh
- -c
- "exec tail -f /dev/null"
================================================
FILE: autoscaling-on-queue/deployment/kafka-pubsub.yaml
================================================
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: autoscaling-pubsub
spec:
type: pubsub.kafka
metadata:
- name: brokers
value: kafka-cp-kafka.kafka.svc.cluster.local:9092
- name: authRequired
value: "false"
- name: allowedTopics
value: metric
- name: consumerID
value: autoscaling-subscriber
================================================
FILE: autoscaling-on-queue/deployment/keda-2.0.0-beta.yaml
================================================
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/name: keda
app.kubernetes.io/part-of: keda-operator
app.kubernetes.io/version: 2.0.0-beta
name: keda
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.3.0
creationTimestamp: null
labels:
app.kubernetes.io/part-of: keda-operator
app.kubernetes.io/version: 2.0.0-beta
name: scaledjobs.keda.sh
spec:
additionalPrinterColumns:
- JSONPath: .spec.triggers[*].type
name: Triggers
type: string
- JSONPath: .spec.triggers[*].authenticationRef.name
name: Authentication
type: string
- JSONPath: .status.conditions[?(@.type=="Ready")].status
name: Ready
type: string
- JSONPath: .status.conditions[?(@.type=="Active")].status
name: Active
type: string
- JSONPath: .metadata.creationTimestamp
name: Age
type: date
group: keda.sh
names:
kind: ScaledJob
listKind: ScaledJobList
plural: scaledjobs
shortNames:
- sj
singular: scaledjob
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: ScaledJob is the Schema for the scaledjobs API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: ScaledJobSpec defines the desired state of ScaledJob
properties:
envSourceContainerName:
type: string
failedJobsHistoryLimit:
format: int32
type: integer
jobTargetRef:
description: JobSpec describes how the job execution will look like.
properties:
activeDeadlineSeconds:
description: Specifies the duration in seconds relative to the startTime
that the job may be active before the system tries to terminate
it; value must be positive integer
format: int64
type: integer
backoffLimit:
description: Specifies the number of retries before marking this
job failed. Defaults to 6
format: int32
type: integer
completions:
description: 'Specifies the desired number of successfully finished
pods the job should be run with. Setting to nil means that the
success of any pod signals the success of all pods, and allows
parallelism to have any positive value. Setting to 1 means that
parallelism is limited to 1 and the success of that pod signals
the success of the job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/'
format: int32
type: integer
manualSelector:
description: 'manualSelector controls generation of pod labels and
pod selectors. Leave `manualSelector` unset unless you are certain
what you are doing. When false or unset, the system pick labels
unique to this job and appends those labels to the pod template. When
true, the user is responsible for picking unique labels and specifying
the selector. Failure to pick a unique label may cause this and
other jobs to not function correctly. However, You may see `manualSelector=true`
in jobs that were created with the old `extensions/v1beta1` API.
More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector'
type: boolean
parallelism:
description: 'Specifies the maximum desired number of pods the job
should run at any given time. The actual number of pods running
in steady state will be less than this number when ((.spec.completions
- .status.successful) < .spec.parallelism), i.e. when the work
left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/'
format: int32
type: integer
selector:
description: 'A label query over pods that should match the pod
count. Normally, the system sets this field for you. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors'
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements.
The requirements are ANDed.
items:
description: A label selector requirement is a selector that
contains values, a key, and an operator that relates the
key and values.
properties:
key:
description: key is the label key that the selector applies
to.
type: string
operator:
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn, Exists
and DoesNotExist.
type: string
values:
description: values is an array of string values. If the
operator is In or NotIn, the values array must be non-empty.
If the operator is Exists or DoesNotExist, the values
array must be empty. This array is replaced during a
strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value} pairs. A single
{key,value} in the matchLabels map is equivalent to an element
of matchExpressions, whose key field is "key", the operator
is "In", and the values array contains only "value". The requirements
are ANDed.
type: object
type: object
template:
description: 'Describes the pod that will be created when executing
a job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/'
properties:
metadata:
description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata'
type: object
spec:
description: 'Specification of the desired behavior of the pod.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
properties:
activeDeadlineSeconds:
description: Optional duration in seconds the pod may be
active on the node relative to StartTime before the system
will actively try to mark it failed and kill associated
containers. Value must be a positive integer.
format: int64
type: integer
affinity:
description: If specified, the pod's scheduling constraints
properties:
nodeAffinity:
description: Describes node affinity scheduling rules
for the pod.
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: The scheduler will prefer to schedule
pods to nodes that satisfy the affinity expressions
specified by this field, but it may choose a node
that violates one or more of the expressions.
The node that is most preferred is the one with
the greatest sum of weights, i.e. for each node
that meets all of the scheduling requirements
(resource request, requiredDuringScheduling affinity
expressions, etc.), compute a sum by iterating
through the elements of this field and adding
"weight" to the sum if the node matches the corresponding
matchExpressions; the node(s) with the highest
sum are the most preferred.
items:
description: An empty preferred scheduling term
matches all objects with implicit weight 0 (i.e.
it's a no-op). A null preferred scheduling term
matches no objects (i.e. is also a no-op).
properties:
preference:
description: A node selector term, associated
with the corresponding weight.
properties:
matchExpressions:
description: A list of node selector requirements
by node's labels.
items:
description: A node selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: The label key that
the selector applies to.
type: string
operator:
description: Represents a key's
relationship to a set of values.
Valid operators are In, NotIn,
Exists, DoesNotExist. Gt, and
Lt.
type: string
values:
description: An array of string
values. If the operator is In
or NotIn, the values array must
be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty. If
the operator is Gt or Lt, the
values array must have a single
element, which will be interpreted
as an integer. This array is replaced
during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchFields:
description: A list of node selector requirements
by node's fields.
items:
description: A node selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: The label key that
the selector applies to.
type: string
operator:
description: Represents a key's
relationship to a set of values.
Valid operators are In, NotIn,
Exists, DoesNotExist. Gt, and
Lt.
type: string
values:
description: An array of string
values. If the operator is In
or NotIn, the values array must
be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty. If
the operator is Gt or Lt, the
values array must have a single
element, which will be interpreted
as an integer. This array is replaced
during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
type: object
weight:
description: Weight associated with matching
the corresponding nodeSelectorTerm, in the
range 1-100.
format: int32
type: integer
required:
- preference
- weight
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
description: If the affinity requirements specified
by this field are not met at scheduling time,
the pod will not be scheduled onto the node. If
the affinity requirements specified by this field
cease to be met at some point during pod execution
(e.g. due to an update), the system may or may
not try to eventually evict the pod from its node.
properties:
nodeSelectorTerms:
description: Required. A list of node selector
terms. The terms are ORed.
items:
description: A null or empty node selector
term matches no objects. The requirements
of them are ANDed. The TopologySelectorTerm
type implements a subset of the NodeSelectorTerm.
properties:
matchExpressions:
description: A list of node selector requirements
by node's labels.
items:
description: A node selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: The label key that
the selector applies to.
type: string
operator:
description: Represents a key's
relationship to a set of values.
Valid operators are In, NotIn,
Exists, DoesNotExist. Gt, and
Lt.
type: string
values:
description: An array of string
values. If the operator is In
or NotIn, the values array must
be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty. If
the operator is Gt or Lt, the
values array must have a single
element, which will be interpreted
as an integer. This array is replaced
during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchFields:
description: A list of node selector requirements
by node's fields.
items:
description: A node selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: The label key that
the selector applies to.
type: string
operator:
description: Represents a key's
relationship to a set of values.
Valid operators are In, NotIn,
Exists, DoesNotExist. Gt, and
Lt.
type: string
values:
description: An array of string
values. If the operator is In
or NotIn, the values array must
be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty. If
the operator is Gt or Lt, the
values array must have a single
element, which will be interpreted
as an integer. This array is replaced
during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
type: object
type: array
required:
- nodeSelectorTerms
type: object
type: object
podAffinity:
description: Describes pod affinity scheduling rules
(e.g. co-locate this pod in the same node, zone, etc.
as some other pod(s)).
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: The scheduler will prefer to schedule
pods to nodes that satisfy the affinity expressions
specified by this field, but it may choose a node
that violates one or more of the expressions.
The node that is most preferred is the one with
the greatest sum of weights, i.e. for each node
that meets all of the scheduling requirements
(resource request, requiredDuringScheduling affinity
expressions, etc.), compute a sum by iterating
through the elements of this field and adding
"weight" to the sum if the node has pods which
matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred.
items:
description: The weights of all of the matched
WeightedPodAffinityTerm fields are added per-node
to find the most preferred node(s)
properties:
podAffinityTerm:
description: Required. A pod affinity term,
associated with the corresponding weight.
properties:
labelSelector:
description: A label query over a set
of resources, in this case pods.
properties:
matchExpressions:
description: matchExpressions is a
list of label selector requirements.
The requirements are ANDed.
items:
description: A label selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label
key that the selector applies
to.
type: string
operator:
description: operator represents
a key's relationship to a
set of values. Valid operators
are In, NotIn, Exists and
DoesNotExist.
type: string
values:
description: values is an array
of string values. If the operator
is In or NotIn, the values
array must be non-empty. If
the operator is Exists or
DoesNotExist, the values array
must be empty. This array
is replaced during a strategic
merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map
of {key,value} pairs. A single {key,value}
in the matchLabels map is equivalent
to an element of matchExpressions,
whose key field is "key", the operator
is "In", and the values array contains
only "value". The requirements are
ANDed.
type: object
type: object
namespaces:
description: namespaces specifies which
namespaces the labelSelector applies
to (matches against); null or empty
list means "this pod's namespace"
items:
type: string
type: array
topologyKey:
description: This pod should be co-located
(affinity) or not co-located (anti-affinity)
with the pods matching the labelSelector
in the specified namespaces, where co-located
is defined as running on a node whose
value of the label with key topologyKey
matches that of any node on which any
of the selected pods is running. Empty
topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
weight:
description: weight associated with matching
the corresponding podAffinityTerm, in the
range 1-100.
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
description: If the affinity requirements specified
by this field are not met at scheduling time,
the pod will not be scheduled onto the node. If
the affinity requirements specified by this field
cease to be met at some point during pod execution
(e.g. due to a pod label update), the system may
or may not try to eventually evict the pod from
its node. When there are multiple elements, the
lists of nodes corresponding to each podAffinityTerm
are intersected, i.e. all terms must be satisfied.
items:
description: Defines a set of pods (namely those
matching the labelSelector relative to the given
namespace(s)) that this pod should be co-located
(affinity) or not co-located (anti-affinity)
with, where co-located is defined as running
on a node whose value of the label with key
<topologyKey> matches that of any node on which
a pod of the set of pods is running
properties:
labelSelector:
description: A label query over a set of resources,
in this case pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The
requirements are ANDed.
items:
description: A label selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: operator represents
a key's relationship to a set
of values. Valid operators are
In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array
of string values. If the operator
is In or NotIn, the values array
must be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty. This
array is replaced during a strategic
merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator
is "In", and the values array contains
only "value". The requirements are ANDed.
type: object
type: object
namespaces:
description: namespaces specifies which namespaces
the labelSelector applies to (matches against);
null or empty list means "this pod's namespace"
items:
type: string
type: array
topologyKey:
description: This pod should be co-located
(affinity) or not co-located (anti-affinity)
with the pods matching the labelSelector
in the specified namespaces, where co-located
is defined as running on a node whose value
of the label with key topologyKey matches
that of any node on which any of the selected
pods is running. Empty topologyKey is not
allowed.
type: string
required:
- topologyKey
type: object
type: array
type: object
podAntiAffinity:
description: Describes pod anti-affinity scheduling
rules (e.g. avoid putting this pod in the same node,
zone, etc. as some other pod(s)).
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: The scheduler will prefer to schedule
pods to nodes that satisfy the anti-affinity expressions
specified by this field, but it may choose a node
that violates one or more of the expressions.
The node that is most preferred is the one with
the greatest sum of weights, i.e. for each node
that meets all of the scheduling requirements
(resource request, requiredDuringScheduling anti-affinity
expressions, etc.), compute a sum by iterating
through the elements of this field and adding
"weight" to the sum if the node has pods which
matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred.
items:
description: The weights of all of the matched
WeightedPodAffinityTerm fields are added per-node
to find the most preferred node(s)
properties:
podAffinityTerm:
description: Required. A pod affinity term,
associated with the corresponding weight.
properties:
labelSelector:
description: A label query over a set
of resources, in this case pods.
properties:
matchExpressions:
description: matchExpressions is a
list of label selector requirements.
The requirements are ANDed.
items:
description: A label selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label
key that the selector applies
to.
type: string
operator:
description: operator represents
a key's relationship to a
set of values. Valid operators
are In, NotIn, Exists and
DoesNotExist.
type: string
values:
description: values is an array
of string values. If the operator
is In or NotIn, the values
array must be non-empty. If
the operator is Exists or
DoesNotExist, the values array
must be empty. This array
is replaced during a strategic
merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map
of {key,value} pairs. A single {key,value}
in the matchLabels map is equivalent
to an element of matchExpressions,
whose key field is "key", the operator
is "In", and the values array contains
only "value". The requirements are
ANDed.
type: object
type: object
namespaces:
description: namespaces specifies which
namespaces the labelSelector applies
to (matches against); null or empty
list means "this pod's namespace"
items:
type: string
type: array
topologyKey:
description: This pod should be co-located
(affinity) or not co-located (anti-affinity)
with the pods matching the labelSelector
in the specified namespaces, where co-located
is defined as running on a node whose
value of the label with key topologyKey
matches that of any node on which any
of the selected pods is running. Empty
topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
weight:
description: weight associated with matching
the corresponding podAffinityTerm, in the
range 1-100.
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
description: If the anti-affinity requirements specified
by this field are not met at scheduling time,
the pod will not be scheduled onto the node. If
the anti-affinity requirements specified by this
field cease to be met at some point during pod
execution (e.g. due to a pod label update), the
system may or may not try to eventually evict
the pod from its node. When there are multiple
elements, the lists of nodes corresponding to
each podAffinityTerm are intersected, i.e. all
terms must be satisfied.
items:
description: Defines a set of pods (namely those
matching the labelSelector relative to the given
namespace(s)) that this pod should be co-located
(affinity) or not co-located (anti-affinity)
with, where co-located is defined as running
on a node whose value of the label with key
<topologyKey> matches that of any node on which
a pod of the set of pods is running
properties:
labelSelector:
description: A label query over a set of resources,
in this case pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The
requirements are ANDed.
items:
description: A label selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: operator represents
a key's relationship to a set
of values. Valid operators are
In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array
of string values. If the operator
is In or NotIn, the values array
must be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty. This
array is replaced during a strategic
merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator
is "In", and the values array contains
only "value". The requirements are ANDed.
type: object
type: object
namespaces:
description: namespaces specifies which namespaces
the labelSelector applies to (matches against);
null or empty list means "this pod's namespace"
items:
type: string
type: array
topologyKey:
description: This pod should be co-located
(affinity) or not co-located (anti-affinity)
with the pods matching the labelSelector
in the specified namespaces, where co-located
is defined as running on a node whose value
of the label with key topologyKey matches
that of any node on which any of the selected
pods is running. Empty topologyKey is not
allowed.
type: string
required:
- topologyKey
type: object
type: array
type: object
type: object
automountServiceAccountToken:
description: AutomountServiceAccountToken indicates whether
a service account token should be automatically mounted.
type: boolean
containers:
description: List of containers belonging to the pod. Containers
cannot currently be added or removed. There must be at
least one container in a Pod. Cannot be updated.
items:
description: A single application container that you want
to run within a pod.
properties:
args:
description: 'Arguments to the entrypoint. The docker
image''s CMD is used if this is not provided. Variable
references $(VAR_NAME) are expanded using the container''s
environment. If a variable cannot be resolved, the
reference in the input string will be unchanged.
The $(VAR_NAME) syntax can be escaped with a double
$$, ie: $$(VAR_NAME). Escaped references will never
be expanded, regardless of whether the variable
exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
items:
type: string
type: array
command:
description: 'Entrypoint array. Not executed within
a shell. The docker image''s ENTRYPOINT is used
if this is not provided. Variable references $(VAR_NAME)
are expanded using the container''s environment.
If a variable cannot be resolved, the reference
in the input string will be unchanged. The $(VAR_NAME)
syntax can be escaped with a double $$, ie: $$(VAR_NAME).
Escaped references will never be expanded, regardless
of whether the variable exists or not. Cannot be
updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
items:
type: string
type: array
env:
description: List of environment variables to set
in the container. Cannot be updated.
items:
description: EnvVar represents an environment variable
present in a Container.
properties:
name:
description: Name of the environment variable.
Must be a C_IDENTIFIER.
type: string
value:
description: 'Variable references $(VAR_NAME)
are expanded using the previous defined environment
variables in the container and any service
environment variables. If a variable cannot
be resolved, the reference in the input string
will be unchanged. The $(VAR_NAME) syntax
can be escaped with a double $$, ie: $$(VAR_NAME).
Escaped references will never be expanded,
regardless of whether the variable exists
or not. Defaults to "".'
type: string
valueFrom:
description: Source for the environment variable's
value. Cannot be used if value is not empty.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
description: 'Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the ConfigMap
or its key must be defined
type: boolean
required:
- key
type: object
fieldRef:
description: 'Selects a field of the pod:
supports metadata.name, metadata.namespace,
metadata.labels, metadata.annotations,
spec.nodeName, spec.serviceAccountName,
status.hostIP, status.podIP, status.podIPs.'
properties:
apiVersion:
description: Version of the schema the
FieldPath is written in terms of,
defaults to "v1".
type: string
fieldPath:
description: Path of the field to select
in the specified API version.
type: string
required:
- fieldPath
type: object
resourceFieldRef:
description: 'Selects a resource of the
container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage,
requests.cpu, requests.memory and requests.ephemeral-storage)
are currently supported.'
properties:
containerName:
description: 'Container name: required
for volumes, optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format
of the exposed resources, defaults
to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to
select'
type: string
required:
- resource
type: object
secretKeyRef:
description: Selects a key of a secret in
the pod's namespace
properties:
key:
description: The key of the secret to
select from. Must be a valid secret
key.
type: string
name:
description: 'Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the Secret
or its key must be defined
type: boolean
required:
- key
type: object
type: object
required:
- name
type: object
type: array
envFrom:
description: List of sources to populate environment
variables in the container. The keys defined within
a source must be a C_IDENTIFIER. All invalid keys
will be reported as an event when the container
is starting. When a key exists in multiple sources,
the value associated with the last source will take
precedence. Values defined by an Env with a duplicate
key will take precedence. Cannot be updated.
items:
description: EnvFromSource represents the source
of a set of ConfigMaps
properties:
configMapRef:
description: The ConfigMap to select from
properties:
name:
description: 'Name of the referent. More
info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the ConfigMap
must be defined
type: boolean
type: object
prefix:
description: An optional identifier to prepend
to each key in the ConfigMap. Must be a C_IDENTIFIER.
type: string
secretRef:
description: The Secret to select from
properties:
name:
description: 'Name of the referent. More
info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the Secret
must be defined
type: boolean
type: object
type: object
type: array
image:
description: 'Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images
This field is optional to allow higher level config
management to default or override container images
in workload controllers like Deployments and StatefulSets.'
type: string
imagePullPolicy:
description: 'Image pull policy. One of Always, Never,
IfNotPresent. Defaults to Always if :latest tag
is specified, or IfNotPresent otherwise. Cannot
be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
type: string
lifecycle:
description: Actions that the management system should
take in response to container lifecycle events.
Cannot be updated.
properties:
postStart:
description: 'PostStart is called immediately
after a container is created. If the handler
fails, the container is terminated and restarted
according to its restart policy. Other management
of the container blocks until the hook completes.
More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
properties:
exec:
description: One and only one of the following
should be specified. Exec specifies the
action to take.
properties:
command:
description: Command is the command line
to execute inside the container, the
working directory for the command is
root ('/') in the container's filesystem.
The command is simply exec'd, it is
not run inside a shell, so traditional
shell instructions ('|', etc) won't
work. To use a shell, you need to explicitly
call out to that shell. Exit status
of 0 is treated as live/healthy and
non-zero is unhealthy.
items:
type: string
type: array
type: object
httpGet:
description: HTTPGet specifies the http request
to perform.
properties:
host:
description: Host name to connect to,
defaults to the pod IP. You probably
want to set "Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in
the request. HTTP allows repeated headers.
items:
description: HTTPHeader describes a
custom header to be used in HTTP probes
properties:
name:
description: The header field name
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
path:
description: Path to access on the HTTP
server.
type: string
port:
anyOf:
- type: integer
- type: string
description: Name or number of the port
to access on the container. Number must
be in the range 1 to 65535. Name must
be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: Scheme to use for connecting
to the host. Defaults to HTTP.
type: string
required:
- port
type: object
tcpSocket:
description: 'TCPSocket specifies an action
involving a TCP port. TCP hooks not yet
supported TODO: implement a realistic TCP
lifecycle hook'
properties:
host:
description: 'Optional: Host name to connect
to, defaults to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: Number or name of the port
to access on the container. Number must
be in the range 1 to 65535. Name must
be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
type: object
preStop:
description: 'PreStop is called immediately before
a container is terminated due to an API request
or management event such as liveness/startup
probe failure, preemption, resource contention,
etc. The handler is not called if the container
crashes or exits. The reason for termination
is passed to the handler. The Pod''s termination
grace period countdown begins before the PreStop
hooked is executed. Regardless of the outcome
of the handler, the container will eventually
terminate within the Pod''s termination grace
period. Other management of the container blocks
until the hook completes or until the termination
grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
properties:
exec:
description: One and only one of the following
should be specified. Exec specifies the
action to take.
properties:
command:
description: Command is the command line
to execute inside the container, the
working directory for the command is
root ('/') in the container's filesystem.
The command is simply exec'd, it is
not run inside a shell, so traditional
shell instructions ('|', etc) won't
work. To use a shell, you need to explicitly
call out to that shell. Exit status
of 0 is treated as live/healthy and
non-zero is unhealthy.
items:
type: string
type: array
type: object
httpGet:
description: HTTPGet specifies the http request
to perform.
properties:
host:
description: Host name to connect to,
defaults to the pod IP. You probably
want to set "Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in
the request. HTTP allows repeated headers.
items:
description: HTTPHeader describes a
custom header to be used in HTTP probes
properties:
name:
description: The header field name
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
path:
description: Path to access on the HTTP
server.
type: string
port:
anyOf:
- type: integer
- type: string
description: Name or number of the port
to access on the container. Number must
be in the range 1 to 65535. Name must
be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: Scheme to use for connecting
to the host. Defaults to HTTP.
type: string
required:
- port
type: object
tcpSocket:
description: 'TCPSocket specifies an action
involving a TCP port. TCP hooks not yet
supported TODO: implement a realistic TCP
lifecycle hook'
properties:
host:
description: 'Optional: Host name to connect
to, defaults to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: Number or name of the port
to access on the container. Number must
be in the range 1 to 65535. Name must
be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
type: object
type: object
livenessProbe:
description: 'Periodic probe of container liveness.
Container will be restarted if the probe fails.
Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
properties:
exec:
description: One and only one of the following
should be specified. Exec specifies the action
to take.
properties:
command:
description: Command is the command line to
execute inside the container, the working
directory for the command is root ('/')
in the container's filesystem. The command
is simply exec'd, it is not run inside a
shell, so traditional shell instructions
('|', etc) won't work. To use a shell, you
need to explicitly call out to that shell.
Exit status of 0 is treated as live/healthy
and non-zero is unhealthy.
items:
type: string
type: array
type: object
failureThreshold:
description: Minimum consecutive failures for
the probe to be considered failed after having
succeeded. Defaults to 3. Minimum value is 1.
format: int32
type: integer
httpGet:
description: HTTPGet specifies the http request
to perform.
properties:
host:
description: Host name to connect to, defaults
to the pod IP. You probably want to set
"Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in the
request. HTTP allows repeated headers.
items:
description: HTTPHeader describes a custom
header to be used in HTTP probes
properties:
name:
description: The header field name
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
path:
description: Path to access on the HTTP server.
type: string
port:
anyOf:
- type: integer
- type: string
description: Name or number of the port to
access on the container. Number must be
in the range 1 to 65535. Name must be an
IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: Scheme to use for connecting
to the host. Defaults to HTTP.
type: string
required:
- port
type: object
initialDelaySeconds:
description: 'Number of seconds after the container
has started before liveness probes are initiated.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
periodSeconds:
description: How often (in seconds) to perform
the probe. Default to 10 seconds. Minimum value
is 1.
format: int32
type: integer
successThreshold:
description: Minimum consecutive successes for
the probe to be considered successful after
having failed. Defaults to 1. Must be 1 for
liveness and startup. Minimum value is 1.
format: int32
type: integer
tcpSocket:
description: 'TCPSocket specifies an action involving
a TCP port. TCP hooks not yet supported TODO:
implement a realistic TCP lifecycle hook'
properties:
host:
description: 'Optional: Host name to connect
to, defaults to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: Number or name of the port to
access on the container. Number must be
in the range 1 to 65535. Name must be an
IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
timeoutSeconds:
description: 'Number of seconds after which the
probe times out. Defaults to 1 second. Minimum
value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
type: object
name:
description: Name of the container specified as a
DNS_LABEL. Each container in a pod must have a unique
name (DNS_LABEL). Cannot be updated.
type: string
ports:
description: List of ports to expose from the container.
Exposing a port here gives the system additional
information about the network connections a container
uses, but is primarily informational. Not specifying
a port here DOES NOT prevent that port from being
exposed. Any port which is listening on the default
"0.0.0.0" address inside a container will be accessible
from the network. Cannot be updated.
items:
description: ContainerPort represents a network
port in a single container.
properties:
containerPort:
description: Number of port to expose on the
pod's IP address. This must be a valid port
number, 0 < x < 65536.
format: int32
type: integer
hostIP:
description: What host IP to bind the external
port to.
type: string
hostPort:
description: Number of port to expose on the
host. If specified, this must be a valid port
number, 0 < x < 65536. If HostNetwork is specified,
this must match ContainerPort. Most containers
do not need this.
format: int32
type: integer
name:
description: If specified, this must be an IANA_SVC_NAME
and unique within the pod. Each named port
in a pod must have a unique name. Name for
the port that can be referred to by services.
type: string
protocol:
description: Protocol for port. Must be UDP,
TCP, or SCTP. Defaults to "TCP".
type: string
required:
- containerPort
- protocol
type: object
type: array
x-kubernetes-list-map-keys:
- containerPort
- protocol
x-kubernetes-list-type: map
readinessProbe:
description: 'Periodic probe of container service
readiness. Container will be removed from service
endpoints if the probe fails. Cannot be updated.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
properties:
exec:
description: One and only one of the following
should be specified. Exec specifies the action
to take.
properties:
command:
description: Command is the command line to
execute inside the container, the working
directory for the command is root ('/')
in the container's filesystem. The command
is simply exec'd, it is not run inside a
shell, so traditional shell instructions
('|', etc) won't work. To use a shell, you
need to explicitly call out to that shell.
Exit status of 0 is treated as live/healthy
and non-zero is unhealthy.
items:
type: string
type: array
type: object
failureThreshold:
description: Minimum consecutive failures for
the probe to be considered failed after having
succeeded. Defaults to 3. Minimum value is 1.
format: int32
type: integer
httpGet:
description: HTTPGet specifies the http request
to perform.
properties:
host:
description: Host name to connect to, defaults
to the pod IP. You probably want to set
"Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in the
request. HTTP allows repeated headers.
items:
description: HTTPHeader describes a custom
header to be used in HTTP probes
properties:
name:
description: The header field name
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
path:
description: Path to access on the HTTP server.
type: string
port:
anyOf:
- type: integer
- type: string
description: Name or number of the port to
access on the container. Number must be
in the range 1 to 65535. Name must be an
IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: Scheme to use for connecting
to the host. Defaults to HTTP.
type: string
required:
- port
type: object
initialDelaySeconds:
description: 'Number of seconds after the container
has started before liveness probes are initiated.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
periodSeconds:
description: How often (in seconds) to perform
the probe. Default to 10 seconds. Minimum value
is 1.
format: int32
type: integer
successThreshold:
description: Minimum consecutive successes for
the probe to be considered successful after
having failed. Defaults to 1. Must be 1 for
liveness and startup. Minimum value is 1.
format: int32
type: integer
tcpSocket:
description: 'TCPSocket specifies an action involving
a TCP port. TCP hooks not yet supported TODO:
implement a realistic TCP lifecycle hook'
properties:
host:
description: 'Optional: Host name to connect
to, defaults to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: Number or name of the port to
access on the container. Number must be
in the range 1 to 65535. Name must be an
IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
timeoutSeconds:
description: 'Number of seconds after which the
probe times out. Defaults to 1 second. Minimum
value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
type: object
resources:
description: 'Compute Resources required by this container.
Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
properties:
limits:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'Limits describes the maximum amount
of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
type: object
requests:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'Requests describes the minimum amount
of compute resources required. If Requests is
omitted for a container, it defaults to Limits
if that is explicitly specified, otherwise to
an implementation-defined value. More info:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
type: object
type: object
securityContext:
description: 'Security options the pod should run
with. More info: https://kubernetes.io/docs/concepts/policy/security-context/
More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
properties:
allowPrivilegeEscalation:
description: 'AllowPrivilegeEscalation controls
whether a process can gain more privileges than
its parent process. This bool directly controls
if the no_new_privs flag will be set on the
container process. AllowPrivilegeEscalation
is true always when the container is: 1) run
as Privileged 2) has CAP_SYS_ADMIN'
type: boolean
capabilities:
description: The capabilities to add/drop when
running containers. Defaults to the default
set of capabilities granted by the container
runtime.
properties:
add:
description: Added capabilities
items:
description: Capability represent POSIX
capabilities type
type: string
type: array
drop:
description: Removed capabilities
items:
description: Capability represent POSIX
capabilities type
type: string
type: array
type: object
privileged:
description: Run container in privileged mode.
Processes in privileged containers are essentially
equivalent to root on the host. Defaults to
false.
type: boolean
procMount:
description: procMount denotes the type of proc
mount to use for the containers. The default
is DefaultProcMount which uses the container
runtime defaults for readonly paths and masked
paths. This requires the ProcMountType feature
flag to be enabled.
type: string
readOnlyRootFilesystem:
description: Whether this container has a read-only
root filesystem. Default is false.
type: boolean
runAsGroup:
description: The GID to run the entrypoint of
the container process. Uses runtime default
if unset. May also be set in PodSecurityContext. If
set in both SecurityContext and PodSecurityContext,
the value specified in SecurityContext takes
precedence.
format: int64
type: integer
runAsNonRoot:
description: Indicates that the container must
run as a non-root user. If true, the Kubelet
will validate the image at runtime to ensure
that it does not run as UID 0 (root) and fail
to start the container if it does. If unset
or false, no such validation will be performed.
May also be set in PodSecurityContext. If set
in both SecurityContext and PodSecurityContext,
the value specified in SecurityContext takes
precedence.
type: boolean
runAsUser:
description: The UID to run the entrypoint of
the container process. Defaults to user specified
in image metadata if unspecified. May also be
set in PodSecurityContext. If set in both SecurityContext
and PodSecurityContext, the value specified
in SecurityContext takes precedence.
format: int64
type: integer
seLinuxOptions:
description: The SELinux context to be applied
to the container. If unspecified, the container
runtime will allocate a random SELinux context
for each container. May also be set in PodSecurityContext. If
set in both SecurityContext and PodSecurityContext,
the value specified in SecurityContext takes
precedence.
properties:
level:
description: Level is SELinux level label
that applies to the container.
type: string
role:
description: Role is a SELinux role label
that applies to the container.
type: string
type:
description: Type is a SELinux type label
that applies to the container.
type: string
user:
description: User is a SELinux user label
that applies to the container.
type: string
type: object
windowsOptions:
description: The Windows specific settings applied
to all containers. If unspecified, the options
from the PodSecurityContext will be used. If
set in both SecurityContext and PodSecurityContext,
the value specified in SecurityContext takes
precedence.
properties:
gmsaCredentialSpec:
description: GMSACredentialSpec is where the
GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa)
inlines the contents of the GMSA credential
spec named by the GMSACredentialSpecName
field.
type: string
gmsaCredentialSpecName:
description: GMSACredentialSpecName is the
name of the GMSA credential spec to use.
type: string
runAsUserName:
description: The UserName in Windows to run
the entrypoint of the container process.
Defaults to the user specified in image
metadata if unspecified. May also be set
in PodSecurityContext. If set in both SecurityContext
and PodSecurityContext, the value specified
in SecurityContext takes precedence.
type: string
type: object
type: object
startupProbe:
description: 'StartupProbe indicates that the Pod
has successfully initialized. If specified, no other
probes are executed until this completes successfully.
If this probe fails, the Pod will be restarted,
just as if the livenessProbe failed. This can be
used to provide different probe parameters at the
beginning of a Pod''s lifecycle, when it might take
a long time to load data or warm a cache, than during
steady-state operation. This cannot be updated.
This is a beta feature enabled by the StartupProbe
feature flag. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
properties:
exec:
description: One and only one of the following
should be specified. Exec specifies the action
to take.
properties:
command:
description: Command is the command line to
execute inside the container, the working
directory for the command is root ('/')
in the container's filesystem. The command
is simply exec'd, it is not run inside a
shell, so traditional shell instructions
('|', etc) won't work. To use a shell, you
need to explicitly call out to that shell.
Exit status of 0 is treated as live/healthy
and non-zero is unhealthy.
items:
type: string
type: array
type: object
failureThreshold:
description: Minimum consecutive failures for
the probe to be considered failed after having
succeeded. Defaults to 3. Minimum value is 1.
format: int32
type: integer
httpGet:
description: HTTPGet specifies the http request
to perform.
properties:
host:
description: Host name to connect to, defaults
to the pod IP. You probably want to set
"Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in the
request. HTTP allows repeated headers.
items:
description: HTTPHeader describes a custom
header to be used in HTTP probes
properties:
name:
description: The header field name
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
path:
description: Path to access on the HTTP server.
type: string
port:
anyOf:
- type: integer
- type: string
description: Name or number of the port to
access on the container. Number must be
in the range 1 to 65535. Name must be an
IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: Scheme to use for connecting
to the host. Defaults to HTTP.
type: string
required:
- port
type: object
initialDelaySeconds:
description: 'Number of seconds after the container
has started before liveness probes are initiated.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
periodSeconds:
description: How often (in seconds) to perform
the probe. Default to 10 seconds. Minimum value
is 1.
format: int32
type: integer
successThreshold:
description: Minimum consecutive successes for
the probe to be considered successful after
having failed. Defaults to 1. Must be 1 for
liveness and startup. Minimum value is 1.
format: int32
type: integer
tcpSocket:
description: 'TCPSocket specifies an action involving
a TCP port. TCP hooks not yet supported TODO:
implement a realistic TCP lifecycle hook'
properties:
host:
description: 'Optional: Host name to connect
to, defaults to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: Number or name of the port to
access on the container. Number must be
in the range 1 to 65535. Name must be an
IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
timeoutSeconds:
description: 'Number of seconds after which the
probe times out. Defaults to 1 second. Minimum
value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
type: object
stdin:
description: Whether this container should allocate
a buffer for stdin in the container runtime. If
this is not set, reads from stdin in the container
will always result in EOF. Default is false.
type: boolean
stdinOnce:
description: Whether the container runtime should
close the stdin channel after it has been opened
by a single attach. When stdin is true the stdin
stream will remain open across multiple attach sessions.
If stdinOnce is set to true, stdin is opened on
container start, is empty until the first client
attaches to stdin, and then remains open and accepts
data until the client disconnects, at which time
stdin is closed and remains closed until the container
is restarted. If this flag is false, a container
processes that reads from stdin will never receive
an EOF. Default is false
type: boolean
terminationMessagePath:
description: 'Optional: Path at which the file to
which the container''s termination message will
be written is mounted into the container''s filesystem.
Message written is intended to be brief final status,
such as an assertion failure message. Will be truncated
by the node if greater than 4096 bytes. The total
message length across all containers will be limited
to 12kb. Defaults to /dev/termination-log. Cannot
be updated.'
type: string
terminationMessagePolicy:
description: Indicate how the termination message
should be populated. File will use the contents
of terminationMessagePath to populate the container
status message on both success and failure. FallbackToLogsOnError
will use the last chunk of container log output
if the termination message file is empty and the
container exited with an error. The log output is
limited to 2048 bytes or 80 lines, whichever is
smaller. Defaults to File. Cannot be updated.
type: string
tty:
description: Whether this container should allocate
a TTY for itself, also requires 'stdin' to be true.
Default is false.
type: boolean
volumeDevices:
description: volumeDevices is the list of block devices
to be used by the container.
items:
description: volumeDevice describes a mapping of
a raw block device within a container.
properties:
devicePath:
description: devicePath is the path inside of
the container that the device will be mapped
to.
type: string
name:
description: name must match the name of a persistentVolumeClaim
in the pod
type: string
required:
- devicePath
- name
type: object
type: array
volumeMounts:
description: Pod volumes to mount into the container's
filesystem. Cannot be updated.
items:
description: VolumeMount describes a mounting of
a Volume within a container.
properties:
mountPath:
description: Path within the container at which
the volume should be mounted. Must not contain
':'.
type: string
mountPropagation:
description: mountPropagation determines how
mounts are propagated from the host to container
and the other way around. When not set, MountPropagationNone
is used. This field is beta in 1.10.
type: string
name:
description: This must match the Name of a Volume.
type: string
readOnly:
description: Mounted read-only if true, read-write
otherwise (false or unspecified). Defaults
to false.
type: boolean
subPath:
description: Path within the volume from which
the container's volume should be mounted.
Defaults to "" (volume's root).
type: string
subPathExpr:
description: Expanded path within the volume
from which the container's volume should be
mounted. Behaves similarly to SubPath but
environment variable references $(VAR_NAME)
are expanded using the container's environment.
Defaults to "" (volume's root). SubPathExpr
and SubPath are mutually exclusive.
type: string
required:
- mountPath
- name
type: object
type: array
workingDir:
description: Container's working directory. If not
specified, the container runtime's default will
be used, which might be configured in the container
image. Cannot be updated.
type: string
required:
- name
type: object
type: array
dnsConfig:
description: Specifies the DNS parameters of a pod. Parameters
specified here will be merged to the generated DNS configuration
based on DNSPolicy.
properties:
nameservers:
description: A list of DNS name server IP addresses.
This will be appended to the base nameservers generated
from DNSPolicy. Duplicated nameservers will be removed.
items:
type: string
type: array
options:
description: A list of DNS resolver options. This will
be merged with the base options generated from DNSPolicy.
Duplicated entries will be removed. Resolution options
given in Options will override those that appear in
the base DNSPolicy.
items:
description: PodDNSConfigOption defines DNS resolver
options of a pod.
properties:
name:
description: Required.
type: string
value:
type: string
type: object
type: array
searches:
description: A list of DNS search domains for host-name
lookup. This will be appended to the base search paths
generated from DNSPolicy. Duplicated search paths
will be removed.
items:
type: string
type: array
type: object
dnsPolicy:
description: Set DNS policy for the pod. Defaults to "ClusterFirst".
Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst',
'Default' or 'None'. DNS parameters given in DNSConfig
will be merged with the policy selected with DNSPolicy.
To have DNS options set along with hostNetwork, you have
to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.
type: string
enableServiceLinks:
description: 'EnableServiceLinks indicates whether information
about services should be injected into pod''s environment
variables, matching the syntax of Docker links. Optional:
Defaults to true.'
type: boolean
ephemeralContainers:
description: List of ephemeral containers run in this pod.
Ephemeral containers may be run in an existing pod to
perform user-initiated actions such as debugging. This
list cannot be specified when creating a pod, and it cannot
be modified by updating the pod spec. In order to add
an ephemeral container to an existing pod, use the pod's
ephemeralcontainers subresource. This field is alpha-level
and is only honored by servers that enable the EphemeralContainers
feature.
items:
description: An EphemeralContainer is a container that
may be added temporarily to an existing pod for user-initiated
activities such as debugging. Ephemeral containers have
no resource or scheduling guarantees, and they will
not be restarted when they exit or when a pod is removed
or restarted. If an ephemeral container causes a pod
to exceed its resource allocation, the pod may be evicted.
Ephemeral containers may not be added by directly updating
the pod spec. They must be added via the pod's ephemeralcontainers
subresource, and they will appear in the pod spec once
added. This is an alpha feature enabled by the EphemeralContainers
feature flag.
properties:
args:
description: 'Arguments to the entrypoint. The docker
image''s CMD is used if this is not provided. Variable
references $(VAR_NAME) are expanded using the container''s
environment. If a variable cannot be resolved, the
reference in the input string will be unchanged.
The $(VAR_NAME) syntax can be escaped with a double
$$, ie: $$(VAR_NAME). Escaped references will never
be expanded, regardless of whether the variable
exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
items:
type: string
type: array
command:
description: 'Entrypoint array. Not executed within
a shell. The docker image''s ENTRYPOINT is used
if this is not provided. Variable references $(VAR_NAME)
are expanded using the container''s environment.
If a variable cannot be resolved, the reference
in the input string will be unchanged. The $(VAR_NAME)
syntax can be escaped with a double $$, ie: $$(VAR_NAME).
Escaped references will never be expanded, regardless
of whether the variable exists or not. Cannot be
updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
items:
type: string
type: array
env:
description: List of environment variables to set
in the container. Cannot be updated.
items:
description: EnvVar represents an environment variable
present in a Container.
properties:
name:
description: Name of the environment variable.
Must be a C_IDENTIFIER.
type: string
value:
description: 'Variable references $(VAR_NAME)
are expanded using the previous defined environment
variables in the container and any service
environment variables. If a variable cannot
be resolved, the reference in the input string
will be unchanged. The $(VAR_NAME) syntax
can be escaped with a double $$, ie: $$(VAR_NAME).
Escaped references will never be expanded,
regardless of whether the variable exists
or not. Defaults to "".'
type: string
valueFrom:
description: Source for the environment variable's
value. Cannot be used if value is not empty.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
description: 'Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the ConfigMap
or its key must be defined
type: boolean
required:
- key
type: object
fieldRef:
description: 'Selects a field of the pod:
supports metadata.name, metadata.namespace,
metadata.labels, metadata.annotations,
spec.nodeName, spec.serviceAccountName,
status.hostIP, status.podIP, status.podIPs.'
properties:
apiVersion:
description: Version of the schema the
FieldPath is written in terms of,
defaults to "v1".
type: string
fieldPath:
description: Path of the field to select
in the specified API version.
type: string
required:
- fieldPath
type: object
resourceFieldRef:
description: 'Selects a resource of the
container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage,
requests.cpu, requests.memory and requests.ephemeral-storage)
are currently supported.'
properties:
containerName:
description: 'Container name: required
for volumes, optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format
of the exposed resources, defaults
to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to
select'
type: string
required:
- resource
type: object
secretKeyRef:
description: Selects a key of a secret in
the pod's namespace
properties:
key:
description: The key of the secret to
select from. Must be a valid secret
key.
type: string
name:
description: 'Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the Secret
or its key must be defined
type: boolean
required:
- key
type: object
type: object
required:
- name
type: object
type: array
envFrom:
description: List of sources to populate environment
variables in the container. The keys defined within
a source must be a C_IDENTIFIER. All invalid keys
will be reported as an event when the container
is starting. When a key exists in multiple sources,
the value associated with the last source will take
precedence. Values defined by an Env with a duplicate
key will take precedence. Cannot be updated.
items:
description: EnvFromSource represents the source
of a set of ConfigMaps
properties:
configMapRef:
description: The ConfigMap to select from
properties:
name:
descriptio
gitextract_3z6jna8z/
├── .gitignore
├── LICENSE
├── README.md
├── apim-gateway/
│ ├── README.md
│ ├── apim/
│ │ ├── api.yaml
│ │ ├── policy-all.json
│ │ ├── policy-echo.json
│ │ ├── policy-message.json
│ │ └── policy-save.json
│ └── k8s/
│ ├── binding.yaml
│ ├── echo-service.yaml
│ ├── event-subscriber.yaml
│ ├── gateway.yaml
│ └── pubsub.yaml
├── autoscaling-on-queue/
│ ├── README.md
│ ├── deployment/
│ │ ├── kafka-client.yaml
│ │ ├── kafka-pubsub.yaml
│ │ ├── keda-2.0.0-beta.yaml
│ │ ├── producer.yaml
│ │ ├── subscriber-scaler.yaml
│ │ └── subscriber.yaml
│ ├── producer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── subscriber/
│ ├── Dockerfile
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── component-api/
│ ├── README.md
│ ├── config/
│ │ ├── email.yaml
│ │ ├── state.yaml
│ │ └── twitter.yaml
│ └── sample/
│ ├── email.json
│ └── twitter.json
├── cron-binding/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── config/
│ │ └── cron.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── component.yaml
│ │ └── deployment.yaml
│ └── main.go
├── dapr-aci/
│ ├── README.md
│ ├── components/
│ │ ├── pubsub.yaml
│ │ └── state.yaml
│ ├── deployment/
│ │ └── app.yaml
│ └── src/
│ ├── Dockerfile
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── dapr-api-on-aci/
│ ├── README.md
│ └── email.yaml
├── daprized-ingress/
│ ├── README.md
│ └── config/
│ ├── ingress-annotations.yaml
│ ├── ingress-config.yaml
│ ├── ingress.yaml
│ └── namespace.yml
├── fan-out/
│ ├── README.md
│ ├── grpc-echo-service/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── deployment.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── http-format-converter/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ ├── source-pubsub.yaml
│ │ │ └── target-binding.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── components.yaml
│ │ │ └── deployment.yaml
│ │ └── main.go
│ ├── queue-event-consumer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ └── source-pabusb.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── deployment.yaml
│ │ │ ├── target-kafka.yaml
│ │ │ └── target-redis.yaml
│ │ └── main.go
│ ├── queue-event-producer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ └── target-pabusb.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── deployment.yaml
│ │ │ ├── target-kafka.yaml
│ │ │ └── target-redis.yaml
│ │ └── main.go
│ ├── queue-format-converter/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ ├── kafka.yaml
│ │ │ ├── source-pabusb.yaml
│ │ │ └── target-pubsub.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── k8s/
│ │ │ ├── deployment.yaml
│ │ │ ├── target-kafka.yaml
│ │ │ └── target-redis.yaml
│ │ └── main.go
│ └── service-format-converter/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config/
│ │ └── source-pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── components.yaml
│ │ └── deployment.yaml
│ └── main.go
├── grpc-echo-service/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── deployment/
│ │ ├── app.yaml
│ │ └── space.yaml
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── grpc-event-subscriber/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── config/
│ │ └── pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── component.yaml
│ │ └── deployment.yaml
│ └── main.go
├── hardened/
│ ├── Makefile
│ ├── README.md
│ ├── config/
│ │ ├── pubsub.yaml
│ │ └── state.yaml
│ ├── deployment/
│ │ ├── hardened/
│ │ │ ├── app1.yaml
│ │ │ ├── app2.yaml
│ │ │ ├── app3.yaml
│ │ │ ├── pubsub.yaml
│ │ │ └── state.yaml
│ │ ├── namespace/
│ │ │ ├── ns.yaml
│ │ │ ├── role.yaml
│ │ │ └── trace.yaml
│ │ └── simple/
│ │ ├── app1.yaml
│ │ ├── app2.yaml
│ │ ├── app3.yaml
│ │ ├── pubsub.yaml
│ │ └── state.yaml
│ └── src/
│ ├── app1/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── app2/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── app3/
│ ├── Dockerfile
│ ├── Makefile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── http-echo-service/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── deployment.yaml
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── http-event-subscriber/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── clooudevent.json
│ ├── config/
│ │ └── pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── k8s/
│ │ ├── component.yaml
│ │ └── deployment.yaml
│ └── main.go
├── order-cancellation/
│ ├── README.md
│ ├── demo/
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── component/
│ │ │ ├── audit-store.yaml
│ │ │ ├── email.yaml
│ │ │ ├── queue.yaml
│ │ │ └── workflow-store.yaml
│ │ ├── config/
│ │ │ └── order-cancel.json
│ │ ├── data/
│ │ │ ├── cancellation.json
│ │ │ ├── email.json
│ │ │ └── meta.json
│ │ └── deployment/
│ │ ├── auditor.yaml
│ │ ├── ingress.yaml
│ │ ├── space.yaml
│ │ ├── viewer.yaml
│ │ └── workflow.yaml
│ └── src/
│ ├── fn/
│ │ ├── .gitignore
│ │ ├── DaprAzFn.csproj
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── ReceiveEvent.cs
│ │ ├── config/
│ │ │ ├── meta.json
│ │ │ ├── pubsub.yaml
│ │ │ └── statestore.yaml
│ │ ├── host.json
│ │ └── local.settings.json
│ └── viewer/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config/
│ │ └── queue.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── resource/
│ ├── static/
│ │ ├── css/
│ │ │ └── app.css
│ │ └── js/
│ │ └── app.js
│ └── template/
│ ├── footer.html
│ ├── header.html
│ └── index.html
├── pipeline/
│ ├── README.md
│ ├── k8s/
│ │ ├── ingress.yaml
│ │ ├── process-pubsub.yaml
│ │ ├── processor.yaml
│ │ ├── provider.yaml
│ │ ├── scorer.yaml
│ │ ├── space.yaml
│ │ ├── state.yaml
│ │ ├── tweeter-pubsub.yaml
│ │ ├── twitter.yaml
│ │ └── viewer.yaml
│ ├── sentiment-scorer/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── config/
│ │ │ └── secret.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── tweet-processor/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── config/
│ │ │ ├── result-pubsub.yaml
│ │ │ └── source-pubsub.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── tweet-provider/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── config/
│ │ │ ├── pubsub.yaml
│ │ │ ├── secret.yaml
│ │ │ ├── state.yaml
│ │ │ └── twitter.yaml
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── tweet-viewer/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config/
│ │ └── source-pubsub.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── resource/
│ │ ├── static/
│ │ │ ├── css/
│ │ │ │ └── app.css
│ │ │ └── js/
│ │ │ └── app.js
│ │ └── template/
│ │ ├── footer.html
│ │ ├── header.html
│ │ └── index.html
│ └── tweet.json
├── setup/
│ ├── Makefile
│ ├── README.md
│ ├── aks/
│ │ ├── Makefile
│ │ └── README.md
│ ├── config/
│ │ ├── actor-dashboard.json
│ │ ├── fluentd-config.yaml
│ │ ├── fluentd.yaml
│ │ ├── ingress-annotations.yaml
│ │ ├── ingress-config.yaml
│ │ ├── ingress-template.yaml
│ │ ├── namespace-template.yml
│ │ ├── sidecar-dashboard.json
│ │ ├── system-services-dashboard.json
│ │ └── zipkin.yaml
│ ├── gke/
│ │ ├── Makefile
│ │ └── README.md
│ └── kubectl-install-dapr
└── state-change-handler/
├── Dockerfile
├── Makefile
├── README.md
├── config/
│ ├── pubsub.yaml
│ └── statechange.yaml
├── go.mod
├── go.sum
└── main.go
SYMBOL INDEX (126 symbols across 26 files)
FILE: autoscaling-on-queue/producer/main.go
constant chars (line 24) | chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
function main (line 41) | func main() {
function monitor (line 92) | func monitor(resultCh <-chan bool, stopCh <-chan struct{}) {
function publish (line 120) | func publish(index int, resultCh chan<- bool, stopCh <-chan struct{}) {
function getEventData (line 141) | func getEventData(index int) []byte {
function getData (line 159) | func getData(length int) string {
type requestContent (line 168) | type requestContent struct
function getEnvVar (line 175) | func getEnvVar(key, fallbackValue string) string {
function getEnvIntOrFail (line 182) | func getEnvIntOrFail(key, fallbackValue string) int {
function getEnvDurationOrFail (line 191) | func getEnvDurationOrFail(key, fallbackValue string) time.Duration {
function getEnvBoolOrFail (line 200) | func getEnvBoolOrFail(key, fallbackValue string) bool {
FILE: autoscaling-on-queue/subscriber/main.go
constant primeStateKey (line 21) | primeStateKey = "high-prime"
function main (line 34) | func main() {
function processRequest (line 111) | func processRequest(ctx context.Context, in interface{}) error {
function getEnvVar (line 117) | func getEnvVar(key, fallbackValue string) string {
FILE: cron-binding/main.go
function main (line 20) | func main() {
function scheduleHandler (line 35) | func scheduleHandler(ctx context.Context, in *common.BindingEvent) (out ...
function getEnvVar (line 43) | func getEnvVar(key, fallbackValue string) string {
FILE: dapr-aci/src/main.go
constant addInvokeHandlerError (line 21) | addInvokeHandlerError = "error adding invocation handler"
constant startingServiceError (line 22) | startingServiceError = "error starting service"
constant clientCreateError (line 23) | clientCreateError = "error creating Dapr client"
constant addSubscriptionError (line 24) | addSubscriptionError = "error subscribing to a topic"
constant addInvocationError (line 25) | addInvocationError = "error creating invcation handler"
constant methodName (line 26) | methodName = "ping"
function main (line 41) | func main() {
function invokeHandler (line 69) | func invokeHandler(ctx context.Context, in *common.InvocationEvent) (out...
function eventHandler (line 77) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 95) | func getEnvVar(key, fallbackValue string) string {
FILE: fan-out/grpc-echo-service/main.go
function main (line 18) | func main() {
function echoHandler (line 35) | func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *...
function getEnvVar (line 50) | func getEnvVar(key, fallbackValue string) string {
FILE: fan-out/http-format-converter/main.go
function main (line 32) | func main() {
type SourceEvent (line 57) | type SourceEvent struct
function eventHandler (line 64) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 114) | func getEnvVar(key, fallbackValue string) string {
FILE: fan-out/queue-event-consumer/main.go
function main (line 20) | func main() {
function eventHandler (line 40) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 45) | func getEnvVar(key, fallbackValue string) string {
FILE: fan-out/queue-event-producer/main.go
function main (line 29) | func main() {
function produce (line 69) | func produce(ctx context.Context, c dapr.Client, t *time.Ticker) error {
type roomReading (line 85) | type roomReading struct
function getRoomReading (line 92) | func getRoomReading() interface{} {
function getEnvVar (line 103) | func getEnvVar(key, fallbackValue string) string {
FILE: fan-out/queue-format-converter/main.go
function main (line 33) | func main() {
type SourceEvent (line 58) | type SourceEvent struct
function eventHandler (line 65) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 105) | func getEnvVar(key, fallbackValue string) string {
FILE: fan-out/service-format-converter/main.go
function main (line 33) | func main() {
type SourceEvent (line 58) | type SourceEvent struct
function eventHandler (line 65) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 112) | func getEnvVar(key, fallbackValue string) string {
FILE: grpc-echo-service/main.go
function main (line 18) | func main() {
function echoHandler (line 35) | func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *...
function getEnvVar (line 50) | func getEnvVar(key, fallbackValue string) string {
FILE: grpc-event-subscriber/main.go
function main (line 20) | func main() {
function eventHandler (line 40) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 51) | func getEnvVar(key, fallbackValue string) string {
FILE: hardened/src/app1/main.go
constant methodName (line 18) | methodName = "ping"
constant invocationError (line 19) | invocationError = "error invoking"
function main (line 32) | func main() {
function handler (line 51) | func handler(ctx context.Context, in *common.InvocationEvent) (out *comm...
function getEnvVar (line 70) | func getEnvVar(key, fallbackValue string) string {
FILE: hardened/src/app2/main.go
constant methodName (line 20) | methodName = "counter"
constant stateCounterKey (line 21) | stateCounterKey = "count"
constant addInvokeHandlerError (line 23) | addInvokeHandlerError = "error adding invocation handler"
constant startingServiceError (line 24) | startingServiceError = "error starting service"
constant clientCreateError (line 25) | clientCreateError = "error creating Dapr client"
constant publisingError (line 26) | publisingError = "error publishing"
constant getStateError (line 27) | getStateError = "error getting state"
constant saveStateError (line 28) | saveStateError = "error saving state"
constant intParsingError (line 29) | intParsingError = "error parsing data"
function main (line 44) | func main() {
function handler (line 62) | func handler(ctx context.Context, in *common.InvocationEvent) (out *comm...
function getEnvVar (line 117) | func getEnvVar(key, fallbackValue string) string {
FILE: hardened/src/app3/main.go
constant eventDataParsingError (line 19) | eventDataParsingError = "error parsing event data"
constant addSubscriptionError (line 20) | addSubscriptionError = "error adding topic subscription"
constant startingServiceError (line 21) | startingServiceError = "error starting service"
constant intParsingError (line 22) | intParsingError = "error parsing data"
function main (line 33) | func main() {
function handler (line 51) | func handler(ctx context.Context, e *common.TopicEvent) (retry bool, err...
function getEnvVar (line 71) | func getEnvVar(key, fallbackValue string) string {
FILE: http-echo-service/main.go
function main (line 18) | func main() {
function echoHandler (line 32) | func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *...
function getEnvVar (line 47) | func getEnvVar(key, fallbackValue string) string {
FILE: http-event-subscriber/main.go
function main (line 23) | func main() {
function eventHandler (line 44) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 55) | func getEnvVar(key, fallbackValue string) string {
FILE: order-cancellation/src/fn/ReceiveEvent.cs
class ReceiveTopicMessage (line 20) | public static class ReceiveTopicMessage
method Run (line 25) | [FunctionName("ReceiveTopicMessage")]
FILE: order-cancellation/src/viewer/main.go
function main (line 34) | func main() {
function wsHandler (line 74) | func wsHandler(w http.ResponseWriter, r *http.Request) {
function rootHandler (line 78) | func rootHandler(w http.ResponseWriter, r *http.Request) {
function faviconHandler (line 97) | func faviconHandler(w http.ResponseWriter, r *http.Request) {
function eventHandler (line 101) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 116) | func getEnvVar(key, fallbackValue string) string {
FILE: order-cancellation/src/viewer/resource/static/js/app.js
function appendLog (line 12) | function appendLog(item) {
FILE: pipeline/sentiment-scorer/main.go
constant languageDefault (line 21) | languageDefault = "en"
constant secretStoreName (line 22) | secretStoreName = "pipeline-secrets"
constant secretStoreKey (line 23) | secretStoreKey = "Azure:CognitiveAPIKey"
function main (line 36) | func main() {
function sentimentHandler (line 54) | func sentimentHandler(ctx context.Context, in *common.InvocationEvent) (...
type SentimentScore (line 80) | type SentimentScore struct
function getSentiment (line 85) | func getSentiment(ctx context.Context, lang, text string) (out *Sentimen...
function getEnvVar (line 170) | func getEnvVar(key, fallbackValue string) string {
function getSecret (line 177) | func getSecret(store, key string) string {
FILE: pipeline/tweet-processor/main.go
function main (line 32) | func main() {
function topicDataToSentimentRequest (line 59) | func topicDataToSentimentRequest(b []byte) (s *SentimentRequest, err err...
function getSentimentScore (line 77) | func getSentimentScore(ctx context.Context, req *SentimentRequest) (scor...
function tweetHandler (line 98) | func tweetHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
type TweetText (line 136) | type TweetText struct
type SentimentRequest (line 145) | type SentimentRequest struct
type SentimentScore (line 151) | type SentimentScore struct
function getEnvVar (line 156) | func getEnvVar(key, fallbackValue string) string {
FILE: pipeline/tweet-provider/main.go
function main (line 28) | func main() {
function tweetHandler (line 51) | func tweetHandler(ctx context.Context, in *common.BindingEvent) (out []b...
function getEnvVar (line 71) | func getEnvVar(key, fallbackValue string) string {
FILE: pipeline/tweet-viewer/main.go
function main (line 34) | func main() {
function wsHandler (line 74) | func wsHandler(w http.ResponseWriter, r *http.Request) {
function rootHandler (line 78) | func rootHandler(w http.ResponseWriter, r *http.Request) {
function faviconHandler (line 97) | func faviconHandler(w http.ResponseWriter, r *http.Request) {
function eventHandler (line 101) | func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool...
function getEnvVar (line 110) | func getEnvVar(key, fallbackValue string) string {
FILE: pipeline/tweet-viewer/resource/static/js/app.js
function appendLog (line 12) | function appendLog(item) {
FILE: state-change-handler/main.go
function main (line 24) | func main() {
function bindingHandler (line 51) | func bindingHandler(ctx context.Context, in *common.BindingEvent) (out [...
function getEnvVar (line 62) | func getEnvVar(key, fallbackValue string) string {
Condensed preview — 291 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,223K chars).
[
{
"path": ".gitignore",
"chars": 342,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# VS Code \nDebug\n\n# Test binary, built with `go tes"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2020 Mark Chmarny\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "README.md",
"chars": 3161,
"preview": "# Dapr demos\n\nCollection of personal [Dapr](https://dapr.io) demos.\n\n> Note, some of these demos require latest version "
},
{
"path": "apim-gateway/README.md",
"chars": 26545,
"preview": "# Dapr & Azure API Management Integration Demo\n\nDapr integration with [Azure API Management](https://azure.microsoft.com"
},
{
"path": "apim-gateway/apim/api.yaml",
"chars": 1112,
"preview": "openapi: 3.0.1\ninfo:\n title: dapr\n version: '1.0'\nservers:\n - url: http://dapr-apim-demo.azure-api.net\n - url: https"
},
{
"path": "apim-gateway/apim/policy-all.json",
"chars": 336,
"preview": "{\n \"properties\": {\n \"format\": \"xml\",\n \"value\": \"<policies><inbound><rate-limit-by-key calls=\\\"120\\\" renewal"
},
{
"path": "apim-gateway/apim/policy-echo.json",
"chars": 288,
"preview": "{\n \"properties\": {\n \"format\": \"xml\",\n \"value\": \"<policies><inbound><base /><set-backend-service backend-id="
},
{
"path": "apim-gateway/apim/policy-message.json",
"chars": 417,
"preview": "{\n \"properties\": {\n \"format\": \"xml\",\n \"value\": \"<policies><inbound><base /><publish-to-dapr topic=\\\"@(""
},
{
"path": "apim-gateway/apim/policy-save.json",
"chars": 693,
"preview": "{\n \"properties\": {\n \"format\": \"xml\",\n \"value\": \"<policies><inbound><base /><set-variable name=\\\"key\\\" value"
},
{
"path": "apim-gateway/k8s/binding.yaml",
"chars": 277,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: demo-binding\nspec:\n type: bindings.redis\n metadata:\n -"
},
{
"path": "apim-gateway/k8s/echo-service.yaml",
"chars": 789,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: echo-service\n labels:\n app: echo-service\n demo: dapr-apim\n"
},
{
"path": "apim-gateway/k8s/event-subscriber.yaml",
"chars": 837,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: event-subscriber\n labels:\n app: event-subscriber\n demo: da"
},
{
"path": "apim-gateway/k8s/gateway.yaml",
"chars": 1728,
"preview": "# NOTE: Before deploying to a production environment, please review the documentation -> https://aka.ms/self-hosted-gate"
},
{
"path": "apim-gateway/k8s/pubsub.yaml",
"chars": 320,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: demo-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "autoscaling-on-queue/README.md",
"chars": 7660,
"preview": "# Autoscaling Dapr service based on queue depth \n\nDapr, with its modular building-block approach, along with the 10+ dif"
},
{
"path": "autoscaling-on-queue/deployment/kafka-client.yaml",
"chars": 211,
"preview": "apiVersion: v1\nkind: Pod\nmetadata:\n name: kafka-client\nspec:\n containers:\n - name: kafka-client\n image: confluentinc"
},
{
"path": "autoscaling-on-queue/deployment/kafka-pubsub.yaml",
"chars": 348,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: autoscaling-pubsub\nspec:\n type: pubsub.kafka\n metadata:"
},
{
"path": "autoscaling-on-queue/deployment/keda-2.0.0-beta.yaml",
"chars": 453032,
"preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n labels:\n app.kubernetes.io/name: keda\n app.kubernetes.io/part-of: keda-"
},
{
"path": "autoscaling-on-queue/deployment/producer.yaml",
"chars": 991,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: autoscaling-producer\n labels:\n app: autoscaling-producer\nspec"
},
{
"path": "autoscaling-on-queue/deployment/subscriber-scaler.yaml",
"chars": 424,
"preview": "apiVersion: keda.sh/v1alpha1\nkind: ScaledObject\nmetadata:\n name: subscriber-scaler\nspec:\n scaleTargetRef:\n name: au"
},
{
"path": "autoscaling-on-queue/deployment/subscriber.yaml",
"chars": 843,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: autoscaling-subscriber\n labels:\n app: autoscaling-subscriber\n"
},
{
"path": "autoscaling-on-queue/producer/Dockerfile",
"chars": 281,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "autoscaling-on-queue/producer/Makefile",
"chars": 1012,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=autoscaling-producer\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help"
},
{
"path": "autoscaling-on-queue/producer/go.mod",
"chars": 358,
"preview": "module github.com/mchmarny/dapr-demos/autoscaling-on-queue/producer\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "autoscaling-on-queue/producer/go.sum",
"chars": 10521,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "autoscaling-on-queue/producer/main.go",
"chars": 4704,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strc"
},
{
"path": "autoscaling-on-queue/subscriber/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "autoscaling-on-queue/subscriber/Makefile",
"chars": 1980,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=autoscaling-subscriber\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: he"
},
{
"path": "autoscaling-on-queue/subscriber/go.mod",
"chars": 359,
"preview": "module github.com/mchmarny/dapr-demos/autoscaling-on-queue/subscriber\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11."
},
{
"path": "autoscaling-on-queue/subscriber/go.sum",
"chars": 10668,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "autoscaling-on-queue/subscriber/main.go",
"chars": 2703,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github"
},
{
"path": "component-api/README.md",
"chars": 5216,
"preview": "# Use of Dapr as a component API Server\n\nThis demo users Dapr instance with API token authentication to show the use of "
},
{
"path": "component-api/config/email.yaml",
"chars": 274,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: send-email\nspec:\n type: bindings.twilio.sendgrid\n metad"
},
{
"path": "component-api/config/state.yaml",
"chars": 295,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: note-store\nspec:\n type: state.redis\n metadata:\n - name"
},
{
"path": "component-api/config/twitter.yaml",
"chars": 511,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: query-twitter\nspec:\n type: bindings.twitter\n metadata:\n"
},
{
"path": "component-api/sample/email.json",
"chars": 172,
"preview": "{\n \"operation\": \"create\",\n \"metadata\": {\n \"emailTo\": \"daprdemo@chmarny.com\",\n \"subject\": \"Dapr Demo\""
},
{
"path": "component-api/sample/twitter.json",
"chars": 148,
"preview": "{\n \"operation\": \"get\",\n \"metadata\": {\n \"query\": \"dapr AND serverless\",\n \"lang\": \"en\",\n \"resul"
},
{
"path": "cron-binding/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "cron-binding/Makefile",
"chars": 1722,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=cron-binding-demo\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: help tidy build "
},
{
"path": "cron-binding/README.md",
"chars": 1727,
"preview": "# cron-binding\n\n## Binding\n\n```yaml\napiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: run\nspec:\n type: bin"
},
{
"path": "cron-binding/config/cron.yaml",
"chars": 148,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: run\nspec:\n type: bindings.cron\n metadata:\n - name: sch"
},
{
"path": "cron-binding/go.mod",
"chars": 100,
"preview": "module github.com/mchmarny/dapr-demos/cron-binding\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "cron-binding/go.sum",
"chars": 9715,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "cron-binding/k8s/component.yaml",
"chars": 181,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: schedule\nspec:\n type: bindings.cron\n metadata:\n - name"
},
{
"path": "cron-binding/k8s/deployment.yaml",
"chars": 769,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: cron-binding-demo\n labels:\n app: cron-binding-demo\n demo: "
},
{
"path": "cron-binding/main.go",
"chars": 1031,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd "
},
{
"path": "dapr-aci/README.md",
"chars": 4862,
"preview": "# Dapr sidecar in ACI\n\nDemo of Dapr sidecar in Azure Container Instances (ACI)\n\n## Setup \n\nThis demo illustrates simple "
},
{
"path": "dapr-aci/components/pubsub.yaml",
"chars": 280,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: pubsub\nspec:\n type: pubsub.azure.servicebus\n metadata:\n"
},
{
"path": "dapr-aci/components/state.yaml",
"chars": 250,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: store\nspec:\n type: state.azure.tablestorage\n metadata:\n"
},
{
"path": "dapr-aci/deployment/app.yaml",
"chars": 1447,
"preview": "apiVersion: 2018-06-01\nlocation: westus\nname: dapraci\nproperties:\n containers:\n - name: app\n properties:\n imag"
},
{
"path": "dapr-aci/src/Dockerfile",
"chars": 266,
"preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "dapr-aci/src/Makefile",
"chars": 1534,
"preview": "IMAGE_NAME ?=aci-app\nIMAGE_TAG ?=v0.2.2\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID ?=aci-app\nA"
},
{
"path": "dapr-aci/src/go.mod",
"chars": 378,
"preview": "module github.com/mchmarny/dapr-demos/dapr-aci/src\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/pkg/e"
},
{
"path": "dapr-aci/src/go.sum",
"chars": 12040,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "dapr-aci/src/main.go",
"chars": 2679,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\tdapr \"github.co"
},
{
"path": "dapr-api-on-aci/README.md",
"chars": 4048,
"preview": "# Dapr API in ACI\n\n* Purpose-configured instance of Dapr deployed into Azure Container Instances (ACI) with API token au"
},
{
"path": "dapr-api-on-aci/email.yaml",
"chars": 269,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: email\nspec:\n type: bindings.twilio.sendgrid\n metadata:\n"
},
{
"path": "daprized-ingress/README.md",
"chars": 6191,
"preview": "# Dapr API on Cluster Ingress Controller \n\nThis how to will walk through the process of configuring Dapr api on your clu"
},
{
"path": "daprized-ingress/config/ingress-annotations.yaml",
"chars": 269,
"preview": "controller:\n podAnnotations:\n dapr.io/enabled: \"true\"\n dapr.io/app-id: \"nginx-ingress\"\n dapr.io/app-protocol: "
},
{
"path": "daprized-ingress/config/ingress-config.yaml",
"chars": 366,
"preview": "---\napiVersion: dapr.io/v1alpha1\nkind: Configuration\nmetadata:\n name: ingress-config\nspec:\n tracing:\n samplingRate:"
},
{
"path": "daprized-ingress/config/ingress.yaml",
"chars": 372,
"preview": "apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: ingress-rules\n annotations:\n kubernetes.io/ingress.cl"
},
{
"path": "daprized-ingress/config/namespace.yml",
"chars": 381,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n name: secret-reader\nrules:\n- apiGroups: [\"\"]\n resources"
},
{
"path": "fan-out/README.md",
"chars": 6611,
"preview": "# fan-out demo \n\n`Fan-out` is a messaging pattern where single message source is \"broadcasted\" to multiple targets. The "
},
{
"path": "fan-out/grpc-echo-service/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "fan-out/grpc-echo-service/Makefile",
"chars": 1967,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=grpc-echo-service\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help\n\n."
},
{
"path": "fan-out/grpc-echo-service/README.md",
"chars": 1742,
"preview": "# grpc-service\n\nFor more information about service invocation see the [Dapr docs](https://github.com/dapr/docs/tree/mast"
},
{
"path": "fan-out/grpc-echo-service/deployment.yaml",
"chars": 804,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-echo-service\n labels:\n app: grpc-echo-service\n demo: "
},
{
"path": "fan-out/grpc-echo-service/go.mod",
"chars": 105,
"preview": "module github.com/mchmarny/dapr-demos/grpc-echo-service\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "fan-out/grpc-echo-service/go.sum",
"chars": 10027,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "fan-out/grpc-echo-service/main.go",
"chars": 1204,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
},
{
"path": "fan-out/http-format-converter/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "fan-out/http-format-converter/Makefile",
"chars": 1525,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=http-format-converter\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT =xml"
},
{
"path": "fan-out/http-format-converter/config/source-pubsub.yaml",
"chars": 206,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-source-pubsub\nspec:\n type: pubsub.redis\n metadat"
},
{
"path": "fan-out/http-format-converter/config/target-binding.yaml",
"chars": 222,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-http-target-post-binding\nspec:\n type: bindings.ht"
},
{
"path": "fan-out/http-format-converter/go.mod",
"chars": 152,
"preview": "module github.com/mchmarny/dapr-demos/fan-out/http-format-converter\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "fan-out/http-format-converter/go.sum",
"chars": 10027,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "fan-out/http-format-converter/k8s/components.yaml",
"chars": 343,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: grpc-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "fan-out/http-format-converter/k8s/deployment.yaml",
"chars": 909,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-event-subscriber\n labels:\n app: grpc-event-subscriber\n "
},
{
"path": "fan-out/http-format-converter/main.go",
"chars": 2919,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github"
},
{
"path": "fan-out/queue-event-consumer/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "fan-out/queue-event-consumer/Makefile",
"chars": 1465,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=queue-format-consumer\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT =xml"
},
{
"path": "fan-out/queue-event-consumer/config/source-pabusb.yaml",
"chars": 206,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-source-pubsub\nspec:\n type: pubsub.redis\n metadat"
},
{
"path": "fan-out/queue-event-consumer/go.mod",
"chars": 117,
"preview": "module github.com/mchmarny/dapr-demos/fan-out/queue-format-consumer\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "fan-out/queue-event-consumer/go.sum",
"chars": 10027,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "fan-out/queue-event-consumer/k8s/deployment.yaml",
"chars": 909,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-event-subscriber\n labels:\n app: grpc-event-subscriber\n "
},
{
"path": "fan-out/queue-event-consumer/k8s/target-kafka.yaml",
"chars": 247,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-queue-kafka-target\nspec:\n type: pubsub.kafka\n me"
},
{
"path": "fan-out/queue-event-consumer/k8s/target-redis.yaml",
"chars": 247,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-queue-kafka-target\nspec:\n type: pubsub.kafka\n me"
},
{
"path": "fan-out/queue-event-consumer/main.go",
"chars": 1191,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
},
{
"path": "fan-out/queue-event-producer/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "fan-out/queue-event-producer/Makefile",
"chars": 1471,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=queue-event-producer\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help"
},
{
"path": "fan-out/queue-event-producer/config/target-pabusb.yaml",
"chars": 206,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-source-pubsub\nspec:\n type: pubsub.redis\n metadat"
},
{
"path": "fan-out/queue-event-producer/go.mod",
"chars": 182,
"preview": "module github.com/mchmarny/dapr-demos/fan-out/queue-event-producer\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0\n\t"
},
{
"path": "fan-out/queue-event-producer/go.sum",
"chars": 10190,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "fan-out/queue-event-producer/k8s/deployment.yaml",
"chars": 909,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-event-subscriber\n labels:\n app: grpc-event-subscriber\n "
},
{
"path": "fan-out/queue-event-producer/k8s/target-kafka.yaml",
"chars": 247,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-queue-kafka-target\nspec:\n type: pubsub.kafka\n me"
},
{
"path": "fan-out/queue-event-producer/k8s/target-redis.yaml",
"chars": 247,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-queue-kafka-target\nspec:\n type: pubsub.kafka\n me"
},
{
"path": "fan-out/queue-event-producer/main.go",
"chars": 2373,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github.com/dapr/"
},
{
"path": "fan-out/queue-format-converter/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "fan-out/queue-format-converter/Makefile",
"chars": 1532,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=queue-format-converter\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT =xm"
},
{
"path": "fan-out/queue-format-converter/config/kafka.yaml",
"chars": 331,
"preview": "version: '2'\nservices:\n zookeeper:\n image: wurstmeister/zookeeper:latest\n ports:\n - \"2181:2181\"\n kafka:\n "
},
{
"path": "fan-out/queue-format-converter/config/source-pabusb.yaml",
"chars": 206,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-source-pubsub\nspec:\n type: pubsub.redis\n metadat"
},
{
"path": "fan-out/queue-format-converter/config/target-pubsub.yaml",
"chars": 218,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-target-pubsub\nspec:\n type: pubsub.kafka\n metadat"
},
{
"path": "fan-out/queue-format-converter/go.mod",
"chars": 153,
"preview": "module github.com/mchmarny/dapr-demos/fan-out/queue-format-converter\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.0"
},
{
"path": "fan-out/queue-format-converter/go.sum",
"chars": 10027,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "fan-out/queue-format-converter/k8s/deployment.yaml",
"chars": 909,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-event-subscriber\n labels:\n app: grpc-event-subscriber\n "
},
{
"path": "fan-out/queue-format-converter/k8s/target-kafka.yaml",
"chars": 247,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-queue-kafka-target\nspec:\n type: pubsub.kafka\n me"
},
{
"path": "fan-out/queue-format-converter/k8s/target-redis.yaml",
"chars": 247,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-queue-kafka-target\nspec:\n type: pubsub.kafka\n me"
},
{
"path": "fan-out/queue-format-converter/main.go",
"chars": 2789,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github"
},
{
"path": "fan-out/service-format-converter/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "fan-out/service-format-converter/Makefile",
"chars": 1660,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=service-format-converter\nDOCKER_USERNAME ?=$(DOCKER_USER)\nTARGET_FORMAT ="
},
{
"path": "fan-out/service-format-converter/config/source-pubsub.yaml",
"chars": 206,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: fanout-source-pubsub\nspec:\n type: pubsub.redis\n metadat"
},
{
"path": "fan-out/service-format-converter/go.mod",
"chars": 155,
"preview": "module github.com/mchmarny/dapr-demos/fan-out/service-format-converter\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11"
},
{
"path": "fan-out/service-format-converter/go.sum",
"chars": 10027,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "fan-out/service-format-converter/k8s/components.yaml",
"chars": 343,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: grpc-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "fan-out/service-format-converter/k8s/deployment.yaml",
"chars": 909,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-event-subscriber\n labels:\n app: grpc-event-subscriber\n "
},
{
"path": "fan-out/service-format-converter/main.go",
"chars": 2943,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github"
},
{
"path": "grpc-echo-service/Dockerfile",
"chars": 266,
"preview": "FROM golang:1.15.5 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "grpc-echo-service/Makefile",
"chars": 1792,
"preview": "RELEASE_VERSION =v1.0.1\nSERVICE_NAME ?=echo\nIMAGE_NAME ?=grpc-echo-service\nIMAGE_TAG ?=v0.1.4\nIMAGE_OWNER"
},
{
"path": "grpc-echo-service/README.md",
"chars": 2303,
"preview": "# grpc-service\n\nFor more information about service invocation see the [Dapr docs](https://github.com/dapr/docs/tree/mast"
},
{
"path": "grpc-echo-service/deployment/app.yaml",
"chars": 742,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: echo-service\n namespace: echo\n labels:\n app: echo-service\nsp"
},
{
"path": "grpc-echo-service/deployment/space.yaml",
"chars": 892,
"preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n name: echo\n---\napiVersion: dapr.io/v1alpha1\nkind: Configuration\nmetadata:\n n"
},
{
"path": "grpc-echo-service/go.mod",
"chars": 254,
"preview": "module github.com/mchmarny/dapr-demos/grpc-echo-service\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v1.0.0-rc-1\n\tgolang."
},
{
"path": "grpc-echo-service/go.sum",
"chars": 11542,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "grpc-echo-service/main.go",
"chars": 1204,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
},
{
"path": "grpc-event-subscriber/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "grpc-event-subscriber/Makefile",
"chars": 3005,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=grpc-event-subscriber\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: tidy test de"
},
{
"path": "grpc-event-subscriber/README.md",
"chars": 2121,
"preview": "# grpc-event-subscriber\n\n## Components\n\n```yaml\napiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: events\nsp"
},
{
"path": "grpc-event-subscriber/config/pubsub.yaml",
"chars": 197,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: grpc-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "grpc-event-subscriber/go.mod",
"chars": 109,
"preview": "module github.com/mchmarny/dapr-demos/grpc-event-subscriber\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "grpc-event-subscriber/go.sum",
"chars": 10027,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "grpc-event-subscriber/k8s/component.yaml",
"chars": 367,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: grpc-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "grpc-event-subscriber/k8s/deployment.yaml",
"chars": 909,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: grpc-event-subscriber\n labels:\n app: grpc-event-subscriber\n "
},
{
"path": "grpc-event-subscriber/main.go",
"chars": 1247,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
},
{
"path": "hardened/Makefile",
"chars": 1379,
"preview": ".PHONY: all\nall: help\n\n.PHONY: apply\napply: ## Applies all and restarts the apps \n\t# apply\n\tkubectl apply -f k8s/ -n har"
},
{
"path": "hardened/README.md",
"chars": 14048,
"preview": "# Hardening Dapr app demo \n\nIn addition to support for Kubernetes namespace isolation and Role-Based Access Control (RBA"
},
{
"path": "hardened/config/pubsub.yaml",
"chars": 346,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: pubsub\n namespace: hardened\nspec:\n type: pubsub.redis\n "
},
{
"path": "hardened/config/state.yaml",
"chars": 227,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: state\n namespace: hardened\nspec:\n type: state.redis\n m"
},
{
"path": "hardened/deployment/hardened/app1.yaml",
"chars": 1329,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app1\n namespace: hardened\n labels:\n app: app1\n demo: hard"
},
{
"path": "hardened/deployment/hardened/app2.yaml",
"chars": 1393,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app2\n namespace: hardened\n labels:\n app: app2\n demo: hard"
},
{
"path": "hardened/deployment/hardened/app3.yaml",
"chars": 1074,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app3\n namespace: hardened\n labels:\n app: app3\n demo: hard"
},
{
"path": "hardened/deployment/hardened/pubsub.yaml",
"chars": 422,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: pubsub\n namespace: hardened\nspec:\n type: pubsub.redis\n "
},
{
"path": "hardened/deployment/hardened/state.yaml",
"chars": 303,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: state\n namespace: hardened\nspec:\n type: state.redis\n m"
},
{
"path": "hardened/deployment/namespace/ns.yaml",
"chars": 57,
"preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n name: hardened"
},
{
"path": "hardened/deployment/namespace/role.yaml",
"chars": 425,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n name: secret-reader\n namespace: hardened\nrules:\n- apiGr"
},
{
"path": "hardened/deployment/namespace/trace.yaml",
"chars": 275,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: zipkin\n namespace: hardened\nspec:\n type: exporters.zipk"
},
{
"path": "hardened/deployment/simple/app1.yaml",
"chars": 760,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app1\n namespace: hardened\n labels:\n app: app1\n demo: hard"
},
{
"path": "hardened/deployment/simple/app2.yaml",
"chars": 813,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app2\n namespace: hardened\n labels:\n app: app2\n demo: hard"
},
{
"path": "hardened/deployment/simple/app3.yaml",
"chars": 760,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app3\n namespace: hardened\n labels:\n app: app3\n demo: hard"
},
{
"path": "hardened/deployment/simple/pubsub.yaml",
"chars": 290,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: pubsub\n namespace: hardened\nspec:\n type: pubsub.redis\n "
},
{
"path": "hardened/deployment/simple/state.yaml",
"chars": 303,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: state\n namespace: hardened\nspec:\n type: state.redis\n m"
},
{
"path": "hardened/src/app1/Dockerfile",
"chars": 266,
"preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "hardened/src/app1/Makefile",
"chars": 1145,
"preview": "IMAGE_NAME ?=hardened-app1\nIMAGE_TAG ?=v0.1.4\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID ?=app"
},
{
"path": "hardened/src/app1/go.mod",
"chars": 140,
"preview": "module github.com/mchmarny/dapr-demos/hardened/src/app1\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/"
},
{
"path": "hardened/src/app1/go.sum",
"chars": 11246,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "hardened/src/app1/main.go",
"chars": 2052,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tdapr \"github.com/dapr/go-sdk/client\"\n\t\"github"
},
{
"path": "hardened/src/app2/Dockerfile",
"chars": 266,
"preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "hardened/src/app2/Makefile",
"chars": 1133,
"preview": "IMAGE_NAME ?=hardened-app2\nIMAGE_TAG ?=v0.1.4\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID ?=app"
},
{
"path": "hardened/src/app2/go.mod",
"chars": 140,
"preview": "module github.com/mchmarny/dapr-demos/hardened/src/app2\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/"
},
{
"path": "hardened/src/app2/go.sum",
"chars": 11246,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "hardened/src/app2/main.go",
"chars": 3292,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\tdapr \"github.com/dapr/go-sdk/"
},
{
"path": "hardened/src/app3/Dockerfile",
"chars": 266,
"preview": "FROM golang:1.15.3 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "hardened/src/app3/Makefile",
"chars": 1133,
"preview": "IMAGE_NAME ?=hardened-app3\nIMAGE_TAG ?=v0.1.4\nIMAGE_OWNER ?=$(shell git config --get user.username)\nAPP_ID ?=app"
},
{
"path": "hardened/src/app3/go.mod",
"chars": 140,
"preview": "module github.com/mchmarny/dapr-demos/hardened/src/app3\n\ngo 1.15\n\nrequire (\n\tgithub.com/dapr/go-sdk v0.11.1\n\tgithub.com/"
},
{
"path": "hardened/src/app3/go.sum",
"chars": 11246,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "hardened/src/app3/main.go",
"chars": 1708,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/servi"
},
{
"path": "http-echo-service/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "http-echo-service/Makefile",
"chars": 1966,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=http-echo-service\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: all\nall: help\n\n."
},
{
"path": "http-echo-service/README.md",
"chars": 1741,
"preview": "# http-service\n\nFor more information about service invocation see the [Dapr docs](https://github.com/dapr/docs/tree/mast"
},
{
"path": "http-echo-service/deployment.yaml",
"chars": 801,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: http-echo-service\n labels:\n app: http-echo-service\n demo: "
},
{
"path": "http-echo-service/go.mod",
"chars": 105,
"preview": "module github.com/mchmarny/dapr-demos/http-echo-service\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "http-echo-service/go.sum",
"chars": 9638,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "http-echo-service/main.go",
"chars": 1126,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n\tdaprd \"github.com/d"
},
{
"path": "http-event-subscriber/Dockerfile",
"chars": 278,
"preview": "FROM golang:1.15.0 as builder\n\nWORKDIR /src/\nCOPY . /src/\n\nENV GO111MODULE=on\n\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64"
},
{
"path": "http-event-subscriber/Makefile",
"chars": 3224,
"preview": "RELEASE_VERSION =v0.11.1\nSERVICE_NAME ?=http-event-subscriber\nDOCKER_USERNAME ?=$(DOCKER_USER)\n\n.PHONY: tidy test de"
},
{
"path": "http-event-subscriber/README.md",
"chars": 2101,
"preview": "# dapr-event-subscriber-template\n\n## Components\n\n```yaml\napiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: "
},
{
"path": "http-event-subscriber/clooudevent.json",
"chars": 417,
"preview": "{\n \"specversion\" : \"1.0\",\n \"type\" : \"some.other.operation\",\n \"source\" : \"https://domain.com/cloudevents/operati"
},
{
"path": "http-event-subscriber/config/pubsub.yaml",
"chars": 198,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: http-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "http-event-subscriber/go.mod",
"chars": 109,
"preview": "module github.com/mchmarny/dapr-demos/http-event-subscriber\n\ngo 1.15\n\nrequire github.com/dapr/go-sdk v0.11.0\n"
},
{
"path": "http-event-subscriber/go.sum",
"chars": 9638,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
},
{
"path": "http-event-subscriber/k8s/component.yaml",
"chars": 367,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: http-events\nspec:\n type: pubsub.redis\n metadata:\n - na"
},
{
"path": "http-event-subscriber/k8s/deployment.yaml",
"chars": 919,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: http-event-subscriber\n labels:\n app: http-event-subscriber\n "
},
{
"path": "http-event-subscriber/main.go",
"chars": 1316,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/dapr/go-sdk/service/common\"\n"
},
{
"path": "order-cancellation/README.md",
"chars": 2944,
"preview": "# Dapr integrations demo\n\n> WIP: This demo is being currently updated to Dapr v1.0.0.rc-1\n\n## Use-case\n\nOrder cancellati"
},
{
"path": "order-cancellation/demo/Makefile",
"chars": 1330,
"preview": ".PHONY: help, workflowport, fnport, postmeta, postmail, postcancel, postgateway\nall: help\n\nworkflowport: ## Forwards Dap"
},
{
"path": "order-cancellation/demo/README.md",
"chars": 2726,
"preview": "# Dapr integrations demo setup\n\n> Note, this setup assumes Kubernetes cluster created using the [demo cluster setup inst"
},
{
"path": "order-cancellation/demo/component/audit-store.yaml",
"chars": 440,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: order-audit-store\n namespace: order\nspec:\n type: state."
},
{
"path": "order-cancellation/demo/component/email.yaml",
"chars": 284,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: order-email\n namespace: order\nspec:\n type: bindings.twi"
},
{
"path": "order-cancellation/demo/component/queue.yaml",
"chars": 343,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: order-queue\n namespace: order\nspec:\n type: pubsub.redis"
},
{
"path": "order-cancellation/demo/component/workflow-store.yaml",
"chars": 432,
"preview": "apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: order-store\n namespace: order\nspec:\n type: state.mongod"
},
{
"path": "order-cancellation/demo/config/order-cancel.json",
"chars": 3916,
"preview": "{\n \"definition\": {\n \"$schema\": \"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-"
},
{
"path": "order-cancellation/demo/data/cancellation.json",
"chars": 665,
"preview": "{\n \"id\": \"f727735e-b64e-11ea-b3de-0242ac130004\",\n \"note\": \"Customer made a mistake\",\n \"submitted_on\": \"2020-06-24T13:"
},
{
"path": "order-cancellation/demo/data/email.json",
"chars": 345,
"preview": "{\n \"operation\": \"create\",\n \"metadata\": {\n \"emailTo\": \"mchmarny@microsoft.com\",\n \"subject\": \"Order cancellation c"
},
{
"path": "order-cancellation/demo/data/meta.json",
"chars": 129,
"preview": "{\n \"id\": \"b76b547e-b64e-11ea-b3de-0242ac130004\",\n \"note\": \"Customer made a mistake\",\n \"submitted_on\": \"2020-06-24T13:"
},
{
"path": "order-cancellation/demo/deployment/auditor.yaml",
"chars": 873,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: order-auditor\n namespace: order\n labels:\n app: order-auditor"
},
{
"path": "order-cancellation/demo/deployment/ingress.yaml",
"chars": 471,
"preview": "apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: order-ingress-rules\n namespace: order\n annotations:\n "
},
{
"path": "order-cancellation/demo/deployment/space.yaml",
"chars": 898,
"preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n name: order\n---\napiVersion: dapr.io/v1alpha1\nkind: Configuration\nmetadata:\n "
},
{
"path": "order-cancellation/demo/deployment/viewer.yaml",
"chars": 1029,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: order-viewer\n namespace: order\n labels:\n app: order-viewer\ns"
},
{
"path": "order-cancellation/demo/deployment/workflow.yaml",
"chars": 1280,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: workflows-host\n namespace: order\n labels:\n app: workflows-ho"
},
{
"path": "order-cancellation/src/fn/.gitignore",
"chars": 96,
"preview": "# Build generated files in src\n/objd/**/*\n/obj/**/*\n/bin/**/*\n/gen/**/*\n/.vs/**/*\n/.vscode/**/*\n"
},
{
"path": "order-cancellation/src/fn/DaprAzFn.csproj",
"chars": 882,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <TargetFramework>netcoreapp3.0</TargetFramework>\n <AzureFunc"
}
]
// ... and 91 more files (download for full content)
About this extraction
This page contains the full source code of the mchmarny/dapr-demos GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 291 files (1.1 MB), approximately 318.3k tokens, and a symbol index with 126 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.