Skip to content
vWorld
Menu
  • Main Page
  • About
  • Study Guide
    • VCAP-CMA Deploy 2018
Menu

From Code to Kubernetes Cluster with Chiselled Ubuntu Images on VMware

Posted on September 29, 2025September 29, 2025 by admin

The strategic partnership announced at VMware Explore, joining the forces of VMware by Broadcom and Canonical, opens a new chapter in building and deploying applications in private clouds. The combination of the leading VMware Cloud Foundation (VCF) platform with the most popular cloud operating system, Ubuntu, brings powerful tools to developers and administrators.

The main hero of this collaboration is Chiselled Ubuntu images. In this article, I will guide you through the entire lifecycle of a modern application, from preparing the environment to building and comparing a “chiselled” image with a traditional one, and finally to its deployment and launch as a service on a VMware Tanzu Kubernetes cluster.

Step 1: Preparing the Environment — The Common Foundation

Before you start creating, ensure that your development environment (e.g., an Ubuntu VM) has all the necessary tools.

1.1. Installing Rockcraft

Rockcraft is a tool from Canonical for building OCI images and snap packages. It is the key to creating “chiselled” images.

sudo snap install rockcraft --classic

1.2. Installing and Configuring the Docker Engine

I will use Docker to test, tag, and push the images to a registry.


sudo apt-get update
sudo apt-get install ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

sudo usermod -aG docker $USER

Important: After running usermod, you must log out and log back in, or run newgrp docker for the permission changes to take effect.

Step 2: Building the Images — A Comparative Approach

I will create two images with Python: one “chiselled” and one “traditional,” to show you the tangible difference.

2.1. The “Chiselled” Image

In a directory named python-chiselled, create a file rockcraft.yaml. In it, I will define only the absolute minimum necessary packages.

name: python-chiselled
base: bare
build-base: ubuntu@24.04
version: '3.12'
summary: Chiselled Python container, based on Ubuntu
description: Example of a python container in Ubuntu.
platforms:
  amd64:

parts:
  install-python:
    plugin: nil
    stage-packages:
      - base-files_release-info
      - python3_core

2.2. The “Traditional” (Fat) Image

In a directory named python-fat, create a rockcraft.yaml file with standard dependencies, which pull in many additional packages.

name: python-fat
base: ubuntu@24.04
version: '3.12'
summary: Full Python container, based on Ubuntu
description: This is our image's description.
platforms:
  amd64:

parts:
  my-part:
    plugin: nil
    stage-packages:
      - base-files
      - python3

2.3. Building Both Images

In each of the directories above, run the build command:

rockcraft pack

Step 3: Importing, Running, and Comparing the Images

3.1. Importing into Docker

Use skopeo (integrated with rockcraft) to import the built .rock images into the local Docker daemon.

# Import the "chiselled" image
rockcraft.skopeo copy oci-archive:../python-chiselled/python-chiselled_3.12_amd64.rock docker-daemon:python-chiselled:3.12

# Import the "traditional" image
rockcraft.skopeo copy oci-archive:../python-fat/python-fat_3.12_amd64.rock docker-daemon:python-fat:3.12

3.2. Comparing Size and Content

Compare the size of both images:

docker images "python-*"

The difference will be striking: ~14MB for the chiselled image compared to ~125MB for the traditional one.

Step 4: Pushing the Chiselled Image to VMware Harbor

Now, I will deploy the better, more secure solution to my central registry.

4.1. Configuring Access to the Private Registry (The Secure Method with a Certificate)

For Docker to securely communicate with your private Harbor registry via HTTPS, it must trust the certificate that secures the Harbor registry. Instead of marking the registry as “insecure,” I will instruct Docker to trust the root certificate (CA) that signed your Harbor’s certificate.

Requirements:
You need the Harbor instance’s root CA certificate. As shown in the screenshot you provided, this can be downloaded directly from the Harbor user interface.

Step 1: Download the Registry Root Certificate from Harbor

  1. Log in to your Harbor UI with an administrator account.
  2. In the left-hand navigation pane, go to Administration -> Configuration.
  3. Ensure you are on the System Settings tab.
  4. Locate the Registry Root Certificate option.
  5. Click the Download link to save the certificate file. It will likely be named ca.crt.

This is the certificate that your Docker client needs to trust.

Step 1: Create a dedicated directory for the Harbor certificate

Docker automatically looks for certificates in directories whose names match the registry’s hostname.

sudo mkdir -p /etc/docker/certs.d/vcf-hbr.vcf.vworld.lab
  • Explanation: The directory name vcf-hbr.vcf.vworld.lab must exactly match your Harbor registry’s address.

Step 2: Copy the CA certificate to the created directory

Copy the CA certificate file into the newly created folder. Docker will automatically recognize it when attempting to connect.


sudo cp ca.crt /etc/docker/certs.d/vcf-hbr.vcf.vworld.lab/ca.crt

Step 3: Restart the Docker service

For Docker to load the new certificate configuration, you must restart its service.

sudo systemctl restart docker

