# Running kapp in a Dagger pipeline In this article we will explore how to leverage kapp in a Dagger pipeline. ### What is Dagger? Dagger is a portable devkit to build powerful CI/CD pipelines quickly and run them anywhere. Read more about Dagger [here](https://dagger.io/) ### Introducing kapp package for dagger If you want to see if the your kubernetes deployments are going smoothly in your dagger pipeline, we highly recommend trying out [kapp deploy](https://github.com/dagger/dagger/tree/main/pkg/universe.dagger.io/alpha/kubernetes/kapp). Below are the steps that one could use to add kapp to a dagger pipeline. ### The micro services demo project Leveraging the well known [microservices demo](https://github.com/GoogleCloudPlatform/microservices-demo) to create dagger plan to deploy. The cloned and updated project to run in a local kind cluster is present [here](https://github.com/renuy/microservices-demo). This project's deployment manifest(configuration) for kubernetes is available as ./release/kubernetes-manifests.yaml ### Build and run locally using dagger plan We need to have a dagger plan in place to deploy the application in the cluster. In this blog since the project is already created and build available as image, will extend the project using the dagger plan to deploy it to a kind cluster. #### Deploy.cue The dagger plan is written in cue allowing it to be simple and readable. Lets look at the anatomy of the plan. ``` yaml import ( "dagger.io/dagger" "universe.dagger.io/alpha/kubernetes/kapp" ) dagger.#Plan & { actions: test: { deploy: kapp.#Deploy & { app: "boutique" fs: client.filesystem."./".read.contents kubeConfig: client.commands.kc.stdout file: "./release/kubernetes-manifests.yaml" } ls: kapp.#List & { fs: client.filesystem."./".read.contents kubeConfig: client.commands.kc.stdout namespace: "default" } inspect: kapp.#Inspect & { app: "boutique" fs: client.filesystem."./".read.contents kubeConfig: client.commands.kc.stdout } delete: kapp.#Delete & { app: "boutique" fs: client.filesystem."./".read.contents kubeConfig: client.commands.kc.stdout } } client: { commands: kc: { name: "kubectl" args: ["config", "view", "--raw"] stdout: dagger.#Secret } filesystem: "./": read: { contents: dagger.#FS include: ["./release/kubernetes-manifests.yaml"] } } } ``` The plan itself consisits of action you would want to perform, in this case `test`, which has four sub-actions. We have supplied the required resources - kube-config and deployment manifest - via the client. The parameters needed to run the kapp commands have been made available in each of the commands. Try out the following command: ``` $dagger do --help $dagger do test --help Usage: dagger do test [flags] Options Available Actions: deploy ls inspect delete ``` Dagger will list out the actions available as defined by your plan. #### Dagger do In our case, we want to deploy the application locally using the dagger pipeline. To do the same use ``` $dagger do test deploy --log-format plain # output ➜ microservices-demo git:(main) ✗ dagger do test deploy --log-format plain 12:34PM INFO actions.test.deploy._image.build._dag."0"._pull | computing 12:34PM INFO client.commands.kc | computing 12:34PM INFO client.filesystem."./".read | computing 12:34PM INFO client.commands.kc | completed duration=100ms 12:34PM INFO client.filesystem."./".read | completed duration=100ms 12:34PM INFO actions.test.deploy._image.build._dag."0"._pull | completed duration=1.4s 12:34PM INFO actions.test.deploy._image.build._dag."1"._copy | computing 12:34PM INFO actions.test.deploy._image.build._dag."1"._copy | completed duration=0s 12:34PM INFO actions.test.deploy.container._exec | computing 12:34PM INFO actions.test.deploy.container._exec | #6 0.370 Target cluster 'https://127.0.0.1:58013' (nodes: kind-control-plane) 12:34PM INFO actions.test.deploy.container._exec | #6 0.512 12:34PM INFO actions.test.deploy.container._exec | #6 0.512 Changes 12:34PM INFO actions.test.deploy.container._exec | #6 0.512 12:34PM INFO actions.test.deploy.container._exec | #6 0.512 Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri 12:34PM INFO actions.test.deploy.container._exec | #6 0.513 default adservice Deployment - - create - reconcile - - 12:34PM INFO actions.test.deploy.container._exec | #6 0.513 ^ adservice Service - - create - reconcile - - 12:34PM INFO actions.test.deploy.container._exec | #6 0.513 ^ cartservice Deployment - - create - reconcile - - . . . 12:35PM INFO actions.test.deploy.container._exec | #6 67.39 7:05:49AM: ok: reconcile deployment/recommendationservice (apps/v1) namespace: default 12:35PM INFO actions.test.deploy.container._exec | #6 67.40 7:05:49AM: ---- waiting on 8 changes [16/24 done] ---- 12:35PM INFO actions.test.deploy.container._exec | #6 74.65 7:05:56AM: ok: reconcile deployment/redis-cart (apps/v1) namespace: default 12:35PM INFO actions.test.deploy.container._exec | #6 74.66 7:05:56AM: ---- waiting on 7 changes [17/24 done] ---- 12:36PM INFO actions.test.deploy.container._exec | #6 77.76 7:06:00AM: ok: reconcile deployment/adservice (apps/v1) namespace: default 12:36PM INFO actions.test.deploy.container._exec | #6 77.77 7:06:00AM: ok: reconcile deployment/currencyservice (apps/v1) namespace: default 12:36PM INFO actions.test.deploy.container._exec | #6 77.77 7:06:00AM: ---- waiting on 5 changes [19/24 done] ---- . . . 12:37PM INFO actions.test.deploy.container._exec | #6 150.7 7:07:13AM: ^ Waiting for 1 unavailable replicas 12:37PM INFO actions.test.deploy.container._exec | #6 150.7 7:07:13AM: L ok: waiting on replicaset/loadgenerator-64f67cd465 (apps/v1) namespace: default 12:37PM INFO actions.test.deploy.container._exec | #6 150.7 7:07:13AM: L ongoing: waiting on pod/loadgenerator-64f67cd465-lhp6l (v1) namespace: default 12:37PM INFO actions.test.deploy.container._exec | #6 150.7 7:07:13AM: ^ Pending: PodInitializing 12:37PM INFO actions.test.deploy.container._exec | #6 162.3 7:07:24AM: ok: reconcile deployment/loadgenerator (apps/v1) namespace: default 12:37PM INFO actions.test.deploy.container._exec | #6 162.3 7:07:24AM: ---- applying complete [24/24 done] ---- 12:37PM INFO actions.test.deploy.container._exec | #6 162.3 7:07:24AM: ---- waiting complete [24/24 done] ---- 12:37PM INFO actions.test.deploy.container._exec | completed duration=2m42.4s 12:37PM INFO actions.test.deploy.container._exec | #6 162.3 12:37PM INFO actions.test.deploy.container._exec | #6 162.3 Succeeded ``` Was happy to see the good old `Succeeded` as part of kapp deploy. Now on to next steps. Since this is a local deployment use port-forwarding to access the application ``` $ kubectl port-forward service/frontend-external 8081:80 ``` And thats it! Go ahead and access your application on http://localhost:8081/. #### Clean up Delete the boutique app locally, using dagger: ``` $ dagger do test deploy ``` Would like to hear of your use case on dagger and how kapp deploy helped you. Drop in your comments on the [Carvel slack channel](https://kubernetes.slack.com/archives/CH8KCCKA5)