Take control of your Kubernetes resources
Deploy and view groups of Kubernetes resources as "applications". Apply changes safely and predictably, watching resources as they converge.
Try in Playground Download Binary
-
Lightweight
kapp is a CLI that does not require server-side components, elevated privileges nor any custom resources. It works well in RBAC-constrained clusters.
-
Explicit
kapp calculates changes between your configuration and live cluster state (a set of create, update, and delete operations) and applies changes you approve. It reports how resources are converging to their desired state providing insight into progress of the deployment.
-
Dependency-aware
kapp orders certain resources (e.g. CRDs and Namespaces are installed before the resources that need them). Add your own rules to declare dependencies (e.g. a Job running DB migrations must finish before the Deployment is updated).
Features
-
Sorts and waits as needed.
Deploys dependencies first (like CRDs and Namespaces) and supports custom change ordering.
Waits for resources to "reconcile."2:13:01PM: ---- waiting on 2 changes [0/2 done] ---- 2:13:01PM: ok: reconcile service/simple-app (v1) namespace: default 2:13:01PM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default 2:13:01PM: ^ Waiting for 1 unavailable replicas 2:13:01PM: L ok: waiting on replicaset/simple-app-7f9c78 (apps/v1) namespace: default 2:13:01PM: L ongoing: waiting on pod/simple-app-7f9c78-h7w (v1) namespace: default 2:13:01PM: ^ Pending: ContainerCreating
-
Plays well with others.
Focuses exclusively on deployment procedure and works equally well with configuration tools such as ytt, kustomize, helm template, and any other tool that can produce standard Kubernetes YAML configuration.
$ kapp deploy -a my-app -f <( ... config tool of your choice ... )
-
GitOps friendly
Include in your GitOps flow via CLI command or kapp-controller
$ kapp app-group deploy -g all-apps --directory .
Basic Usage
# Configurations picked up from a directory $ kapp deploy -a my-app -f ./examples/simple-app-example/config-1.yml # Can be used with helm charts, removing need for Tiller $ kapp -y deploy -a my-chart -f <(helm template my-chart --values my-vals.yml) # ... and with kustomize $ kapp -y deploy -a my-app -f <(kustomize build ./my-app) # ... or templated with ytt $ kapp -y deploy -a my-app -f <(ytt -f ./examples/simple-app-example/config-1.yml)
Playground and Example Workflow
You can follow along in Katacoda Kubernetes playground while going through below workflow. To set up playground:
- Open Katacoda Playground
- then, click "Start scenario" button
- focus in "Terminal Host 1" prompt
- and install
kapp
in playground before continuing with the workflow$ wget -O- https://get-kapp.io/install-katacoda.sh | bash $ cd kapp/ $ kapp version
And now onto using kapp
:
In this example, we are installing example app from kapp repository. Changes summary shows that all resources are new. |
$ kapp deploy -a app1 -f examples/simple-app-example/config-1.yml Target cluster 'https://x.x.x.x' (nodes: gke-dk-jan-9-pool-1-d01bcd06-bgie, 4+) Changes Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri default simple-app Deployment - - create - reconcile - - ^ simple-app Service - - create - reconcile - - Op: 2 create, 0 delete, 0 update, 0 noop Wait to: 2 reconcile, 0 delete, 0 noop |
Let's confirm to continue, and follow deployment progress. |
Continue? [yN]: y 2:12:59PM: ---- applying 2 changes [0/2 done] ---- 2:13:00PM: create service/simple-app (v1) namespace: default 2:13:01PM: create deployment/simple-app (apps/v1) namespace: default 2:13:01PM: ---- waiting on 2 changes [0/2 done] ---- 2:13:01PM: ok: reconcile service/simple-app (v1) namespace: default 2:13:01PM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default 2:13:01PM: ^ Waiting for 1 unavailable replicas 2:13:01PM: L ok: waiting on replicaset/simple-app-7f9c78ccd8 (apps/v1) namespace: default 2:13:01PM: L ongoing: waiting on pod/simple-app-7f9c78ccd8-h7wlc (v1) namespace: default 2:13:01PM: ^ Pending: ContainerCreating 2:13:01PM: ---- waiting on 1 changes [1/2 done] ---- 2:13:03PM: ok: reconcile deployment/simple-app (apps/v1) namespace: default 2:13:03PM: ---- applying complete [2/2 done] ---- 2:13:03PM: ---- waiting complete [2/2 done] ---- Succeeded |
ls command shows list of all apps stored in current namespace. Apps themselves can span multiple namespaces and cluster scope. |
$ kapp ls Target cluster 'https://x.x.x.x' (nodes: gke-dk-jan-9-pool-1-d01bcd06-bgie, 4+) Apps in namespace 'default' Name Namespaces Lcs Lca app1 default true 25s Lcs: Last Change Successful Lca: Last Change Age 1 apps Succeeded |
Now let's update from one app configuration to another using deploy command.Since --diff-changes is used, kapp will show detailed diff against versions of resources in the cluster.These first two resources will be created. |
$ kapp deploy -a app1 -f examples/simple-app-example/config-2.yml --diff-changes Target cluster 'https://x.x.x.x' (nodes: gke-dk-jan-9-pool-1-d01bcd06-bgie, 4+) @@ create service/simple-app-node (v1) namespace: default @@ 0 + apiVersion: v1 1 + kind: Service 2 + metadata: 3 + labels: 4 + kapp.k14s.io/app: "1594663909283037000" 5 + kapp.k14s.io/association: v1.6e43c1cd2c7173a969d84f77ad6a72c2 6 + name: simple-app-node 7 + namespace: default 8 + spec: 9 + ports: 10 + - nodePort: 31111 11 + port: 80 12 + targetPort: 80 13 + selector: 14 + kapp.k14s.io/app: "1594663909283037000" 15 + simple-app: "" 16 + type: NodePort 17 + @@ create configmap/simple-app (v1) namespace: default @@ 0 + apiVersion: v1 1 + data: 2 + hello_msg: friend 3 + kind: ConfigMap 4 + metadata: 5 + labels: 6 + kapp.k14s.io/app: "1594663909283037000" 7 + kapp.k14s.io/association: v1.afcdfc989e2a0b3f3e526dc1c4176060 8 + name: simple-app 9 + namespace: default 10 + |
This resource will be updated. |
@@ update deployment/simple-app (apps/v1) namespace: default @@ ... 29, 29 - name: HELLO_MSG 30 - value: stranger 30 + valueFrom: 31 + configMapKeyRef: 32 + key: hello_msg 33 + name: simple-app 31, 34 image: docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1f... 32, 35 name: simple-app |
This resource is will be deleted. |
@@ delete service/simple-app (v1) namespace: default @@
0 - apiVersion: v1
1 - kind: Service
2 - metadata:
3 - creationTimestamp: "2020-07-13T18:12:59Z"
4 - labels:
5 - kapp.k14s.io/app: "1594663909283037000"
6 - kapp.k14s.io/association: v1.462a95c01b2a0bdc4d5acadc4a22dd74
7 - name: simple-app
8 - namespace: default
9 - resourceVersion: "69009086"
10 - selfLink: /api/v1/namespaces/default/services/simple-app
11 - uid: 4e8bb148-2de4-46b3-a2e1-53dacbaaff34
12 - spec:
13 - clusterIP: 10.76.6.94
14 - ports:
15 - - port: 80
16 - targetPort: 80
17 - selector:
18 - kapp.k14s.io/app: "1594663909283037000"
19 - simple-app: ""
20 - status:
21 - loadBalancer: {}
22 -
|
Changes summary is presented before deploy will continue. There are only few changes in this example. |
Changes Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri default simple-app ConfigMap - - create - reconcile - - ^ simple-app Deployment 2/2 t 2m update - reconcile ok - ^ simple-app Service - 2m delete - delete ok - ^ simple-app-node Service - - create - reconcile - - Op: 2 create, 1 delete, 1 update, 0 noop Wait to: 3 reconcile, 1 delete, 0 noop |
Detailed progress log shows kapp waiting for associated resources to be ready. Readiness checks are specific to resource types. |
Continue? [yN]: 2:21:15PM: ---- applying 2 changes [0/4 done] ---- 2:21:15PM: delete service/simple-app (v1) namespace: default 2:21:15PM: create configmap/simple-app (v1) namespace: default 2:21:15PM: ---- waiting on 2 changes [0/4 done] ---- 2:21:15PM: ok: delete service/simple-app (v1) namespace: default 2:21:15PM: ok: reconcile configmap/simple-app (v1) namespace: default 2:21:15PM: ---- applying 2 changes [2/4 done] ---- 2:21:15PM: create service/simple-app-node (v1) namespace: default 2:21:17PM: update deployment/simple-app (apps/v1) namespace: default 2:21:17PM: ---- waiting on 2 changes [2/4 done] ---- 2:21:17PM: ok: reconcile service/simple-app-node (v1) namespace: default 2:21:17PM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default 2:21:17PM: ^ Waiting for 1 unavailable replicas 2:21:17PM: L ok: waiting on replicaset/simple-app-8558f78495 (apps/v1) namespace: default 2:21:17PM: L ok: waiting on replicaset/simple-app-7f9c78ccd8 (apps/v1) namespace: default 2:21:17PM: L ok: waiting on pod/simple-app-8558f78495-zqwxt (v1) namespace: default 2:21:17PM: L ongoing: waiting on pod/simple-app-7f9c78ccd8-h7wlc (v1) namespace: default 2:21:17PM: ^ Deleting 2:21:17PM: ---- waiting on 1 changes [3/4 done] ---- 2:21:18PM: ok: reconcile deployment/simple-app (apps/v1) namespace: default 2:21:18PM: ---- applying complete [4/4 done] ---- 2:21:18PM: ---- waiting complete [4/4 done] ---- Succeeded |
inspect command shows list of live objects associated with given app. --tree view optionally shows simple parent-child resource relationships. |
$ kapp inspect -a app1 --tree Target cluster 'https://x.x.x.x' (nodes: gke-dk-jan-9-pool-1-d01bcd06-bgie, 4+) Resources in app 'app' Namespace Name Kind Owner Conds. Rs Ri Age default simple-app Deployment kapp 2/2 t ok - 8m default L simple-app-7f9c78ccd8 ReplicaSet cluster - ok - 8m default L simple-app-8558f78495 ReplicaSet cluster - ok - 28s default L.. simple-app-8558f78495-zqwxt Pod cluster 4/4 t ok - 28s default simple-app-node Service kapp - ok - 28s default L simple-app-node Endpoints cluster - ok - 28s default simple-app ConfigMap kapp - ok - 28s Rs: Reconcile state Ri: Reconcile information 7 resources Succeeded |
logs command starts streaming logs from all Pods associated with given app. |
$ kapp logs -f -a app1 Target cluster 'https://x.x.x.x' (nodes: gke-dk-jan-9-pool-1-d01bcd06-bgie, 4+) # starting tailing 'simple-app-8558f78495-zqwxt > simple-app' logs simple-app-8558f78495-zqwxt > simple-app | 2020/07/13 18:21:16 Server started ^C |
delete command finds all resources in the cluster associated with given app, issues delete operation and waits for them be be deleted. |
$ kapp delete -a app1 Target cluster 'https://x.x.x.x' (nodes: gke-dk-jan-9-pool-1-d01bcd06-bgie, 4+) Changes Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri default simple-app ConfigMap - 1m delete - delete ok - ^ simple-app Deployment 2/2 t 10m delete - delete ok - ^ simple-app-7f9c78ccd8 ReplicaSet - 10m - - delete ok - ^ simple-app-8558f78495 ReplicaSet - 1m - - delete ok - ^ simple-app-8558f78495-zqwxt Pod 4/4 t 1m - - delete ok - ^ simple-app-8558f78495-zqwxt PodMetrics - 0s - - delete ok - ^ simple-app-node Endpoints - 1m - - delete ok - ^ simple-app-node Service - 1m delete - delete ok - Op: 0 create, 3 delete, 0 update, 5 noop Wait to: 0 reconcile, 8 delete, 0 noop Continue? [yN]: y 2:23:24PM: ---- applying 8 changes [0/8 done] ---- 2:23:24PM: noop endpoints/simple-app-node (v1) namespace: default 2:23:24PM: noop replicaset/simple-app-7f9c78ccd8 (apps/v1) namespace: default 2:23:24PM: noop pod/simple-app-8558f78495-zqwxt (v1) namespace: default 2:23:24PM: noop podmetrics/simple-app-8558f78495-zqwxt (metrics.k8s.io/v1beta1) namespace: default 2:23:24PM: noop replicaset/simple-app-8558f78495 (apps/v1) namespace: default 2:23:24PM: delete deployment/simple-app (apps/v1) namespace: default 2:23:24PM: delete service/simple-app-node (v1) namespace: default 2:23:24PM: delete configmap/simple-app (v1) namespace: default 2:23:24PM: ---- waiting on 8 changes [0/8 done] ---- 2:23:24PM: ongoing: delete replicaset/simple-app-7f9c78ccd8 (apps/v1) namespace: default 2:23:24PM: ok: delete endpoints/simple-app-node (v1) namespace: default 2:23:24PM: ok: delete configmap/simple-app (v1) namespace: default 2:23:24PM: ongoing: delete replicaset/simple-app-8558f78495 (apps/v1) namespace: default 2:23:24PM: ongoing: delete pod/simple-app-8558f78495-zqwxt (v1) namespace: default 2:23:24PM: ok: delete service/simple-app-node (v1) namespace: default 2:23:24PM: ok: delete deployment/simple-app (apps/v1) namespace: default 2:23:24PM: ongoing: delete podmetrics/simple-app-8558f78495-zqwxt (metrics.k8s.io/v1beta1) namespa... 2:23:24PM: ---- waiting on 4 changes [4/8 done] ---- 2:23:26PM: ok: delete replicaset/simple-app-8558f78495 (apps/v1) namespace: default 2:23:26PM: ok: delete replicaset/simple-app-7f9c78ccd8 (apps/v1) namespace: default 2:23:26PM: ---- waiting on 2 changes [6/8 done] ---- 2:23:27PM: ok: delete podmetrics/simple-app-8558f78495-zqwxt (metrics.k8s.io/v1beta1) namespace: d... 2:23:27PM: ok: delete pod/simple-app-8558f78495-zqwxt (v1) namespace: default 2:23:27PM: ---- applying complete [8/8 done] ---- 2:23:27PM: ---- waiting complete [8/8 done] ---- Succeeded |