{"id":15805224,"url":"https://github.com/ddobrin/cnb-multi-module-repos","last_synced_at":"2026-03-18T16:44:45.996Z","repository":{"id":134175596,"uuid":"250359331","full_name":"ddobrin/cnb-multi-module-repos","owner":"ddobrin","description":"Cloud-native buildpacks for multi-module repositories creating multiple Docker images without the need of Dockerfiles","archived":false,"fork":false,"pushed_at":"2020-05-12T17:26:00.000Z","size":170,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-06T02:05:38.302Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://buildpacks.io/","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ddobrin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-26T20:01:10.000Z","updated_at":"2022-09-28T08:24:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"d4e4ea74-821a-4b96-bfaa-2fd86ef39d31","html_url":"https://github.com/ddobrin/cnb-multi-module-repos","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fcnb-multi-module-repos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fcnb-multi-module-repos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fcnb-multi-module-repos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fcnb-multi-module-repos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddobrin","download_url":"https://codeload.github.com/ddobrin/cnb-multi-module-repos/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246547369,"owners_count":20794970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-05T02:05:11.509Z","updated_at":"2026-01-08T16:53:29.887Z","avatar_url":"https://github.com/ddobrin.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Demo for building source code with multiple modules in the repository\nThis demo explores building images using cloud-native buildpacks for multi-module repositories, producing single/multiple images.\nIt goes more in-depth, past the default behavior, on how buildpacks are used: \n\n1. [Cloud-native buildpacks](#1)\n2. [Kpack](#2)\n\n## The demo repository\n\nThis demo leverages the code from the blue-green deployment on Kubernetes repository. The repo has the source code from multiple modules, sharing a parent POM file and producing individual images (billboard-client, message-service).\n\nThis demo can also be leveraged for building single images from a repo\n\nThe code can be found here: [Source code](https://github.com/ddobrin/bluegreen-deployments-k8s) and \n\nLet's start with cloning the repo. You can follow building with [buildpacks](#1) and [kpack](#2) afterwards.\n\n\n## What are cloud-native buildpacks\n[Buildpacks](https://https://buildpacks.io/) provide a higher-level abstraction for building apps compared to Dockerfiles.\n\n1. Provide a balance of control that reduces the operational burden on developers and supports enterprise operators who manage apps at scale.\n2. Ensure that apps meet security and compliance requirements without developer intervention.\n3. Provide automated delivery of both OS-level and application-level dependency upgrades, efficiently handling day-2 app operations that are often difficult to manage with Dockerfiles.\n4. Rely on compatibility guarantees to safely apply patches without rebuilding artifacts and without unintentionally changing application behavior.\n\n## What is Kpack\n\n[kpack](https://github.com/pivotal/kpack) is a Kubernetes native system to automatically, continuously convert your applications or build artifacts into runnable Docker images.\n\nkpack extends Kubernetes and utilizes unprivileged kubernetes primitives to provide builds of OCI images as a platform implementation of Cloud Native Buildpacks (CNB).\n\nkpack provides a declarative image type that builds an image and schedules image rebuilds on relevant buildpack and source changes.\n\n\u003ca name=\"1\"\u003e\u003c/a\u003e\n## Building modules in a repo using [cloud-native buildpacks](https://https://buildpacks.io/)\n\nThe source code:\n```shell\n\u003e git clone git@github.com:ddobrin/bluegreen-deployments-k8s.git\n\u003e cd bluegreen-deployments-k8s\n```\n\nBefore starting to build one of the modules, let's analyze the syntax of the ```pack``` command with an example:\n\n```shell\n\u003e pack build \u003cimage\u003e \u003cpath\u003e \u003cbuilder\u003e \u003c--publish\u003e \u003cenv variables\u003e\n\n# where:\n# image --\u003e the name of the image you wish to build \n#           (ex.:triathlonguy/message-service:blue \n#                org=triathlonguy, \n#                image name=message-service, \n#                tag=blue)\n# path --\u003e the path of the repository (ex. current path . , hosts the parent POM file)\n# builder --\u003e the name of the builder to use, if not set as default (ex. cloudfoundry/cnb:bionic)\n# publish --\u003e indicates whether the image will be published to the repository\n# env variables:\n#   BP_MAVEN_BUILT_MODULE--\u003e the module to build (ex. message-service)\n#   BP_MAVEN_BUILD_ARGUMENTS --\u003e build arguments \n#       pl --\u003e Comma-delimited list of specified reactor projects to build instead\n#                of all projects. A project can be specified by [groupId]:artifactId\n#                   or by its relative path\n#       am --\u003e If project list is specified, also build projects required by the list\n\n# ex: build message-service \n\u003e pack build triathlonguy/message-service:blue --publish --path . --builder cloudfoundry/cnb:bionic --env BP_MAVEN_BUILT_MODULE=message-service --env BP_MAVEN_BUILD_ARGUMENTS=\"-Dmaven.test.skip=true package -pl message-service -am\"\n\n# with Paketo buildpacks\n\u003e pack build triathlonguy/message-service:blue --publish --path . --builder gcr.io/paketo-buildpacks/builder:base --env BP_MAVEN_BUILT_MODULE=message-service --env BP_MAVEN_BUILD_ARGUMENTS=\"-Dmaven.test.skip=true package -pl message-service -am\"\n\nex.: build billboard-client\n\u003e pack build triathlonguy/billboard-client:blue --publish --path . --builder cloudfoundry/cnb:bionic --env BP_MAVEN_BUILT_MODULE=billboard-client --env BP_MAVEN_BUILD_ARGUMENTS=\"-Dmaven.test.skip=true package -pl billboard-client -am\"\n\n# with Paketo buildpacks\n\u003e pack build triathlonguy/billboard-client:blue --publish --path . --builder gcr.io/paketo-buildpacks/builder:base --env BP_MAVEN_BUILT_MODULE=billboard-client --env BP_MAVEN_BUILD_ARGUMENTS=\"-Dmaven.test.skip=true package -pl billboard-client -am\"\n```\n\nUsing the default builder and parameters and running the ```pack``` command from the folder of the module will lead to build errors, as the path can not be resolved for all components\n\nThe important aspects to consider here:\n1. BP_MAVEN_BUILT_MODULE sets the module to be built\n2. BP_MAVEN_BUILD_ARGUMENTS sets the Maven build arguments where the sub-module must be specified, to avoid building every module of the repository. It is a perfomance optimization\n\nThe build process starts with the detection, analysis and image restoration from cache phases:\n```shell\n===\u003e DETECTING\n[detector] 6 of 15 buildpacks participating\n[detector] paketo-buildpacks/bellsoft-liberica 2.5.3\n[detector] paketo-buildpacks/maven             1.2.2\n[detector] paketo-buildpacks/executable-jar    1.2.3\n[detector] paketo-buildpacks/apache-tomcat     1.1.3\n[detector] paketo-buildpacks/dist-zip          1.3.0\n[detector] paketo-buildpacks/spring-boot       1.5.3\n===\u003e ANALYZING\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:jvmkill\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:link-local-dns\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:memory-calculator\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:openssl-security-provider\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:security-providers-configurer\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:class-counter\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:java-security-properties\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:jre\" from app image\n[analyzer] Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:jdk\" from cache\n[analyzer] Restoring metadata for \"paketo-buildpacks/maven:cache\" from cache\n[analyzer] Restoring metadata for \"paketo-buildpacks/maven:application\" from cache\n[analyzer] Restoring metadata for \"paketo-buildpacks/executable-jar:class-path\" from app image\n===\u003e RESTORING\n[restorer] Restoring data for \"paketo-buildpacks/bellsoft-liberica:jdk\" from cache\n[restorer] Restoring data for \"paketo-buildpacks/maven:application\" from cache\n[restorer] Restoring data for \"paketo-buildpacks/maven:cache\" from cache\n...\n```\n\n... followed by the code build:\n```\n[builder] \n[builder] Paketo BellSoft Liberica Buildpack 2.5.3\n[builder]     Set $BPL_JVM_HEAD_ROOM to configure the headroom in memory calculation. Default 0.\n[builder]     Set $BPL_JVM_LOADED_CLASS_COUNT to configure the number of loaded classes in memory calculation. Default 35% of classes.\n[builder]     Set $BPL_JVM_THREAD_COUNT to configure the number of threads in memory calculation. Default 250.\n[builder]     Set $BP_JVM_VERSION to configure the Java version. Default 11.*.\n[builder]   BellSoft Liberica JDK 11.0.7: Reusing cached layer\n[builder]   BellSoft Liberica JRE 11.0.7: Reusing cached layer\n[builder]   Memory Calculator 4.0.0: Reusing cached layer\n[builder]   Class Counter: Reusing cached layer\n[builder]   JVMKill Agent 1.16.0: Reusing cached layer\n[builder]   Link-Local DNS: Reusing cached layer\n[builder]   Java Security Properties: Reusing cached layer\n[builder]   Security Providers Configurer: Reusing cached layer\n[builder]   OpenSSL Security Provider 1.0.2: Reusing cached layer\n[builder] \n[builder] Paketo Maven Buildpack 1.2.2\n[builder]     Set $BP_MAVEN_BUILD_ARGUMENTS to configure the arguments to pass to Maven. Default -Dmaven.test.skip=true package.\n[builder]     Set $BP_MAVEN_BUILT_ARTIFACT to configure the built application artifact explicitly.  Supersedes $BP_MAVEN_BUILT_MODULE. Default target/*.[jw]ar.\n[builder]     Set $BP_MAVEN_BUILT_MODULE to configure the module to find application artifact in\n[builder]     Set $BP_MAVEN_SETTINGS to configure  the contents of a `settings.xml` file to be used at build time\n[builder]     Creating cache directory /home/cnb/.m2\n[builder]   Compiled Application: Reusing cached layer\n[builder]   Removing source code\n[builder] \n[builder] Paketo Executable JAR Buildpack 1.2.3\n[builder]   Process types:\n[builder]     executable-jar: java -cp \"${CLASSPATH}\" ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher\n[builder]     task:           java -cp \"${CLASSPATH}\" ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher\n[builder]     web:            java -cp \"${CLASSPATH}\" ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher\n[builder] \n[builder] Paketo Spring Boot Buildpack 1.5.3\n[builder]   Image labels:\n[builder]     org.opencontainers.image.title\n[builder]     org.opencontainers.image.version\n[builder]     org.springframework.boot.spring-configuration-metadata.json\n[builder]     org.springframework.boot.version\n\n...\n[INFO] ------------------------------------------------------------------------\n[builder] [INFO] Reactor Summary for spring-cloud-k8s 1.0.0:\n[builder] [INFO]\n[builder] [INFO] parent............................................. SUCCESS [  0.013 s]\n[builder] [INFO] billboard-client................................... SUCCESS [  3.653 s]\n[builder] [INFO] ------------------------------------------------------------------------\n[builder] [INFO] BUILD SUCCESS\n[builder] [INFO] ------------------------------------------------------------------------\n[builder] [INFO] Total time:  4.010 s\n[builder] [INFO] Finished at: 2020-03-28T14:37:00Z\n[builder] [INFO] ------------------------------------------------------------------------\n```\n\n... and results in the building of the image:\n\n```\n===\u003e EXPORTING\n[exporter] Reusing layer 'launcher'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:class-counter'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:jre'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:jvmkill'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:link-local-dns'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:memory-calculator'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:openssl-security-provider'\n[exporter] Reusing layer 'paketo-buildpacks/bellsoft-liberica:security-providers-configurer'\n[exporter] Reusing layer 'paketo-buildpacks/executable-jar:class-path'\n[exporter] Reusing 1/1 app layer(s)\n[exporter] Adding layer 'config'\n[exporter] *** Images (2aa64a98a973):\n[exporter]       index.docker.io/triathlonguy/billboard-client:blue\n[exporter] Reusing cache layer 'paketo-buildpacks/bellsoft-liberica:jdk'\n[exporter] Reusing cache layer 'paketo-buildpacks/maven:application'\n[exporter] Reusing cache layer 'paketo-buildpacks/maven:cache'\nSuccessfully built image triathlonguy/billboard-client:blue\n```\n\n... with the image being published in the repository:\n\n![message-service - Blue Version Deployment](https://github.com/ddobrin/cnb-multi-module-repos/blob/master/images/dockerhub.png)  \n\n\n\u003ca name=\"2\"\u003e\u003c/a\u003e\n## Building modules in a repo using [kpack](https://github.com/pivotal/kpack)\n\nThe source code:\n```shell\n\u003e git clone git@github.com:ddobrin/bluegreen-deployments-k8s.git\n\u003e cd bluegreen-deployments-k8s\n```\n\nDownload the [latest kpack release](https://github.com/pivotal/kpack/releases): you should have a ```file release-\u003cversion\u003e.yaml```. Please note that the file is available in the ```Assets``` section of the kpack release.\n\nDeploy kpack using kubectl:\n```shell\n\u003e kubectl apply -f release-\u003cversion\u003e.yaml\n\n# ex.: release.-0.0.8.yaml \n# https://github.com/pivotal/kpack/releases/download/v0.0.8/release-0.0.8.yaml\n\n# Validate that kpack is running\n\u003e kubectl -n kpack get pods\n\nNAME                                READY   STATUS    RESTARTS   AGE\nkpack-controller-5756f5b65b-f6rnn   1/1     Running   0          3d\nkpack-webhook-7884b8f45b-7d22r      1/1     Running   0          24h\n```\n\n1. First, we create a builder resource for Docker images in K8s: \n```yaml\n# cnb-builder.yaml\n\napiVersion: build.pivotal.io/v1alpha1\nkind: ClusterBuilder\nmetadata:\n  name: default\nspec:\n  image: cloudfoundry/cnb:bionic\n```\n\nCreate it by running:\n```\n\u003e kubectl apply -f cnb-builder.yaml\n```\n\n2. Second, we create a Secret for DockerHub credentials; you can substitute the credentials and repository of your choice (Docker, Harbor, etc.)\n```\n# dockerhub-creds.yml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: dockerhub-creds\n  annotations:\n    build.pivotal.io/docker: https://index.docker.io/v1/\ntype: kubernetes.io/basic-auth\nstringData:\n  username: \u003cuser\u003e\n  password: \u003cpwd\u003e\n```\nCreate it by running:\n```\n\u003e kubectl apply -f dockerhub-creds.yml\n```\n\n3. Third, we create a Secret for Github credentials:\n```\n# github-creds.yml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: github-creds\n  annotations:\n    build.pivotal.io/git: https://github.com\ntype: kubernetes.io/basic-auth\nstringData:\n  username: \u003cuser\u003e\n  password: \u003cpassword\u003e or \u003caccess token for 2FA enabled accounts\u003e\n```\nCreate it by running:\n```\n\u003e kubectl apply -f github-creds.yml\n```\n\n4. Before creating an image resource for building the Docker image for the service, we need to create a service account tying together all the required credentials\n\n```\n# kpack-service-account.yml \napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: kpack-service-account\nsecrets:\n  - name: dockerhub-creds\n  - name: github-creds\n```\nCreate it by running:\n```\n\u003e kubectl apply -f kpack-service-account.yml \n```\n\n5. Finally, we need to create the Image resource for building the Docker image\n```\n# app-source-bg-kbs.yml\napiVersion: build.pivotal.io/v1alpha1\nkind: Image\nmetadata:\n  name: message-service \nspec:\n  tag: triathlonguy/message-service:blue # --\u003e Set your Docker image\n  serviceAccount: kpack-service-account\n  builder:\n    name: default\n    kind: ClusterBuilder\n  cacheSize: \"1Gi\"\n  source:\n    git:\n      url: https://github.com/ddobrin/bluegreen-deployments-k8s # --\u003e set the repo and branch from which to build\n      revision: master\n  build:\n    env:\n      - name: BP_JAVA_VERSION\n        value: 11.*     # --\u003e Java 11 is used by default, you can set the Java version you require\n      - name: BP_BUILT_MODULE # --\u003e set the module to be built \n        value: message-service\n      - name: BP_BUILD_ARGUMENTS # --\u003e set the Maven build arguments\n        value: \"-Dmaven.test.skip=true package -pl message-service -am\"\n\n# where env variables to be set are:\n#   BP_BUILT_MODULE --\u003e the module to build (ex. message-service)\n#   BP_BUILD_ARGUMENTS --\u003e build arguments \n#       pl --\u003e Comma-delimited list of specified reactor projects to build instead\n#                of all projects. A project can be specified by [groupId]:artifactId\n#                   or by its relative path\n#       am --\u003e If project list is specified, also build projects required by the list\n```\n\nCreate the Image resource:\n```\n\u003e kubectl apply -f app-source-bg-kbs.yml\n```\n\nIn total, we have created 5 Kubernetes resources:\n* builder\n* source repository secret\n* image repository secret\n* service account\n* image \n\nWe can follow the progress of the builds:\n```shell\n\n# at the start, status is unknown for the build\n\u003e kubectl get cnbbuilds\nNAME                            IMAGE   SUCCEEDED\nmessage-service-build-1-s227c           Unknown\n\n# the image has been created but is in unknown state\n\u003e kubectl get image\nNAME              LATESTIMAGE   READY\nmessage-service                 Unknown\n\n# the pod is created and executes the first step\n\u003e kubectl get pods\nNAME                                      READY   STATUS     RESTARTS   AGE\nmessage-service-build-1-s227c-build-pod   0/1     Init:0/6   0          10s\n\n# as the build progresses\n\u003e kubectl get pods\nNAME                                      READY   STATUS     RESTARTS   AGE\nmessage-service-build-1-s227c-build-pod   0/1     Init:4/6   0          89s\n\n# when it is complete, we can observe that the pod has completed its run\n\u003e kubectl get pods\nNAME                                      READY   STATUS      RESTARTS   AGE\nmessage-service-build-1-s227c-build-pod   0/1     Completed   0          2m58s\n\n# we can check the logs throughout the build:\n\u003e kubectl logs message-service-build-1-s227c-build-pod\nBuild successful\n\n# we check whether the build was successful:\n\u003e kubectl get cnbbuilds\nNAME                            IMAGE                                                                                                                  SUCCEEDED\nmessage-service-build-1-s227c   index.docker.io/triathlonguy/message-service@sha256:dceb137ac9133d6247aa45b629c005cec9da9a61d97aff57a55b28e147f7e6e2   True\n\n# last, we check whether the image has been created\n\u003e kubectl get image\nNAME              LATESTIMAGE                                                                                                            READY\nmessage-service   index.docker.io/triathlonguy/message-service@sha256:dceb137ac9133d6247aa45b629c005cec9da9a61d97aff57a55b28e147f7e6e2   True\n```\n\n... with the image being published in the repository:\n\n![message-service - Blue Version Deployment](https://github.com/ddobrin/cnb-multi-module-repos/blob/master/images/dockerhub.png)  \n\n\nIf we decide to remove the kpack image and the continuous build of the image, we delete the image:\n```\n\u003e kubectl delete image message-service \n```\n... which removes the Image and associated Pod and ClusterBuilder resources.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddobrin%2Fcnb-multi-module-repos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddobrin%2Fcnb-multi-module-repos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddobrin%2Fcnb-multi-module-repos/lists"}