Part of k14s.io: ytt | kbld | kapp | kwt

Features

  • Works with standard Kubernetes YAMLs
  • Focuses exclusively on deployment workflow, not packaging or templating
  • Converges application resources (creates, updates and/or deletes resources) in each deploy
    • based on comparison between provided files and live objects in the cluster
  • Separates calculation of changes (diff stage) from application of changes (apply stage)
  • Waits for resources to be "ready"
  • Creates CRDs and Namespaces first and supports custom change ordering
  • Works without admin privileges and does not depend on any custom CRDs
    • making it possible to use kapp as a regular user in a single namespace
  • Records application deployment history
  • Opt-in resource version management
    • for example, to trigger Deployment rollout when ConfigMap changes
  • Works with any group of labeled resources (kapp -a label:tier=web inspect -t)
  • Works without server side components
  • GitOps friendly (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

Try out kapp in Katacoda Kubernetes interactive playground or check out example workflow below:

Start Katacoda Playground

After launching playground, follow these steps to install kapp and example k8s app:

$ wget -O- https://get-kapp.io/install-katacoda.sh | bash
$ cd kapp/
$ kapp version
$ kapp deploy -a app1 -f examples/simple-app-example/config-1.yml
$ kapp inspect -a app1
$ kapp deploy -a app1 -f examples/simple-app-example/config-2.yml
$ kapp delete -a app1

Example Workflow

In this example, we are installing sample app from kapp repository.
$ kapp deploy -a app1 -f examples/simple-app-example/config-1.yml
Changes summary shows that all resources are new.
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.
$ kapp deploy -a app1 -f examples/simple-app-example/config-2.yml --diff-changes
This resource will be created.
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:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
 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) namespace: default
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: default
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