18
Effective Java Docker Pipeline Effective build for lean and secure Java Docker images

Webinar: Creating an Effective Docker Build Pipeline for Java Apps

Embed Size (px)

Citation preview

Effective Java Docker Pipeline

Effective build for lean and secure Java Docker images

About me…•Chief of Research @codefresh.io

•github.com/alexei-led/pumba

•#docker, #golang, #aws

•medium.com/@alexeiled

•@alexeiled

The “Naive” ApproachFollow familiar VM build and install flow

# start from ubuntu FROM ubuntu:14.04

# add required packages and java repository RUN apt-get update && apt-get install -y python-software-properties software-properties-common RUN add-apt-repository ppa:webupd8team/java

# install Oracle JDK 8 with auto-accept license agreement RUN echo "oracle-java8-installer shared/accepted-oracle-license-v1-1 boolean true" | debconf-set-selections RUN apt-get update && apt-get install -y oracle-java8-installer maven

# add ALL project files ADD . /usr/local/app

# build Java application with Maven (fetch packages, compile, test and deploy) RUN cd /usr/local/app && mvn install

# define default command to run the application CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.active=test", "/usr/local/app/target/spring-boot-rest-example-0.3.0.war"]

Docker Image Size = 1.3 GB Docker Built Time = 27 min

“Standard” Approach

FROM java:8

# Install maven RUN apt-get update RUN apt-get install -y maven

WORKDIR /code

# Prepare by downloading dependencies ADD pom.xml /code/pom.xml RUN ["mvn", "dependency:resolve"] RUN ["mvn", "verify"]

# Adding source, compile and package into a fat jar ADD src /code/src RUN ["mvn", "package"]

EXPOSE 4567 CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.active=test", "target/spring-boot-rest-example-0.3.0.war"]

Docker Image Size = 1.2 GB Docker Built Time = 15 min

Take Library OpenJDK image, add pom.xml first…

Stay away from these abstractions

Containers are not VM and

they are not like “lightweight” VM

–Joe Fernandes, senior director, OpenShift Product Management, Red Hat

“A Linux container is nothing more than a process that runs on Linux. It shares a host kernel with other containerized processes.”

What is the bare minimum required to run Java App?

1. Base Image with C Runtime and Posix shell (Alpine)

2. Java Runtime Environment (OpenJDK JRE)

3. Application byte-code and resources (app.jar)

4. 3rd Party Libraries (lib/*.jar)

5. Optionally HTTP server (Tomcat/Jetty/Netty/…)

Docker Image Size• time to build

• network latency

• storage

• service availability and elasticity

• security

• development agility

Docker Builder Pattern• 2 Dockerfiles

• 1st for build tools

• 2nd for runtime

Java Docker Builder1. Base Image with C Runtime and Posix shell (Alpine)

2. Java Development Kit (OpenJDK)

3. Javac or other JVM compiler (Scala, Kotlin, …)

4. Build Management Tool (Maven, SBT, Gradle, …)

5. Linters, code scanners, test frameworks, test tools, …

Maven Builder DockerfileFROM openjdk:8-jdk-alpine

RUN apk add --no-cache curl tar bash

ARG MAVEN_VERSION=3.3.9 ARG USER_HOME_DIR="/root"

RUN mkdir -p /usr/share/maven && \ curl -fsSL http://apache.osuosl.org/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar -xzC /usr/share/maven --strip-components=1 && \ ln -s /usr/share/maven/bin/mvn /usr/bin/mvn

ENV MAVEN_HOME /usr/share/maven ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2" # speed up Maven JVM a bit ENV MAVEN_OPTS="-XX:+TieredCompilation -XX:TieredStopAtLevel=1"

ENTRYPOINT ["/usr/bin/mvn"]

# make source folder RUN mkdir -p /usr/src/app WORKDIR /usr/src/app

# install maven dependency packages (keep in image) COPY pom.xml /usr/src/app RUN mvn -T 1C install && rm -rf target

# copy other source files (keep in image) COPY src /usr/src/app/src

Java App DockerfileFROM openjdk:8-jre-alpine

COPY spring-boot-*.war /app.war

CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.active=test", "/app.war"]

263 MB 143 MB

Build Pipeline Orchestration

GNU make

Docker multi-stage build

Next Container101 Webinar

Makefile…

builder:     docker build -t $(NS)/builder:mvn -f Dockerfile.build .

mvn-package: builder     docker run -it --rm -v $(shell pwd)/target:/usr/src/app/target $(NS)/builder:mvn package -T 1C -o -Dmaven.test.skip=true

mvn-test: builder     docker run -it --rm -v $(shell pwd)/target:/usr/src/app/target $(NS)/builder:mvn -T 1C -o test

docker:     docker build -t $(NS)/$(REPO):$(VERSION) target

build: builder     make docker

push:     docker push $(NS)/$(REPO):$(VERSION)

release: build     make push -e VERSION=$(VERSION)

default: build

version: '1.0'

steps:

mvn_builder: type: build description: create Maven builder dockerfile: Dockerfile.build image_name: alexeiled/mvn-builder

mvn_test: description: run unit tests image: ${{mvn_builder}} commands: - mvn -T 1C -o test mvn_package: description: package application WAR image: ${{mvn_builder}} commands: - mvn package -T 1C -o -Dmaven.test.skip=true

build_image: type: build description: create Docker image with application WAR dockerfile: Dockerfile working_directory: ${{main_clone}}/target image_name: alexei-led/sbdemo

image_push: type: push description: push to DockerHub candidate: '${{build_image}}' tag: ‘${{CF_BRANCH}}'

Codefresh YAML

https://codefresh.io/blog/java_docker_pipeline/

Next Steps

• Try Codefresh free- www.codefresh.io • Additional info on Docker - www.codefresh.io/blog • Meetups & Webinars - www.codefresh.io/meetups • Twitter - @codefresh