We have already discussed the basics of microservices architecture and Spring Cloud projects in the first part of this book. In the second part, we looked at the most common elements of that architecture and we discussed how to implement them using Spring Cloud. So far, we have talked about some important topics related to microservice migration, such as centralized logging, distributed tracing, security, and automated testing. Now, as we are armed with that knowledge, we may proceed to the final part of the book, where we will discuss the real power of microservices as a cloud-native development approach. The ability to isolate applications from each other using containerization tools, implementing continuous deployment in the software delivery process and the ability to easily scale an application are things that all contribute to the rapidly growing popularity of microservices.
As you will probably remember from earlier chapters, we have used Docker images for running third-party tools and solutions on the local machine. With that in mind, I would like to introduce you to the main concepts of Docker, such as its basic commands and use cases. This information will help you to run the samples presented in previous chapters. We will then discuss how to build images with our example Spring Boot application, as well as how to run them inside the containers on the local machine. We will use simple Docker commands for that, as well as more advanced tools such as the Jenkins server, which helps you to perform full, continuous delivery and enables a Continuous Integration process in your organization. Finally, we will introduce one of the most popular tools used for the automation of deploying, scaling, and managing containerized applications: Kubernetes. All of our examples will be run locally on a single-node Kubernetes cluster via Minikube.
Docker is a tool that helps you to create, deploy, and run applications by using containers. It was designed with the view to benefit both developers and system administrators in accordance with the DevOps philosophy. Docker helps to improve the software delivery process by solving some important concerns related with it. One of those concerns is the idea of immutable delivery, which is related to something called it works for me. It is especially important that a developer uses the same image for their tests as the one that is used in production when working in Docker. The only difference that should be seen is during configuration. Software delivery in an immutable delivery pattern seems to be particularly important for a microservices-based system as there are many applications deployed independently. Thanks to Docker, developers can now focus on writing code without worrying about the target OS (where the application would be launched). The operation can, therefore, use the same interface for deploying, starting, and maintaining all the applications.
There are also many other reasons for Docker's growing popularity. After all, the containerization idea is nothing new in the Information Technology world. Linux containers were introduced many years ago and have been a part of the kernel since 2008. However, Docker has introduced several new things and solutions that other technologies haven't. Firstly, it provides a simple interface that allows you to easily package an application with dependencies to a single container before running it across different versions and implementations of Linux kernel. The container may be run locally or remotely on any Docker-enabled server, and every container starts in seconds. We can also easily run every command on it without going inside a container. In addition, the sharing and distribution mechanisms of Docker images allows developers to commit their changes and push and pull images in the same way they share source code, for example, using Git. Currently, almost all of the most popular software tools are published on Docker Hub as an image, some we have successfully used for running the tools required for our sample applications.
There are some essential definitions and elements that Docker architecture is composed of; the most important is a container. Containers run on a single machine and share the OS kernel with that machine. They contain everything you need to run specific software on your machine code: runtime, system tools, system libraries, and settings. Containers are created from the instructions found within a Docker image. Images are like a kind of recipe or template that defines the steps for installing and running necessary software on a container. Containers can also be compared to virtual machines as they have similar resource isolation and allocation benefits. However, they virtualize the operating system instead of the hardware, making them more portable and efficient than VMs. The following diagram illustrates the architectural differences between a Docker container and a virtual machine:
All containers are launched on a physical or virtual machine that is called a Docker host. Docker hosts, in turn, run a Docker daemon, which listens for the commands sent by the Docker client through a Docker API. Docker clients may be command-line tools or other software such as Kinematic. Besides running a daemon, a Docker host is responsible for storing cached images and containers created from those images. Every image is built from a set of layers. Each layer contains only the incremental differences from the parent layer. Such an image is not small and needs to be stored elsewhere. This place is called the Docker registry. You may create your own private repository or use the existing public repository available on the web. The most popular repository is Docker Hub, which contains almost all of the required images.
Docker installation instructions for Linux are specific to each distribution (https://docs.docker.com/install/#supported-platforms). However, sometimes you have to run a Docker daemon after installation, which you can do by calling the following command:
dockerd --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375
In this section, we will focus on instructions for the Windows platform. Generally, you have two available options when installing Docker Community Edition (CE) on Windows or Mac. The fastest and easiest way is by using Docker for Windows, which is available at https://www.docker.com/docker-windows. This is a native Windows application that provides an easy-to-use development environment for building, shipping, and running containerized applications. This is definitely the best option to utilize, because it uses Windows-native Hyper-V virtualization and networking. There is, however, one disadvantageâit is available only for Microsoft Windows 10 Professional or Enterprise 64-bit. Earlier versions of Windows should use Docker Toolbox, which can be downloaded here at, https://docs.docker.com/toolbox/toolbox_install_windows/. This includes the Docker platform, the command-line with Docker Machine, Docker Compose, Kitematic, and VirtualBox. Note that you canât run Docker Engine natively on Windows using Docker Toolbox because it uses Linux-specific kernel features. Instead, you must use the Docker Machine command (docker-machine), which creates a Linux VM on the local machine and runs it using Virtual Box. This VM may be accessed by your machine using a virtual address that is, by default, 192.168.99.100. All previously discussed examples were integrating with the Docker tools available at that IP address.
After installing Docker Toolbox on Windows you should run Docker Quickstart Terminal. It does everything that is needed, including creating and starting Docker Machine and providing the command line interface. If you type a Docker command without any parameters, you should now be able to see the full list of available Docker client commands with descriptions. These are the types of commands we will look at:
- Running and stopping a container
- List and remove container
- Pull and push images
- Building an image
- Networking
The first Docker command that is usually run after installation is docker run. As you may remember, this command is one of the most commonly used in previous examples. This command does two things: it pulls and downloads the image definition from the registry, in case it is not cached locally, and starts the container. There are many options that can be set for this command, which you can easily check by running docker run --help. Some options have one-letter shortcuts, which are often the most commonly used options. Option âd runs a container in the background, while âi keeps stdin open even if it is not attached. If your container has to expose any ports outside, you can use the activate option âp with the definition <po...