
In this post, i will help you to create a tanzu package from scratch, then add that package in a repository and finally install the package on a Tanzu Community Edition Standalone cluster using tanzu cli. I was really interested to understand this in detail because there was change in TKG v1.4 where all the extensions are not packaged as a package and installed using tanzu cli. Let’s get started.
Few Checks
NOTE:
If you are looking for a steps to create Tanzu Community Edition Standalone cluster on your laptop, Refer my earlier post: https://mappslearning.wordpress.com/2021/10/06/setting-up-tanzu-community-edition-tce-on-a-mac/
If you are looking to understand more about ytt, I think this is a very good tutorial https://ik.am/entries/544/en
If you are looking for a guided web based lab, you can refer https://katacoda.com/carvel/scenarios/kapp-controller-package-management
Install Carvel tools, You can run
wget -O- https://raw.githubusercontent.com/vmware-tanzu/carvel-kapp-controller/fc5458fe2102d67e85116c26534a35e265b28125/hack/install-deps.sh | bash
Once you have created a cluster, you will have following in place.
- Check the kapp controller pod status
$ k get po -n tkg-system
NAME READY STATUS RESTARTS AGE
kapp-controller-6499b8866-qdx4n 1/1 Running 0 15h
tanzu-capabilities-controller-manager-6ff97656b8-v2dpg 1/1 Running 0 15h
- Check the created CRD’s
$ kubectl api-resources --api-group packaging.carvel.dev
NAME SHORTNAMES APIGROUP NAMESPACED KIND
packageinstalls pkgi packaging.carvel.dev true PackageInstall
packagerepositories pkgr packaging.carvel.dev true PackageRepository
$ kubectl api-resources --api-group data.packaging.carvel.dev
NAME SHORTNAMES APIGROUP NAMESPACED KIND
packagemetadatas pkgm data.packaging.carvel.dev true PackageMetadata
packages pkg data.packaging.carvel.dev true Package
$ kubectl api-resources --api-group kappctrl.k14s.io
NAME SHORTNAMES APIGROUP NAMESPACED KIND
apps kappctrl.k14s.io true App
Package creation process
Creating a package is two step process:
- Creating a Package Content bundle
- Creating a Package Repository bundle
1. Creating a Package Content bundle
A package bundle is an imgpkg bundle that holds package contents such as Kubernetes YAML configuration, ytt templates etc.
- Create a kubernetes resource yaml file for POD and Service
$ cat > config.yml << EOF
#@ load("@ytt:data", "data")
#@ def labels():
simple-app: ""
#@ end
---
apiVersion: v1
kind: Service
metadata:
namespace: default
name: simple-app
spec:
ports:
- port: #@ data.values.svc_port
targetPort: #@ data.values.app_port
selector: #@ labels()
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: simple-app
spec:
selector:
matchLabels: #@ labels()
template:
metadata:
labels: #@ labels()
spec:
containers:
- name: simple-app
image: docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
env:
- name: HELLO_MSG
value: #@ data.values.hello_msg
EOF
- View the created file
$ ls
carvel-kapp config.yml
- Create a yaml file that will have variables and values
$ cat > values.yml <<- EOF
#@data/values
---
svc_port: 80
app_port: 80
hello_msg: stranger
EOF
- View the Created files
$ l
total 16
drwxr-xr-x 4 dinetrip staff 128B Oct 31 14:21 .
drwxr-xr-x+ 229 dinetrip staff 7.2K Oct 31 14:22 ..
-rw-r--r-- 1 dinetrip staff 711B Oct 31 14:21 config.yml
-rw-r--r-- 1 dinetrip staff 64B Oct 31 14:21 values.yml
- Create a required directory structure and copy the files
$ mkdir -p package-contents/config/
$ cp config.yml package-contents/config/config.yml
$ cp values.yml package-contents/config/values.yml
$ ls -l package-contents/config
total 16
-rw-r--r-- 1 dinetrip staff 711 Oct 31 14:22 config.yml
-rw-r--r-- 1 dinetrip staff 64 Oct 31 14:22 values.yml
- Locate the used images and update the images.yml file
$ kbld -f package-contents/config/ --imgpkg-lock-output package-contents/.imgpkg/images.yml
resolve | final: docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0 -> index.docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
---
simple-app: ""
---
apiVersion: v1
kind: Service
metadata:
name: simple-app
namespace: default
spec:
ports:
- port: null
targetPort: null
selector: null
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kbld.k14s.io/images: |
null
name: simple-app
namespace: default
spec:
selector:
matchLabels: null
template:
metadata:
labels: null
spec:
containers:
- env:
- name: HELLO_MSG
value: null
image: index.docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
name: simple-app
---
app_port: 80
hello_msg: stranger
svc_port: 80
Succeeded
- View the content of image.yml file
$ cat package-contents/.imgpkg/images.yml
---
apiVersion: imgpkg.carvel.dev/v1alpha1
images:
- annotations:
kbld.carvel.dev/id: docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
image: index.docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
kind: ImagesLock
-
Once these files have been added, our package contents bundle is ready to be pushed!
-
Push the content bundle to a nimage registry
$ imgpkg push -b dineshtripathi30/simple-app:1.0.0 -f package-contents/
dir: .
dir: .imgpkg
file: .imgpkg/images.yml
dir: config
file: config/config.yml
file: config/values.yml
Pushed 'index.docker.io/dineshtripathi30/simple-app@sha256:8b199051061fcfef126446e82ddcf024c3c014b150a7fd916b62fe246eb3798b'
Succeeded
- Now, The package content bundle is created and pushed to an image registry.
2. Creating a Package Repository bundle
A package repository bundle is an imgpkg bundle that holds PackageMetadata and Package CRs.
- Create a metadata.yml file
$ cat > metadata.yml << EOF
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: PackageMetadata
metadata:
# This will be the name of our package
name: simple-app.corp.com
spec:
displayName: "Simple App"
longDescription: "Simple app consisting of a k8s deployment and service"
shortDescription: "Simple app for demoing"
categories:
- demo
EOF
- Create a package CR
cat 1.0.0.yml
---
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
name: simple-app.corp.com.1.0.0
spec:
refName: simple-app.corp.com
version: 1.0.0
releaseNotes: |
Initial release of the simple app package
valuesSchema:
openAPIv3:
title: simple-app.corp.com values schema
examples:
- svc_port: 80
app_port: 80
hello_msg: stranger
properties:
svc_port:
type: integer
description: Port number for the service.
default: 80
examples:
- 80
app_port:
type: integer
description: Target port for the application.
default: 80
examples:
- 80
hello_msg:
type: string
description: Name used in hello message from app when app is pinged.
default: stranger
examples:
- stranger
template:
spec:
fetch:
- imgpkgBundle:
image: dineshtripathi30/simple-app:1.0.0
template:
- ytt:
paths:
- "config/"
- kbld:
paths:
- "-"
- ".imgpkg/images.yml"
deploy:
- kapp: {}
- Create the required package folder structure and copy the files
$ mkdir -p my-pkg-repo/.imgpkg my-pkg-repo/packages/simple-app.corp.com
$ cp 1.0.0.yml my-pkg-repo/packages/simple-app.corp.com
$ cp metadata.yml my-pkg-repo/packages/simple-app.corp.com
- Relocate the image and update image.yml file
$ kbld -f my-pkg-repo/packages/ --imgpkg-lock-output my-pkg-repo/.imgpkg/images.yml
resolve | final: dineshtripathi30/simple-app:1.0.0 -> index.docker.io/dineshtripathi30/simple-app@sha256:8b199051061fcfef126446e82ddcf024c3c014b150a7fd916b62fe246eb3798b
---
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
annotations:
kbld.k14s.io/images: |
- Metas:
- Tag: 1.0.0
Type: resolved
URL: dineshtripathi30/simple-app:1.0.0
URL: index.docker.io/dineshtripathi30/simple-app@sha256:8b199051061fcfef126446e82ddcf024c3c014b150a7fd916b62fe246eb3798b
name: simple-app.corp.com.1.0.0
spec:
refName: simple-app.corp.com
releaseNotes: |
Initial release of the simple app package
template:
spec:
deploy:
- kapp: {}
fetch:
- imgpkgBundle:
image: index.docker.io/dineshtripathi30/simple-app@sha256:8b199051061fcfef126446e82ddcf024c3c014b150a7fd916b62fe246eb3798b
template:
- ytt:
paths:
- config/
- kbld:
paths:
- '-'
- .imgpkg/images.yml
valuesSchema:
openAPIv3:
examples:
- app_port: 80
hello_msg: stranger
svc_port: 80
properties:
app_port:
default: 80
description: Target port for the application.
examples:
- 80
type: integer
hello_msg:
default: stranger
description: Name used in hello message from app when app is pinged.
examples:
- stranger
type: string
svc_port:
default: 80
description: Port number for the service.
examples:
- 80
type: integer
title: simple-app.corp.com values schema
version: 1.0.0
---
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: PackageMetadata
metadata:
name: simple-app.corp.com
spec:
categories:
- demo
displayName: Simple App
longDescription: Simple app consisting of a k8s deployment and service
shortDescription: Simple app for demoing
Succeeded
- Push the bundle in a container registry
$ imgpkg push -b ${REPO_HOST}/my-pkg-repo:1.0.0 -f my-pkg-repo
dir: .
dir: .imgpkg
file: .imgpkg/images.yml
dir: packages
dir: packages/simple-app.corp.com
file: packages/simple-app.corp.com/1.0.0.yml
file: packages/simple-app.corp.com/metadata.yml
Pushed 'index.docker.io/dineshtripathi30/my-pkg-repo@sha256:f876115b629c87b6735070f6f747631fb727d127c3fe2f3fcfd9d063919186ba'
Succeeded
- Now, We have created both artifacts and ready to install the package on a tanzu standalone cluster
Installing the newly created package
Add the package repository
$ tanzu package repository add simple-package-repository --url dineshtripathi30/my-pkg-repo:1.0.0 --namespace default
/ Adding package repository 'simple-package-repository'...
Added package repository 'simple-package-repository'
Install the package
$ tanzu package install simple-app --package-name simple-app.corp.com --version 1.0.0
/ Installing package 'simple-app.corp.com'
| Getting namespace 'default'
/ Getting package metadata for 'simple-app.corp.com'
| Creating service account 'simple-app-default-sa'
| Creating cluster admin role 'simple-app-default-cluster-role'
| Creating cluster role binding 'simple-app-default-cluster-rolebinding'
- Creating package resource
- Package install status: Reconciling
Added installed package 'simple-app' in namespace 'default'
Validating the created resources
$ k get po,svc
NAME READY STATUS RESTARTS AGE
pod/simple-app-cc8f98744-dfm4c 1/1 Running 0 9s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 100.64.0.1 <none> 443/TCP 21h
service/simple-app ClusterIP 100.66.92.86 <none> 80/TCP 9s
- Port forward the service to access it
$ k port-forward service/simple-app 30000:80
Forwarding from 127.0.0.1:30000 -> 80
Forwarding from [::1]:30000 -> 80
Handling connection for 30000
$ curl localhost:30000
<h1>Hello stranger!</h1>%
So, We have been able to install the newly created package. We can use same method and create any new package and install it.
Hey! This post could not be written any better! Reading through this post reminds me of my good old room mate! He always kept talking about this. I will forward this article to him. Pretty sure he will have a good read. Thank you for sharing!
LikeLike
Thank you
LikeLike