After completing these steps, the Docker daemon will trust your Harbor registry. The connection will be fully encrypted and verified.

4.2. Tagging, Authenticating, and Pushing

Now that the connection is trusted, the rest of the process remains the same.

# 1. Tag the image to match the registry's naming scheme
docker tag python-chiselled:3.12 vcf-hbr.vcf.vworld.lab/library/python-chiselled:3.12

# 2. Log in to the Harbor registry 
docker login vcf-hbr.vcf.vworld.lab

# 3. Push the image
docker push vcf-hbr.vcf.vworld.lab/library/python-chiselled:3.12

4.3. Harbor View: A Side-by-Side Comparison

After pushing the python-chiselled image, I did the same for the traditional python-fat (shown as python-full in the Harbor UI) image so I could compare them directly within the VMware Harbor registry. The results are a powerful demonstration of the benefits of chiselled images.

Looking at the artifacts in Harbor, the differences are immediately clear, just as the provided screenshots illustrate:

The Chiselled Image (python-chiselled):

  • Size: 13.29MB.
  • Vulnerabilities: A clean slate with No vulnerability. This is the direct result of including only the bare minimum runtime components, eliminating shells, package managers, and other common sources of CVEs.

The Traditional Image (python-full):

  • Size: 44.03MB—over three times larger than its chiselled counterpart.
  • Vulnerabilities: The scanner immediately flags 12 Total vulnerabilities, with 1 of them being fixable. These vulnerabilities exist in the additional packages and system utilities included in a standard image, but are not necessary for my Python application to run.

This side-by-side view in Harbor provides the ultimate proof. The chiselled image is not just an exercise in minimalism; it’s a direct and effective security strategy. By drastically reducing the image size and attack surface, I have produced an artifact that is faster to pull, cheaper to store, and, most importantly, verifiably more secure right out of the box, with zero CVEs detected by Harbor’s scanner.

Step 5: Using the Image in a Kubernetes Cluster (Tanzu) — The Realistic Version

My secure image is now in the registry. It’s time to run it as an application on a vSphere-integrated Kubernetes cluster. This section accounts for the realities of production-grade, secured clusters that often enforce strict security policies.

5.1. Configuring Cluster Access to the Harbor Registry

The Kubernetes cluster needs to know how to authenticate with Harbor to pull the image. For this, I will create a special Secret of type docker-registry.

kubectl create secret docker-registry harbor-cred \
  --docker-server=vcf-hbr.vcf.vworld.lab \
  --docker-username=YOUR_USERNAME \
  --docker-password=YOUR_PASSWORD

5.2. Defining the Deployment with Security Policies in Mind

Create a deployment.yaml file. The following definition is enhanced with crucial security contexts, which are necessary to run a Pod in a cluster with a restricted policy (commonly found in Tanzu).

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-chiselled-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-chiselled
  template:
    metadata:
      labels:
        app: python-chiselled
    spec:
      securityContext:
        runAsUser: 1001
        runAsGroup: 1001
        fsGroup: 1001
      imagePullSecrets:
      - name: harbor-cred
      containers:
      - name: python-app
        image: vcf-hbr.vcf.vworld.lab/library/python-chiselled:3.12
        command: ["python3", "-c"]
        args:
        - |
          import time
          print("Hello from a Chiselled container running on Kubernetes!", flush=True)
          while True:
            time.sleep(60)
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - "ALL"
          runAsNonRoot: true 
          seccompProfile:
            type: "RuntimeDefault"

5.3. Deploying and Verifying the Application

Now, apply the manifest to create the deployment in the cluster:

kubectl apply -f deployment.yaml

Check the deployment status and ensure the Pod has started successfully:


kubectl get deployment python-chiselled-app

kubectl get pods -l app=python-chiselled

kubectl logs deployment/python-chiselled-app

In the logs, you should see the message: Hello from a Chiselled container running on Kubernetes!.

Conclusion

I have walked you through a complete, modern, and realistic CI/CD path: from code, through building, to secure storage and a final, successful deployment on a secured cluster. This practical exercise proves that Chiselled images are not just a theory but a powerful, practical tool. Thanks to the VMware and Canonical partnership, integrating this technology with the VCF and Tanzu ecosystem is simple and seamless, enabling the creation of applications that are inherently more secure, lightweight, and ready to run at private cloud scale.

Share with:


Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • The Full Power of VCF Automation in Action: How I Connect the Dots and Build a Multi-Tier App with Kubernetes Objects.
  • From Code to Kubernetes Cluster with Chiselled Ubuntu Images on VMware
  • From Zero to Database-as-a-Service: A Deep Dive into VMware Data Services Manager 9.0 and VCF Automation
  • Complete Guide: Configuring SSO in VMware Cloud Foundation with Active Directory and VCF Automation Integration
  • From Zero to a Scalable Application in VCF 9.0: The Complete, Hyper-Detailed Configuration Guide

Archives

Follow Me!

Follow Me on TwitterFollow Me on LinkedIn

GIT

  • GITHub – vWorld GITHub – vWorld 0
© 2025 vWorld | Powered by Superbs Personal Blog theme