In this article, you’ll learn what Dapr contributes to a Kubernetes application and where its building blocks stop short of replacing application design. That distinction matters because cloud failures usually emerge at the seams between configuration, identity, networking, and operations.
TL;DR: Not as forgiving as I’d have liked …
I was a speaker at a meet-up in Manchester in late 2020. I spoke about Dapr, Keda and the NestJS Framework. My talk topic was on “Writing less code - let your architecture and abstractions help with your *-cases”. The * in the title is a wildcard for use/edge/corner.
My code examples can be found here (includes both docker compose & Kubernetes manifests) - https://github.com/garrardkitchen/meetup-nov20
Challenge #1
This took a little longer than I’d have liked!
I was using the internal DNS to resolve the port of my redis service. My Redis single instance was deployed via a deployment manifest, along with a LoadBalancer Service - purely to give me remote access.
I’d first create a secret, by typing:
$ kubectl create secret generic db-passwords --from-literal=redis-password='<password>'This is the deployment manifest:
apiVersion: v1
kind: Service
metadata:
name: redis-svc
namespace: meetup-dapr-demo
labels:
run: redis-svc
spec:
type: LoadBalancer
ports:
- port: 6379
targetPort: 6379
protocol: TCP
selector:
run: redis
---
apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1
kind: Deployment
metadata:
name: redis
namespace: meetup-dapr-demo
spec:
selector:
matchLabels:
run: redis
replicas: 1
template:
metadata:
labels:
run: redis
spec:
containers:
- name: cache
image: redis
args: ["redis-server", "--requirepass", $(PASSWORD) ]
env:
- name: PASSWORD
valueFrom:
secretKeyRef:
name: db-passwords
key: redis-password
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379This deployed correctly.
I then deployed my Dapr state store component:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: mystore
namespace: meetup-dapr-demo
spec:
type: state.redis
metadata:
- name: redisHost
value: redis.meetup-dapr-demo.svc.cluster.local:6379
- name: redisPassword
value: "********"However, I could not for the life of me give my application access to the state store!
$ dapr logs -a http-api -k -n meetup-dapr-demo
...
time="2020-11-06T09:47:02.218770653Z" level=error msg="process component mystore error, redis store: error connecting to redis at redis.meetup-dapr-demo.svc.cluster.local:6379: dial tcp: lookup redis.meetup-dapr-demo.svc.cluster.local on 10.0.0.10:53: no such host" app_id=http-api instance=http-api-6bc44f8957-q2lvn scope=dapr.runtime type=log ver=0.11.3Having trying every permutation known to non-gender-specific-person-entity I remembered I was kaing it available behind a service. So, I’d been using redis.meetup-dapr-demo.svc.cluster.local:6379 when I should have used redis-svc.meetup-dapr-demo.svc.cluster.local:6379.
Once I’d corrected my mistake, it connected without error.
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: mystore
namespace: meetup-dapr-demo
spec:
type: state.redis
metadata:
- name: redisHost
value: redis-svc.meetup-dapr-demo.svc.cluster.local:6379
- name: redisPassword
value: "********"Challenge #2
secrets!
You’re application is going to report something similar to this - NOAUTH Authentication required - if you’re Dapr is deployed to a different namespace to that of your application:
time="2020-11-06T11:19:06.985273661Z" level=error msg="process component mystore error, redis store: error connecting to redis at redis-svc.meetup-dapr-demo.svc.cluster.local:6379: NOAUTH Authentication required." app_id=http-api instance=http-api-7d49cf59d5-9blwf scope=dapr.runtime type=log ver=0.11.3To circumvent this, you must create a role and binding this to the default ServiceAccount. This role secret-reader allows a get of the secrets resource within the meetup-depr-demo namespace. An example manifest is here:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: meetup-dapr-demo
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dapr-secret-reader
namespace: meetup-dapr-demo
subjects:
- kind: ServiceAccount
name: default
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.ioOnce deployed, you’ll see something similar to this in your dapr logs:
time="2020-11-06T11:23:20.529658232Z" level=info msg="component loaded. name: mystore, type: state.redis" app_id=http-api instance=http-api-7d49cf59d5-kszdz scope=dapr.runtime type=log ver=0.11.3This post was created some time ago. Now, we’re using the Secrets Store CSI Driver to map Azure KeyVault secrets to containers running in our AKS clusters.
Ref: https://docs.microsoft.com/en-us/azure/aks/csi-secrets-store-driver
References
Closing thought
Dapr can standardise access to distributed-system capabilities, but it cannot decide which state belongs together or which failures the application must be prepared to own.