{"id":68860,"date":"2017-09-25T10:00:16","date_gmt":"2017-09-25T07:00:16","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=68860"},"modified":"2023-12-11T10:22:16","modified_gmt":"2023-12-11T08:22:16","slug":"docker-java-developers-docker-command-line","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html","title":{"rendered":"Docker for Java Developers: Docker over command line"},"content":{"rendered":"<p><em>This article is part of our Academy Course titled <a href=\"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-tutorial-java-developers.html\">Docker Tutorial for Java Developers<\/a>.<\/p>\n<p>In this course, we provide a series of tutorials so that you can develop your own Docker based applications. We cover a wide range of topics, from Docker over command line, to development, testing, deployment and continuous integration. With our straightforward tutorials, you will be able to get your own projects up and running in minimum time. Check it out <a href=\"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-tutorial-java-developers.html\">here<\/a>!<\/em><\/p>\n<div class=\"toc\">\n<h3>Table Of Contents<\/h3>\n<dl>\n<dt><a href=\"#introduction\">1. Introduction<\/a><\/dt>\n<dt><a href=\"#images\">2. Images<\/a><\/dt>\n<dt><a href=\"#containers\">3. Containers<\/a><\/dt>\n<dt><a href=\"#ports\">4. Ports<\/a><\/dt>\n<dt><a href=\"#volumes\">5. Volumes<\/a><\/dt>\n<dt><a href=\"#networks\">6. Networks<\/a><\/dt>\n<dt><a href=\"#linking\">7. Linking<\/a><\/dt>\n<dt><a href=\"#health\">8. Health Checks<\/a><\/dt>\n<dt><a href=\"#limits\">9. Resource Limits<\/a><\/dt>\n<dt><a href=\"#clean\">10. Clean up<\/a><\/dt>\n<dt><a href=\"#compose\">11. All-in-One: The Deployment Stack<\/a><\/dt>\n<dt><a href=\"#conclusions\">12. Conclusions<\/a><\/dt>\n<dt><a href=\"#next\">12. What\u2019s next<\/a><\/dt>\n<\/dl>\n<\/div>\n<h2><a name=\"introduction\"><\/a>1. Introduction<\/h2>\n<p>In this section of the tutorial we are going to master the Swiss army knife of <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>, its command line tool of the same name <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> and its best friend <a href=\"https:\/\/docs.docker.com\/compose\/reference\/overview\/\">docker-compose<\/a>. To give these tools some credit, each of them supports myriads of different command line arguments and options so discussing all of them would make this section literally endless. Instead, we would be focusing on most useful classes of the commands, pointing to the relevant sections of the documentation in case you would like to learn more right away.<\/p>\n<p><a href=\"https:\/\/www.docker.com\/\">Docker<\/a> evolves very fast and as such, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> and <a href=\"https:\/\/docs.docker.com\/compose\/reference\/overview\/\">docker-compose<\/a> are constantly changing as well, adding some new command line arguments while deprecating others. Breaking changes are not so rare but this is a reality <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> users are facing for quite a while now.<\/p>\n<p>One of the largest changes which came into effect recently concerned exactly the command line tooling. In the past, the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> used to accept a single command as the first argument followed by list of options. However, the amount of different commands grew so large, that the tool became really confusing and cumbersome to use. It was decided to split the commands into classes (for example <strong>image<\/strong>, <strong>container<\/strong>, <strong>network<\/strong>, <strong>volume<\/strong>, <strong>plugin<\/strong>, <strong>system<\/strong>, \u2026) so the every command will be preceded by its class (for example, <strong>docker build<\/strong> becomes <strong>docker image build<\/strong>). It was a really needed change and although the old-style usage of the commands is still supported, we would adhere to the recommended practices in the tutorial.<\/p>\n<p>The section is structured in such a way so to familiarize you with the most useful commands while not really digging into the details and usage scenarios. The rationale behind is quite simple though, in the next sections of the tutorial we are going to battle-test most (if not all) of them while doing really practical things.<\/p>\n<h2><a name=\"images\"><\/a>2. Images<\/h2>\n<p>It looks logical to start from the bottom and get acquainted with <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> by learning how to build images. In the first section of the tutorial we have briefly walked through the process but it is time to do it ourselves using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_build\/\">build<\/a> command.<\/p>\n<pre class=\"brush:bash\">docker image build [OPTIONS] PATH | URL | -\n<\/pre>\n<p>As we remember, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> builds images from the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a>s, executing each instruction in the order it is specified. The PATH or URL options are the hints where to look for the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a>.<\/p>\n<p>Building small and efficient images, and doing so fast, is one of the key goals to aim for in order to be successful with <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>. Image caching, labeling, tagging, reducing the final size of the image and many other topics are nicely summarized in the <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/dockerfile_best-practices\/\">best practices for writing Dockerfiles<\/a>, it is highly recommended to go over this read.<\/p>\n<p>You may rarely find the need to build your own base images so let us talk instead what would be our choices in order to pick the base image for Java applications.<\/p>\n<p>As of now, objectively, the <a href=\"https:\/\/alpinelinux.org\/\">Alpine Linux<\/a> is the de facto base Linux distribution for the containerized applications. If you happen to run your applications on <a href=\"https:\/\/en.wikipedia.org\/wiki\/OpenJDK\">OpenJDK<\/a>, you are really lucky as the project\u2019s <a href=\"https:\/\/hub.docker.com\/_\/openjdk\/\">official DockerHub repository<\/a> provides plenty of the images based on <a href=\"https:\/\/alpinelinux.org\/\">Alpine Linux<\/a>. Quickly, here is a simplest <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> example:<\/p>\n<pre class=\"brush:bash\">FROM openjdk:8u131-jdk-alpine\nCMD [\"java\", \"-version\"]\n<\/pre>\n<p>Assuming your shell is pointing to the same folder where this <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> resides, you can build (and also tag) the image with this command:<\/p>\n<pre class=\"brush:bash\">docker image build . --tag base:openjdk-131-jdk\n<\/pre>\n<p>In case you bet on <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html\">Oracle JVM<\/a> distributions, sadly the <a href=\"https:\/\/alpinelinux.org\/\">Alpine Linux<\/a> is not officially supported yet (although you may see that some people are trying to marry those two together, please be aware that it kind of feasible but the JVM process in the container could crash any time). The options here are either to use <a href=\"https:\/\/store.docker.com\/images\/oracle-serverjre-8\">official Oracle Java 8 SE (Server JRE) image<\/a> or build your own based on <a href=\"https:\/\/hub.docker.com\/_\/ubuntu\/\">Ubuntu<\/a> or <a href=\"https:\/\/hub.docker.com\/_\/debian\/\">Debian<\/a> distributions.<\/p>\n<p>In terms of which JVM version to build upon, please make sure to use at least <strong>Java 8 update 131<\/strong> or later, for the reasons we will discuss in details in the upcoming sections (but if you are curious, here is the <a href=\"https:\/\/blogs.oracle.com\/java-platform-group\/java-se-support-for-docker-cpu-and-memory-limits\">sneak peek behind the curtain<\/a>).<\/p>\n<p>Along with <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/build\/\">build<\/a>, there is a couple of very useful commands which are worth mentioning. The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_ls\/\">ls<\/a> command shows all the images:<\/p>\n<pre class=\"brush:bash\">docker image ls [OPTIONS] [REPOSITORY[:TAG]]\n<\/pre>\n<p>The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_history\/\">history<\/a> command shows the history of an image:<\/p>\n<pre class=\"brush:bash\">docker image history [OPTIONS] IMAGE\n<\/pre>\n<p>While the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_rm\/\">rm<\/a> command removes one or more images:<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"brush:bash\">docker image rm [OPTIONS] IMAGE [IMAGE...]\n<\/pre>\n<p>To interface with registries, there are <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_pull\/\">pull<\/a> and <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_push\/\">push<\/a> commands. The first one fetches the image from a registry while the latter uploads it to the registry.<\/p>\n<pre class=\"brush:bash\">docker image pull [OPTIONS] NAME[:TAG|@DIGEST]\ndocker image push [OPTIONS] NAME[:TAG]\n<\/pre>\n<p>Lastly, the exceptionally useful <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_prune\/\">prune<\/a> command removes all unused images (which you have better to use with <strong>-a<\/strong> option all the time):<\/p>\n<pre class=\"brush:bash\">docker image prune [OPTIONS]\n<\/pre>\n<p>One of the tremendously useful features introduced by <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> in the recent release is the support of <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a> which allows to have multiple FROM statements in the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a>. We would just mention that here but it will come back to us in the upcoming sections of the tutorial.<\/p>\n<h2><a name=\"containers\"><\/a>3. Containers<\/h2>\n<p>Container management constitutes a large portion of the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> functionally and there are a lot of different commands to back it up. Let us start by dissecting super powerful <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_run\/\">run<\/a> command, which spawns a new container:<\/p>\n<pre class=\"brush:bash\">docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]\n<\/pre>\n<p>To get a feeling of how easy it is, we could run the container using our <a href=\"https:\/\/en.wikipedia.org\/wiki\/OpenJDK\">OpenJDK<\/a>-based image which we have hand-built previously:<\/p>\n<pre class=\"brush:bash\">$ docker container run base:openjdk-131-jdk\n\nopenjdk version \"1.8.0_131\"\nOpenJDK Runtime Environment (IcedTea 3.4.0) (Alpine 8.131.11-r2)\nOpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)\n<\/pre>\n<p>Once you have the containers running, you could <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_attach\/\">attach<\/a> to them or use <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_start\/\">start<\/a> \/ <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_stop\/\">stop<\/a> \/ <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_restart\/\">restart<\/a> commands to manage their lifecycle.<\/p>\n<pre class=\"brush:bash\">docker container attach [OPTIONS] CONTAINER\ndocker container start [OPTIONS] CONTAINER [CONTAINER...]\ndocker container stop [OPTIONS] CONTAINER [CONTAINER...]\ndocker container restart [OPTIONS] CONTAINER [CONTAINER...]\n<\/pre>\n<p>Additionally, with <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_pause\/\">pause<\/a> \/ <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_unpause\/\">unpause<\/a> commands you have the control over the state of the processes within the containers.<\/p>\n<pre class=\"brush:bash\">docker container pause CONTAINER [CONTAINER...]\ndocker container unpause CONTAINER [CONTAINER...]\n<\/pre>\n<p>Probably, the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_ls\/\">ls<\/a> command will be the most used one as it lists all running containers (and with <strong>-a<\/strong> option all containers, running and stopped):<\/p>\n<pre class=\"brush:bash\">docker container ls [OPTIONS]\n<\/pre>\n<p>Consequently, the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_inspect\/\">inspect<\/a> command display detailed information about one or more containers:<\/p>\n<pre class=\"brush:bash\">docker container inspect [OPTIONS] CONTAINER [CONTAINER...]\n<\/pre>\n<p>The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_stats\/\">stats<\/a> command is designated to expose runtime statistics about the container. The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_top\/\">top<\/a> command shows running container processes while the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_logs\/\">logs<\/a> command fetches the logs of the container.<\/p>\n<pre class=\"brush:bash\">docker container stats [OPTIONS] [CONTAINER...]\ndocker container top CONTAINER \ndocker container logs [OPTIONS] CONTAINER\n<\/pre>\n<p>Over its lifetime container could go through many modifications and diverge from its base image significantly. The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_diff\/\">diff<\/a> command inspects all the changes to files or directories on a container\u2019s filesystem and reports them.<\/p>\n<pre class=\"brush:bash\">docker container diff CONTAINER\n<\/pre>\n<p>In case you would need to capture these changes, there is a handy <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_commit\/\">commit<\/a> command which creates a new image from the container.<\/p>\n<pre class=\"brush:bash\">docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]\n<\/pre>\n<p>Once container is not needed anymore, it could be terminated using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_rm\/\">rm<\/a> command. Please be cautious as all the data stored inside the container will be gone (unless it is backed by <a href=\"https:\/\/docs.docker.com\/engine\/admin\/volumes\/volumes\/\">volumes<\/a>).<\/p>\n<pre class=\"brush:bash\">docker container rm [OPTIONS] CONTAINER [CONTAINER...]\n<\/pre>\n<p>More extreme version of <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_rm\/\">rm<\/a> command, the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_prune\/\">prune<\/a> command, mass-removes all stopped containers.<\/p>\n<pre class=\"brush:bash\">docker container prune [OPTIONS]\n<\/pre>\n<h2><a name=\"ports\"><\/a>4. Ports<\/h2>\n<p>Every container could expose ports to listen at runtime, either through image <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> instructions or through the options of the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_run\/\">run<\/a> command. The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_port\/\">port<\/a> command lists all port mappings (or a specific mapping) for the container.<\/p>\n<pre class=\"brush:bash\">docker container port CONTAINER [PRIVATE_PORT[\/PROTO]]\n<\/pre>\n<h2><a name=\"volumes\"><\/a>5. Volumes<\/h2>\n<p>As we remember, containers are ephemeral and once the container is terminated, all the data it holds will be lost. It might not be a problem in many cases, but if you run the data store in a container for example, it is very likely you would prefer to keep your data.<\/p>\n<p>To fill this gap <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> introduces <a href=\"https:\/\/docs.docker.com\/engine\/admin\/volumes\/volumes\/\">volumes<\/a> as the preferred mechanism for persisting data used by containers and, obviously, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> has a dedicated class of commands for that (<a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_create\/\">create<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_inspect\/\">inspect<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_ls\/\">ls<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_prune\/\">prune<\/a> and <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_rm\/\">rm<\/a>).<\/p>\n<pre class=\"brush:bash\">docker volume create [OPTIONS] [VOLUME]\ndocker volume inspect [OPTIONS] VOLUME [VOLUME...]\ndocker volume ls [OPTIONS]\ndocker volume prune [OPTIONS]\ndocker volume rm [OPTIONS] VOLUME [VOLUME...]\n<\/pre>\n<p>[ulp id=&#8217;MD25RnPuC2vrVItl&#8217;]<br \/>\n&nbsp;<\/p>\n<h2><a name=\"networks\"><\/a>6. Networks<\/h2>\n<p><a href=\"https:\/\/www.docker.com\/\">Docker<\/a> has pretty good <a href=\"Docker%20container%20networking\">networking support<\/a> for containers with a number of network drivers available out of the box. Surely, the standard set of <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_create\/\">create<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_inspect\/\">inspect<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_ls\/\">ls<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_prune\/\">prune<\/a> and <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/volume_rm\/\">rm<\/a> commands is available to manage the networks.<\/p>\n<pre class=\"brush:bash\">docker network create [OPTIONS] NETWORK\ndocker network inspect [OPTIONS] NETWORK [NETWORK...]\ndocker network ls [OPTIONS]\ndocker network prune [OPTIONS]\ndocker network rm NETWORK [NETWORK...]\n<\/pre>\n<p>What distinguishes <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> networking is the fact the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/dockerd\/\">dockerd<\/a> daemon contains an embedded DNS server which provides names resolution among containers connected to the same user-define network (so that the containers could be referenced by their names, not only IP addresses).<\/p>\n<p>Any running container could be connected to the network or disconnected from the network using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/network_connect\/\">connect<\/a> and <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/network_disconnect\/\">disconnect<\/a> commands respectively.<\/p>\n<pre class=\"brush:bash\">docker network connect [OPTIONS] NETWORK CONTAINER\ndocker network disconnect [OPTIONS] NETWORK CONTAINER\n<\/pre>\n<p>Aside from that, the container could be connected to a particular network by passing the options to the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_run\/\">run<\/a> command. All unused networks could be removed by invoking the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/network_prune\/\">prune<\/a> command.<\/p>\n<pre class=\"brush:bash\">docker network prune [OPTIONS]\n<\/pre>\n<h2><a name=\"linking\"><\/a>7. Linking<\/h2>\n<p>More often than not your application stack would be composed of many connected components rather than standalone ones (a typical example would be a Java server-side application which talks to <a href=\"https:\/\/hub.docker.com\/_\/mysql\/\">MySQL<\/a> data store). Projecting that to the world of containers, you would need a group of containers which could somehow discover their upstream dependencies and communicate with each other. In <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> it used to be known as <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/networking\/default_network\/dockerlinks\/\">linking<\/a> but nowadays it could be easily achieved using <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/networking\/work-with-networks\/#connect-containers\">user-defined networks<\/a> (which is also the recommended practice).<\/p>\n<h2><a name=\"health\"><\/a>8. Health Checks<\/h2>\n<p>Usually <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> daemon provisions the containers pretty fast however it does not mean that the applications packaged inside the containers are ready and fully functional. For many <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> users it used to be one of the most annoying issues to deal with, forcing the community to come up with many ad-hoc solutions to the problem.<\/p>\n<p>But kudos to <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> team, we now have <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#healthcheck\">health checks<\/a> (which could be specified in the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> or using the options of the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_run\/\">run<\/a> command). It is an additional verification layer which instructs the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> on how to test that the application inside the container is working. It resulted into adding a new <strong>health status<\/strong> property to complement the regular container status.<\/p>\n<h2><a name=\"limits\"><\/a>9. Resource Limits<\/h2>\n<p>Interestingly, by default a container has no resource constraints and may consume all the resources of its host operating system. It could have been a show-stopper but fortunately <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> provides <a href=\"https:\/\/docs.docker.com\/engine\/admin\/resource_constraints\/\">a way to control<\/a> how much memory, CPU, or block I\/O a particular container can use by passing a number of options to the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_run\/\">run<\/a> command. Alternatively, for the running containers the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/container_update\/\">update<\/a> command allows to adjust the container configuration (primary, resource limits) dynamically.<\/p>\n<pre class=\"brush:bash\">docker container update [OPTIONS] CONTAINER [CONTAINER...]\n<\/pre>\n<p>With respect to JVM running inside the container, the subject of the CPU and memory limits gets a bit trickier. As of <strong>Java SE 8u131<\/strong> (and surely in <strong>JDK 9<\/strong>) and later, the <a href=\"https:\/\/blogs.oracle.com\/java-platform-group\/java-se-support-for-docker-cpu-and-memory-limits\">JVM is Docker-aware<\/a> and with just a little bit of tuning is able to play nicely according to the rules.<\/p>\n<h2><a name=\"clean\"><\/a>10. Clean up<\/h2>\n<p>As we have seen so far, there are a lot of abstractions you can manage with <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>. However, with a time <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> generates a lot of garbage (like unused layers, images, containers, volumes, \u2026), eating the precious disk space. It has been a known issue for years but since not long ago we have a dedicated <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/system_prune\/\">prune<\/a> command which cleans up all unused data:<\/p>\n<pre class=\"brush:bash\">docker system prune [OPTIONS]\n<\/pre>\n<p>Please note that by default the command will not clean up the volumes unless the <strong>&#8211;volumes<\/strong> option is specified.<\/p>\n<h2><a name=\"compose\"><\/a>11. All-in-One: The Deployment Stack<\/h2>\n<p>As we have seen up to this point, you can accomplish any task using just <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> command line tool. But managing lifecycle of multiple containers connected together will quickly become a burden and force you to think about automating the process, ether with bunch of shell scripts or alike.<\/p>\n<p>The community has realized the problem early on and came up with a brilliant solution to that, known these days as <a href=\"https:\/\/docs.docker.com\/compose\/overview\/\">Docker Compose<\/a>. In a nutshell, <a href=\"https:\/\/docs.docker.com\/compose\/overview\/\">Docker Compose<\/a> provides the declarative way for defining and then running multiple <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> containers, drastically simplifying the rather complex deployment of the containerized application stacks.<\/p>\n<p>So how does it work? There are just a three simple steps involved, some of them we are already quite familiar with:<\/p>\n<ul>\n<li>Prepare the images for your applications, usually by means of <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a>s<\/li>\n<li>Use <a href=\"https:\/\/docs.docker.com\/compose\/compose-file\/compose-file-v2\/\">docker-compose.yml<\/a> specification to outline your stack in terms of containers<\/li>\n<li>Use <a href=\"https:\/\/docs.docker.com\/compose\/reference\/overview\/\">docker-compose<\/a> command line tool to materialize the specification into a set of running (and usually connected) containers<\/li>\n<\/ul>\n<p>Let us take a quick look on imaginable deployment stack which involves the JDK image we have created before, <code>base:openjdk-131-jdk<\/code>, and <a href=\"https:\/\/hub.docker.com\/_\/mysql\/\">MySQL<\/a> database image <code>mysql:8.0.2<\/code>, all put into the <a href=\"https:\/\/docs.docker.com\/compose\/compose-file\/compose-file-v2\/\">docker-compose.yml<\/a> file.<\/p>\n<pre class=\"brush:bash\">version: '2.1'\n\nservices:\n  mysql:\n    image: mysql:8.0.2\n    environment:\n      - MYSQL_ROOT_PASSWORD=p$ssw0rd\n      - MYSQL_DATABASE=my_app_db\n    expose:\n      - 3306\n    networks:\n      - my-app-network\n\n  java-app:\n    image: base:openjdk-131-jdk\n    mem_limit: 256M\n    environment:\n      - DB=mysql:3306\n    ports:\n      - 8080\n    depends_on:\n      - mysql\n    networks:\n      - my-app-network\n\nnetworks:\n    my-app-network:\n       driver: bridge\n<\/pre>\n<p>Pretty neat and straightforward, isn\u2019t it? The versioning of the <a href=\"https:\/\/docs.docker.com\/compose\/compose-file\/compose-file-v2\/\">docker-compose.yml<\/a> specification formats needs a particular discussion. The latest and recommended specification format is <code>3.x<\/code>, but <code>2.x<\/code> which we have used in the example above <a href=\"https:\/\/docs.docker.com\/compose\/compose-file\/compose-versioning\/\"> is also supported and evolves independently<\/a>. Why is that?<\/p>\n<p>The <code>3.x<\/code> is designed to be cross-compatible between <a href=\"https:\/\/docs.docker.com\/compose\/overview\/\">Docker Compose<\/a> and <a href=\"https:\/\/docs.docker.com\/engine\/swarm\/swarm-tutorial\/\">Docker Swarm<\/a> (clustering solution we are going to touch upon briefly later on in the tutorial) but sadly, it also removes several very useful options (along with adding a few more). In general, we are going to stick to <code>3.x<\/code> whenever we can, falling back to <code>2.x<\/code> from time to time to showcase some really neat features.<\/p>\n<h2><a name=\"conclusions\"><\/a>12. Conclusions<\/h2>\n<p>In this section we glanced over <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> awesome command line tooling, <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> and <a href=\"https:\/\/docs.docker.com\/compose\/reference\/overview\/\">docker-compose<\/a>, highlighting the most useful and important commands. We have not seen most of them in action yet but in the next sections of the tutorial each of them is going to find the time to appear on the stage.<\/p>\n<h2><a name=\"next\"><\/a>12. What\u2019s next<\/h2>\n<p>Although it is quite possible that these tools would be your primary (if not the only) way to deal with <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>,\u00a0in the next section of the tutorial we are going to learn the other option by leveraging <a href=\"https:\/\/docs.docker.com\/engine\/api\/\">Docker Engine REST(ful) APIs<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can develop your own Docker based applications. We cover a wide range of topics, from Docker over command line, to development, testing, deployment and continuous integration. With our straightforward &hellip;<\/p>\n","protected":false},"author":141,"featured_media":24013,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[936],"class_list":["post-68860","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-docker"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Docker for Java Developers: Docker over command line - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Docker for Java Developers: Docker over command line - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2017-09-25T07:00:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-11T08:22:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Andrey Redko\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrey Redko\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html\"},\"author\":{\"name\":\"Andrey Redko\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\"},\"headline\":\"Docker for Java Developers: Docker over command line\",\"datePublished\":\"2017-09-25T07:00:16+00:00\",\"dateModified\":\"2023-12-11T08:22:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html\"},\"wordCount\":2271,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"keywords\":[\"Docker\"],\"articleSection\":[\"DevOps\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html\",\"name\":\"Docker for Java Developers: Docker over command line - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"datePublished\":\"2017-09-25T07:00:16+00:00\",\"dateModified\":\"2023-12-11T08:22:16+00:00\",\"description\":\"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/09\\\/docker-java-developers-docker-command-line.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DevOps\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/devops\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Docker for Java Developers: Docker over command line\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\",\"name\":\"Andrey Redko\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"caption\":\"Andrey Redko\"},\"description\":\"Andriy is a well-grounded software developer with more then 12 years of practical experience using Java\\\/EE, C#\\\/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).\",\"sameAs\":[\"http:\\\/\\\/aredko.blogspot.com\\\/\",\"http:\\\/\\\/ca.linkedin.com\\\/in\\\/aredko\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/andrey-redko\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Docker for Java Developers: Docker over command line - Java Code Geeks","description":"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html","og_locale":"en_US","og_type":"article","og_title":"Docker for Java Developers: Docker over command line - Java Code Geeks","og_description":"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can","og_url":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2017-09-25T07:00:16+00:00","article_modified_time":"2023-12-11T08:22:16+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","type":"image\/jpeg"}],"author":"Andrey Redko","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Andrey Redko","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html"},"author":{"name":"Andrey Redko","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413"},"headline":"Docker for Java Developers: Docker over command line","datePublished":"2017-09-25T07:00:16+00:00","dateModified":"2023-12-11T08:22:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html"},"wordCount":2271,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","keywords":["Docker"],"articleSection":["DevOps"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html","url":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html","name":"Docker for Java Developers: Docker over command line - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","datePublished":"2017-09-25T07:00:16+00:00","dateModified":"2023-12-11T08:22:16+00:00","description":"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2017\/09\/docker-java-developers-docker-command-line.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"DevOps","item":"https:\/\/www.javacodegeeks.com\/category\/devops"},{"@type":"ListItem","position":3,"name":"Docker for Java Developers: Docker over command line"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413","name":"Andrey Redko","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","caption":"Andrey Redko"},"description":"Andriy is a well-grounded software developer with more then 12 years of practical experience using Java\/EE, C#\/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).","sameAs":["http:\/\/aredko.blogspot.com\/","http:\/\/ca.linkedin.com\/in\/aredko"],"url":"https:\/\/www.javacodegeeks.com\/author\/andrey-redko"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/68860","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/141"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=68860"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/68860\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/24013"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=68860"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=68860"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=68860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}