which makes me wonder what the deployment labels are for.
Every label is just a way to refer to a collection of resources without knowing their names. However, as you pointed out, kubernetes itself uses labels in a couple of ways related to your question:
Deployments use labels for tracking the health and cardinality of their managed Pods (since the names of Pods are mostly random)
Services use labels for tracking the Pods in Ready state to which traffic should be sent
With Deployments, one also needs to exercise caution that the Deployment object itself has labels, but those are not related to the template: { metadata: { labels: {} } } that are stamped onto newly created Pods and those are the ones which must be a subset of the matchLabels: for a Deployment to manage them
Same story with the Service, which again can have its own labels but are unrelated to the labels it uses for Service membership. Be aware that while it is super common to have the labels in matchLabels: be the same as those in the Service's selector:, they otherwise have no relationship to one another
This is a perfectly fine setup, since the Deployment cares only about the Pods being awesome and the Service cares only about those Pods being v1, and both are fulfilled by newly spawned Pods from the Deployment because of the template's labels applied to them
kind: Deployment
spec:
...
matchLabels:
app: awesome
template:
metadata:
labels:
app: awesome
release: v1
---
kind: Service
spec:
selector:
release: v1