Debugging any JVM in a Docker container

Thanks to JAVA_TOOL_OPTIONS variable it’s easy to run any JVM-based Docker image in debug mode. All we have to do is  add environment variable definition „JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005” in docker run or docker-compose.yml and expose port to connect debugger

Reklamy

On why and how to exit JVM on OnOutOfMemoryError

For a long time all my JVM-based Docker images were configured to exit on OOM error with -XX:OnOutOfMemoryError=”kill -9 %p” (%p is the current JVM process PID placeholder). It works well with XX:+HeapDumpOnOutOfMemoryError, because JVM will dump heap first, and then execute OnOutOfMemoryError command (see the relevant code in vm/utilities/debug.cpp ). But with version 8u92 there’s now a JVM option in the JDK to make the JVM exit when an OutOfMemoryError occurs:

From the release notes:

ExitOnOutOfMemoryError
When you enable this option, the JVM exits on the first occurrence of an out-of-memory error. It can be used if you prefer restarting an instance of the JVM rather than handling out of memory errors.

CrashOnOutOfMemoryError
If this option is enabled, when an out-of-memory error occurs, the JVM crashes and produces text and binary crash files.

Enhancement Request: JDK-8138745 (parameter naming is wrong though JDK-8154713ExitOnOutOfMemoryError instead of ExitOnOutOfMemory)

 

Why exit on OOM? OutOfMemoryError may seem like any other exception, but if it escapes from Thread.run() it will cause thread to die. When thread dies it is no longer a GC root, and thus all references kept only by this thread are eligible for garbage collection. While it means that JVM has a chance recover from OOME, its not recommended that you try. It may work, but it is generally a bad idea. See this answer on SO.

JVM in Docker and PTRACE_ATTACH

