The Java programming language was created over 20 years ago. It continues to be the most popular and widely used programming language after all these years. The design patterns and antipatterns of Java deployment are well known. The usual steps to deploy a Java application involve using a script that downloads and installs the operating system package such as JDK on a machine—whether physical or virtual. Operating system threads and memory need to be configured, the network needs to be set up, the correct database identified, and several other such requirements need to be configured for the application to work. These applications are typically deployed on a virtual machine (VM). Starting up these VMs is an expensive operation and can take quite a few minutes in most cases. The number of VMs that can run on a host is also limited because the entire operating system needs to be started, and thus there are stringent requirements on CPU and memory of the host.
Containers provide several benefits over traditional VM-based deployments. Faster startup and deployments, security and network sandboxing, higher density, and portability across different environments are some of the commonly known advantages. They also improve portability across machines and reduce the impedance mismatch between dev, test, and prod environments.
There are efforts like the Open Container Initiative (OCI) that aim to create an industry standard around container formats and runtime. Docker is the first container implementation based on OCI specifications, and is unarguably the most popular container format. Docker nicely complements the Java programming model by allowing you to package your application including libraries, dependencies, and configuration as a single artifact. The unit of deployment becomes a Docker image as opposed to a .war or .jar file. Different components of an application such as an application server, database, or web server can be started as separate containers. All of these containers can then be connected to each other using orchestration frameworks. The entire setup can then be deployed in a variety of operating systems and run as containers.
This book is targeted toward developers who are interested in learning the basic concepts of Docker and commonly used orchestration frameworks around them. The first chapter introduces the basic concepts and terminology of Docker. The second chapter explains, using code samples, how to build and run your first Docker container using Java. The third chapter explains how support for Docker is available in popular developer toolchains. The fourth chapter is a quick summary. The examples in this book use the Java programming language, but the concepts are applicable for anybody interested in getting started with Docker.
I would like to express gratitude to the people who made writing this book a fun experience. First and foremost, many thanks to O’Reilly for providing an opportunity to write this book. The team provided excellent support throughout the editing, reviewing, proofreading, and publishing processes. At O’Reilly, Brian Foster believed in the idea and helped launch the project. Nan Barber was thorough and timely with her editing, which made the book fluent and consistent. Thanks also to the rest of the O’Reilly team, some of whom we may not have interacted with directly, but who helped in many other ways. Daniel Bryant (@danielbryantuk) and Roland Huß (@ro14nd) did an excellent technical review of the book. This ensured that the book stayed true to its purpose and explained the concepts in the simplest possible ways. A vast amount of information in this book is the result of delivering the Docker for Java Developers workshop all around the world. A huge thanks goes to all the attendees of these workshops whose questions helped clarify my thoughts. Last, but not least, I seek forgiveness from all those who have helped us over the past few months and whose names we have failed to mention.