You are tasked with optimizing the container image for a Go application. The application is a simple web service with a front page and a few API endpoints. The service uses an SQLite database to store the visitor counter, and since SQLite is a C library, the application is dynamically linked.
The source code of the application is located in the ~/app
directory,
along with an initial Dockerfile.
You can use the make docker-build
command to build the image
and make docker-run
to run the container.
However, the current setup does not adhere to containerization best practices.
Your goal is to improve the Dockerfile and create a production-ready container image.
Build a Docker image named registry.iximiuz.com/app:v1.0.0
that meets the following requirements:
- Base Image:
- Use a minimalistic base image.
- All application's dependencies must be satisfied.
- Security:
- The image must run as a non-root user.
- Ensure there is no shell in the image.
- Performance:
- The final image size must not exceed
40 MB
.
- Runtime:
- The application must:
- Listen on
0.0.0.0:3000
. - Include all HTML files from the
templates
folder. - Include all assets from the
static
folder. - Serve APIs and static files correctly.
- Listen on
- Testing:
- Verify the application by running a container and checking the main page and the API handlers responses.
The final solution will be validated using automated checks. You can access dynamic hints from the checks by clicking the task box below.
Good luck! ๐
Hint 1 ๐ก
If you're new to Docker, you may want to solve this simpler challenge first: Build and Publish a Container Image With Docker
Hint 2 ๐ก
The problem with the application's original Dockerfile is that it includes the dev- and build-time dependencies in the final image. It includes not only the Go compiler, but also hundreds of other packages and tools that are not needed at runtime but increase the image size and the attack surface:
To separate the build- and runtime dependencies, a multi-stage Docker build can be used:
If you're not familiar with this technique, check out this tutorial on how to produce smaller container images with multi-stage builds.
Hint 3 ๐ก
The Go application in this challenge is dynamically linked
(i.e., depends on the system-wide libc
, the sqlite3
C library, and potentially other external libraries),
so choosing the right base image for the runtime stage is going to be trickier than for a statically linked application.
For instance, the (quite popular) FROM scratch
approach won't work unless you're willing to carefully craft a custom FROM scratch
image
adding not only the necessary Linux rootfs layout and the certificate authority (CA) bundle,
but also the required C libraries.
Switching to a minimalistic but full-fledged Linux distro like alpine
won't do the trick either
because of the requirement not to include a shell in the image.
Distroless base images to the rescue:
But be careful: not all distroless images are suitable for a dynamically linked application.
Level up your Server Side game โ Join 9,000 engineers who receive insightful learning materials straight to their inbox