Kwert-soft.ru

IT Софт для ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Docker java 8

Docker + Java Microservices: Choosing the Base Image for Java 8/9 Microservices (on Linux and Windows)

Defining the base image is one of the most important decisions when creating docker containers. Here I will describe some of the reasoning when you do that for Java Spring Boot Microservices.

Introduction

Containers were designed to be self-contained and isolated. However, the environment in which it runs does affect the decision on what base image you should use.

You may run on a Windows machine that is already running Linux Docker Containers. Or the machine is running only windows containers (or no containers at all). Or maybe you are even thinking about running a Linux container on the same Windows Server. There are relevant questions on what Java base image you should choose.

In this article, I will share some of the things I learned along the way on how to make those decisions, and how to justify them to your Devops department.

Note: If you haven’t yet learned how to create a Java Spring Boot Microservice, I recommend you this reading: Docker + Spring Boot Microservice (with Gradle).

Quick pick on Docker Layers

It would be wasteful to go too much into detail about how Docker Layers work due to the extensive documentation available in the Docker website.

However, it’s important to review some of its practical concepts here for the purpose of this article:

  1. «Each Docker image has its own root filesystem, which needs to have some sort of OS installed» (Rohan Singh on his Stackoverflow answer)
  2. If you then create 3 microservice and Dockerize them using the same base layer, you will have to distribute your base layer just once, and then 3 smaller container images for each of your microservices.

Let’s move on and talk about Java base images, which are the ones we are interested about.

Difference between Windows Containers and Linux Containers

Docker provides to its containers the same types of resources in both OS. It also has a compatible API for both distributions.

However, there are differences on the “flavours” with which these resources are delivered to the containers.

