This topic describes how you can use an existing image with Supply Chain Choreographer.
For apps that build container images in a predefined way, the supply chains in the Out of the Box packages enable you to specify a prebuilt image. This uses the same stages as any other workload.
Supply chains aim at Knative as the runtime for the container image you provide. Your app must adhere to the following Knative standards:
Container port listens on port 8080
The Knative service is created with the container port set to 8080
in the pod template spec Therefore, your container image must have a socket listening on 8080
.
ports:
- containerPort: 8080
name: user-port
protocol: TCP
Non-privileged user ID
By default, the container initiated as part of the pod is run as user 1000.
securityContext:
runAsUser: 1000
Arguments other than the image’s default ENTRYPOINT
In most cases the container image runs using the ENTRYPOINT
it was configured with. In the case of Dockerfiles, the combination of ENTRYPOINT
and CMD
.
If you need extra configuration for your image, use --env
flags with the tanzu apps workload create
command or modify spec.env
in your workload.yaml
file.
Credentials for pulling the container image at runtime
The image you provide is not relocated to an internal container image registry. Any components associated with the image must have the necessary credentials to pull it. For the service accounts used for the workload and deliverable, you must attach a secret that contains the credentials to pull the container image.
If the image is hosted in a registry that has certificates signed by a private certificate authority, the components of the supply chains, delivery, and the Kubernetes nodes in the run cluster must trust the certificate.
To select a prebuilt image, set the spec.image
field in your workload.yaml
file with the name of the container image that contains the app to deploy by running:
tanzu apps workload create WORKLOAD-NAME \
--app APP-NAME \
--type TYPE \
--image IMAGE
Where:
WORKLOAD-NAME
is the name you choose for your workload.APP-NAME
is the name of your app.TYPE
is the type of your app.IMAGE
is the container image that contains the app you want to deploy.For example, if you have an image named IMAGE
, you can create a workload with the flag mentioned earlier:
tanzu apps workload create tanzu-java-web-app \
--app tanzu-java-web-app \
--type web \
--image IMAGE
Expected output:
Create workload:
1 + |---
2 + |apiVersion: carto.run/v1alpha1
3 + |kind: Workload
4 + |metadata:
5 + | labels:
6 + | app.kubernetes.io/part-of: hello-world
7 + | apps.tanzu.vmware.com/workload-type: web
8 + | name: tanzu-java-web-app
9 + | namespace: default
10 + |spec:
11 + | image: IMAGE
When you run tanzu apps workload create
command with the --image
field, the source resolution and build phases of the supply chain are skipped.
The following examples show ways that you can build container images for a Java-based app and complete the supply chains to a running service.
Using a Dockerfile is the most common way of building container images. You can select a base image, on top of which certain operations must occur, such as compiling code, and mutate the contents of the file system to a final container image that has a build of your app and any required runtime dependencies.
Here you use the maven
base image for compiling your app code, and then the minimal distroless java17-debian11
image for providing a JRE that can run your app when it is built.
After building the image, you push it to a container image registry, and then reference it in the workload.
Create a Dockerfile that describes how to build your app and make it available as a container image:
ARG BUILDER_IMAGE=maven
ARG RUNTIME_IMAGE=gcr.io/distroless/java17-debian11
FROM $BUILDER_IMAGE AS build
ADD . .
RUN unset MAVEN_CONFIG && ./mvnw clean package -B -DskipTests
FROM $RUNTIME_IMAGE AS runtime
COPY --from=build /target/demo-0.0.1-SNAPSHOT.jar /demo.jar
CMD [ "/demo.jar" ]
Push the container image to a container image registry by running:
docker build -t IMAGE .
docker push IMAGE
Create a workload by running:
tanzu apps workload create tanzu-java-web-app \
--type web \
--app tanzu-java-web-app \
--image IMAGE
Expected output:
Create workload:
1 + |---
2 + |apiVersion: carto.run/v1alpha1
3 + |kind: Workload
4 + |metadata:
5 + | labels:
6 + | app.kubernetes.io/part-of: hello-world
7 + | apps.tanzu.vmware.com/workload-type: web
8 + | name: tanzu-java-web-app
9 + | namespace: default
10 + |spec:
11 + | image: IMAGE
Run the following workload:
tanzu apps workload get tanzu-java-web-app
Expected output:
# tanzu-java-web-app: Ready
---
lastTransitionTime: "2022-04-06T19:32:46Z"
message: ""
reason: Ready
status: "True"
type: Ready
Workload pods
NAME STATUS RESTARTS AGE
tanzu-java-web-app-00001-deployment-7d7df5ccf5-k58rt Running 0 32s
tanzu-java-web-app-config-writer-xjmvw-pod Succeeded 0 89s
Workload Knative Services
NAME READY URL
tanzu-java-web-app Ready http://tanzu-java-web-app.default.example.com
You can use Spring Boot’s build-image
target to build a container image that runs your app. The build-image
target must use a Dockerfile.
For example, using the same sample repository as mentioned before (https://github.com/vmware-tanzu/application-accelerator-samples/tree/main/tanzu-java-web-app):
Build the image by running the following command from the root of the repository:
IMAGE=ghcr.io/kontinue/hello-world:tanzu-java-web-app
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=$IMAGE
Expected output:
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.example:demo >--------------------------
[INFO] Building demo 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
...
[INFO]
[INFO] Successfully built image 'ghcr.io/kontinue/hello-world:tanzu-java-web-app'
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 39.257 s
[INFO] Finished at: 2022-04-06T19:40:16Z
[INFO] ------------------------------------------------------------------------
Push the image you built to the container image registry by running:
IMAGE=ghcr.io/kontinue/hello-world:tanzu-java-web-app
docker push $IMAGE
Expected output:
The push refers to repository [ghcr.io/kontinue/hello-world]
1dc94a70dbaa: Preparing
...
9d6787a516e7: Pushed
tanzu-java-web-app: digest: sha256:7140722ea396af69fb3d0ad12e9b4419bc3e67d9c5d8a2f6a1421decc4828ace size: 4497
After you push the container image, you see the same results as building the image using a Dockerfile.
For more information about building container images for a Spring Boot app, see Spring Boot with Docker
In Tanzu Application Platform, the ootb-supply-chain-basic
, ootb-supply-chain-testing
, and ootb-supply-chain-testing-scanning
packages each receive a new supply chain that provides a prebuilt container image for your app.
ootb-supply-chain-basic
(cluster) basic-image-to-url ClusterSupplyChain (!) new
^ source-to-url ClusterSupplyChain
ootb-supply-chain-testing
(cluster) testing-image-to-url ClusterSupplyChain (!) new
^ source-test-to-url ClusterSupplyChain
ootb-supply-chain-testing-scanning
(cluster) scanning-image-scan-to-url ClusterSupplyChain (!) new
^ source-test-scan-to-url ClusterSupplyChain
To leverage the supply chains that expect a prebuilt image, you must set the spec.image
field in the workload to the name of the container image that contains the app to deploy.
The new supply chains use a Cartographer feature that lets VMware increase the specificity of supply chain selection by using the matchFields
selector rule.
The selection takes place as follows:
ootb-supply-chain-basic
apps.tanzu.vmware.com/workload-type: web
apps.tanzu.vmware.com/workload-type: web
and set spec.image
in the workload.yaml
ootb-supply-chain-testing
apps.tanzu.vmware.com/workload-type: web
and apps.tanzu.vmware.com/has-tests: true
apps.tanzu.vmware.com/workload-type: web
and set spec.image
in the workload.yaml
ootb-supply-chain-testing-scanning
apps.tanzu.vmware.com/workload-type: web
and apps.tanzu.vmware.com/has-tests: true
apps.tanzu.vmware.com/workload-type: web
and set spec.image
in the workload.yaml
Workloads that already work with the supply chains before Tanzu Application Platform v1.1 continue to work with the same supply chain. Workloads that bring a prebuilt container image must set spec.image
in the workload.yaml
.
An ImageRepository
object is created to keep track of new images pushed under that name. ImageRepository
makes the image available to further resources in the supply chain, providing the final digest of the latest image.
Whenever a new image is pushed to the workload’s image location, the ImageRepository
detects the change. The image is then available to further resources by updating its imagerepository.status.artifact.revision
with an absolute reference to that image.
For example, if you create a workload using an image named hello-world
, tagged tanzu-java-web-app
hosted under ghcr.io
in the kontinue
repository:
tanzu apps workload create tanzu-java-web-app \
--app tanzu-java-web-app \
--type web \
--image ghcr.io/kontinue/hello-world:tanzu-java-web-app
After a couple seconds, you see the ImageRepository
object created to keep track of images named ghcr.io/kontinue/hello-world:tanzu-java-web-app
:
Workload/tanzu-java-web-app
├─ImageRepository/tanzu-java-web-app
├─PodIntent/tanzu-java-web-app
├─ConfigMap/tanzu-java-web-app
└─Runnable/tanzu-java-web-app-config-writer
└─TaskRun/tanzu-java-web-app-config-writer-p2lzv
└─Pod/tanzu-java-web-app-config-writer-p2lzv-pod
If you inspect the status in status.resources
in the workload.yaml
, you see the image-provider
resource promoting the image it found to further resources:
apiVersion: carto.run/v1alpha1
kind: Workload
spec:
image: ghcr.io/kontinue/hello-world:tanzu-java-web-app
status:
resources:
- name: image-provider
outputs:
# output being made available to further resources in the supply chain
# (in this case, the latest image it found under that name).
#
- name: image
lastTransitionTime: "2022-04-01T15:05:01Z"
preview: ghcr.io/kontinue/hello-world:tanzu-java-web-app@sha256:9fb930a...
# reference to the object managed by the supply chain for this
# resource
#
stampedRef:
apiVersion: source.apps.tanzu.vmware.com/v1alpha1
kind: ImageRepository
name: tanzu-java-web-app
namespace: workload
# reference to the template that defined how this object should look
# like
#
templateRef:
apiVersion: carto.run/v1alpha1
kind: ClusterImageTemplate
name: image-provider-template
The image found by the ImageRepository
object is carried through the supply chain to the final configuration. This is pushed to either a Git repository or image registry so that it is deployed in a run cluster.
NoteThe image name matches the image name supplied in the
spec.image
field in theworkload.yaml
, but also includes the digest of the latest image found under the tag. If a new image is pushed to the same tag, you see theImageRepository
resolving the name to a different digest corresponding to the new image pushed.