Optimize images & performance — Multi-stage Docker
Everyone is migrated to kubernetes environment & started adopting this niche technology. However each of this also need tuning requirement. Default setup may not be the best for all purpose. We will check to reduce the size of the images by using runtime environment rather build time environent. Sometimes this is helpful for the security aspects too. Let’s use multi-stage build for the same.
Build for the Golang
Golang provides binary file after build command & that binary can be run on any platform without need of golang environment. We will check old & new configuration. This will reduce the size of the image from 450MB to 34MB.
Old configuration
FROM golang:1.15.7-alpine3.13# Set the Current Working Directory inside the container
WORKDIR /root/# Copy everything from the current directory to the PWD (Present Working Directory) inside the container
COPY . .ENV GIN_MODE=release
ENV SERVER_PORT=8080# Install the package
RUN go build -tags=jsoniter .
# This container exposes port 8080 to the outside world
EXPOSE 8080# Run the executable
CMD ["./app"]
New configuration
FROM golang:1.15.7-alpine3.13# Set the Current Working Directory inside the container
WORKDIR /root/# Copy everything from the current directory to the PWD (Present Working Directory) inside the container
COPY . .ENV GIN_MODE=release# Install the package
RUN go build -tags=jsoniter .FROM alpine:latest
WORKDIR /root/
COPY --from=0 /root/app .ENV SERVER_PORT=8080# This container exposes port 8080 to the outside world
EXPOSE 8080
# Run the executable
CMD ["./app"]
Build for the JAVA
In JAVA we can have multiple options based on build package we use. I scratched two cases gradle build & maven build process.
Old configuration (Gradle Build)
FROM openjdk:8
ENV APP_HOME=/root/dev/myapp/
RUN mkdir -p $APP_HOME/src/main/java
WORKDIR $APP_HOME
COPY build.gradle gradlew gradlew.bat $APP_HOME
COPY gradle $APP_HOME/gradle
# download dependencies
RUN ./gradlew build -x :bootRepackage -x test --continue
COPY . .
RUN ./gradlew build
New configuration
FROM openjdk:8 AS BUILD_IMAGE
ENV APP_HOME=/root/dev/myapp/
RUN mkdir -p $APP_HOME/src/main/java
WORKDIR $APP_HOME
COPY build.gradle gradlew gradlew.bat $APP_HOME
COPY gradle $APP_HOME/gradle
# download dependencies
RUN ./gradlew build -x :bootRepackage -x test --continue
COPY . .
RUN ./gradlew buildFROM openjdk:8-jre
WORKDIR /root/
COPY --from=BUILD_IMAGE /root/dev/myapp/build/libs/myapp.jar .
EXPOSE 8080
CMD ["java","-jar","myapp.jar"]
Old configuration (type 2)
FROM openjdk:8-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/my-application.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
New configuration
FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src
RUN ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
Build for the .Net application
For .Net application we can reduce the size of the image from 1.7GB to ~200mb.
Old configuration
FROM microsoft/dotnet:2.0-sdk
COPY . ./docker-size-test
WORKDIR /docker-size-test/
RUN dotnet build -c Release
ENTRYPOINT ["dotnet", "run", "-c", "Release", "--no-build"]
New configuration
FROM microsoft/dotnet:2.0-sdk AS build
COPY . ./docker-size-test
WORKDIR /docker-size-test/
RUN dotnet build -c Release -o outputFROM microsoft/dotnet:2.0-runtime AS runtime
COPY --from=build /docker-size-test/output .
ENTRYPOINT ["dotnet", "docker-size-test.dll"]