1) Python
3) Go
5) Kotlin
7) Conclusion
1) Unoptimized build
FROM ubuntu:latest
MAINTAINER Michael Chirozidi 'chirozidi.m@gmail.com'
RUN apt-get update -qy
RUN apt-get install -qy python3.10 python3-pip python3.10-dev
COPY . /app
WORKDIR /app
RUN pip install pipreqs
RUN pipreqs && echo 'uvicorn[standard]==0.21.1' >> requirements.txt
RUN pip install -r requirements.txt
CMD ["uvicorn", "spaceship.main:app", "--host=0.0.0.0","--port=8080"]
bash $ docker build . -t py-fastapi:1.0
bash $ docker run -p 8080:8080 --rm py-fastapi:1.0
2) Changing of app.py
bash $ docker build . -t py-fastapi:2.0
bash $ docker run -p 8080:8080 --rm py-fastapi:2.0
ubuntu:latest
was cached.3) Dockerfile optimization
FROM python:slim-bullseye
MAINTAINER Michael Chirozidi chirozidi.m@gmail.com
COPY requirements/backend.in .
RUN pip install --no-cache-dir -r backend.in
COPY . .
CMD ["uvicorn", "spaceship.main:app", "--host=0.0.0.0", "--port=8080"]
bash $ docker build . -t py-fastapi:3.0
bash $ docker run -p 8080:8080 --rm py-fastapi:3.0
4) Upgrading of app.py
bash $ docker build . -t py-fastapi:4.0
bash $ docker run -p 8080:8080 --rm py-fastapi:4.0
python:slim-bullseye
was cached.5) NumPy
NumPy==1.24.3
fastapi==0.95.0
pydantic==1.10.7
starlette==0.26.1
uvicorn[standard]==0.21.1
pyproject.toml==0.0.10
On Bullseye
bash $ docker build . -t py-fastapi:5.0
bash $ docker run -p 8080:8080 --rm py-fastapi:5.0
On Alpine
FROM python:alpine
MAINTAINER Michael Chirozidi chirozidi.m@gmail.com
RUN apk add --no-cache musl-dev g++ gcc lapack-dev
WORKDIR /app
COPY requirements/backend.in .
RUN pip install --no-cache-dir -r backend.in
COPY . .
CMD ["uvicorn", "spaceship.main:app", "--host=0.0.0.0", "--port=8080"]
bash $ docker build . -t py-fastapi:5.0
bash docker run -p 8080:8080 --rm py-fastapi:5.0
1) Default build
FROM golang:latest
MAINTAINER Michael Chirozidi chirozidi.m@gmail.com
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o build/fizzbuzz
EXPOSE 8080
CMD ["./build/fizzbuzz", "serve"]
bash $ docker build . -t golang:1.0
bash $ docker run -p 8080:8080 --rm golang:1.0
2) Multi-stage building with Scratch
FROM golang:latest AS builder
MAINTAINER Michael Chirozidi chirozidi.m@gmail.com
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-w -s -extldflags '-static'" -o build/fizzbuzz
FROM scratch
COPY --from=builder /app/build/fizzbuzz /
COPY --from=builder /app/templates/index.html /templates/
EXPOSE 8080
CMD ["./build/fizzbuzz", "serve"]
bash $ docker build . -t golang:2.0
bash $ docker run -p 8080:8080 --rm golang:2.0
3) Multi-stage building with Distorless
FROM golang:latest AS builder
MAINTAINER Michael Chirozidi chirozidi.m@gmail.com
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o build/fizzbuzz
FROM gcr.io/distroless/base
COPY --from=builder /app/build/fizzbuzz /
COPY --from=builder /app/templates/index.html /templates/
EXPOSE 8080
CMD ["./build/fizzbuzz", "serve"]
bash $ docker build . -t golang:3.0
bash $ docker run -p 8080:8080 --rm golang:3.0
If we compare using a Scratch image and a Distroless image as the base, Scratch allows us to create a highly optimized and lightweight image that contains only the necessary components and dependencies. However, it requires manually installing all the dependencies and libraries inside the image, which takes time and expertise, and may not be the best choice during development.
Distroless images are designed to be used with specific programming languages and frameworks such as Java, Python, or Node.js, and already include dependencies and libraries for those languages and frameworks. Therefore, if you don’t want to deal with manually installing dependencies and libraries and prefer to use a ready-made image that already contains all the necessary components to run your program, a Distroless image can be the best choice.
It should be noted that using a multi-stage build, regardless of the choice of the base image, is more optimal compared to using a golang-based image for the reasons mentioned earlier.
1) Code of simple server on Ktor framework for Kotlin language
fun Application.module() { configureSerialization() configureRouting() }
* Serialization.kt:
```Kotlin
fun Application.configureSerialization() {
install(ContentNegotiation) {
json()
}
helloWorldJson()
}
fun Application.configureRouting() {
helloWorldRouting()
}
fun Application.helloWorldJson(){ routing { get(“/json/hello”) { call.respond(HttpStatusCode.OK, mapOf(“hello” to “world”)) } } }
2) Dockerfile for mutli-stage building image
``` Dockerfile
FROM gradle:7-jdk11 AS build
COPY --chown=gradle:gradle . /app
WORKDIR /app
RUN gradle buildFatJar --no-daemon
FROM openjdk:11
EXPOSE 8080:8080
RUN mkdir /server
COPY --from=build /app/build/libs/*.jar /server/kotlin-all.jar
ENTRYPOINT ["java","-jar","/server/kotlin-all.jar"]
bash $ docker build . -t kotlin:1.0
bash $ docker run -p 8080:8080 --rm kotlin:1.0
After familiarizing myself with working with Docker, the following conclusions can be drawn:
In general, working with Docker allows you to simplify the deployment and management of applications, provides portability and consistency of the environment, and allows you to speed up the development process. The choice between different types of images, such as Scratch and Distroless, depends on your needs and project requirements. With Docker, you can create an infrastructure that is easily scalable and maintainable, which contributes to the efficient operation of the software.