Docker nowadays (since 1.10, the original pull request is here docker/docker/#17989) adds some security to running containers by wrapping them in both AppArmor (or presumably SELinux on RedHat systems) and seccomp eBPF based syscall filters (here’s a nice article about it). And ptrace is disabled in the default seccomp profile.

$ docker run alpine sh -c 'apk add -U strace && strace echo'
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
(1/1) Installing strace (4.11-r2)
Executing busybox-1.24.2-r11.trigger
OK: 6 MiB in 12 packages
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
+++ exited with 1 +++

Why am I writing about this? Because some JDK tools depend on PTRACE_ATTACH on Linux. One of them is  very useful jmap.

Turning seccomp off (–security-opt seccomp=unconfined) is not recommended, but we can add just this one explicit capability  with –cap-add=SYS_PTRACE.

$ docker run --cap-add=SYS_PTRACE alpine sh -c 'apk add -U strace && strace echo'
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
(1/1) Installing strace (4.11-r2)
Executing busybox-1.24.2-r11.trigger
OK: 6 MiB in 12 packages
execve("/bin/echo", ["echo"], [/* 5 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7feaca3a8b28) = 0
set_tid_address(0x7feaca3a8b60) = 10
mprotect(0x7feaca3a5000, 4096, PROT_READ) = 0
mprotect(0x558c47ec6000, 16384, PROT_READ) = 0
getuid() = 0
write(1, "\n", 1) = 1
exit_group(0) = ?
+++ exited with 0 +++

Docker Compose supports cap_add since version 1.1.0 (2015-02-25).

If you run into an issue with the jmap and jstack from OpenJDK failing with exception java.lang.RuntimeException: unknown CollectedHeap type : class sun.jvm.hotspot.gc_interface.CollectedHeap make sure you install openjdk-debuginfo package (or openjdk-8-dbg or something similiar depending on distro).

Play! Framework – część I

Z związku z moim zainteresowaniem Scalą i Akką naturalnym jest zajęcie się ostatnim elementem stosu reaktywnych technologii dla JVM od Typesafe – frameworkiem Play. Niniejszy wpis stanowi, mam nadzieję, pierwszy z serii wpisów opisujących moją przygodę z tym frameworkiem.

Czym jest Play?

Play jest moim zdaniem najlepszym frameworkiem ogólnego przeznaczenia dla JVM
Ogólnie rzeczy ujmując Play to implementacja wzorca MVC w oparciu o model aktów Akka połączona ze środowiskiem do zarządzania projektem i uruchamiania go

Co w nim tak bardzo mi się podoba?

Jednym z głównych filarów architektonicznych Play jest podejście bezstanowe i asynchroniczne.  W Play nie ma tradycyjnej „sesji”. Takie podejście nastręcza czasami pewne trudności, ale są one z nawiązką rekompensowane przez zalety takie jak łatwość horyzontalnego skalowania i wsparcie dla technologi reaktywnych. I Scala. Uwielbiam Scalę.

Zacznijmy jednak od podstaw.

Szkielet aplikacji Play można łatwo wygenerować za pomocą narzędzia Typesafe Activator  – activator new [name] [template-id] – ale nie jest dobry sposób na rozpoczęcie przygody z Play.

activator new my-play-app play-scala

Zacznijmy więc od minimalnej aplikacji Play do której będziemy dodawać kolejne elementy w miarę potrzeby. Minimalna aplikacja jest naprawdę niewielka i składa się z czterech plików z których jeden (application.conf) jest pusty a jeden (build.properties) tak naprawdę  opcjonalny.

$ ls -R
.:
build.properties build.sbt conf/ project/

./conf:
application.conf

./project:
plugins.sbt

build.sbt

name := """my-play-app"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.7"

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

project/plugins.sbt

// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.4")

project/build.properties

sbt.version=0.13.11

Nie jest to co prawda zbyt przydatna aplikacja – ale kompiluje się i uruchamia bez przeszkód o czym możemy się przekonać wydając polecenie activator ~run w katalogu aplikacji.

Skrypt wykonujący poszczególne krotki jest dostępny jako Gist

bash <(curl -fsSL https://git.io/vKW88) my-play-app

Running Linux graphical applications in Docker on Windows with Cygwin/X

Install Babun

Cygwin is a great tool, but not the easiest to install. Babun consists of a pre-configured Cygwin  that does not interfere with existing Cygwin installation.

Download the dist file from http://babun.github.io, unzip it and run the install.bat script. After a few minutes the application will be installed to the %USERPROFILE%\.babun directory. You can use the /target (or /t)  option to install babun to a custom directory.

Install Cygwin/X

Run pact from babun shell (pact is a babun package manager )

pact install xorg-server xinit xhost

Start the X server

Once the installation has completed, open a Cygwin terminal and run XWin :0 -listen tcp -multiwindow. This will start an X server on Windows machine
with the ability to listen to connections from the network (-listen tcp) and display
each application in its own window (-multiwindow), rather than a single window acting
as a virtual screen to display applications on. Once it’s started, you should see an
„X” icon in Windows tray area.

Run graphical application

fr3nd/xeyes  is a good test to run

// don't forget to change WINDOWS_MACHINE_IP_ADDR!
// 'localhost' obviously won't work from within Docker container
docker run -e DISPLAY=$WINDOWS_MACHINE_IP_ADDR:0 --rm fr3nd/xeyes

Or we can build ourselves image with Firefox using the following Dockerfile as a starting point

FROM centos

RUN yum -y update && yum install -y firefox

CMD /usr/bin/firefox

docker build -t firefox . it and run the container with

export DISPLAY=$WINDOWS_MACHINE_IP_ADD:0
docker run -ti --rm -e DISPLAY=$DISPLAY firefox

If all goes well you should see Firefox running from within a Docker container.

Troubleshooting

If you have issues with authorization you may want to try running the insecure xhost + command to permit access from all machines. See xhost(1) Linux man page.

Alternatives

There are a few different options to run GUI applications inside a Docker container like using SSH with X11 forwarding or VNC.

Podstawy Akka – izolacja aktorów

Aktorzy w Akka mogą się komunikować tylko przez asynchroniczne przesyłanie komunikatów. Do wysłania komunikatu potrzebny jest uchwyt na aktora (lub selecja) który może być uzyskany w wyniku

  • rodzicielstwa (parenthood) – aktor A tworzy B więc posiada na niego referencję
  • obdarowania (endowment) – kiedy A tworzy B może mu przekazać cześć lub wszystkie uchwyty które sam posiada
  • przedstawienia (introduction) –  jeśli aktor A posiada uchwyty na B i C może wysłać do C komunikat zawierający uchwyt do B. B może wówczas zachować ten uchwyt do dalszego użycia
  • selekcji – w praktyce selekcja jest bardzo podobna do uchwytu. Aktor może wyszukać innych aktorów po nazwach stosując m.in wyrażenia wieloznaczne (context.actorSelection(„/user/*”)) i ścieżki względne (context.actorSelection(„../*”))

 

http://doc.akka.io/docs/akka/current/general/addressing.html