Microservices
score-compose
and score-k8s
11 minute read
Overview
In this example we will walk you through how you can deploy eleven containerized applications illustrating the OnlineBoutique demo, and this with both score-compose
and score-k8s
.
flowchart TD dns[DNS] --> frontend(frontend) subgraph Workloads loadgenerator(loadgenerator)-->frontend frontend-->recommendation(recommendation) frontend-->ad(ad) frontend-->shipping(shipping) frontend-->currency(currency) frontend-->checkout(checkout) frontend-->cart(cart) checkout-->cart checkout-->payment(payment) checkout-->email(email) checkout-->currency checkout-->productcatalog(productcatalog) recommendation-->productcatalog frontend-->productcatalog end cart-->redis[(Redis)]
Score files
We will describe each containerized application with its own Score file for each. The demo code can be found here.
Open your IDE and paste in the following score-frontend.yaml
file, which describes the frontend
containerized application exposed via a DNS that queries different other applications on each request:
apiVersion: score.dev/v1b1
metadata:
name: frontend
containers:
frontend:
image: .
livenessProbe:
httpGet:
path: /_healthz
port: 8080
httpHeaders:
- name: Cookie
value: shop_session-id=x-liveness-probe
readinessProbe:
httpGet:
path: /_healthz
port: 8080
httpHeaders:
- name: Cookie
value: shop_session-id=x-readiness-probe
variables:
AD_SERVICE_ADDR: "${resources.ad.name}:9555"
CART_SERVICE_ADDR: "${resources.cart.name}:7070"
CHECKOUT_SERVICE_ADDR: "${resources.checkout.name}:5050"
CURRENCY_SERVICE_ADDR: "${resources.currency.name}:7000"
ENABLE_PROFILER: "0"
PAYMENT_SERVICE_ADDR: "${resources.payment.name}:50051"
PORT: "8080"
PRODUCT_CATALOG_SERVICE_ADDR: "${resources.productcatalog.name}:3550"
RECOMMENDATION_SERVICE_ADDR: "${resources.recommendation.name}:8080"
SHIPPING_SERVICE_ADDR: "${resources.shipping.name}:50051"
SHOPPING_ASSISTANT_SERVICE_ADDR: "not-used-here:8080"
CYMBAL_BRANDING: "false"
FRONTEND_MESSAGE: ""
ENABLE_ASSISTANT: "false"
resources:
limits:
memory: "50Mi"
cpu: "50m"
requests:
memory: "30Mi"
cpu: "30m"
service:
ports:
http:
port: 8080
targetPort: 8080
resources:
dns:
type: dns
route:
type: route
params:
host: ${resources.dns.host}
path: /
port: 8080
ad:
type: service
cart:
type: service
checkout:
type: service
currency:
type: service
payment:
type: service
productcatalog:
type: service
recommendation:
type: service
shipping:
type: service
The following score-cart.yaml
file, which describes the cart
containerized application exposed via a DNS that queries different other applications on each request:
apiVersion: score.dev/v1b1
metadata:
name: cart
containers:
cart:
image: .
variables:
REDIS_ADDR: "${resources.redis-cart.host}:${resources.redis-cart.port},user=${resources.redis-cart.username},password=${resources.redis-cart.password}"
resources:
limits:
memory: "90Mi"
cpu: "220m"
requests:
memory: "70Mi"
cpu: "200m"
service:
ports:
grpc:
port: 7070
targetPort: 7070
resources:
redis-cart:
type: redis
Just two Score files have been illustrated above, you can grab the other Score files from this GitHub repository.
Deployment with score-compose
and score-k8s
From here, we will now see how to deploy this exact same Score files with either with score-compose
or with score-k8s
:
To begin, follow the installation instructions to install the latest version of score-compose
.
init
Initialize your current score-compose
workspace, run the following command in your terminal:
score-compose init --no-sample \
--provisioners https://raw.githubusercontent.com/score-spec/community-provisioners/refs/heads/main/service/score-compose/10-service.provisioners.yaml
The init
command will create the .score-compose
directory with the default resource provisioners available. We are also importing one external file to support the service
dependencies: service
provisioner.
You can see the resource provisioners available by running this command:
score-compose provisioners list
The Score files illustrated use four resource types: dns
, redis
, route
and service
.
+-------------------+-------+------------------+--------------------------------+--------------------------------+
| TYPE | CLASS | PARAMS | OUTPUTS | DESCRIPTION |
+-------------------+-------+------------------+--------------------------------+--------------------------------+
| dns | (any) | | host | Outputs a *.localhost domain |
| | | | | as the hostname |
+-------------------+-------+------------------+--------------------------------+--------------------------------+
| redis | (any) | | host, password, port, username | Provisions a dedicated Redis |
| | | | | instance. |
+-------------------+-------+------------------+--------------------------------+--------------------------------+
| route | (any) | host, path, port | | Provisions an Ingress route on |
| | | | | a shared Nginx instance |
+-------------------+-------+------------------+--------------------------------+--------------------------------+
| service | (any) | | name | Outputs the name of the |
| | | | | Workload dependency if |
| | | | | it exists in the list of |
| | | | | Workloads. |
+-------------------+-------+------------------+--------------------------------+--------------------------------+
generate
Convert the score-*.yaml
files into a runnable compose.yaml
, run the following commands in your terminal:
score-compose generate score-cart.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/cartservice:v0.10.3
score-compose generate score-currency.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/currencyservice:v0.10.3
score-compose generate score-payment.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/paymentservice:v0.10.3
score-compose generate score-email.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/emailservice:v0.10.3
score-compose generate score-productcatalog.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/productcatalogservice:v0.10.3
score-compose generate score-shipping.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/shippingservice:v0.10.3
score-compose generate score-ad.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/adservice:v0.10.3
score-compose generate score-recommendation.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/recommendationservice:v0.10.3
score-compose generate score-checkout.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/checkoutservice:v0.10.3
score-compose generate score-frontend.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/frontend:v0.10.3
score-compose generate score-loadgenerator.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/loadgenerator:v0.10.3
The generate
commands will add the input score-*.yaml
workloads with a particular container image to the .score-compose/state.yaml
state file and generate the output compose.yaml
.
If you want to build the container image when this compose.yaml
will be deployed, you can run these generate
commands with the --build
parameter instead:
score-compose generate score-frontend.yaml --build 'main={"context":".","tags":["frontend:local"]}'
See the generated compose.yaml
by running this command:
cat compose.yaml
If you make any modifications to the score-*.yaml
files, run score-compose generate score-*.yaml
to regenerate the output compose.yaml
.
resources
Get the information of the resources dependencies of the workloads, run the following command:
score-compose resources list
+-----------------------------------------------+--------------------------------+
| UID | OUTPUTS |
+-----------------------------------------------+--------------------------------+
| dns.default#frontend.dns | host |
+-----------------------------------------------+--------------------------------+
| redis.default#cart.redis-cart | host, password, port, username |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.cart | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.currency | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.email | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.payment | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.productcatalog | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.shipping | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.ad | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.cart | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.checkout | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.currency | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.payment | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.productcatalog | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.recommendation | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.shipping | name |
+-----------------------------------------------+--------------------------------+
| service.default#loadgenerator.frontend | name |
+-----------------------------------------------+--------------------------------+
| service.default#recommendation.productcatalog | name |
+-----------------------------------------------+--------------------------------+
| route.default#frontend.route | |
+-----------------------------------------------+--------------------------------+
At this stage, we can already see the value of the dns
resource generated of the frontend
workload:
score-compose resources get-outputs dns.default#frontend.dns --format '{{ .host }}'
dnsyh32qu.localhost
Same for the redis
resource of the cart
workload:
score-compose resources get-outputs redis.default#cart.redis-cart
{
"host": "redis-NYOMHD",
"password": "REDACTED",
"port": 6379,
"username": "REDACTED"
}
docker compose
Run docker compose up
to execute the generated compose.yaml
file:
docker compose up -d
[+] Running 16/16
✔ Network ob_default Created
✔ Volume "redis-NYOMHD-data" Created
✔ Container ob-redis-NYOMHD-1 Started
✔ Container ob-routing-K7ZrCr-1 Started
✔ Container ob-wait-for-resources-1 Exited
✔ Container ob-checkout-checkout-1 Started
✔ Container ob-email-email-1 Started
✔ Container ob-currency-currency-1 Started
✔ Container ob-frontend-frontend-1 Started
✔ Container ob-recommendation-recommendation-1 Started
✔ Container ob-productcatalog-productcatalog-1 Started
✔ Container ob-shipping-shipping-1 Started
✔ Container ob-cart-cart-1 Started
✔ Container ob-ad-ad-1 Started
✔ Container ob-payment-payment-1 Started
✔ Container ob-loadgenerator-loadgenerator-1 Started
docker ps
See the running containers:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2420e4a5b044 us-central1-docker.pkg.dev/google-samples/microservices-demo/frontend:v0.10.3 "/src/server" 9 minutes ago 9 minutes ago 8080/tcp ob-frontend-frontend-1
0c8705f6571a us-central1-docker.pkg.dev/google-samples/microservices-demo/adservice:v0.10.3 "/app/build/install/…" 9 minutes ago Up 9 minutes 9555/tcp ob-ad-ad-1
0d72556cc169 us-central1-docker.pkg.dev/google-samples/microservices-demo/loadgenerator:v0.10.3 "/bin/sh -c 'locust …" 9 minutes ago Up 9 minutes ob-loadgenerator-loadgenerator-1
8c72e85b4c66 us-central1-docker.pkg.dev/google-samples/microservices-demo/checkoutservice:v0.10.3 "/src/checkoutservice" 9 minutes ago Up 9 minutes 5050/tcp ob-checkout-checkout-1
2dd9df6fa024 us-central1-docker.pkg.dev/google-samples/microservices-demo/productcatalogservice:v0.10.3 "/src/server" 9 minutes ago Up 9 minutes 3550/tcp ob-productcatalog-productcatalog-1
a6d0ebc3aab2 us-central1-docker.pkg.dev/google-samples/microservices-demo/paymentservice:v0.10.3 "node index.js" 9 minutes ago Up 9 minutes 50051/tcp ob-payment-payment-1
e2511187e454 us-central1-docker.pkg.dev/google-samples/microservices-demo/recommendationservice:v0.10.3 "python recommendati…" 9 minutes ago Up 9 minutes 8080/tcp ob-recommendation-recommendation-1
a4156abacd40 us-central1-docker.pkg.dev/google-samples/microservices-demo/cartservice:v0.10.3 "/app/cartservice" 9 minutes ago Up 9 minutes 7070/tcp ob-cart-cart-1
2379e57ac8ca us-central1-docker.pkg.dev/google-samples/microservices-demo/currencyservice:v0.10.3 "node server.js" 9 minutes ago Up 9 minutes 7000/tcp ob-currency-currency-1
81efe5bcde69 us-central1-docker.pkg.dev/google-samples/microservices-demo/emailservice:v0.10.3 "python email_server…" 9 minutes ago Up 9 minutes 8080/tcp ob-email-email-1
d83a61963aa6 us-central1-docker.pkg.dev/google-samples/microservices-demo/shippingservice:v0.10.3 "/src/shippingservice" 9 minutes ago Up 9 minutes 50051/tcp ob-shipping-shipping-1
ed5f79d80259 mirror.gcr.io/redis:7-alpine "redis-server /usr/l…" 9 minutes ago Up 9 minutes 6379/tcp ob-redis-NYOMHD-1
6ee7b587922f mirror.gcr.io/nginx:1-alpine "/docker-entrypoint.…" 9 minutes ago Up 9 minutes 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp ob-routing-K7ZrCr-1
curl localhost:8080
Test the running frontend
container, run the following command:
curl localhost:8080 -H "Host: dnsyh32qu.localhost"
Congrats! You’ve successfully deploy, with the score-compose
implementation, the eleven containerized workload exposed via a DNS and talking to a redis
database. You provisioned them through Docker, without writing the Docker Compose file by yourself.
To begin, follow the installation instructions to install the latest version of score-k8s
.
init
Initialize your current score-k8s
workspace, run the following command in your terminal:
score-k8s init --no-sample \
--provisioners https://raw.githubusercontent.com/score-spec/community-provisioners/refs/heads/main/service/score-compose/10-service.provisioners.yaml
The init
command will create the .score-k8s
directory with the default resource provisioners available. We are also importing one external file to support the service
dependencies: service
provisioner.
You can see the resource provisioners available by running this command:
score-k8s provisioners list
The Score files illustrated use three resource types: dns
, route
, redis
and service
.
+------------------+-------+------------------+--------------------------------+---------------------------------+
| TYPE | CLASS | PARAMS | OUTPUTS | DESCRIPTION |
+------------------+-------+------------------+--------------------------------+---------------------------------+
| dns | (any) | | host | Outputs a *.localhost domain |
| | | | | as the hostname |
+------------------+-------+------------------+--------------------------------+---------------------------------+
| route | (any) | host, path, port | | Provisions an Ingress route on |
| | | | | a shared Nginx instance |
+------------------+-------+------------------+--------------------------------+---------------------------------+
| redis | (any) | | host, password, port, username | Provisions a dedicated redis |
| | | | | instance |
+------------------+-------+------------------+--------------------------------+---------------------------------+
| service | (any) | | name | Outputs the name of the |
| | | | | Workload dependency if |
| | | | | it exists in the list of |
| | | | | Workloads. |
+------------------+-------+------------------+--------------------------------+---------------------------------+
generate
Convert the score-*.yaml
files into a runnable manifests.yaml
, run the following command in your terminal:
score-k8s generate score-cart.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/cartservice:v0.10.3
score-k8s generate score-currency.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/currencyservice:v0.10.3
score-k8s generate score-payment.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/paymentservice:v0.10.3
score-k8s generate score-email.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/emailservice:v0.10.3
score-k8s generate score-productcatalog.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/productcatalogservice:v0.10.3
score-k8s generate score-shipping.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/shippingservice:v0.10.3
score-k8s generate score-ad.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/adservice:v0.10.3
score-k8s generate score-recommendation.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/recommendationservice:v0.10.3
score-k8s generate score-checkout.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/checkoutservice:v0.10.3
score-k8s generate score-frontend.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/frontend:v0.10.3
score-k8s generate score-loadgenerator.yaml \
--image us-central1-docker.pkg.dev/google-samples/microservices-demo/loadgenerator:v0.10.3
The generate
command will add the input score-*.yaml
workloads with a particular container image to the .score-k8s/state.yaml
state file and generate the output manifests.yaml
.
See the generated manifests.yaml
by running this command:
cat manifests.yaml
If you make any modifications to the score.yaml
file, run score-k8s generate score.yaml
to regenerate the output manifests.yaml
.
resources
Get the information of the resources dependencies of the workload, run the following command:
score-k8s resources list
+-----------------------------------------------+--------------------------------+
| UID | OUTPUTS |
+-----------------------------------------------+--------------------------------+
| dns.default#frontend.dns | host |
+-----------------------------------------------+--------------------------------+
| redis.default#cart.redis-cart | host, password, port, username |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.cart | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.currency | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.email | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.payment | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.productcatalog | name |
+-----------------------------------------------+--------------------------------+
| service.default#checkout.shipping | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.ad | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.cart | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.checkout | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.currency | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.payment | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.productcatalog | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.recommendation | name |
+-----------------------------------------------+--------------------------------+
| service.default#frontend.shipping | name |
+-----------------------------------------------+--------------------------------+
| service.default#loadgenerator.frontend | name |
+-----------------------------------------------+--------------------------------+
| service.default#recommendation.productcatalog | name |
+-----------------------------------------------+--------------------------------+
| route.default#frontend.route | |
+-----------------------------------------------+--------------------------------+
At this stage, we can already see the value of the dns
resource generated for the frontend
workload:
score-k8s resources get-outputs dns.default#frontend.dns --format '{{ .host }}'
dnsjbzrxg.localhost
Same for the redis
resource of the cart
workload:
score-k8s resources get-outputs redis.default#cart.redis-cart
{
"host": "redis-cart-deeb231e",
"password": "🔐💬redis-cart-deeb231e_password💬🔐",
"port": 6379,
"username": "REDACTED"
}
kubectl apply
Here you will need to have access to a Kubernetes cluster to execute the following commands. You can follow these instructions if you want to set up a Kind cluster.
Run kubectl apply
to execute the generated manifests.yaml
file:
kubectl apply -f manifests.yaml
secret/redis-cart-deeb231e created
statefulset.apps/redis-cart-deeb231e created
service/redis-cart-deeb231e created
httproute.gateway.networking.k8s.io/route-frontend-baaed48f created
service/payment created
deployment.apps/payment created
deployment.apps/loadgenerator created
service/cart created
deployment.apps/cart created
service/currency created
deployment.apps/currency created
service/productcatalog created
deployment.apps/productcatalog created
service/shipping created
deployment.apps/shipping created
service/email created
deployment.apps/email created
service/frontend created
deployment.apps/frontend created
service/recommendation created
deployment.apps/recommendation created
service/ad created
deployment.apps/ad created
service/checkout created
deployment.apps/checkout created
kubectl get all
See the running containers:
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/ad-dc7944975-bj8w4 1/1 Running 0 119s
pod/cart-798bd7698-264pg 1/1 Running 0 2m1s
pod/checkout-744f8dcfb-7g56m 1/1 Running 0 118s
pod/currency-784446ffff-zwwmk 1/1 Running 0 2m1s
pod/email-65fc89df67-c28s8 1/1 Running 0 2m
pod/frontend-6d767bc76c-lm48h 1/1 Running 0 2m
pod/loadgenerator-687f78699b-xv9lr 1/1 Running 0 2m1s
pod/payment-64f96b95dc-zg5bz 1/1 Running 0 2m1s
pod/productcatalog-7889b57645-kz7ng 1/1 Running 0 2m
pod/recommendation-5c9fb7b8cd-lwd4v 1/1 Running 0 119s
pod/redis-cart-deeb231e-0 1/1 Running 0 2m1s
pod/shipping-5cccdb6547-kwdwf 1/1 Running 0 2m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ad ClusterIP 10.96.73.134 <none> 9555/TCP 119s
service/cart ClusterIP 10.96.157.103 <none> 7070/TCP 2m1s
service/checkout ClusterIP 10.96.44.132 <none> 5050/TCP 119s
service/currency ClusterIP 10.96.241.104 <none> 7000/TCP 2m1s
service/email ClusterIP 10.96.160.93 <none> 5000/TCP 2m
service/frontend ClusterIP 10.96.241.155 <none> 8080/TCP 2m
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d22h
service/payment ClusterIP 10.96.226.73 <none> 50051/TCP 2m1s
service/productcatalog ClusterIP 10.96.242.16 <none> 3550/TCP 2m1s
service/recommendation ClusterIP 10.96.63.169 <none> 8080/TCP 2m
service/redis-cart-deeb231e ClusterIP 10.96.128.79 <none> 6379/TCP 2m1s
service/shipping ClusterIP 10.96.198.168 <none> 50051/TCP 2m1s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ad 1/1 1 1 119s
deployment.apps/cart 1/1 1 1 2m1s
deployment.apps/checkout 1/1 1 1 119s
deployment.apps/currency 1/1 1 1 2m1s
deployment.apps/email 1/1 1 1 2m
deployment.apps/frontend 1/1 1 1 2m
deployment.apps/loadgenerator 1/1 1 1 2m1s
deployment.apps/payment 1/1 1 1 2m1s
deployment.apps/productcatalog 1/1 1 1 2m1s
deployment.apps/recommendation 1/1 1 1 2m
deployment.apps/shipping 1/1 1 1 2m
NAME DESIRED CURRENT READY AGE
replicaset.apps/ad-dc7944975 1 1 1 119s
replicaset.apps/cart-798bd7698 1 1 1 2m1s
replicaset.apps/checkout-744f8dcfb 1 1 1 119s
replicaset.apps/currency-784446ffff 1 1 1 2m1s
replicaset.apps/email-65fc89df67 1 1 1 2m
replicaset.apps/frontend-6d767bc76c 1 1 1 2m
replicaset.apps/loadgenerator-687f78699b 1 1 1 2m1s
replicaset.apps/payment-64f96b95dc 1 1 1 2m1s
replicaset.apps/productcatalog-7889b57645 1 1 1 2m1s
replicaset.apps/recommendation-5c9fb7b8cd 1 1 1 2m
replicaset.apps/shipping-5cccdb6547 1 1 1 2m
NAME READY AGE
statefulset.apps/redis-cart-deeb231e 1/1 2m1s
curl localhost
Test the running container, run the following command:
curl localhost -H "Host: dnsjbzrxg.localhost"
Congrats! You’ve successfully deploy, with the score-k8s
implementation, a sample NodeJS containerized workload talking to a Dapr StateStore (Redis) and exposed via a DNS. You provisioned them through kubectl
, without writing the Kubernetes manifests file by yourself.
Next steps
- Explore more examples: Check out more examples to dive into further use cases and experiment with different configurations.
- Join the Score community: Connect with fellow Score developers on our CNCF Slack channel or start find your way to contribute to Score.