Why
Let me quote from its official site.
Restricting what's in your runtime container to precisely what's necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years. It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.
Distroless images are very small. The smallest distroless image,
gcr.io/distroless/static-debian11
, is around 2 MiB. That's about 50% of the size ofalpine
(~5 MiB), and less than 2% of the size ofdebian
(124 MiB).
How
Currently, we use gradle plugin jib to generate docker images. And you can find the following lines in your build.gradle.kts for that.
id("com.google.cloud.tools.jib") version "3.2.1"
As how to configure this plugin, please refer to its official page. Google guys have published distroless images for different scenarios. And you can go to its offical repo page for details.
Currently, we are using jdk17, and let’s just copy and paste the following lines to build.gradle.kts
jib { from { image = "gcr.io/distroless/java17-debian11:latest@sha256:d5024ba6d66e3e56f8746b48aad7e8f58a81092044b64efa292defa1550cd497" } container { creationTime = "USE_CURRENT_TIMESTAMP" environment = mapOf( "MICRONAUT_ENV_DEDUCTION" to "false", ) } }
the from.image part specifies the base image we wanna use; for security reason, please don’t forget to add the SHA256 value there.
After that, run the following command to generate the image
./gradlew jibDockerBuild
Take audit-log-manager for example, we’ll get the following audit-log-manager image
REPOSITORY TAG IMAGE ID CREATED SIZE audit-log-manager 0.1-SNAPSHOT c30caa9ec2b2 6 minutes ago 284MB <none> <none> fdc8f7f3f189 37 minutes ago 284MB <none> <none> a2c716335d1c 38 minutes ago 284MB <none> <none> 8c74b9932404 45 minutes ago 263MB googleapi-gateway 0.1 50c29279f081 2 weeks ago 166MB advanceai-gateway 0.1 11861d474f5e 2 weeks ago 285MB temporalio/ui 2.1.3 c74779884d07 4 weeks ago 66.6MB <none> <none> bb8a808d9ddc 5 weeks ago 166MB temporalio/auto-setup 1.17.0 c2929e9d7743 6 weeks ago 278MB temporalio/admin-tools 1.17.0 dbba814dc293 6 weeks ago 282MB istio/proxyv2 1.14.1 8dcc4ed7a1e6 8 weeks ago 264MB istio/pilot 1.14.1 9ae2f8164693 8 weeks ago 210MB postgres 14.2 9dbc24674f25 2 months ago 376MB temporalio/auto-setup 1.16.2 7cbdc156e7b6 2 months ago 254MB temporalio/admin-tools 1.16.2 c24c6cbc23b5 2 months ago 284MB timescale/timescaledb 2.6.1-pg14 669208eedae5 3 months ago 287MB
Let’s run the docker container we just created. Of course, we should start other dependent docker containers first.
docker run --network=host -e "DB_URL=jdbc:postgresql://localhost:15432/audit" -e "DB_USER=postgres" -e "DB_PASSWORD=postgres" -e "AUDIT_EVENT_KAFKA_URL=localhost:9092" -e "SCHEMA_REGISTRY_ URL=http://127.0.0.1:8082" -e "SAFI_CUSTOMER_MANAGER_URL=https://customer-manager.apps.dev.safibank.online" audit-log-manager:0.1-SNAPSHOT
And the output
I tried it on my Windows machine, and hopefully it will work on all platforms that support Docker.
Cons
We cannot enter the running conainer by running “docker exec -it xxxx bash“ or something like that, so it’s troublesome if we wanna troubleshoot problems and wanna execute commands within the container.