Ajeet Singh Raina, docker captain, wrote a great article on «A Comparative Study of Docker Engine on Windows Server Vs Linux Platform» (see more at http://collabnix.com/archives/1965), from which we can learn details about the resource sharing differences for each platform.

For that reason, the underlying operating system running the Docker Engine will affect (a) the base image supported and therefore (b) the applications that can possibly run on top of that base image.

Running Java Spring Boot Microservices, how do I choose between Windows Containers or Linux Containers?

The following flowchart is what I use as decision tree when it comes to defining what type of image I will be deploying:

My personal take is: I prefer in most of the cases, prefer Linux Containers running Alpine base images.

Can I run Windows Containers and Linux Containers alongs >Currently, Docker for Windows cannot run Linux Containers alongside Windows Containers. That limitation might disappear, but I rarely see any benefit of locking myself in, even in the short run, specially when developing to run on top of the the JVM.

Also, the Linux Containers can run beautifully on Windows as well. The main difference is that they will run inside a Hyper-V Linux VM. And remember: Hyper-V is a Type1 Hypervisor, therefore suffers less with the overhead.

Hyper-V on requires BIOS Virtualization ON, and breaks VirtualBox

Hyper-V, as well as other Type 1 hypervisors, requires the Virtualization option to be ON in your BIOS.

That can cause some Type 2 Hypervisors (like VirtualBox, Virtual PC, VMWare Workstation) to stop working. It’s a known problem between Hyper-V and VirtualBox to fight each other.

I will keep ourselves in the Containers land, but it’s not hard to find more information about the differences between the 2 types of hypervisors.

Base Java Images for Linux Containers

Having left clear that my preference is run on top of Linux Containers the most I can, I will now show some details on using them.

Official Dockerhub Java Repository

Let’s start with the official java repository on dockerhub, you will quickly notice that it’s been DEPRECATED and it will be referring you to the openjdk repository.

OpenJDK Dockerhub Repository

When you land to the openjdk repository on Dockerhub, you will notice a large number of images, including a few ones I would like to highlight here for now:

As you can see that the 9-jdk is alone, but the 8-jre and 7-jre have companions: their alpine editions.

What is the difference? Their base image.

openjdk:8-jre-alpine, a smaller image

Taking a look at the size of the images, you will find the sizes for each image. And there, you will see the advantage of using an alpine image.

Let’s dig a little to find why these images are so different.

Why *-alpine base images are smaller?

Regular openjdk uses a debian:jessie base image. On the other hand, the openjdk-alpine images use a linux alpine base image. The later is fairly lighter than the first.

These base images will use 2 different linux distros, and that is their main difference. To know more about these distros:

Читать еще:  Создание игр на javascript книга

For Java Spring Boot Microservices, which image?

If you are writing a Java Spring Boot Microservice, you are probably better with the alpine image.

Unless you really use debian specific stuff directly from your java application, it’s very unlikely it will be an advantage for you.

So, as a general rule, you may want to write your microservice containers using «8-jre-alpine» as the base image.

Openjdk images Under the Hood

Visiting the Github of the OpenJDK Dockerfiles of the images, you would quickly spot the difference:

Alternatives to Linux Java Images?

A few days ago, I was doing some research on base image alternatives and I found an article named «Smaller Java Images with Alpines» from the Atlassian Developers blog, talking exactly about it.

In a nutshell, by the time the article was writing, docker pull java would result in approximately 800MB downloaded. And they were suggesting the alpine:3.2 image base layer as solution.

Fortunately, openjdk has better images now (even the regular images are smaller), including the alpine alternatives.

Therefore, my conclusion is that the official openjdk base images are stable enough to be used, and you should probably stick to them.

If you go away from the official images, beware of licensing. I’m going to go a little bit more into licensing further down the road in this paper.

Base Java Images for Windows Containers

There are basically 2 types of Containers that run on Windows:

  • Windows Server Containers: natively delivering Windows Kernel features to the Container, hence forcing the container to run a Windows base image that is compatible to those features of the Kernel.
  • Hyper-V Containers: which run ins > In this section we will talk exclusively about Windows Server Containers, because the Hyper-V Containers do not differ from the Linux Containers mentioned above in any aspect.

«Switching to Windows Containers…»

At the moment, it’s only possible to run one or the other (Windows containers OR Linux Containers), not the 2 at the same time. This limitation will probably be removed in future and Windows will become advantageous in that aspect.

When you install Docker on a Windows machine you will see, in the context menu of your notification area Docker icon, the following:

When you do this, you will have selected to only run Windows Containers, which are the ones we will be covering from now onwards.

OpenJDK Dockerhub Repository (for Windows Images)

The Dockerhub repository has a lot of images for running windows containers as well. I will narrow down the list into the following:

What? 5GB on WindowsServerCore? What can I do on the Nanoserver?

Yes, you got it right! windowsservercore images are 5GB, 90% bigger than the nanoserver images. Why? It’s a whole Windows Server (Core Edition) packaged up.

Listening to the Dockercast Podcast with Stefan Scherer, I was introduced to a few limitations that the NanoServer can have. The one that caught my attention was the lack of ability to install MSIs.

I insist on my belief that: Docker Containers should run a simple (self-hosted, in case of web apps or rest apis) process runs with a single command line statement. Even (and specially) for ASP.NET WebApi, be it .NETCore or not.

If you stick to single command line self-hosted applications, the nanoserver will probably be enough for you, and a much lighter option.

Github for Windows JDK Container Images

  • I found that most of the Dockerfiles for Windows containers load the entire JDK, not just the JVM.
  • Curiously, I d > openjdk:8-nanoserver, Dockerfile

A word or two on Licensing…

Special thanks to Dermot Bradley who pointed me out to the Licensing problem on Oracle Java Images during the Northern Ireland Developers Conference April/2017 and also led me to check for the official OpenJDK Dockerhub Repository.

Dermot is a Devops Champion in Belfast, Northern Ireland area who has spoken in meetups and has a GREAT! presentation on Microcontainers, Microservices and Microservers, extremely recommended, who has helped me a lot to understand better about the underlying structure of Docker.

Your base image must not distribute Oracle’s JDK/JRE, make sure your base image uses OpenJDK

Until not long ago, the only JRE/JDK version available for Java 8 was Oracle’s.

We now have OpenJDK 8 and 9, which does not breach their Licensing terms of distribution, even when distributed with your Docker containers.

Therefore, double check if you are not by mistake using any base image that breaches any license terms before you start doing your things with it.

Licensing on Windows Containers

Researching on Windows Containers license, here is what popped up:

For production, licensing is at the host level, i.e. each machine or VM which is running Docker. Your Windows licence on the host allows you to run any number of Windows Docker containers on that host. With Windows Server 2016 you get the commercially supported version of Docker included in the licence costs, with support from Microsoft and Docker, Inc.

For development, Docker for Windows runs on Windows 10 and is free, open-source software. Docker for Windows can also run a Linux VM on your machine, so you can use both Linux and Windows containers in development. Like the server version, your Windows 10 licence allows you to run any number of Windows Docker containers.

Windows admins will want a unified platform for managing images and containers. That’s Docker Datacenter which is separately licensed, and will be available for Windows soon.

In simple terms, as long as the underlying Windows Server is properly licensed, you can run Windows Docker Containers with it. And form Windows Server 2016, you have specific licensing terms applying to it.

Conclusion

Linux Containers and Alpine images would be my choice for Java Spring Boot Microservices whenever it is possible.

It’s just a matter of checking if your production environment will already be locked into Windows Containers, which will very unlikely be the case, and your decision will be an easy one.

Thanks for the time, and I hope you enjoyed it.

Docker java 8

GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.

Clone with HTTPS

Use Git or checkout with SVN using the web URL.

Downloading

Want to be notified of new releases in William-Yeh/docker-java8 ?

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio

Latest commit

Files

Permalink

TypeNameLatest commit messageCommit time
Failed to load latest commit information.
.dockerignore
.gitignore
Dockerfile
README.md
Vagrantfile

Repository name in Docker Hub: williamyeh/java8

This repository contains Dockerized Java 1.8, published to the public Docker Hub via automated build mechanism.

This docker image contains the following software stack:

OS: Debian jessie (built from debian:jessie).

Java: Oracle JDK 1.8.0_31-b13

Why yet another Java image for Docker?

There has been quite a few Java images for Docker (e.g., search in the Docker Hub), so why reinvent the wheel?

In the beginning I used the pulse00/java. It worked well, but left some room for improvement:

Base OS image — It was built from stackbrew/ubuntu:13.10, which may not be the smallest one. On the other hand, debian:jessie, as recommended in this article, worth a try.

Unnecessary dependencies — It installed, at the very beginning of its Dockerfile, the software-properties-common package, which in turns installed some Python3 packages. I prefered to incorporate these stuff only when absolutely needed.

Therefore, I built this Docker image on my own, also as an exercise.

errordeveloper/oracle-jdk, if you prefer a minimalistic Oracle JDK 8 container on top of busybox.

java or azul/zulu-openjdk, if you prefer OpenJDK.

Used mostly as a base image for other Java-based applications. But if you’d like to use the CLI, here are some examples for you.

Java внутри Docker: что нужно знать, чтобы не было проблем

На моем последнем проекте я столкнулся с проблемой: приложения Java внутри Linux Docker-контейнеров потребляли очень много памяти. Например, некоторые из наших микросервисов (на основе Spring Boot) внутри контейнера могли использовать до двух гигабайт памяти, тогда как при обычном запуске вне контейнера показатель был в районе 200-300 мегабайт.

После недолгого гугления оказалось, что когда мы запускаем приложения как «java -jar mypplication-fat.jar», то JVM по умолчанию приспосабливается к среде выполнения, в которой она работает и таким образом обеспечивается максимально возможное быстродействие java-программ.

CGroups и старые приложения

В Docker-контейнерах, как и в виртуальных машинах (Virtual Machines, VM), можно разграничивать ресурсы, выделять количество ядер и виртуальной памяти. При этом контейнеры обладают отличной изоляцией ресурсов (CPU, память, файловые системы), и один контейнер совершенно ничего не знает о других. Таким образом контейнеры не мешают работе друг друга, и мы можем запускать десятки контейнеров с разными переменными средами (environment) и конфигурациями. Такая изоляция возможно только благодаря возможности ядра Linux — cgroups.

Однако некоторые из приложений были разработаны задолго до появления cgroups. Такие инструменты, как ‘top’, ‘ps’, ‘free’, а также и JVM, не оптимизированы для эффективной работы в контейнерах.

Ограничим память

Первое, что может прийти на ум — это ограничить размер самого Docker-контейнера. Создадим простое приложение на Spring Boot и запустим контейнер, поставив ограничение памяти 150 мегабайт. Вот пример команды на хосте с одним гигабайтом памяти:

В приложении заранее был создан rest-метод, который загружает память до отказа объектами типа String. Вызовем его:

Вызванный метод возвращает что-то вроде «Выделено более чем 80% памяти (219.8 MiB) из максимально доступных JVM (241.7 MiB) «.

Но отсюда два вопроса:

1. Почему максимальный размер для JVM 241 мегабайт?

2. Если мы выше указали, что контейнеру доступно только 150 мегабайт памяти, то почему приложение потребляет почти 220?

Первое, что нужно помнить о максимальном размере кучи (max heap size) у JVM, это то, что размер по умолчанию будет занимать 1/4 памяти. И второе — когда мы при запуске контейнера выше указывали флаг «-m 150M», то докер зарезервировал 150 мегабайт в оперативной памяти и 150 мегабайт в Swap. Поэтому-то приложение и не рухнуло и отработало как нужно. Но при этом вы должны понимать, что увеличение памяти в контейнере — это не решение проблемы. Всегда может случиться ситуация, когда Java-приложение может выйти за рамки лимита, и тогда процесс будет убит.

Решение проблемы

Решений проблем может быть несколько, но мы поговорим о лучшем, на мой взгляд, способе.

Начиная с JDK 8u131+ и JDK 9 нам дали возможность использовать экспериментальные возможности JVM, которые позволяют нам обращаться к возможностям вышеупомянутых CGroups. Одна из этих возможностей — это настроить JVM так, чтобы она автоматически определяла максимальное возможное потребление памяти с помощью опции -XX:+UseCGroupMemoryLimitForHeap. Попробуем:

JVM прочитала, что максимум доступно памяти 600 мегабайт, и создала JVM с максимальным размером памяти примерно 150 мегабайт. Ровно четверть, как и говорилось выше.

Ну и как пример, мое приложение на работе без ограничений использовало 1.7 гигабайта памяти, после того, как я использовал экспериментальные фичи и ограничил размер контейнера до 512 мегабайт — 331 мегабайт.

Кроме того, ограничение памяти контейнеров таким образом помогает легко и быстро проводить нагрузочное тестирование, чтобы узнать о возможностях своего детища.

Материал подготовлен и частично переведен при помощи статьи с developers.readhat.com

Материал опубликован пользователем.
Нажмите кнопку «Написать», чтобы рассказать свою историю.

Docker support in Java 8 — finally!

Java 8 didn’t play nice with Docker, now the problems are gone.

Please note: In this post I use OpenJDK official docker images licensed under GNU GPL v2 license . In Oracle Java SE docker support described here was introduced in update 191 . Oracle changed the license for Java 8 updates in April 2019 and since Java SE 8 Update 211 commercial use is no longer free.

Have you ever experienced “random” failures of JVM based applications running in the docker? Or maybe some strange freezes? Both could be caused by poor docker support in Java 8 (which is still widely used).

Docker uses control groups (cgroups) to limit resources. It’s definitely a good idea to limit memory and CPU while running applications in containers — it prevents an application from using the whole available memory and/or CPU, which makes other containers running on the same system unresponsive. Limiting resources improves reliability and stability of applications. It also allows to plan for the hardware capacity. It’s especially important when running containers on an orchestration system, like Kubernetes or DC/OS.

The problem

The JVM “sees” the whole memory and all CPU cores available on the system and aligns its resources to it. It sets — by default — the maximum heap size to 1/4 of system memory and sets some thread pools size (for example for GC) to the number of physical cores. Let’s run an example.

We’ll run a simple application which consumes as much memory as it can (found on this site):

We run it on a system with 64GB of memory, so let’s check the default maximum heap size:

As said — it’s 1/4 of physical memory — 16GB. What will happen if we limit the memory using docker cgroups? Let’s check:

The JVM process was killed. Since it was a child process — the container itself survived, but normally when java is the only process inside a container (with PID 1) the container will crash.

Let’s look into system logs:

Failures like these can be very difficult to debug — there is nothing in the application logs. It can be especially difficult on managed systems like AWS ECS.

And how about CPUs? Let’s check it again running a small program which displays the number of available processors:

Let’s run it in a docker container with cpu number set to 1:

Not good — there are 12 CPUs on this system indeed. So even the number of available processors is limited to 1, the JVM will try to use 12 — for example the GC threads number is set by this formula:

On a machine with N hardware threads where N is greater than 8, the parallel collector uses a fixed fraction of N as the number of garbage collector threads. The fraction is approximately 5/8 for large values of N. At values of N below 8, the number used is N.

The Solution

OK, we are now aware of the problem. Is there a solution for it? Fortunately — yes, there is!

The new Java version (10 and above) docker support is already built-in. But sometimes upgrading is not an option — for example if the application is incompatible with the new JVM.

The good news: Docker support was also backported to Java 8. Let’s check the newest openjdk image tagged as 8u212 . We’ll limit the memory to 1G and use 1 CPU: docker run -ti —cpus 1 -m 1G openjdk:8u212-jdk

It’s 256M — exactly 1/4 of allocated memory.

Exactly as we wanted.

Moreover, there are some new settings:

They allow to fine-tune the heap size — the meaning of those settings is explained in this excellent answer on StackOverflow. Please note — they set the percentage, not the fixed values. Thanks to it changing Docker memory settings will not break anything.

If for some reason the new JVM behaviour is not desired it can be switched off using -XX:-UseContainerSupport .

Summary

It’s extremely important to set correct heap size for JVM-based applications. With the newest Java 8 version you can rely on the default settings which are safe (but quite conservative, though). There is no need to use any hacky workarounds in a docker entrypoint, nor setting Xmx as fixed value anymore.

Ссылка на основную публикацию
Adblock
detector