Implementing a continuous delivery (CD) pipeline for Java applications is not trivial, and the introduction of container technology to the development stack can bring additional challenges and requirements. This session looks at key lessons learned when creating an effective pipeline for building and deploying Docker container-based Java applications. Key takeaways include:
• The impact on Java and continuous delivery of using Docker containers
• The benefits and challenges of packaging containerized Java applications
• Validating nonfunctional/operational requirement changes imposed by executing Java applications within a container
• Lessons learned the hard way (in production, at 3 a.m., with lots of coffee)
6. Velocity (with stability) is key to business success
“Continuous delivery is achieved when stability and
speed can satisfy business demand.
Discontinuous delivery occurs when stability and speed
are insufficient.”
- Steve Smith (@SteveSmithCD)
18/09/2019 @danielbryantuk
7. Velocity (with stability) is key to business success
“Continuous delivery is achieved when stability and
speed can satisfy business demand.
Discontinuous delivery occurs when stability and speed
are insufficient.”
- Steve Smith (@SteveSmithCD)
18/09/2019 @danielbryantuk
9. The good (with Docker and Java)
• Dev environment setup can Dockerized
• Docker enables repeatable builds
• Legacy tech (old frameworks etc) can be hermetically sealed
18/09/2019 @danielbryantuk
10. The bad (lessons learned for speed/stability)
“Why is the container image 1GB?
It’s a helloworld Java app!!!”
“Dinosaurs must have completed their
dev/test/deploy loop faster than me”
“This Java app runs slow (or freezes)
in Docker”
18/09/2019 @danielbryantuk
16. Make your dev environment like production
• Must build/test containers locally
• Perform (at least) happy path tests
• Use identical base images from production
• With same configuration
18/09/2019 @danielbryantuk
17. Lesson learned: Dockerfile content is super important
• OS choice (alpine or Distroless?)
• OS configuration
• Build artifacts
• Ports, volumes etc
• Oracle vs OpenJDK vs …?
• JDK vs JRE (vs jlinked binary?)
• Hotspot vs OpenJ9 vs SubstrateVM vs…?
• AOT vs JIT && CDS and ACDS
18/09/2019 @danielbryantuk
18. Please talk to the sysadmin people:
Their operational knowledge is invaluable
18/09/2019 @danielbryantuk
19. Start from good foundations: base image
18/09/2019 @danielbryantuk
https://github.com/danielbryantuk/oreilly-docker-java-
shopping
31. The bad: different test and prod containers?
• Create “test” version of container
• Full OS (e.g. Ubuntu), JDK
• Test tools and data
• Create “prod” version of the container
• Minimal OS
• JRE only
• Easy to see app/configuration drift
18/09/2019 @danielbryantuk
34. Lots of tooling in DevEx space
18/09/2019 @danielbryantuk
https://blog.hasura.io/draft-vs-gitkube-vs-helm-vs-
ksonnet-vs-metaparticle-vs-skaffold-f5aa9561f948
https://www.slideshare.net/dbryant_uk/mucon-2019-creating-an-
effective-developer-experience-for-cloudnative-apps-148402134
42. (Technical Speed): Docker and Java
• Migrate to Java 11 LTS
• Eclipse OpenJ9
• www.eclipse.org/openj9/oj9_performance.html
• Ahead of Time (AOT) Compilation
• OpenJ9 and SubstrateVM
• Application Class Data Sharing (ACDS)
• blog.codefx.org/java/application-class-data-sharing/
18/09/2019 @danielbryantuk
https://www.ibm.com/developerworks/library/j-rtj2/
43. Stability: Docker and Java
• Watch for JVM cgroup/taskset awareness (with JDK <= 8u131)
• getAvailableProcessors() may incorrectly report the number of cpus in Docker (JDK-8140793)
• Runtime.availableProcessors() ignores Linux taskset command (JDK-6515172)
• GC threads, default fork/join thread pool sizes (and others) is based from host CPU count
• Set container memory appropriately
• JVM requirements = Heap size (Xmx) + Metaspace + JVM overhead
• Account for native thread requirements e.g. thread stack size (Xss)
• Entropy
• Host entropy can soon be exhausted by crypto operations and /dev/random blocks
• -Djava.security.egd=file:/dev/./urandom (notes on this)
18/09/2019 @danielbryantuk 43
48. Delaying NFRs to the ‘Last Responsible Moment’
Newsflash!
Sometimes the
last responsible moment
is up-front
Modern platforms/architectures
don’t necessarily make this easier
18/09/2019 @danielbryantuk
50. In summary
• Docker and Java are a great combination
• But make sure you understand the technology and challenges
• Continuous delivery is essential with modern architecture/tech
• Container images must be the (single) source of truth within pipeline
• Provenance (metadata) and validation (testing NFR) of builds is vital
• Not all developers are operationally aware
18/09/2019 @danielbryantuk