<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Roland Huß</title><link>https://ro14nd.de/</link><description>Recent content on Roland Huß</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>© 2026 Roland Huß</copyright><lastBuildDate>Sat, 04 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://ro14nd.de/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog winter is over</title><link>https://ro14nd.de/blog-winter-is-over/</link><pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate><guid>https://ro14nd.de/blog-winter-is-over/</guid><description>&lt;p&gt;The last post on this blog was about &lt;a href="https://github.com/GoogleContainerTools/jib" target="_blank" rel="noreferrer"&gt;Jib&lt;/a&gt;, Google&amp;rsquo;s daemonless Java image builder. That was July 2018. Almost eight years ago. Anybody remember when that was the latest hotness?&lt;/p&gt;
&lt;p&gt;Before that, I wrote about Docker when Docker was still exciting and built a &lt;a href="https://ro14nd.de/kubernetes-on-raspberry-pi3/" &gt;Kubernetes cluster on Raspberry Pi 3&lt;/a&gt; nodes when that was still a weekend adventure. I spent way too many words on Jolokia and JMX. 27 posts between 2010 and 2018, then silence. If you&amp;rsquo;ve been reading tech blogs long enough, you know how that goes.&lt;/p&gt;
&lt;p&gt;So what breaks eight years of silence?&lt;/p&gt;

&lt;h2 class="relative group"&gt;Why the silence
 &lt;div id="why-the-silence" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#why-the-silence" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s no dramatic story here, no burnout or life crisis.
I just stopped at some point because my writing energy went elsewhere.
I co-authored &lt;a href="https://learning.oreilly.com/library/view/kubernetes-patterns-2nd/9781098131678/" target="_blank" rel="noreferrer"&gt;Kubernetes Patterns&lt;/a&gt; with Bilgin Ibryam (first edition in 2019, second in 2023). More recently, I finished &lt;a href="https://learning.oreilly.com/library/view/generative-ai-on/9781098171919/" target="_blank" rel="noreferrer"&gt;Generative AI on Kubernetes&lt;/a&gt; with Daniele Zonca in 2026.&lt;/p&gt;
&lt;img src="https://ro14nd.de/images/blog-winter-is-over/books-k8s-patterns-genai.png" alt="Kubernetes Patterns and Generative AI on Kubernetes" style="max-width: 350px; margin: 1em auto; display: block;" /&gt;
&lt;p&gt;Writing books is a strange experience.
You pour months into a manuscript, and when it ships, you&amp;rsquo;re proud and drained at the same time.
But once the last book was out in March 2026, something shifted. The pressure was gone, the gap between having something to say and sitting down to write it started closing, and I wanted to write shorter, more opinionated pieces again.&lt;/p&gt;

&lt;h2 class="relative group"&gt;What changed
 &lt;div id="what-changed" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#what-changed" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The tech world of 2026 looks nothing like 2018. AI-first engineering isn&amp;rsquo;t a conference buzzword anymore. It&amp;rsquo;s how I work every day. The way I write code, design systems, and think about developer experience has shifted more in the last year than in the decade before. Last month I scaffolded a complete operator in two days that would have taken two weeks in 2018, and most of my work was writing the specification, not the code.&lt;/p&gt;
&lt;p&gt;Context engineering became something I care about deeply. Not in the abstract &amp;ldquo;prompt engineering&amp;rdquo; sense, but in the practical &amp;ldquo;how do you structure specifications so that AI agents produce useful output&amp;rdquo; sense. I&amp;rsquo;ve been deep into Spec Driven Development, particularly &lt;a href="https://github.com/github/spec-kit" target="_blank" rel="noreferrer"&gt;spec-kit&lt;/a&gt; from GitHub. I have opinions about it, even as the whole field is still taking shape.&lt;/p&gt;
&lt;p&gt;When you find yourself explaining the same ideas in conversations, Slack threads, and pull request descriptions over and over again, that&amp;rsquo;s usually a sign you should write them down properly.&lt;/p&gt;

&lt;h2 class="relative group"&gt;What&amp;rsquo;s coming
 &lt;div id="whats-coming" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#whats-coming" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The topic I keep coming back to is &lt;strong&gt;context engineering and Spec Driven Development&lt;/strong&gt;: how I structure specifications for agentic coding workflows, what works, what fails, and why the &amp;ldquo;just give it a prompt&amp;rdquo; approach misses the point. This will probably be a recurring theme, because the field is moving fast and there&amp;rsquo;s a lot to figure out in public.&lt;/p&gt;
&lt;p&gt;Close behind is &lt;strong&gt;AgentOps on Kubernetes&lt;/strong&gt;. Running agentic workloads on Kubernetes and OpenShift is a different beast than classic web services. Agents are unpredictable, long-running, and resource-hungry. They talk to the outside world in ways that make security teams nervous. I&amp;rsquo;m ramping up on this topic professionally, figuring out how to operate these workloads in a secure and scalable way. Expect posts about the particular demands of AI agents and why your existing Deployment patterns won&amp;rsquo;t cut it.&lt;/p&gt;
&lt;p&gt;Beyond those two, expect posts about AI-first engineering in daily practice (the surprising wins, the things that still don&amp;rsquo;t work), agentic coding projects and tools, the home K3s cluster that&amp;rsquo;s been running on five Raspberry Pi 4 nodes for over five years, book-adjacent Kubernetes patterns, and whatever else catches my attention.&lt;/p&gt;

&lt;h2 class="relative group"&gt;On AI and this blog
 &lt;div id="on-ai-and-this-blog" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#on-ai-and-this-blog" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Since AI changed how I work, it naturally changed how I write too. I use AI tools for ideation, polishing, and managing the publishing workflow. The thinking and the opinions stay mine. Every post carries an &lt;a href="https://aiattribution.github.io" target="_blank" rel="noreferrer"&gt;AI attribution tag&lt;/a&gt; at the bottom so you know exactly what role AI played. I apply the same principle I advocate in the &lt;a href="https://vibe-coding-manifesto.com/" target="_blank" rel="noreferrer"&gt;Responsible Vibe Coding Guide&lt;/a&gt;: use AI as a tool, but own the result. I&amp;rsquo;ll write more about the process in a future post.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Let&amp;rsquo;s see
 &lt;div id="lets-see" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lets-see" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not going to promise a posting schedule. That kind of commitment didn&amp;rsquo;t work last time, and I see no reason to repeat it. But I have more things to write about now than at any point during the old blog&amp;rsquo;s run. Eight years ago, Jib was the latest hotness. The next post won&amp;rsquo;t take that long.&lt;/p&gt;
&lt;div class="ai-attribution"&gt;
&lt;p&gt;&lt;a href="https://aiattribution.github.io/statements/AIA-HAb-CeNc-Hin-R-?model=Claude%20Opus%204.6-v1.0" target="_blank" rel="noreferrer"&gt;AIA HAb CeNc Hin R Claude Opus 4.6 v1.0&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description></item><item><title>First look at Jib</title><link>https://ro14nd.de/jib-vs-dmp/</link><pubDate>Wed, 11 Jul 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jib-vs-dmp/</guid><description>&lt;p&gt;As soon as Google&amp;rsquo;s blog post &lt;a href="https://cloudplatform.googleblog.com/2018/07/introducing-jib-build-java-docker-images-better.html" target="_blank" rel="noreferrer"&gt;&amp;ldquo;Introducing Jib — build Java Docker images better&amp;rdquo;&lt;/a&gt; was online, all my channels went crazy about &lt;a href="https://github.com/GoogleContainerTools/jib" target="_blank" rel="noreferrer"&gt;Jib&lt;/a&gt;.
That was a bit surprising as Jib was started over one year ago but with this blog post this project rockets with more than 1000 new GitHub stars within one day. Crazy.&lt;/p&gt;
&lt;p&gt;I got a lot asked yesterday how Jib compares to &lt;a href="https://github.com/fabric8io/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;fabric8io/docker-maven-plugin&lt;/a&gt; (d-m-p) or &lt;a href="https://github.com/fabric8io/fabric8-maven-plugin" target="_blank" rel="noreferrer"&gt;fabric8io/fabric8-maven-plugin&lt;/a&gt; which includes d-m-p.&lt;/p&gt;
&lt;p&gt;Let me try to shed some light on the differences and pro and cons of both approaches.&lt;/p&gt;

&lt;h2 class="relative group"&gt;How Jib works
 &lt;div id="how-jib-works" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#how-jib-works" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s first have a quick look what Jib offers today and what makes it unique.&lt;/p&gt;
&lt;p&gt;Looking at the Jib Maven plugin it currently supports three goals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jib:dockerBuild&lt;/code&gt; for assembling an image and loading it to a Docker daemon.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jib:build&lt;/code&gt; for assembling the image and pushing it to a Docker registry.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jib:exportDockerContext&lt;/code&gt; for creating a Dockerfile along with all the files required for performing a build against a Docker daemon.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The unique asset of Jib is that it does all of this &lt;em&gt;without consulting a Docker daemon&lt;/em&gt; by creating all image layers and metadata locally, conforming to either the Docker or OCI format.
And that all directly with plain Java code.&lt;/p&gt;
&lt;p&gt;Also, Jib assumes a very opinionated project setup with a so-called &lt;em&gt;flat classpath app&lt;/em&gt; with main class, dependencies and resources all in different artefacts.
Compare this to &lt;em&gt;fat jars&lt;/em&gt; popularised by Spring Boot, where the application code, resources and dependencies are all stored in the same jar file.
There are some drawbacks of flat classpath app, but one benefit is, that you can organise the various files into several layers in your image, putting the one which is changing less (like dependencies) at the bottom of the layer stack.
That&amp;rsquo;s what Jib does: It puts all dependency jars into one layer, all resource files (like property files to be loaded from the classpath) in another and the application classes into a third layer.
All of these layers get aggressively cached locally.
That way, you can be much faster when recreating images than with fat jars which apparently can be stored only in one single layer.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s have a look how Jib works in detail. The steps performed by a &lt;code&gt;jib:dockerBuild&lt;/code&gt; or &lt;code&gt;jib:build&lt;/code&gt; are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fetch base image&amp;rsquo;s layers and cache them locally. By default the base image is &lt;code&gt;gcr.io/distroless/java&lt;/code&gt;, but this can be configured.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create three application image layers for&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependencies&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;li&gt;Classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since these layers are cached, if any of them doesn&amp;rsquo;t change (which is likely for dependencies), then the layer is not recreated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the application image locally. The two previous steps were performed asynchronously; this step continues when both previous steps have been finished. The &lt;code&gt;ENTRYPOINT&lt;/code&gt; of this image is fixed set to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; java &amp;lt;jvm-flags&amp;gt; -cp dep_dir/*:resource_dir/:class_dir/ &amp;lt;main-class&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;&amp;lt;jvm-flags&amp;gt;&lt;/code&gt; can optionally be configured and &lt;code&gt;&amp;lt;main-class&amp;gt;&lt;/code&gt; is the mandatory main class to specify. The information leading to the classpath comes from the underlying Maven or Gradle project information. Also, any Java arguments configured to become the &lt;code&gt;CMD&lt;/code&gt; of the image, as well the exposed ports (&lt;code&gt;EXPOSE&lt;/code&gt;) can be added, too.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally the local image layers along with its meta-data is tarred up, and either loaded into a Docker daemon or pushed to a Docker registry.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;How does Jib compare to d-m-p ?
 &lt;div id="how-does-jib-compare-to-d-m-p-" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#how-does-jib-compare-to-d-m-p-" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Jib is impressive for the use case it supports and brings a fresh spin to the way how Java apps can be packaged into Docker images.&lt;/p&gt;
&lt;p&gt;The most significant benefits of Jib are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast for incremental builds when you have a &lt;em&gt;flat classpath application&lt;/em&gt;, resulting in three different layers for dependencies, resources and your application classes.&lt;/li&gt;
&lt;li&gt;No Docker daemon required, which reduces the build requirements and increases security because the image creation happens without root permissions.&lt;/li&gt;
&lt;li&gt;Produces reproducible images by wiping out file owner and modifications date. However, not sure whether e.g. generated timestamps in resource files like properties are wiped out, too.&lt;/li&gt;
&lt;li&gt;It supports both, Maven and Gradle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, there are also some limitations. Some of them might be tackled in the future, but other might not be changed due to the unique way how Jib works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can be only used for simple &lt;em&gt;flat classpath&lt;/em&gt; Java applications. There is currently no support for fat jars (i.e. Spring Boot fat jars) nor other packaging formats like WAR file.&lt;/li&gt;
&lt;li&gt;Simplistic startup of the application with a plain &lt;code&gt;java&lt;/code&gt; call instead of using a full features startup script like &lt;a href="https://github.com/fabric8io-images/run-java-sh" target="_blank" rel="noreferrer"&gt;run-java-sh&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;No additional files like configuration files outside the classpath or agents like &lt;code&gt;jmx_exporter&lt;/code&gt; agent can be added (but there is a &lt;a href="https://github.com/GoogleContainerTools/jib/pull/455" target="_blank" rel="noreferrer"&gt;PR&lt;/a&gt; pending for agents).&lt;/li&gt;
&lt;li&gt;Fixed classpath order, e.g. doesn&amp;rsquo;t allow for overwritten resources in dependencies as dependencies are always first on the classpath.&lt;/li&gt;
&lt;li&gt;Jib uses a custom XML configuration syntax instead of plain Dockerfile syntax (which I often heard as a major critique about d-m-p which also supports a custom XML configuration, but as alternative to Dockerfiles).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;d-m-p provides some additional features which are not supported by Jib, like&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running containers for integration testing (that&amp;rsquo;s very likely the most prominent difference)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dockerfile&lt;/code&gt; support&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; support&lt;/li&gt;
&lt;li&gt;Enhanced authentication support OpenShift and Amazon ECR support&lt;/li&gt;
&lt;li&gt;Support for watching code change and then automatically triggering a rebuild of images and restart of containers&lt;/li&gt;
&lt;li&gt;Support for arbitrary assembly and base images, including Spring Boot fat jar and JavaEE containers.&lt;/li&gt;
&lt;li&gt;Healthchecks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And if you jump to &lt;a href="https://github.com/fabric8io/fabric8-maven-plugin" target="_blank" rel="noreferrer"&gt;fabric8-maven-plugin&lt;/a&gt;, which includes d-m-p for its image building business, you have even more high level features like a &lt;a href="https://maven.fabric8.io/#zero-config" target="_blank" rel="noreferrer"&gt;zero config&lt;/a&gt; mode which analyses your &lt;code&gt;pom.xml&lt;/code&gt; and selects opinionated defaults like base images and handcrafted startup scripts, depending on the type of tech stack you are using (like Spring Boot, Thorntail, Vert.x, Tomcat, &amp;hellip;)&lt;/p&gt;

&lt;h2 class="relative group"&gt;Next steps &amp;hellip;
 &lt;div id="next-steps-" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#next-steps-" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This overview is only a quick glance on Jib. In one of the next posts, I plan to show some real-life examples and also measuring the performance gain by using Jib.&lt;/p&gt;
&lt;p&gt;Also, there a plans for d-m-p to add support for Jib backend and other daemonless build systems like &lt;a href="https://github.com/genuinetools/img" target="_blank" rel="noreferrer"&gt;img&lt;/a&gt;, &lt;a href="https://github.com/projectatomic/buildah" target="_blank" rel="noreferrer"&gt;buildah&lt;/a&gt; or &lt;a href="https://github.com/GoogleContainerTools/kaniko" target="_blank" rel="noreferrer"&gt;kaniko&lt;/a&gt;.
The mid to longterm plan is to enhance the build abstraction within d-m-p and offer, based on the Java project given, different ways to build images.&lt;/p&gt;
&lt;p&gt;BTW, if you are interested in what&amp;rsquo;s going on in Docker image building business these days, you probably might find this &lt;a href="https://www.youtube.com/watch?v=qhykcC94ukg" target="_blank" rel="noreferrer"&gt;KubeCon presentation&lt;/a&gt; as useful as I did. Daemonless FTW :)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Psst, d-m-p also likes GitHub &lt;a href="https://github.com/fabric8io/docker-maven-plugin/stargazers" target="_blank" rel="noreferrer"&gt;★&lt;/a&gt; ;-)&lt;/em&gt;&lt;/p&gt;</description></item><item><title>docker-maven-plugin might be still useful</title><link>https://ro14nd.de/dmp-not-so-bad/</link><pubDate>Thu, 05 Jul 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/dmp-not-so-bad/</guid><description>&lt;p&gt;Yesterday a blog post &lt;a href="https://codefresh.io/howtos/using-docker-maven-maven-docker/" target="_blank" rel="noreferrer"&gt;Using Docker from Maven and Maven from Docker&lt;/a&gt; by &lt;a href="https://twitter.com/codepipes" target="_blank" rel="noreferrer"&gt;Kostis Kapelonis&lt;/a&gt; was published which gives some insights on the possible relationships between Docker and Maven.
The article makes some essential points really, and gives an overview for the two remaining Docker Maven plugins as well as how &lt;a href="https://codefresh.io/" target="_blank" rel="noreferrer"&gt;Codefresh&lt;/a&gt; recommends doing Docker multi-stage builds as the alternative.
As I&amp;rsquo;m the maintainer of the &lt;a href="https://dmp.fabric8.io/" target="_blank" rel="noreferrer"&gt;fabric8io/docker-maven-plugin&lt;/a&gt;, I&amp;rsquo;d like to comment on this matter.&lt;/p&gt;
&lt;p&gt;I already commented on the original blog post (thanks for approving the comment), but I&amp;rsquo;m happy to repeat my arguments
here again.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://codefresh.io/howtos/using-docker-maven-maven-docker/" target="_blank" rel="noreferrer"&gt;article&lt;/a&gt; ditches two docker-maven-plugins before it promotes Docker multi-stage builds for some reasons.&lt;/p&gt;
&lt;p&gt;To be honest, I think both approaches have their benefits, but let me comment first on two arguments given concerning the &lt;a href="https://github.com/fabric8io/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;fabric8io/docker-maven-plugin&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;There have been cases in the past where Docker has broken compatibility even between its client and server, so a Maven plugin that uses the same API will instantly break as well.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;This compatibility issue might be right especially if you use a typed approach to access the Docker REST API which is used by various Docker client libraries. As explained in the post, fabric8 d-m-p accesses the Docker daemon directly without any client library and with not marshalling. This is because it accesses only the parts required for the plugin&amp;rsquo;s feature set, which also means that json responses are handled in a very defensive and untyped way.&lt;/p&gt;
&lt;p&gt;And yes, there was one issue in the early days in 2014 with a backwards-incompatible API change from Docker. This issue could be fixed quite quickly because d-m-p hadn&amp;rsquo;t to wait for a client library to be updated. However, since then there never has been an issue and for the core functionality that d-m-p uses.&lt;/p&gt;
&lt;p&gt;I think the relevance of Docker API incompatibilities is exaggerated in this blog post.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Hopefully, the fabric8 plugin also supports plain Dockerfiles. Even there, however, it has some strong opinions. It assumes that the Dockerfile of a project is in src/main/docker and also it uses the assembly syntax for actually deciding what artefact is available during the Docker build step.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;That is simply not true. You can just put a Dockerfile on the same level as the pom.xml, refer to your artefacts in the &lt;code&gt;target/&lt;/code&gt; directory (with Maven property substitution), and then declare the plugin &lt;em&gt;without any configuration&lt;/em&gt;.
See my &lt;a href="https://ro14nd.de/simple-dockerfile-mode-dmp" target="_blank" rel="noreferrer"&gt;other blog post&lt;/a&gt; for a short description of how it works.&lt;/p&gt;
&lt;p&gt;BTW, the reason for the own XML syntax is a historical one. The plugin started in 2014 when Dockerfile was entirely unknown to Java developers. But Maven plugin XML configuration was (and still is) a well-known business. As time passed by and Docker become more and more popular for Java developers, the &lt;code&gt;Dockerfile&lt;/code&gt; syntax is well known now these days, too. So, I completely agree, that you should use Dockerfiles if possible, and that&amp;rsquo;s why the plugin supports Dockerfiles as a first-class citizen since the recent versions. The next step is to add similar support for &lt;code&gt;docker-compose.yml&lt;/code&gt; files for running containers. There is already docker compose support included, albeit a bit hidden.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I agree that multi-stage Docker builds are fantastic for generating reproducible builds, as the build tool (Maven) is used in a well-defined version. However, using a locally installed Maven during development has advantages, too. E.g. the local Maven repository avoids downloading artefacts over and over again, resulting in much faster build times and turnaround times. Of course, you can add caching to the mix for multi-stage builds, but then the setup gets more and more involved. Compare this to using a d-m-p for which you don&amp;rsquo;t even need a local Docker CLI installed, and you can &amp;lsquo;just start&amp;rsquo;. For CI builds this properly doesn&amp;rsquo;t matter much though (and that&amp;rsquo;s what the blog post is all about I guess).&lt;/p&gt;
&lt;p&gt;Other advantages of using fabric8&amp;rsquo;s d-m-p :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running all your containers (app + deps) locally without the need of support from a CI system. As a side note, the custom compose-like syntax of codefresh&amp;rsquo;s CI is not so much different to the custom configuration syntax of fabric8&amp;rsquo;s d-m-p. It&amp;rsquo;s custom.&lt;/li&gt;
&lt;li&gt;Extended authentication support against various registries (Amazon ECR, Google GCR, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;Automatic rebuilds during development with &lt;code&gt;docker:watch&lt;/code&gt; which increase turnaround times tremendously&lt;/li&gt;
&lt;li&gt;Download support files (e.g. startup scripts) automatically by just declaring a dependency in the plugin (blog post pending)&lt;/li&gt;
&lt;li&gt;&amp;hellip;. and even more stuff.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end, your mileage may vary, but having an article conclusion without really trying to compare pros and cons of both approaches is far too biased for me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: Kostis replied to my comment, and an interesting discussion is going over &lt;a href="https://codefresh.io/howtos/using-docker-maven-maven-docker/#comment-159" target="_blank" rel="noreferrer"&gt;there&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Elegant Camel route configuration</title><link>https://ro14nd.de/camel-routes-simplified/</link><pubDate>Tue, 03 Jul 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/camel-routes-simplified/</guid><description>&lt;p&gt;I&amp;rsquo;m a big fan of the &lt;a href="https://camel.apache.org/java-dsl.html" target="_blank" rel="noreferrer"&gt;Camel Java DSL&lt;/a&gt; for defining Camel routes with a &lt;code&gt;RouteBuilder&lt;/code&gt;. This is super easy and slim. However, in this blog post I show you a nerdy trick how this can be done even more elegant.&lt;/p&gt;
&lt;!--
&lt;img src="https://ro14nd.de/images/camel-routes-simplified/camel-logo.png" style="margin-top: 0px; margin-left: 40px; float: right"/&gt;
--&gt;
&lt;p&gt;If you are a Camel user, you know, that defining a route for a given Camel context &lt;code&gt;ctx&lt;/code&gt; ist just a matter to implement the &lt;code&gt;configure()&lt;/code&gt; method of the abstract &lt;code&gt;RouteBuilder&lt;/code&gt; class:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ctx.&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; RouteBuilder {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;configure&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; Exception {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; from(&lt;span style="color:#e6db74"&gt;&amp;#34;file:data/inbox?noop=true&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;file:data/outbox&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Its really simple and you can use the whole Camel machinery from within your &lt;code&gt;configure()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;However, this kind of configuration can be performed even simpler. Let&amp;rsquo;s assume that you have a no-op default implementation of &lt;code&gt;RouteBuilder&lt;/code&gt; called &lt;code&gt;Routes&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Routes&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; RouteBuilder {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;configure&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; Exception { }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, the configuration can be rewritten simply as&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ctx.&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Routes {{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; from(&lt;span style="color:#e6db74"&gt;&amp;#34;file:data/inbox?noop=true&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;file:data/outbox&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This trick just uses Java&amp;rsquo;s &lt;a href="https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html" target="_blank" rel="noreferrer"&gt;object initializers&lt;/a&gt;, a not so well known language feature. The inspiration for providing the DSL context like this comes from &lt;a href="https://jmockit.github.io/tutorial/Mocking.html#expectation" target="_blank" rel="noreferrer"&gt;JMockit&lt;/a&gt; which defines its mock expectations the same way. I think object initializers are really an elegant albeit hipster way to implement DSLs.&lt;/p&gt;
&lt;p&gt;Although you can easily define the &lt;code&gt;Routes&lt;/code&gt; class on your own, you might vote for this Camel &lt;a href="https://issues.apache.org/jira/browse/CAMEL-12608" target="_blank" rel="noreferrer"&gt;issue&lt;/a&gt; or &lt;a href="https://github.com/apache/camel/pull/2401" target="_blank" rel="noreferrer"&gt;pull request&lt;/a&gt; if you want to have this in upstream Camel, too.&lt;/p&gt;</description></item><item><title>When a Dockerfile is just good enough</title><link>https://ro14nd.de/simple-dockerfile-mode-dmp/</link><pubDate>Thu, 12 Apr 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/simple-dockerfile-mode-dmp/</guid><description>&lt;p&gt;As you might know, one of my Open Source babies is the one and only &lt;a href="https://github.com/fabric8io/docker-maven-plugin/" target="_blank" rel="noreferrer"&gt;fabric8io/docker-maven-plugin&lt;/a&gt; (d-m-p).
If you already use this Maven plugin, you know, that it is super powerful and flexible to configure.
This flexibility comes at a price so that the configuration can become quite complicated.
Now, if you only want to &lt;em&gt;build&lt;/em&gt; Docker images with Maven, I have good news:
Since 0.25.1 d-m-p supports a zero XML configuration mode, the so-called &lt;a href="https://dmp.fabric8.io/#simple-dockerfile-build" target="_blank" rel="noreferrer"&gt;Simple Dockerfile Build&lt;/a&gt; mode.&lt;/p&gt;
&lt;p&gt;The idea of this mode started with a Twitter discussion:&lt;/p&gt;
&lt;img src="https://ro14nd.de/images/simple-dockerfile-mode-dmp/maven-dmp-tweet.png" class="shadow center"/&gt;
&lt;p&gt;And actually, it&amp;rsquo;s true: If all that you want is to build a single Docker image from a Dockerfile, then the initial configuration is indeed too complex.&lt;/p&gt;
&lt;p&gt;d-m-p already supports &lt;a href="https://dmp.fabric8.io/#external-dockerfile" target="_blank" rel="noreferrer"&gt;plain Dockerfiles&lt;/a&gt; for quite some time, and that even for multiple images.
However, you still have to reference those Dockerfiles in the XML configuration of the plugin.&lt;/p&gt;
&lt;p&gt;Since 0.25.1 you can now use the so-called &lt;a href="https://dmp.fabric8.io/#simple-dockerfile-build" target="_blank" rel="noreferrer"&gt;Simple Dockerfile Build&lt;/a&gt; mode (kudos go to Rohan Kumar for the initial &lt;a href="https://github.com/fabric8io/docker-maven-plugin/pull/969" target="_blank" rel="noreferrer"&gt;implementation&lt;/a&gt;).
All you have to do is to add d-m-p to your &lt;code&gt;pom.xml&lt;/code&gt; and add a Dockerfile.
The smallest possible Maven project for creating a Docker image consists of this &lt;code&gt;pom.xml&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span style="color:#f92672"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;fabric8&lt;span style="color:#f92672"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;smallest&lt;span style="color:#f92672"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1-SNAPSHOT&lt;span style="color:#f92672"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.fabric8&lt;span style="color:#f92672"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;docker-maven-plugin&lt;span style="color:#f92672"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.26.0&lt;span style="color:#f92672"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;and a &lt;code&gt;Dockerfile&lt;/code&gt; alongside this pom:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;busybox&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CMD&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;echo&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;world!&amp;#34;&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This image does not really much.
With &lt;code&gt;mvn docker:build&lt;/code&gt; you can build it, with &lt;code&gt;docker run fabric8/smallest&lt;/code&gt; you can test it.
Or use &lt;code&gt;mvn docker:run&lt;/code&gt; so that you even don&amp;rsquo;t have to provide the image name.&lt;/p&gt;
&lt;p&gt;A more realistic Dockerfile could look like&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;openjdk:jre&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ARG&lt;/span&gt; jar&lt;span style="color:#f92672"&gt;=&lt;/span&gt;target/app-1.0.0-SNAPSHOT.jar&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ADD&lt;/span&gt; $jar /app.jar&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CMD&lt;/span&gt; java -cp /app.jar HelloWorld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;where we define &lt;code&gt;jar&lt;/code&gt; as &lt;a href="https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg" target="_blank" rel="noreferrer"&gt;build arg&lt;/a&gt; in the Dockerfile but also as property in the &lt;code&gt;pom.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;jar&amp;gt;&lt;/span&gt;${project.build.directory}/${project.build.finalName}.jar&lt;span style="color:#f92672"&gt;&amp;lt;/jar&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can use Maven properties in the Dockerfile which get automatically replaced by &lt;code&gt;docker:build&lt;/code&gt; when creating the image.
But you can use that Dockerfile also without Maven with &lt;code&gt;docker build .&lt;/code&gt;
You can&amp;rsquo;t use Maven properties with &lt;code&gt;.&lt;/code&gt; directly as dots are not allowed in Docker build args, therefore we use an extra property.
However, a maven-less usage probably does not make much sense when you don&amp;rsquo;t also build the artefacts.
The full example can be found in the &lt;a href="https://github.com/fabric8io/docker-maven-plugin/tree/master/samples/zero-config" target="_blank" rel="noreferrer"&gt;dmp GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you can forgo Docker build args you can use predefined Maven properties directly:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;openjdk:jre&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ADD&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;project.build.directory&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;project.build.finalName&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;.jar /app.jar&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CMD&lt;/span&gt; java -cp /app.jar HelloWorld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The image name is auto-generated, but you can set this name also by yourself by setting the property &lt;code&gt;docker.name&lt;/code&gt; (and you can use &lt;a href="https://dmp.fabric8.io/#image-name-placeholders" target="_blank" rel="noreferrer"&gt;placeholders&lt;/a&gt; within this name)&lt;/p&gt;
&lt;p&gt;You can even start the container with &lt;code&gt;mvn docker:run&lt;/code&gt; although without any additional configuration (e.g. like port mappings).
Also, you can &lt;code&gt;docker:push&lt;/code&gt; the image.&lt;/p&gt;
&lt;p&gt;You can still configure certain aspects like authentication or bind d-m-p goals to default lifecycle phases.
Using this mode is very similar to the functionality offered by &lt;a href="https://github.com/spotify/dockerfile-maven" target="_blank" rel="noreferrer"&gt;spotify/dockerfile-maven&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you need more horsepower, you can gradually expand on this simple setup.
Features which are waiting to be discovered are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setup of multiple images for running integration tests&lt;/li&gt;
&lt;li&gt;Custom networks and volumes for your tests&lt;/li&gt;
&lt;li&gt;Using docker-compose files for running the containers directly from the plugin&lt;/li&gt;
&lt;li&gt;Exporting the Docker image as an archive&lt;/li&gt;
&lt;li&gt;Watch docker containers and restart them when the code changes&lt;/li&gt;
&lt;li&gt;All can be configured via properties, too and since with the latest versions, you can mix it with XML configuration.&lt;/li&gt;
&lt;li&gt;&amp;hellip;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are interested in more to find out, then please have a look at the &lt;a href="https://dmp.fabric8.io/" target="_blank" rel="noreferrer"&gt;reference manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m curious what you think about this new mode.
Please use the comments below if you want to leave some feedback.
In fact, there are concrete plans for d-m-p to include the &lt;a href="https://maven.fabric8.io/#generators" target="_blank" rel="noreferrer"&gt;generators&lt;/a&gt; from the fabric8-maven-plugin functionality of autodetecting the tech stacks used for creating opinionated Docker images.&lt;/p&gt;</description></item><item><title>Bringing Octobox to OpenShift Online</title><link>https://ro14nd.de/octobox-oso/</link><pubDate>Sun, 25 Mar 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/octobox-oso/</guid><description>&lt;p&gt;&lt;a href="https://github.com/octobox/octobox" target="_blank" rel="noreferrer"&gt;Octobox&lt;/a&gt; is for sure one of my favourite tools in my GitHub centred developer workflow.
It is incredible for GitHub notification management which allows me to ignore all the hundreds of GitHub notification emails I get daily.&lt;/p&gt;
&lt;p&gt;Octobox is a Ruby-on-Rails application and can be used as SaaS at &lt;a href="https://octobox.io" target="_blank" rel="noreferrer"&gt;octobox.io&lt;/a&gt; or installed and used separately.
Running Octobox in an own account is especially appealing for privacy reasons and for advanced features which are not enabled in the hosted version (like periodic background fetching or more information per notification).&lt;/p&gt;
&lt;p&gt;This post shows how Octobox can be ported to the free &amp;ldquo;starter&amp;rdquo; tier of &lt;a href="https://www.openshift.com/pricing/index.html" target="_blank" rel="noreferrer"&gt;OpenShift Online&lt;/a&gt;.&lt;/p&gt;
&lt;img src="https://ro14nd.de/images/octobox-oso/octobox.png" style="margin: auto;"/&gt;

&lt;h2 class="relative group"&gt;Application setup
 &lt;div id="application-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#application-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;An Octobox installation consists of three parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Octobox itself, a Rails application&lt;/li&gt;
&lt;li&gt;Redis as an ephemeral cache, used as a session store&lt;/li&gt;
&lt;li&gt;Postgresql as the backend database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Naturally, this would lead to three services.
However, as I&amp;rsquo;m not striving for an HA setup and the sake of simplicity, I decided to combine Octobox and Redis in a single pod.
Since a combined lifecycle for Octobox and Redis is a reasonable, fair choice, this reduces the number of OpenShift resource objects considerably.&lt;/p&gt;
&lt;p&gt;As persistent store for Postgres, we use a plain &lt;code&gt;PersistentVolume&lt;/code&gt; which is good enough for our low-footprint database requirements.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Docker Images
 &lt;div id="docker-images" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#docker-images" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;To get an application onto OpenShift, you first need to package all parts of your application into Docker images which eventually become container during runtime.&lt;/p&gt;
&lt;p&gt;There are some &lt;a href="https://docs.openshift.org/latest/creating_images/guidelines.html" target="_blank" rel="noreferrer"&gt;restrictions&lt;/a&gt; for Docker images to be usable on OpenShift.
The most important one is that all containers run under a random UID, which is part of the Unix group &lt;code&gt;root&lt;/code&gt;.
This restriction has the consequence that all directories and files to which the application process want to write should belong to group &lt;code&gt;root&lt;/code&gt; and must be group writable.&lt;/p&gt;
&lt;p&gt;Octobox already is distributed as a &lt;a href="https://github.com/octobox/octobox/blob/bd6c2cbc4745363240482f36210509830d0c4bc1/Dockerfile" target="_blank" rel="noreferrer"&gt;Docker image&lt;/a&gt; and has recently be [updated][octobox-dockerfile-chgrp] to be OpenShift compatible.
The &lt;a href="https://docs.openshift.com/container-platform/3.7/using_images/db_images/postgresql.html" target="_blank" rel="noreferrer"&gt;Postgres image&lt;/a&gt; is directly picked up from an OpenShift provided ImageStream, so there is no issue at all.
The &lt;a href="https://hub.docker.com/r/centos/redis-32-centos7/" target="_blank" rel="noreferrer"&gt;Redis Imagee&lt;/a&gt; is also already prepared for OpenShift
However, when using Redis from this image in an ephemeral mode (so not using persistence) there is a subtle issue which prevents starting the Pod:
As the Dockerfile declares a &lt;a href="https://github.com/sclorg/redis-container/blob/7689bf310dc29f363f0cf7e0e74a457cda5a3f6e/3.2/Dockerfile#L73" target="_blank" rel="noreferrer"&gt;VOLUME&lt;/a&gt; and even though in our setup we don&amp;rsquo;t need it, we &lt;strong&gt;have&lt;/strong&gt; to declare a volume in the Pod definition anyway.
Otherwise, you end up with a cryptic error message in the OpenShift console (like &lt;code&gt;can't create volume ...&lt;/code&gt;).
An &lt;code&gt;emptyDir&lt;/code&gt; volume as perfectly good enough for this.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Template
 &lt;div id="template" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#template" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;To install the application an &lt;a href="https://github.com/octobox/octobox/blob/master/openshift/octobox-template.yml" target="_blank" rel="noreferrer"&gt;OpenShift Template&lt;/a&gt; has been created.
It contains the following objects&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DeploymentConfig&lt;/code&gt;s for &amp;ldquo;Octobox with Redis&amp;rdquo; and &amp;ldquo;Postgres&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Service&lt;/code&gt;s for Octobox and Postgres&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PersistentVolumeClaim&lt;/code&gt; for Postgres&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A route for accessing the app is created later on the OpenShift console.
Please refer to these &lt;a href="https://github.com/octobox/octobox/blob/master/openshift/OPENSHIFT_INSTALLATION.md" target="_blank" rel="noreferrer"&gt;installation instructions&lt;/a&gt; for more details how to use this templats.&lt;/p&gt;

&lt;h2 class="relative group"&gt;OpenShift Online Starter
 &lt;div id="openshift-online-starter" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#openshift-online-starter" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.openshift.com/pricing/index.html" target="_blank" rel="noreferrer"&gt;OpenShift Online Starter&lt;/a&gt; is the free tier of OpenShift online which is very useful for learning OpenShift concept and get one&amp;rsquo;s feet wet.
However, it has some quite restrictive resource limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 GB Memory&lt;/li&gt;
&lt;li&gt;1 GB Storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This budget is good enough for small applications like Octobox, but if you need more horsepower than you can easily upgrade to OpenShift Online Pro.&lt;/p&gt;
&lt;p&gt;The challenge is now to distribute the three parts (Octobox, Postgres, Redis) over these 1 GB.
As Octobox as rails application is quite a memory hog, we want to dedicate as much memory as possible to it.
For Postgres, we do not need much Memory at all, so 50 to 100 MB is good enough.
The same for Redis as an initial guess.
We can always tune this later if we found out that our initial guess a wrong.&lt;/p&gt;
&lt;p&gt;Ok, let&amp;rsquo;s start with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;875 MB Octobox&lt;/li&gt;
&lt;li&gt;50 MB Redis&lt;/li&gt;
&lt;li&gt;75 MB Postgres&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When trying out these limits, I quickly found out that this doesn&amp;rsquo;t work.
The reason is that OpenShift Online has a &lt;strong&gt;minimum&lt;/strong&gt; size for a container which is 100 MB.
Also, you can&amp;rsquo;t choose &lt;a href="https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/" target="_blank" rel="noreferrer"&gt;requests and limits&lt;/a&gt; freely, but there is a fixed ratio of 50% to calculate the &lt;code&gt;request&lt;/code&gt; from a given &lt;code&gt;limit&lt;/code&gt; (the &lt;code&gt;request&lt;/code&gt; specified is always ignored).
This fact not only means that you get a &lt;a href="https://medium.com/google-cloud/quality-of-service-class-qos-in-kubernetes-bb76a89eb2c6" target="_blank" rel="noreferrer"&gt;&lt;em&gt;Burstable&lt;/em&gt;&lt;/a&gt; QoS class, but also that you &lt;strong&gt;have&lt;/strong&gt; to specify 200 MB as &lt;code&gt;limit&lt;/code&gt; to get at least 100 MB &lt;code&gt;request&lt;/code&gt; to exceed the required minimum.&lt;/p&gt;
&lt;p&gt;So we end up with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;600 MB Octobox&lt;/li&gt;
&lt;li&gt;200 MB Redis&lt;/li&gt;
&lt;li&gt;200 MB Postgres&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apparently, this is not optimal, but that&amp;rsquo;s how it works for OpenShift Online Starter tier (and probably also the Pro Tier).
For other OpenShift cluster it, of course, depends on the setup of this specific cluster.
We could put Redis and Octobox in the same container, and start two processes in the container.
This change would free up another 150 MB for Octobox but is ugly design.
So we won&amp;rsquo;t do it ;-)&lt;/p&gt;

&lt;h2 class="relative group"&gt;tl;dr
 &lt;div id="tldr" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tldr" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Porting an application to OpenShift is not difficult.
Especially the free &lt;a href="https://www.openshift.com/pricing/index.html" target="_blank" rel="noreferrer"&gt;OpenShift Online Starter&lt;/a&gt; is very appealing for such experiments.
The challenges are mostly around creating proper Docker images and getting resource limits right.
As a result, you get a decent running and managed installation.&lt;/p&gt;
&lt;p&gt;For the full installation instructions, please refer to the OpenShift specific Octobox &lt;a href="https://github.com/octobox/octobox/blob/master/openshift/OPENSHIFT_INSTALLATION.md" target="_blank" rel="noreferrer"&gt;installation instructions&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Dash2Alexa - Amazon Alexa Audio API Access</title><link>https://ro14nd.de/dash-2-alexa/</link><pubDate>Mon, 12 Mar 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/dash-2-alexa/</guid><description>&lt;p&gt;Since I got my first Amazon Echo end of last year, I love it.
And although, as a typical German, I&amp;rsquo;m still a bit concerned about data privacy, at the end, convenience wins (as always :).
There are many things which work flawlessly, and to be honest, the most used feature for me is a simple timer.
But when it comes to aggregate actions, Alexa is still quite limited.
Ok, you can define your routines, but for only an insufficient set of fixed actions.
What I really would love to have is to start the radio when I get up in the morning, but this is not possible at the moment.&lt;/p&gt;
&lt;p&gt;So I remembered my last years Amazon Dash button hacks and thought it would be cool to combine both, the Dash button and Alexa.&lt;/p&gt;
&lt;p&gt;And here it is, my weekend hack &amp;hellip;..&lt;/p&gt;
&lt;iframe src="https://player.vimeo.com/video/259570045?byline=0&amp;portrait=0" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;In a nutshell, the setup looks like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure your router to not forward packets from your Dash Button.&lt;/li&gt;
&lt;li&gt;Spoof on ARP requests for the Dash button&amp;rsquo;s MAC.&lt;/li&gt;
&lt;li&gt;If found, call out to a text-to-speech service to convert configured Alexa commands to audio.&lt;/li&gt;
&lt;li&gt;Play the received audio output via RaspberryPi attached speakers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s it.
You can use this &lt;a href="https://github.com/rhuss/dash2alexa" target="_blank" rel="noreferrer"&gt;sample code&lt;/a&gt; for doing the dirty work, but maybe you are interested in some more details.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Amazon Dash Button
 &lt;div id="amazon-dash-button" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#amazon-dash-button" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Amazon_Dash" target="_blank" rel="noreferrer"&gt;Amazon Dash Button&lt;/a&gt; is part of Amazon&amp;rsquo;s consumer goods ordering service.
This button contains a Wifi sender and is quite inexpensive.
Each button is specific for a brand for which you can connect to a specific good.
When you press the button, this good is ordered (e.f. 24 cans of beer ;-)&lt;/p&gt;
&lt;p&gt;But this intended use case is not the only way how you can use this button.
In fact, it can be used just as a plain Wifi button for any purpose.&lt;/p&gt;
&lt;p&gt;First of all, you have to buy such a button e.g. 5 Euro here in Germany, but you can spend this five bucks for your first order.
You just configure it as described by Amazon and maybe order something to spend your credits.&lt;/p&gt;
&lt;p&gt;After this, you have to block the button in your home Wifi router for calling out to the internet.
For obvious reasons, this is &lt;strong&gt;very important&lt;/strong&gt; ;-)
When the button is blocked, it will flash red eventually when being pressed (in contrast to flashing green when an order is placed).&lt;/p&gt;
&lt;p&gt;When you press the button, it first asks via DHCP for an IP address.
The MAC address of the button is relevant, so its time to pick that up, e.g.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By looking into your DHCP servers log&lt;/li&gt;
&lt;li&gt;By trying &lt;code&gt;arp -a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;By checking your Wifi Router&amp;rsquo;s admin UI&lt;/li&gt;
&lt;li&gt;Via Wireshark spoofing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This Mac address will be watched for later by spoofing ARP package traffic.
When &lt;a href="https://golang.org" target="_blank" rel="noreferrer"&gt;golang&lt;/a&gt; is your preferred programming language, then you can use directly &lt;a href="https://github.com/rhuss/dash" target="_blank" rel="noreferrer"&gt;rhuss/dash&lt;/a&gt; which is based on top of &lt;a href="https://github.com/google/gopacket" target="_blank" rel="noreferrer"&gt;gopacket&lt;/a&gt; to watch for certain ARP packages and trigger an action when received.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Amazon Polly API access
 &lt;div id="amazon-polly-api-access" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#amazon-polly-api-access" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;In our use case, when we detect that a button is pressed, then we want to send out some fixed, text-based audio.
For converting text coming from a configuration, a text-to-speech service is used.&lt;/p&gt;
&lt;p&gt;There are several such services available.
For our purpose, we are using &lt;a href="https://aws.amazon.com/polly/developers/?nc1=h_ls" target="_blank" rel="noreferrer"&gt;Amazon Polly&lt;/a&gt;, which offers a free tier for the first 12 months (including 5 million characters per month, fair enough for a handful of buttons ;-) and then 4 $ per one million of chars.&lt;/p&gt;
&lt;p&gt;A short cost calculation beyond the free tier: 100 characters for Alexa commands per button press (which is already quite a mouthful) costs ~ 0.4 cents.
Or the other way round, for five bucks you can press the button 1.250 times: Three times a day per yeare for 5 $
Well, for me that&amp;rsquo;s worth the fun ;-)&lt;/p&gt;
&lt;p&gt;You need an &lt;a href="https://portal.aws.amazon.com/billing/signup" target="_blank" rel="noreferrer"&gt;AWS account&lt;/a&gt; to access the speech API.
The access and secret token can be either that of your &lt;a href="https://console.aws.amazon.com/iam/home#/security_credential" target="_blank" rel="noreferrer"&gt;root AWS account&lt;/a&gt;, or you probably should create a dedicated &lt;a href="https://console.aws.amazon.com/iam/home#/users" target="_blank" rel="noreferrer"&gt;IAM User&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course, you can also use different text-to-speech tool.
Maybe even the good old Unix &lt;code&gt;speak&lt;/code&gt; will do it ?
Not tried it yet, but will check that for sure very soonish.
For now, the Polly voices are recognised quite well by my echo so that I won&amp;rsquo;t change it right now.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Raspberry Pi Audio
 &lt;div id="raspberry-pi-audio" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#raspberry-pi-audio" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The final jigsaw piece is the hardware on which to run the watcher.
For my use case, a Raspberry Pi 2 with some &lt;a href="https://www.amazon.de/gp/product/B00JRW0M32/" target="_blank" rel="noreferrer"&gt;inexpensive speakers&lt;/a&gt; was totally good enough.&lt;/p&gt;

&lt;h2 class="relative group"&gt;dash2alexa command
 &lt;div id="dash2alexa-command" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dash2alexa-command" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/rhuss/dash2alexa" target="_blank" rel="noreferrer"&gt;dash2alexa&lt;/a&gt; command actually takes a configuration file (defautl: &lt;code&gt;~/.dash2alexa.yml&lt;/code&gt;)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Sample configuration file for dash2alexa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Adapt and copy it to ~/.dash2alexa.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Access and secret for accessing the services&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;access&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;..........&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;secret&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;..........&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Network interface to listen for ARP requests when a Dash button is pressed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;interface&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;wlan0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Language (&amp;#34;de&amp;#34; or &amp;#34;en&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;language&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;de&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Gender which can be either &amp;#34;male&amp;#34; or &amp;#34;female&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;gender&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;male&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Keyword to use for alexa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;keyword&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Alexa&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Player to use when playing an mp3 sound file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;player&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;mpeg123&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# List of Dash Buttons with associated Alexa command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;buttons&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Symbolic name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;heineken&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mac adress of Dash button&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mac&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ac:63:be:00:11:22&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# How many seconds to wait between Alexa commands&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;wait&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Messages to talk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;messages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;Lautstärke 4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;Spiele Bayern 3&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s not much documentation yet, but some will follow soon.
Feel free to adapt the code, and I&amp;rsquo;m happy to integrate any pull requests.
Also, as I&amp;rsquo;m a bloody golang greenhorn still, would be curious whether things could be done better.&lt;/p&gt;

&lt;h2 class="relative group"&gt;tl;dr
 &lt;div id="tldr" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tldr" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This little hack uses Amazon Echo via its &amp;lsquo;Audio API&amp;rsquo; to perform specific action on a button press.
It&amp;rsquo;s entirely suited for a situation when its calm around, like putting the button right beside the bed for getting started even when your Echo is out of sight.&lt;/p&gt;
&lt;p&gt;And finally, it&amp;rsquo;s just pure fun ;-) Enjoy!&lt;/p&gt;
&lt;p&gt;P.S. Let me know in the comments whether you tried it out, too and how it works for you.&lt;/p&gt;</description></item><item><title>RasPi 3 Kubernetes Cluster - An Update</title><link>https://ro14nd.de/k8s-on-pi-update/</link><pubDate>Wed, 05 Apr 2017 00:00:00 +0000</pubDate><guid>https://ro14nd.de/k8s-on-pi-update/</guid><description>&lt;p&gt;Our Ansible Playbooks for installing Kubernetes on a Raspberry Pi Cluster have been constantly updated and are now using the awesome &lt;a href="https://github.com/kubernetes/kubeadm" target="_blank" rel="noreferrer"&gt;kubeadm&lt;/a&gt;. The update to Kubernetes 1.6. was a bit tricky, though.&lt;/p&gt;
&lt;p&gt;Recently I had the luck to meet Mr. &lt;a href="https://twitter.com/kubernetesonarm" target="_blank" rel="noreferrer"&gt;@kubernetesonarm&lt;/a&gt; Lucas Käldström at the&lt;a href="https://devops-gathering.io/" target="_blank" rel="noreferrer"&gt; DevOps Gathering&lt;/a&gt; where he demoed his multi-arch cluster. That was really impressing. Lucas really squeezes out the maximum what is possible these days with Raspberry Pis and other SOC devices on the Kubernetes platform. Please follow his &lt;a href="https://github.com/luxas/kubeadm-workshop" target="_blank" rel="noreferrer"&gt;Workshop&lt;/a&gt; on GitHub for a multi-platform setup with ingress controller, persistent volumes, custom API servers and more.&lt;/p&gt;
&lt;p&gt;Needless to say that after returning home one of the first task was to update our &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3" target="_blank" rel="noreferrer"&gt;Ansible playbooks&lt;/a&gt; for updating to Kubernetes 1.6 on my RasPi cluster. The goal of these playbooks are a bit different than Lucas workshop setup: Instead of living at the edge, the goal here is to provide an easy, automated and robust way to install a standard Kubernetes installation on a Raspberry Pi 3 cluster. &lt;code&gt;kubeadm&lt;/code&gt; is a real great help and makes many things so much easier. However there are still some steps to do in addition.&lt;/p&gt;
&lt;p&gt;After following the &lt;a href="https://github.com/luxas/kubeadm-workshop/blob/master/README.md" target="_blank" rel="noreferrer"&gt;workshop instructions&lt;/a&gt; it turned out soon, that it was probably not the best time for the update. Kubernetes 1.6. has just been released and it turned out that last minute pre-release changes &lt;a href="https://github.com/kubernetes/kubeadm/issues/212" target="_blank" rel="noreferrer"&gt;broke kubeadm 1.6.0&lt;/a&gt;. Luckily these were fixed quickly with 1.6.1. However the so called &lt;em&gt;self hosted&lt;/em&gt; mode of kubeadm broke, too (and is currently still &lt;a href="https://github.com/luxas/kubeadm-workshop/issues/8" target="_blank" rel="noreferrer"&gt;broken&lt;/a&gt; in 1.6.1 but should be fixed soon). So the best bet for the moment is to use a standard install (with external processes for api-server et. al).&lt;/p&gt;
&lt;p&gt;Also this time I wanted to use &lt;a href="https://github.com/weaveworks/weave" target="_blank" rel="noreferrer"&gt;Weave&lt;/a&gt; instead of Flannel as the overlay network. In turned out that this didn&amp;rsquo;t worked on my cluster because every of my nodes got the same virtual Mac address assigned by Weave. That&amp;rsquo;s because this address is &lt;a href="https://github.com/weaveworks/weave/blob/916ff7aa3979fced84fceef1635ab8c868d71e25/net/uuid.go#L26" target="_blank" rel="noreferrer"&gt;calculated&lt;/a&gt; based on &lt;code&gt;/etc/machine-id&lt;/code&gt;. And guess what. All my nodes had the &lt;em&gt;same machine id&lt;/em&gt; &lt;code&gt;9989a26f06984d6dbadc01770f018e3b&lt;/code&gt;. This it what the base Hypriot 1.4.0 system decides to install (in fact it is derived by &lt;code&gt;systemd-machine-id-setup&lt;/code&gt; from &lt;code&gt;/var/lib/dbus/machine-id&lt;/code&gt;). And every Hypriot installation out there has this very same machine-id ;-) For me it wasn&amp;rsquo;t surprising, that this happened (well, developing bugs is our daily business ;-), but I was quite puzzled that this hasn&amp;rsquo;t been a bigger &lt;a href="https://github.com/hypriot/image-builder-rpi/issues/167" target="_blank" rel="noreferrer"&gt;issue&lt;/a&gt; yet, because I suspect that especially in cluster setups (may it be Docker Swarm or Kubernetes) at some point the nodes need their unique id. Of course most of the time the IP and hostname is enough. But for a more rigorous UUID &lt;code&gt;/etc/machine-id&lt;/code&gt; is normally good fit.&lt;/p&gt;
&lt;p&gt;After knowing this and re-creating the UUID on my own (with &lt;code&gt;dbus-uuidgen &amp;gt; /etc/machine-id&lt;/code&gt;) everything works smoothly now again, so that I have a base Kubernetes 1.6 cluster with DNS and proper overlay network again. Uff, was quite a mouthful of work :)&lt;/p&gt;
&lt;p&gt;You find the installation instructions and the updated playbooks at &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3" target="_blank" rel="noreferrer"&gt;https://github.com/Project31/ansible-kubernetes-openshift-pi3&lt;/a&gt;. If your router is configured properly, it takes not much more than half an hour to &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3#ansible-playbooks" target="_blank" rel="noreferrer"&gt;setup the full cluster&lt;/a&gt;. I did it several times now since last week, always starting afresh with flashing the SD cards. I can confirm that its reproducible and idempotent now ;-)&lt;/p&gt;
&lt;p&gt;The next steps are to add persistent volumes with &lt;a href="https://github.com/rook/rook" target="_blank" rel="noreferrer"&gt;Rook&lt;/a&gt;, &lt;a href="https://traefik.io/" target="_blank" rel="noreferrer"&gt;Træfik&lt;/a&gt; as ingress controller and an own internal registry.&lt;/p&gt;
&lt;p&gt;Feel free to give it a try and open many &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3/issues/new" target="_blank" rel="noreferrer"&gt;issues&lt;/a&gt; ;-)&lt;/p&gt;</description></item><item><title>Why Jolokia is not RESTful</title><link>https://ro14nd.de/jolokia-is-not-rest/</link><pubDate>Thu, 03 Nov 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jolokia-is-not-rest/</guid><description>&lt;p&gt;From time to time people come to me and say: &amp;ldquo;I really would love Jolokia if only it would be RESTful&amp;rdquo;. This post tells you why.&lt;/p&gt;
&lt;p&gt;I really like REST, yes I do.
If I would crete a new application on a green field, its remote access API would very likely obey the REST paradigm.&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;However, &lt;a href="https://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt; is a different beast.
It is a bridge to the world of JMX, providing an open minded alternative to the rusty and Java specific JSR-160 standard.
Its protocol is based on JSON over HTTP, so in principle it could be REST.
But it is not, mainly for the following two reasons:&lt;/p&gt;

&lt;h3 class="relative group"&gt;JMX resource naming is a mess
 &lt;div id="jmx-resource-naming-is-a-mess" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#jmx-resource-naming-is-a-mess" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Jolokia doesn&amp;rsquo;t not have any influence on the naming of the resources it accesses.
These resources are JMX &lt;a href="https://docs.oracle.com/javase/tutorial/jmx/mbeans/" target="_blank" rel="noreferrer"&gt;MBeans&lt;/a&gt; and their identifiers are &lt;a href="http://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html" target="_blank" rel="noreferrer"&gt;ObjectNames&lt;/a&gt;.
ObjectNames have a certain structure but beside this they can be named arbitrarily.
So if you want to provide an HTTP API for accessing these repositories, this free form addressing poses some challenges, especially for read operations with &lt;code&gt;GET&lt;/code&gt;.
For example it is impossible to transmit a slash (&lt;code&gt;/&lt;/code&gt;) or backslash (&lt;code&gt;\\&lt;/code&gt;) as part of an URL&amp;rsquo;s path info.
The reason is &lt;a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0450" target="_blank" rel="noreferrer"&gt;security related&lt;/a&gt;, and each application server handles this differently: Tomcat for example completely rejects such requests whereas Wildfly / Undertow &lt;a href="https://issues.jboss.org/browse/UNDERTOW-879" target="_blank" rel="noreferrer"&gt;refuses&lt;/a&gt; to URL decode &lt;code&gt;%2F&lt;/code&gt; (for &lt;code&gt;/&lt;/code&gt;) and &lt;code&gt;%5C&lt;/code&gt; for &lt;code&gt;\\&lt;/code&gt;.
Jetty doesn&amp;rsquo;t care much.
So in order to address a JMX MBean which contains these characters as part of their names, the typical encoding as part of an URL path doesn&amp;rsquo;t work.
One could use query parameters for this kind of addressing and in fact, Jolokia &lt;a href="https://jolokia.org/reference/html/protocol.html#get-request" target="_blank" rel="noreferrer"&gt;supports&lt;/a&gt; this, too.
But it&amp;rsquo;s still ugly.
Also, implementers of MBeans tend to put semantic information into the MBean name like the port of a connector or the name of a database scheme.
It can&amp;rsquo;t excluded that the MBean name alone can carry sensitive information.
However GET urls are &lt;em&gt;not&lt;/em&gt; secured via the transport protocol and tend to end up in log files.
So, its much safer to send these requests via POST, even when only performing read operations on JMX attributes.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Bulk requests
 &lt;div id="bulk-requests" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#bulk-requests" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;A special feature of Jolokia are &lt;a href="https://jolokia.org/reference/html/protocol.html#post-request" target="_blank" rel="noreferrer"&gt;Bulk Requests&lt;/a&gt;.
This allows a very efficient monitoring of multiple values with a single HTTP request.
It works by sending a list of individual, JSON encoded Jolokia requests with a single HTTP &lt;code&gt;POST&lt;/code&gt; request.
That list can contain any valid Jolokia operation:
Reading and writing attributes, executing some operations, searching for or listing of MBeans.
The heterogenous nature of this kind of requests makes it hard to map them to one single HTTP verb as REST suggests.
Also, the sheer length of the request parameter forbids to send a bulk request via GET as Servlet container or other application servers impose certain restrictions on the length of an URL, which vary however from server to server.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Jolokia implements both
 &lt;div id="jolokia-implements-both" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#jolokia-implements-both" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;For every Jolokia operation, we play both: GET and POST &lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;.
As an integration tool, which helps to bridge different worlds without really having control over these worlds, the focus is on maximal flexibility so that it can adapt to any environment where it is used.
REST is only of second importance here, but if you think the issues described above can be solved in a more RESTful way, I&amp;rsquo;m more than open.&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I&amp;rsquo;ve to confess that I&amp;rsquo;m really not a REST expert, so if you don&amp;rsquo;t agree with my arguments, I&amp;rsquo;d kindly ask you to leave a comment or tweet me for corrections.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;or: &amp;ldquo;Country and Western&amp;rdquo;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item><item><title>Java EE Management is dead</title><link>https://ro14nd.de/java-management-is-dead/</link><pubDate>Mon, 10 Oct 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/java-management-is-dead/</guid><description>&lt;p&gt;Now that some weeks has been passed we all had time to absorb the &lt;a href="https://java.net/downloads/javaee-spec/JavaEE8Update.pdf" target="_blank" rel="noreferrer"&gt;revised Java EE 8 proposal&lt;/a&gt; presented at Java One. As you know, some JSRs remained, some things were added and some stuff was dropped. &lt;a href="https://www.jcp.org/en/jsr/detail?id=373" target="_blank" rel="noreferrer"&gt;Java EE Management API 2.0&lt;/a&gt;, supposed to be a modern successor of JSR 77, is one of the three JSRs to be dropped.&lt;/p&gt;
&lt;p&gt;What does this mean for the future of Java EE management and monitoring ?&lt;/p&gt;
&lt;p&gt;First of all it&amp;rsquo;s fair to state that &lt;a href="https://www.jcp.org/en/jsr/detail?id=373" target="_blank" rel="noreferrer"&gt;JSR 373&lt;/a&gt; never really took off. Since February 2015 there were not more than &lt;a href="https://java.net/projects/javaee-mgmt/lists/jsr373-experts/archive" target="_blank" rel="noreferrer"&gt;86 mails&lt;/a&gt; on the expert group mailing list, half of them written in March 2015 during incubation. At the latest of January 2016 it was clear that JSR-373 &lt;a href="https://java.net/projects/javaee-mgmt/lists/jsr373-experts/archive/2016-01/message/2" target="_blank" rel="noreferrer"&gt;is not on Oracle&amp;rsquo;s focus anymore&lt;/a&gt;. To be honest, even we members of the expert group, we were not able to push this JSR further.&lt;/p&gt;
&lt;p&gt;How did it come that far ? Let&amp;rsquo;s have a look back into history.&lt;/p&gt;
&lt;p&gt;All starts with &lt;a href="https://jcp.org/en/jsr/detail?id=3" target="_blank" rel="noreferrer"&gt;JSR 3&lt;/a&gt; back in 1999. This first JMX specification is the foundation of all Java resources management. As it can been seen by its age, Java folks took care about Management and Monitoring from the very beginning on. And even better, since &lt;a href="http://docs.oracle.com/javase/1.5.0/docs/guide/management/index.html" target="_blank" rel="noreferrer"&gt;JS2E 5&lt;/a&gt; JMX is integral part of Java SE so its available on every JVM out there.&lt;/p&gt;
&lt;p&gt;Over the years, additional JSRs were added on top of this base:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jcp.org/en/jsr/detail?id=160" target="_blank" rel="noreferrer"&gt;JSR 160&lt;/a&gt; defines a remote protocol for JMX,, which is based on &lt;a href="http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136424.html" target="_blank" rel="noreferrer"&gt;RMI&lt;/a&gt;. This might have been a good decision in 2003, but turned out to be awful to use especially for non-Java based monitoring systems.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jcp.org/en/jsr/detail?id=262" target="_blank" rel="noreferrer"&gt;JSR 262&lt;/a&gt; was started to overcome this by defined a &amp;ldquo;WebServices Connector for Java Management Extensions Agents&amp;rdquo; which was mostly around SOAP services. However although even an initial implementation existed, it was withdrawn before the final release. It&amp;rsquo;s not completely clear why it was stopped in 2008 and later withdrawn, as the &lt;a href="https://jcp.org/en/jsr/results?id=4548" target="_blank" rel="noreferrer"&gt;public review ballot has been approved&lt;/a&gt;, although it was a tight result. The biggest objections were on dependencies on &amp;ldquo;proprietary&amp;rdquo; WS-* specifications.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;J2EE Management&amp;rdquo; &lt;a href="https://jcp.org/en/jsr/detail?id=77" target="_blank" rel="noreferrer"&gt;JSR 77&lt;/a&gt; was finished in 2002 and defines a hierarchy how Management and Monitoring resources exposed by a Java EE server is structured. It allows a uniform interface for how to access the various Java EE resources, like web applications or connector pools. Beside this it also defines how statistics are exposed by defining various metrics formats. However, implementing the &lt;code&gt;StatisticsProvider&lt;/code&gt; model is not mandatory and from my personal experience it was implemented only rarely by some vendors and if so, not for every resource.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jcp.org/en/jsr/detail?id=88" target="_blank" rel="noreferrer"&gt;JSR 88&lt;/a&gt; complements JSR 77 and defines a common format for deploying Java EE artefacts.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jcp.org/en/jsr/detail?id=255" target="_blank" rel="noreferrer"&gt;JSR 255&lt;/a&gt; was started to be the next version of JMX and supposed to be included in Java 7. Although it was already nearly finished and integrated, &lt;a href="https://community.oracle.com/blogs/emcmanus/2009/06/16/jsr-255-jmx-api-20-postponed" target="_blank" rel="noreferrer"&gt;it didn&amp;rsquo;t make it into Java 7&lt;/a&gt; (nor Java 8). The spec was then dormant until it was finally withdrawn in 2016.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the dead of JMX 2.0 in 2009 the evolution of JMX as a standard for Java SE has stalled. But what&amp;rsquo;s about Java EE Management ? At least JSR 77 is still part of Java EE 7 and for Java EE 8 the successor was supposed to be JSR 373. JSR 373 tackles the problem of remote access, whereas JSR 77 still relies on RMI as a standard implementation protocol as defined in JSR 160.&lt;/p&gt;
&lt;p&gt;The two major goals of JSR 373 were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provide an update of the hierarchal resource and statistics structure as defined by JSR 77&lt;/li&gt;
&lt;li&gt;Provide a REST access to these resources independent of JMX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the often cited &lt;a href="https://java.net/downloads/javaee-spec/JavaEE8_Community_Survey_Results.pdf" target="_blank" rel="noreferrer"&gt;Java EE 8 Community Survey&lt;/a&gt; more than 60% were in favour of defining a new API for managing application, which should be based on REST (83% pro-votes). This finally lead to JSR 373. However, as it seems in retrospective, a deep interest in this topic was not really given and probably lead to this final decision to drop JSR 373 from Java EE 8.&lt;/p&gt;
&lt;p&gt;So, what is the state of Monitoring and Management of Java and in particular Java EE applications nowadays and what can be expected in the future ? Let&amp;rsquo;s have a look into the crystal ball.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JMX is here to stay&lt;/strong&gt;. It is part of Java SE and I don&amp;rsquo;t know of any plans for removing it from future Java editions. Ok, it feels a bit rusty but it is still rock solid and gives you deep insight in the state of your JVM. With tools like &lt;a href="https://jolokia.org/" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt; you can overcome most of the restrictions JSR 160 imposes. (Disclaimer: since I&amp;rsquo;m the author of Jolokia all my personal opinions given here should be evaluated in this light :)&lt;/li&gt;
&lt;li&gt;It is not clear how the Management API of Java EE 8 and beyond looks like. It does not look like that JSR 77 will survive. Will there be a standard for Java EE management at all ? Probably not, and so there is the danger that vendors will push their proprietary management APIs, which already &lt;a href="https://docs.jboss.org/author/display/WFLY10/The&amp;#43;HTTP&amp;#43;management&amp;#43;API" target="_blank" rel="noreferrer"&gt;happens&lt;/a&gt; to some extent. Luckily, most of these proprietary APIs are also mirrored in JMX these days.&lt;/li&gt;
&lt;li&gt;On the other hand, it could be also a good thing that there is no other Management API which is not based on JMX. That&amp;rsquo;s because you will always need JMX to monitor the basic aspects like Heap Memory usage or Thread count, which are covered by Java SE. Adding a different, REST like protocol for Java EE monitoring requires operators to access a Java EE server with two different protocols (JMX &lt;strong&gt;and&lt;/strong&gt; Rest), duplicating configuration efforts on the monitoring side. This can only be avoided if the &lt;a href="https://java.net/projects/javaee-mgmt/lists/jsr373-experts/archive/2016-06/message/1" target="_blank" rel="noreferrer"&gt;Java EE resources are mirrored in JMX&lt;/a&gt;, too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To sum it up, I think its a shame that Management and Monitoring, which played a prominent role over the whole evolution of Java EE, will probably be dropped completely in Java EE 8. As a replacement the new &lt;a href="https://java.net/downloads/javaee-spec/JavaEE8Update.pdf" target="_blank" rel="noreferrer"&gt;Health Check&lt;/a&gt; API has been announced, but to be honest, that can&amp;rsquo;t be a full replacement for classical management and monitoring where the evaluation of a system&amp;rsquo;s health is done on a dedicated monitoring platform (e.g. like Nagios or Prometheus). These platforms take the plain metrics data exposed by the application and does the data evaluation on their own.&lt;/p&gt;
&lt;p&gt;The good thing is still that you have JMX to the rescue and I&amp;rsquo;m pretty sure that this technology will survive also this storm. Especially if vendors are willing to support it for their application server metrics, too.&lt;/p&gt;
&lt;p&gt;Even without a Java EE standard.&lt;/p&gt;</description></item><item><title>A Raspberry Pi 3 Kubernetes Cluster</title><link>https://ro14nd.de/kubernetes-on-raspberry-pi3/</link><pubDate>Wed, 27 Apr 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/kubernetes-on-raspberry-pi3/</guid><description>&lt;p&gt;Let&amp;rsquo;s build a Raspberry Pi Cluster running Docker and Kubernetes. There has been already a handful of good recipes, however this howto is a bit different and provides some unique features.&lt;/p&gt;
&lt;img src="https://ro14nd.de/images/kubernetes-on-raspberry-pi3/pi_cluster.jpg" style="float:right; margin: 50px 0px 20px 30px"/&gt;
&lt;p&gt;My main motivation for going the Raspberry Pi road for a Kubernetes cluster was that I wanted something fancy for my &lt;a href="https://github.com/rhuss/jax-kubernetes-2016" target="_blank" rel="noreferrer"&gt;Kubernetes talk&lt;/a&gt; to show, shamelessly stealing the idea &lt;a href="https://opensource.com/life/16/2/build-a-kubernetes-cloud-with-raspberry-pi" target="_blank" rel="noreferrer"&gt;from&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?time_continue=4&amp;amp;v=AAS5Mq9EktI" target="_blank" rel="noreferrer"&gt;others&lt;/a&gt; (kudos to &lt;code&gt;@KurtStam&lt;/code&gt;, &lt;code&gt;@saturnism&lt;/code&gt;, &lt;code&gt;@ArjenWassink&lt;/code&gt; and &lt;code&gt;@kubernetesonarm&lt;/code&gt; for the inspiration ;-)&lt;/p&gt;
&lt;p&gt;I.e. the following Pi-K8s projects already existed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/Project31/kubernetes-installer-rpi" target="_blank" rel="noreferrer"&gt;kubernetes-installer-rpi&lt;/a&gt;&lt;/strong&gt; : A set up shell scripts and precompiled ARM binaries for running Kubernetes by &lt;a href="https://twitter.com/KurtStam" target="_blank" rel="noreferrer"&gt;@KurtStam&lt;/a&gt; on top of the Hypriot Docker Image for Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/luxas/kubernetes-on-arm" target="_blank" rel="noreferrer"&gt;Kubernetes on ARM&lt;/a&gt;&lt;/strong&gt; : An opinionated approach by &lt;a href="https://twitter.com/kubernetesonarm" target="_blank" rel="noreferrer"&gt;@kubernetesonarm&lt;/a&gt; with an own installer for setting up Kubernetes no only for the Pi but also for other ARM based platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/awassink/k8s-on-rpi" target="_blank" rel="noreferrer"&gt;K8s on Rpi&lt;/a&gt;&lt;/strong&gt; : Another shell based installer for installing a Kubernetes cluster by &lt;a href="https://twitter.com/ArjenWassink" target="_blank" rel="noreferrer"&gt;@ArjenWassink&lt;/a&gt; and &lt;a href="https://twitter.com/saturnism" target="_blank" rel="noreferrer"&gt;@saturnism&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When there are already multiple recipes out there, why then trying yet another approach ?&lt;/p&gt;
&lt;p&gt;My somewhat selfish goals were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using (and learning on the way) Ansible for not only a one-shot installation but also maintainance and upgrades.&lt;/li&gt;
&lt;li&gt;Learning myself how to setup a Kubernetes cluster. This setup includes flannel as an overlay network, the SkyDNS extension and soon also a registry. Using Ansible helps me to incrementally add on top of things already installed.&lt;/li&gt;
&lt;li&gt;Want to use WiFi for connecting the cluster. See below for the reason.&lt;/li&gt;
&lt;li&gt;Get &lt;a href="https://github.com/openshift/origin" target="_blank" rel="noreferrer"&gt;OpenShift Origin&lt;/a&gt; running and be able to switch between Ansible and OpenShift via Ansible.&lt;/li&gt;
&lt;li&gt;Create a demonstration platform for my favourite development and integration platform &lt;a href="http://fabric8.io" target="_blank" rel="noreferrer"&gt;fabric8&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As it turns out the whole experience was very enlightening to me. Its one thing to start Kubernetes on a single node within a VM (because multiple VM-based nodes kill soon your machine resourcewise) or having a small bare metal cluster, which blinks red and green and where you can plug wires at will. Not to mention the the geek factor :)&lt;/p&gt;

&lt;h2 class="relative group"&gt;Shopping List
 &lt;div id="shopping-list" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#shopping-list" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s my shopping list for a Raspberry Pi 3 cluster, along with (non-affiliate) links to (German) shops, but I&amp;rsquo;m sure you can find them elswhere, too.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Amount&lt;/th&gt;
 &lt;th&gt;Part&lt;/th&gt;
 &lt;th&gt;Price&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.watterott.com/de/Raspberry-Pi-3" target="_blank" rel="noreferrer"&gt;Raspberry Pi 3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;4 * 38 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B013UDL5RU" target="_blank" rel="noreferrer"&gt;Micro SD Card 32 GB&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;4 * 11 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00XPUIDFQ" target="_blank" rel="noreferrer"&gt;WLAN Router&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;22 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B016BEVNK4" target="_blank" rel="noreferrer"&gt;USB wires&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;9 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00PTLSH9G" target="_blank" rel="noreferrer"&gt;Power Supply&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;30 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00NB1WPEE" target="_blank" rel="noreferrer"&gt;Case&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;10 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00NB1WQZW" target="_blank" rel="noreferrer"&gt;Intermediate Case Plate&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;3 * 7 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All in all, a 4 node Pi cluster for &lt;strong&gt;288 EUR&lt;/strong&gt; (as of April 2016). Not so bad.&lt;/p&gt;
&lt;p&gt;Some remarks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using WiFi for the connection has the big advantage that the Raspberry Pi 3 integrated BCM43438 WiFi chip doesn&amp;rsquo;t go over USB and saves valuable bandwidth used for IO in general. That way you are able to to get ~ 25 MB/s for disk IO and network traffic, respectively. And also less cables, of course. You can alway plug the power wire for demos, too ;-)&lt;/li&gt;
&lt;li&gt;A class 10 Mirco SD is recommended but it doesn&amp;rsquo;t have to be the fastest on the world as the USB bus only allows around 35 MB/s anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;Initial Pi Setup
 &lt;div id="initial-pi-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#initial-pi-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Most of the installation is automated by using &lt;a href="https://www.ansible.com/" target="_blank" rel="noreferrer"&gt;Ansible&lt;/a&gt;. However the initial setup is a bit more involved. It certainly can be improved (e.g. automatic filesystem expanding of the initial Raspian setup). If you have ideas how to improve this, please open issues and PRs on &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3" target="_blank" rel="noreferrer"&gt;Project31/ansible-kubernetes-openshift-pi3&lt;/a&gt;. Several base distributions has been tried out. It turned out that the most stable setup is based on a stock Raspian. Unfortunately it doesn&amp;rsquo;t provide a headless WLAN setup as it is possible with the latest &lt;a href="https://github.com/hypriot/image-builder-rpi/releases/latest" target="_blank" rel="noreferrer"&gt;Hypriot&lt;/a&gt; images, but for the moment it much more stable (I had strange kernel panics and 200% CPU load issues with the Hypriot image for no obvious reasons). Since this is a one time effort, let&amp;rsquo;s use Raspbian. If you want to try out the Hypriot image, there&amp;rsquo;s an &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3/tree/hypriot" target="_blank" rel="noreferrer"&gt;experimental branch&lt;/a&gt; for the Ansible playbooks which can be used with Hypriot. I will retry Hypriot OS for sure some times later.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download the latest Raspian image and store it as &lt;code&gt;raspbian.zip&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; curl -L https://downloads.raspberrypi.org/raspbian_lite_latest \
 -o raspbian.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Hypriots&amp;rsquo; &lt;a href="https://github.com/hypriot/flash" target="_blank" rel="noreferrer"&gt;flash&lt;/a&gt; installer script. Follow the directions on the installation page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Insert you Micro-SD card in your Desktop computer (via an adapter possibly) and run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; flash raspbian.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be asked to which device to write. Check this carefully, otherwise you could destroy your Desktop OS if selecting the the wrong device. Typically its something like &lt;code&gt;/dev/disk2&lt;/code&gt; on OS X, but depends on the number of hard drives you have.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Insert the Micro SSD card into your Raspberry Pi and connect it to a monitor and keyboard. Boot up. Login in with &lt;em&gt;pi&lt;/em&gt; / &lt;em&gt;raspberry&lt;/em&gt;. Then:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; raspi-config --expand-rootfs
 vi /etc/wpa_supplicant/wpa_supplicant.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then add your WLAN credentials&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; network={
 ssid=&amp;quot;MySSID&amp;quot;
 psk=&amp;quot;s3cr3t&amp;quot;
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reboot&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat step 2. to 5. for each Micro SD card.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;Network Setup
 &lt;div id="network-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#network-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;It is now time to configure your WLAN router. This of course depends on which router you use. The following instructions are based on a &lt;a href="http://www.tp-link.com/en/products/details/cat-9_TL-WR802N.html" target="_blank" rel="noreferrer"&gt;TP-Link TL-WR802N&lt;/a&gt; which is quite inexepensive but still absolutely ok for our purposes since it sits very close to the cluster and my notebook anyway.&lt;/p&gt;
&lt;p&gt;First of all you need to setup the SSID and password. Use the same credentials with which you have configured your images.&lt;/p&gt;
&lt;p&gt;My setup is, that I span a private network &lt;code&gt;192.168.23.0/24&lt;/code&gt; for the Pi cluster which my MacBook also joins via its integrated WiFi.&lt;/p&gt;
&lt;p&gt;The addresses I have chosen are :&lt;/p&gt;
&lt;p&gt;| &lt;code&gt;192.168.23.1&lt;/code&gt; | WLAN Router |
| &lt;code&gt;192.168.23.100&lt;/code&gt; | MacBook&amp;rsquo;s WLAN |
| &lt;code&gt;192.168.23.200&lt;/code&gt; &amp;hellip; &lt;code&gt;192.168.23.203&lt;/code&gt; | Raspberry Pis |&lt;/p&gt;
&lt;p&gt;The MacBook is setup for NAT and forwarding from this private network to the internet. This &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3/blob/master/tools/setup_nat_on_osx.sh" target="_blank" rel="noreferrer"&gt;script&lt;/a&gt; helps in setting up the forwarding and NAT rules on OS X.&lt;/p&gt;
&lt;p&gt;In order to configure your WLAN router you need to connect to it according to its setup instructions. The router is setup in &lt;strong&gt;Access Point&lt;/strong&gt; mode with DHCP enabled. As soon as the MAC of the Pis are known (which you can see as soon as they connect for the first time via WiFi), I configured them to always use the same DHCP lease. For the TL-WR802N this can be done in the configuration section &lt;em&gt;DHCP -&amp;gt; Address Reservation&lt;/em&gt;. In the &lt;em&gt;DHCP -&amp;gt; DHCP-Settings&lt;/em&gt; the default gateway is set to &lt;code&gt;192.168.23.100&lt;/code&gt;, which my notebook&amp;rsquo;s WLAN IP.&lt;/p&gt;
&lt;p&gt;Startup all nodes, you should be able to ping every node in your cluster. I added &lt;code&gt;n0&lt;/code&gt; &amp;hellip; &lt;code&gt;n3&lt;/code&gt; to my notebook&amp;rsquo;s &lt;code&gt;/etc/hosts&lt;/code&gt; pointing to &lt;code&gt;192.168.23.200&lt;/code&gt; &amp;hellip; &lt;code&gt;192.168.23.203&lt;/code&gt; for convenience.&lt;/p&gt;
&lt;p&gt;You should be able to ssh into every Pi with user &lt;em&gt;pi&lt;/em&gt; and password &lt;em&gt;raspberry&lt;/em&gt;. Also, if you set up the forwarding on your desktop properly you should be able to ping from within the pi to the outside world.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Ansible Playbooks
 &lt;div id="ansible-playbooks" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ansible-playbooks" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;After this initial setup is done, the next step is to initialize the base system with Ansible. You will need Ansible 2 installed on your desktop (e.g. &lt;code&gt;brew install ansible&lt;/code&gt; when running on OS X)&lt;/p&gt;

&lt;h3 class="relative group"&gt;Ansible Configuration
 &lt;div id="ansible-configuration" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ansible-configuration" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Checkout the Ansible playbooks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; git clone https://github.com/Project31/ansible-kubernetes-openshift-pi3.git k8s-pi
 cd k8s-pi
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy over &lt;code&gt;hosts.example&lt;/code&gt; and adapt it to your needs&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cp hosts.example hosts
 vi hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are three Ansible groups which are refered to in the playbooks:&lt;/p&gt;
&lt;p&gt;| &lt;strong&gt;pis&lt;/strong&gt; | All cluster node | &lt;code&gt;n0&lt;/code&gt;, &lt;code&gt;n1&lt;/code&gt;, &lt;code&gt;n2&lt;/code&gt;, &lt;code&gt;n3&lt;/code&gt; |
| &lt;strong&gt;master&lt;/strong&gt; | Master node | &lt;code&gt;n0&lt;/code&gt; |
| &lt;strong&gt;nodes&lt;/strong&gt; | All nodes which are not master | &lt;code&gt;n1&lt;/code&gt;, &lt;code&gt;n2&lt;/code&gt;, &lt;code&gt;n3&lt;/code&gt;|&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy over the configuration and adapt it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cp config.yml.example config.yml
 vi config.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should at least put in your WLAN credentials, but you are also free to adapt the other values.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;Basic Node Setup
 &lt;div id="basic-node-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#basic-node-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;If you have already created a cluster with these playbooks and want to start a fresh, please be sure that you cleanup your &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; from the old host keys. You should be able to ssh into each of the nodes without warnings. Also you must be able to reach the internet from the nodes.&lt;/p&gt;
&lt;p&gt;In the next step the basic setup (without Kubernetes) is performed. This is done by&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -k -i hosts setup.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you are prompted for the password, use &lt;em&gt;raspberry&lt;/em&gt;. You will probably also need to confirm the SSH authentity for each host with &lt;em&gt;yes&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The following steps will be applied by this command (which may take a bit):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker will be installed from the Hypriot repositories&lt;/li&gt;
&lt;li&gt;Your public SSH key is copied over to &lt;em&gt;pi&amp;rsquo;s&lt;/em&gt; authenticated_keys and the users password will be taken from &lt;code&gt;config.yml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Some extra tools are installed for your convenience and some benchmarking:
&lt;ul&gt;
&lt;li&gt;hdparm&lt;/li&gt;
&lt;li&gt;iperf&lt;/li&gt;
&lt;li&gt;mtr&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hostname is set to the name of the node configured. Also &lt;code&gt;/etc/hosts&lt;/code&gt; is setup to contain all nodes with their short names.&lt;/li&gt;
&lt;li&gt;A swapfile is enabled (just in case)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this basic setup you have already a working Docker environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Now its time to reboot the whole cluster since some required boot params has been added. Plug the wire.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;Kubernetes Setup
 &lt;div id="kubernetes-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#kubernetes-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;The final step for a working Kubernetes cluster is to run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -i hosts kubernetes.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will install one master at n0 and threed additional nodes n1, n2, n3.&lt;/p&gt;
&lt;p&gt;The following features are enabled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;etcd&lt;/code&gt;, &lt;code&gt;flanneld&lt;/code&gt; and &lt;code&gt;kubelet&lt;/code&gt; are installed as systemd services on the master&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubelet&lt;/code&gt; and &lt;code&gt;flanneld&lt;/code&gt; are installed as systemd services on the nodes&lt;/li&gt;
&lt;li&gt;Docker is configured to use the Flannel overlay network&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt; is installed (and an alias &lt;code&gt;k&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there are some issues when restarting services in the master, don&amp;rsquo;t worry. However you should best restart the master node n0 when this happens, because when setting up the other nodes the would fail if not all services are running on the master.&lt;/p&gt;
&lt;p&gt;After an initial installation it may take a bit until all infrastructure docker images has been loaded. Eventually should be able to use &lt;code&gt;kubectl get nodes&lt;/code&gt; from e.g. &lt;code&gt;n0&lt;/code&gt;. When this wotks but you see only one node, please reboot the cluster since some services may have not been started on the nodes (plug the cables when &lt;code&gt;n0&lt;/code&gt; is ready).&lt;/p&gt;

&lt;h3 class="relative group"&gt;Install SkyDNS
 &lt;div id="install-skydns" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#install-skydns" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;For service discovery via DNS you should finally install the SkyDNS addon, but only when the cluster is running, i.e. the master must be up and listening. For this final step call:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -i hosts skydns.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class="relative group"&gt;Wrap Up
 &lt;div id="wrap-up" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#wrap-up" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This has become a rather long recipe. I re-did everything from scratch within 60 minutes, so this could be considered as a lower boundary (because I already did it several times :). The initial setup might be a bit flaky, but should be easy to fix. I&amp;rsquo;d love to hear your feedback on this, and maybe we get it more stable afterwards. Remember, that&amp;rsquo;s my first Ansible playbook :)&lt;/p&gt;
&lt;p&gt;Now go out, buy and setup your Kubernetes cluster and have fun :-)&lt;/p&gt;</description></item><item><title>docker-maven-plugin moves on</title><link>https://ro14nd.de/dmp-moves-on/</link><pubDate>Wed, 24 Feb 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/dmp-moves-on/</guid><description>&lt;p&gt;&lt;strong&gt;rhuss/docker-maven-plugin&lt;/strong&gt; is dead, long live &lt;strong&gt;fabric8io/docker-maven-plugin&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;If you follow the Docker Maven Plugin Scene&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;, you probably noticed that there has been quite some progress in the last year. Started as a personal research experiment early 2014, &lt;a href="https://github.com/fabric8io/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;rhuss/docker-maven-plugin&lt;/a&gt; (d-m-p) has took off a little bit. With more than 300 GitHub stars it&amp;rsquo;s now the second most popular docker-maven-plugin. With 38 contributors we were able to do 36 releases. It is really fantastic to see that many people contributing to a rather niche product. Many kudos go out to &lt;a href="https://github.com/jgangemi" target="_blank" rel="noreferrer"&gt;Jae&lt;/a&gt; for his many contributions and continued support on fixing and answering issues. Thanks also for always being very patient with my sometimes quite opinionated and picky code reviews :)&lt;/p&gt;
&lt;p&gt;However it is now time to ignite the next stage and bring this personal &amp;lsquo;pet&amp;rsquo; project to a wider context. And what is better suited here than the fabric8 community ?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://fabric8.io" target="_blank" rel="noreferrer"&gt;Fabric8&lt;/a&gt; is a next generation DevOps and integration platform for Docker based applications, with a focus on &lt;a href="http://kubernetes.io/" target="_blank" rel="noreferrer"&gt;Kubernetes&lt;/a&gt; and &lt;a href="https://www.openshift.com/" target="_blank" rel="noreferrer"&gt;OpenShift&lt;/a&gt; as orchestration and build infrastructure. Its a collection of multiple interrelated projects including Maven tooling for interacting with Kubernetes and OpenShift. d-m-p is already included as foundation for creating Docker application images.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m very happy that d-m-p has now found its place in this ecosystem where it will continue to flourish even faster.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://fabric8.io/community/index.html" target="_blank" rel="noreferrer"&gt;fabric8 community&lt;/a&gt; is very open and has established multiple communications channels on which you will find d-m-p now, too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#fabric8&lt;/code&gt; on &lt;code&gt;irc.freenode.net&lt;/code&gt; is an IRC channel with a lot of helpful hands (including myself)&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://groups.google.com/forum/#!forum/fabric8" target="_blank" rel="noreferrer"&gt;mailing list&lt;/a&gt; for more in depth discussions&lt;/li&gt;
&lt;li&gt;Issues are still tracked with &lt;a href="https://github.com/fabric8io/docker-maven-plugin/issues" target="_blank" rel="noreferrer"&gt;GitHub issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;d-m-p specific blog posts will go out on the &lt;a href="https://blog.fabric8.io/" target="_blank" rel="noreferrer"&gt;fabric8 blog&lt;/a&gt; in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, what changed ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rhuss/docker-maven-plugin&lt;/code&gt; has been transferred to &lt;a href="https://github.com/fabric8io/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;fabric8io/docker-maven-plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Maven group id has changed from &lt;code&gt;org.jolokia&lt;/code&gt; to &lt;code&gt;io.fabric8&lt;/code&gt; for all releases 0.14.0 and later.&lt;/li&gt;
&lt;li&gt;CI and release management will be done on the fabric8 platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And what will &lt;strong&gt;not&lt;/strong&gt; change ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;d-m-p will always be usable with plain Docker, speaking either to a remote or local Docker daemon. No Kubernetes, no OpenShift required.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ll continue to work on d-m-p ;-)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks so much for all the fruitful feedback and pull requests. Keep on rocking ;-)&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;with more than 15 &lt;code&gt;docker-maven-plugin&lt;/code&gt;s its probably fair to call it a &amp;ldquo;scene&amp;rdquo; ;-)&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item><item><title>Registry Magic with docker-maven-plugin</title><link>https://ro14nd.de/registry-magic-with-dmp/</link><pubDate>Thu, 21 Jan 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/registry-magic-with-dmp/</guid><description>&lt;p&gt;Dealing with multiple Docker registries is hard, mostly because the meta information where a image is located is part of a Docker image&amp;rsquo;s name, which is typically used as an identifier, too.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how the &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;rhuss/docker-maven-plugin&lt;/a&gt; deals with this peculiarity.&lt;/p&gt;
&lt;p&gt;When setting up a Maven build for creating Docker images out of your Java application, the classical way to specify the registry where to push the final Docker image is to bake it into the image&amp;rsquo;s name. The drawback however is that you couple your build to this particular registry so that it is not possible to push your image to another registry when building the image.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Pull and Push
 &lt;div id="pull-and-push" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pull-and-push" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;docker-maven-plugin&lt;/a&gt; (&lt;code&gt;d-m-p&lt;/code&gt; in short) interacts&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; with Docker registries in two use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pulling&lt;/strong&gt; base images from a registry when building images with &lt;code&gt;docker:build&lt;/code&gt; or starting images with &lt;code&gt;docker:start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pushing&lt;/strong&gt; built images to a registry with &lt;code&gt;docker:push&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases you can define your build agnostic from any registry by omitting the registry part in your image names&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; and specify it externally as meta information. This can be done in various ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding it to the plugin configuration as an &lt;code&gt;&amp;lt;registry&amp;gt;&lt;/code&gt; element. This can be easily put into a Maven profile (either directly in the &lt;code&gt;pom.xml&lt;/code&gt; or also in &lt;code&gt;~/.m2/settings.xml&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Using a system property &lt;code&gt;docker.registry&lt;/code&gt; when running Maven&lt;/li&gt;
&lt;li&gt;As a final fallback an environment variable &lt;code&gt;DOCKER_REGISTRY&lt;/code&gt; can be used, too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn -Ddocker.registry=myregistry.domain.com:5000 docker:push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you combine build and push steps in a single call like in&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn package docker:build docker:push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;a pull operation for a base image and a push operation can happen. To allow different registries in this situation the properties &lt;code&gt;docker.pull.registry&lt;/code&gt; and &lt;code&gt;docker.push.registry&lt;/code&gt; are supported, too, (with the corresponding configuration elements &lt;code&gt;&amp;lt;pullRegistry&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;pushRegistry&amp;gt;&lt;/code&gt;, respectively).&lt;/p&gt;
&lt;p&gt;When pushing an image this way, the following happens behind the scene (assuming an image named &lt;code&gt;user/myimage&lt;/code&gt; and target registry &lt;code&gt;myregistry:5000&lt;/code&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The image &lt;code&gt;user/myimage&lt;/code&gt; is tagged temporarily as &lt;code&gt;myregistry:5000/user/myimage&lt;/code&gt; in the Docker daemon.&lt;/li&gt;
&lt;li&gt;The image &lt;code&gt;myregistry:5000/user/myimage&lt;/code&gt; is pushed.&lt;/li&gt;
&lt;li&gt;The tag is removed again.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;Authentication
 &lt;div id="authentication" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#authentication" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;That&amp;rsquo;s all fine, but how does d-m-p deal with authentication ? Again, there are several possibilities how authentication can be performed against a registry:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using a &lt;code&gt;&amp;lt;authConfig&amp;gt;&lt;/code&gt; section in the plugin configuration with&lt;code&gt;&amp;lt;username&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;password&amp;gt;&lt;/code&gt; elements.&lt;/li&gt;
&lt;li&gt;Providing system properties &lt;code&gt;docker.username&lt;/code&gt; and &lt;code&gt;docker.password&lt;/code&gt; when running Maven&lt;/li&gt;
&lt;li&gt;Using a &lt;code&gt;&amp;lt;server&amp;gt;&lt;/code&gt; configuration in &lt;code&gt;~/.m2/settings.xml&lt;/code&gt; with possible encrypted password. That&amp;rsquo;s the most maven-ish way for doing authentication.&lt;/li&gt;
&lt;li&gt;Login into the registry with &lt;code&gt;docker login&lt;/code&gt;. The plugin will pick up the credentials from &lt;code&gt;~/.docker/config.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are again variants to distinguish between authentication for pulling and pushing images to registries (e.g. &lt;code&gt;docker.push.username&lt;/code&gt; and &lt;code&gt;docker.push.password&lt;/code&gt;). All the details can be found in the &lt;a href="http://ro14nd.de/docker-maven-plugin/authentication.html" target="_blank" rel="noreferrer"&gt;reference manual&lt;/a&gt;.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Using the OpenShift Registry
 &lt;div id="using-the-openshift-registry" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#using-the-openshift-registry" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.openshift.com/" target="_blank" rel="noreferrer"&gt;OpenShift&lt;/a&gt; is an awesome PaaS platform on top of &lt;a href="http://kubernetes.io/" target="_blank" rel="noreferrer"&gt;Kubernetes&lt;/a&gt;. It comes with an &lt;a href="https://docs.openshift.com/enterprise/latest/install_config/install/docker_registry.html" target="_blank" rel="noreferrer"&gt;own Docker registry&lt;/a&gt; which can be used by d-m-p, too. However, there are some things to watch out for.&lt;/p&gt;
&lt;p&gt;First of all, the registry needs to be exposed to the outside so that a Docker daemon outside the OpenShift cluster can talk with the registry:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;oc expose service/docker-registry --hostname=docker-registry.mydomain.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hostname provided should be resolved by your host to the OpenShift API server&amp;rsquo;s IP (this happens automatically if you use the &lt;a href="http://fabric8.io/guide/getStarted/vagrant.html" target="_blank" rel="noreferrer"&gt;fabric8 OpenShift Vagrant image&lt;/a&gt; for a one-node developer installation of OpenShift).&lt;/p&gt;
&lt;p&gt;Next, it is important to know, that the OpenShift registry use the regular OpenShift SSO authentication, so you have to login into OpenShift before you can push to the registry. The access token obtained from the login is then used as the password for accessing the registry:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Login to OpenShift. Credentials are stored in ~/.kube/config.json:
oc login

# Use user and access token for authentication:
mvn docker:push -Ddocker.registry=docker-registry.mydomain.com \
 -Ddocker.username=$(oc whoami) \
 -Ddocker.password=$(oc whoami -t)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last step can be simplified by using &lt;code&gt;-Ddocker.useOpenShiftAuth&lt;/code&gt; which does the user and token lookup transparently.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn docker:push -Ddocker.registry=docker-registry.mydomain.com \
 -Ddocker.useOpenShiftAuth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The configuration option &lt;code&gt;useOpenShiftAuth&lt;/code&gt; again comes in multiple flavours: a default one, and dedicated for push and pull operations (&lt;code&gt;docker.pull.useOpenShiftAuth&lt;/code&gt; and &lt;code&gt;docker.push.useOpenShiftAuth&lt;/code&gt;).&lt;/p&gt;

&lt;h3 class="relative group"&gt;tl;dr
 &lt;div id="tldr" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tldr" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Among all the &lt;a href="https://github.com/search?utf8=%E2%9C%93&amp;amp;q=docker-maven-plugin" target="_blank" rel="noreferrer"&gt;many docker maven plugins&lt;/a&gt;, &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;rhuss/docker-maven-plugin&lt;/a&gt; provides the most flexible options for accessing Docker registries and authentication. The gory details can be found in the &lt;a href="http://ro14nd.de/docker-maven-plugin/" target="_blank" rel="noreferrer"&gt;reference manual&lt;/a&gt; which documents &lt;a href="http://ro14nd.de/docker-maven-plugin/" target="_blank" rel="noreferrer"&gt;registry handling&lt;/a&gt; and &lt;a href="http://ro14nd.de/docker-maven-plugin/authentication.html" target="_blank" rel="noreferrer"&gt;authentication&lt;/a&gt; in detail.&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;The interaction is always indirectly via the Docker daemon, since a Docker client like d-m-p only talks with the Docker daemon directly.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Of course you can the registry part in your image names in which case this registry has always the highest priority.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item><item><title>Jolokia 2.0 - JMX Notifications</title><link>https://ro14nd.de/jolokia-notifications/</link><pubDate>Wed, 13 Jan 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jolokia-notifications/</guid><description>&lt;p&gt;This screencast gives a live demo of the forthcoming JMX notification support in Jolokia 2.0.&lt;/p&gt;
&lt;iframe src="https://player.vimeo.com/video/151629488" width="720" height="405" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Jolokia supports currently two notification modes. In all modes, the Jolokia agent itself subscribe to a JMX notification locally and then dispatches the notifications to its clients.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull Mode&lt;/strong&gt; : Here, the agent keeps the notification received for a client in memory and sends it back on an JMX request to a Jolokia specific MBean. A client typically queries this notification MBean periodically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSE Mode&lt;/strong&gt; : &lt;a href="http://www.w3.org/TR/2011/WD-eventsource-20110208/" target="_blank" rel="noreferrer"&gt;Server Sent Events&lt;/a&gt; are a W3C standard for pushing events from an HTTP server to a client. With this mode the Jolokia agents directly pushes any notification it receives to the client. The advantage is of course a much lower latency compared to the pull mode, but SSE is &lt;a href="http://caniuse.com/#feat=eventsource" target="_blank" rel="noreferrer"&gt;not available for Internet Explorer&lt;/a&gt;, including 11. What a pity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://jolokia.org/reference/html/protocol.html" target="_blank" rel="noreferrer"&gt;Jolokia protocol&lt;/a&gt; has been extended with the top level action &lt;code&gt;notification&lt;/code&gt; and subcommands.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;register&lt;/code&gt; / &lt;code&gt;unregister&lt;/code&gt; : Register / unregister a notification client&lt;/li&gt;
&lt;li&gt;&lt;code&gt;add&lt;/code&gt; / &lt;code&gt;remove&lt;/code&gt; : Add / remove a listener subscription&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list&lt;/code&gt; : list all subscriptions for a client&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ping&lt;/code&gt; : Keep subscription alive&lt;/li&gt;
&lt;li&gt;&lt;code&gt;open&lt;/code&gt; : Use for creating a back channel. E.g. the &lt;em&gt;SSE&lt;/em&gt; mode keeps this GET request for pushing back an event stream.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Currently only the new Jolokia JavaScript client supports JMX notification. If you are interested in having it in other clients (e.g. Java), too, please let me know. I would be more than happy for coders jumping on the Jolokia bandwagon since there is still quite some stuff to do for 2.0.&lt;/p&gt;
&lt;p&gt;The source code to this demo and the new Jolokia JavaScript client is on GitHub: &lt;a href="https://github.com/jolokia-org/jolokia-client-javascript" title="https://github.com/jolokia-org/jolokia-client-javascript" target="_blank" rel="noreferrer"&gt;https://github.com/jolokia-org/jolokia-client-javascript&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Welcome to 2016 - the year Jolokia 2.0 will see the light of day</title><link>https://ro14nd.de/jolokia-in-2016/</link><pubDate>Wed, 06 Jan 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jolokia-in-2016/</guid><description>&lt;p&gt;I hope you all had a good start into 2016 and have charged all your batteries during the time of stillness.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt; had a good start, too. During the holiday season I took the opportunity to continue to work on version 2.0 which now takes on form. If you have followed the history of Jolokia you know that work on 2.0 started early 2013 but advanced quite slowly for multiple reasons.&lt;/p&gt;
&lt;p&gt;Now its time to go out on a limb with announcing Jolokia 2.0 for 2016. A bit of pressure sometimes really helps ;-)&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s are the major themes for Jolokia 2.0:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Jolokia 2.0 will be &lt;strong&gt;backwards compatible&lt;/strong&gt; on the protocol level. This is a design goal. There might be some changes in default values, however this should be easy to fix. Any such change will be announced prominently (like artefact renaming). So, all your clients will be usable with 2.0 with minor changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;JMX Notification&lt;/strong&gt; support is here. Yeah, this was quite some work. The extensions to the Jolokia 2.0 protocol are able to push notifications in various ways. Currently the agents supports two modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull mode&lt;/strong&gt; will collect JMX notification on the server (agent) side and can be fetched by a client with an HTTP request, which typically happens periodically. This introduces some latencies but is the most robust way to transmit notifications to a client.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSE mode&lt;/strong&gt; uses &lt;a href="http://www.w3.org/TR/2011/WD-eventsource-20110208/" target="_blank" rel="noreferrer"&gt;Server Sent Events&lt;/a&gt; for pushing JMX notifications immediately with very low latency. This is the preferred mode if a client supports this (Internet Explorer does not).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The notification support is nearly complete on the agent side, and the Jolokia JavaScript client already supports both modes. In the future more mode like WebSockets or Web-Hooks should be easy to add. The next post will give a demo about the notification support.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Namespaces&lt;/strong&gt; extend Jolokia beyond JMX which means you can access other entities than JMX MBeans with the very same protocol. This feature is still in the conceptual state but one can easily imagine to access&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Beans&lt;/li&gt;
&lt;li&gt;CDI Objects&lt;/li&gt;
&lt;li&gt;JNDI Directories&lt;/li&gt;
&lt;li&gt;Zookeeper Directories&lt;/li&gt;
&lt;li&gt;&amp;hellip;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;the same was as JMX. The namespace is selected as part of the (MBean) name. More on this in this &lt;a href="https://github.com/rhuss/jolokia/wiki/Requesthandler" target="_blank" rel="noreferrer"&gt;design document&lt;/a&gt;. Since this feature would extend the usage pattern of Jolokia quite a bit, I&amp;rsquo;m not 100% sure whether to include it into 2.0 since it feels a bit against my Unix based education (&amp;ldquo;do one thing and do it well&amp;rdquo;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With the addition of even more features, &lt;strong&gt;modularization&lt;/strong&gt; becomes even more important. Jolokia was and is always picky about its footprint, which is currently 430k for the WAR agent with all features included. Jolokia 2.0 introduces various &lt;a href="https://github.com/rhuss/jolokia/wiki/Jolokia-Services" target="_blank" rel="noreferrer"&gt;internal services&lt;/a&gt; which can be picked and chosen by repackaging the agent. Or the agent can be extended with own functionality, too. A way for easily packaging and creating agents will be provided either by a Web-UI or by a CLI tool (or both).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition there are also some non-functional changes to polish Jolokia a bit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Non-agent based addition like client libraries, integration tests, JBoss Forge support are extracted into extra GitHub repositories. All this will happen within the GitHub organization &lt;a href="https://github.com/jolokia-org" target="_blank" rel="noreferrer"&gt;jolokia-org&lt;/a&gt;. The first project here is the JavaScript client which already moved to a dedicated &lt;a href="https://github.com/jolokia-org/jolokia-client-javascript" target="_blank" rel="noreferrer"&gt;jolokia-client-javascript&lt;/a&gt; repository.&lt;/li&gt;
&lt;li&gt;The website will get a face-lift.&lt;/li&gt;
&lt;li&gt;Documentation will switch from Docbook to a Markdown or AsciiDoc based format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally some stuff will get dropped. This happens because of limited resources (Jolokia, to be frankly, still doesn&amp;rsquo;t have a big community, so that most of the work is done by a single person. &amp;lsquo;would like to change that, though) and because I think these feature never took off:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mule agent&lt;/strong&gt;. I never got much feedback from the Mule community so I&amp;rsquo;m really not sure whether this agent is really used or needed. Jolokia 1.x will continue to support the Mule agent, however there will be no stock Jolokia 2.0 Mule agent. Said that, you are always free to adopt Jolokia 2.0 to the Mule management platform. Considering the extra code needed included in Jolokia 1.3 for Mule support this should be fairly trivial. I&amp;rsquo;m happy to support anyone doing the port. Also, there is always the alternative to use the JVM agent for attaching Jolokia to Mule, which is the preferred way for 2.0 to monitor Mule with Jolokia.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Roo Support&lt;/strong&gt; will be dropped for much the same reasons. I never received an issue on the Jolokia Spring Roo support, which is a clear sign that nobody is using it. It might popup as an extra project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, what&amp;rsquo;s the roadmap ? Here&amp;rsquo;s the plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Milestone 2.0.0-M1 is here. You find the &lt;a href="http://search.maven.org/remotecontent?filepath=org/jolokia/jolokia-agent-jvm/2.0.0-M1/jolokia-agent-jvm-2.0.0-M1-agent.jar" target="_blank" rel="noreferrer"&gt;JVM&lt;/a&gt; and &lt;a href="http://search.maven.org/remotecontent?filepath=org/jolokia/jolokia-agent-war/2.0.0-M1/jolokia-agent-war-2.0.0-M1.war" target="_blank" rel="noreferrer"&gt;WAR&lt;/a&gt; agents in Maven central.&lt;/li&gt;
&lt;li&gt;Every month, a new milestone will be released.&lt;/li&gt;
&lt;li&gt;Final release is aligned to &lt;a href="http://www.redhat.com/summit/" target="_blank" rel="noreferrer"&gt;Red Hat Summit&lt;/a&gt; / &lt;a href="http://www.devnation.org/" target="_blank" rel="noreferrer"&gt;DevNation&lt;/a&gt;. July 1st.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Isn&amp;rsquo;t this a nice new year&amp;rsquo;s resolution ? ;-)&lt;/p&gt;
&lt;p&gt;In the next post I will demo JMX notifications and how you can use them in your JavaScript projects.&lt;/p&gt;</description></item><item><title>fish-pepper - Docker on Capsaicin</title><link>https://ro14nd.de/fish-pepper-announcement/</link><pubDate>Mon, 07 Sep 2015 00:00:00 +0000</pubDate><guid>https://ro14nd.de/fish-pepper-announcement/</guid><description>&lt;p&gt;When I had to create multiple Docker base images which only differ slightly for some minor variations I couldn&amp;rsquo;t avoid to feel quite dirty because of all the copying &amp;amp; pasting of Dockerfile fragments. We all know how this smells, but unfortunately Docker has only an answer for &lt;strong&gt;inheritance&lt;/strong&gt; but not for &lt;strong&gt;composition&lt;/strong&gt; of Docker images. Luckily there is now &lt;a href="https://github.com/fabric8io/fish-pepper" target="_blank" rel="noreferrer"&gt;fish-pepper&lt;/a&gt;, a multi-dimensional docker build generator, which steps into the breach.&lt;/p&gt;
&lt;p&gt;For example consider a Java base image: Some users might require Java 7, some want Java 8. For running Microservices a JRE might be sufficient. In other use cases you need a full JDK. These four variants are all quite similar with respect to documentation, Dockerfiles and support files like startup scripts. Copy-and-paste might seem to work for the initial setup but there are severe drawbacks considering image evolution or introduction of even more parameters.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;fish-pepper&lt;/code&gt; you can use flexible templates which are filled with variations of the base image (like &lt;code&gt;'version' : ['java7', 'java8'], 'type': ['jdk', 'jre']&lt;/code&gt;) and which will create multiple, similar Dockerfile builds.&lt;/p&gt;
&lt;p&gt;The main configuration of an image family is &lt;code&gt;images.yml&lt;/code&gt; which defines the possible parameters. For the example above it is&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fish-pepper:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &amp;#34;version&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &amp;#34;type&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The possible values for these parameters are given in a dedicated &lt;code&gt;config&lt;/code&gt; section:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;config:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; openjdk7:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; java: &amp;#34;java:7u79&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fullVersion: &amp;#34;OpenJDK 1.7.0_79&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; openjdk8:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; java: &amp;#34;java:8u45&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fullVersion: &amp;#34;OpenJDK 1.8.0_45&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jre:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extension: &amp;#34;-jre&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jdk:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extension: &amp;#34;-jdk&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Given this configuration, four builds will be generated when calling &lt;code&gt;fish-pepper&lt;/code&gt;, one for each combination of &lt;em&gt;version&lt;/em&gt; (&amp;ldquo;openjdk7&amp;rdquo; and &amp;ldquo;openjdk8&amp;rdquo;) and &lt;em&gt;type&lt;/em&gt; (&amp;ldquo;jre&amp;rdquo; and &amp;ldquo;jdk&amp;rdquo;) parameter values.&lt;/p&gt;
&lt;p&gt;These value can now be filled into templates which are stored in a &lt;code&gt;templates/&lt;/code&gt; directory. The &lt;code&gt;Dockerfile&lt;/code&gt; in this directory can refer to this configuration through a context object &lt;code&gt;fp&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FROM {{ &amp;#34;{{= fp.config.version.java + fp.config.type.extension &amp;#34; }}}}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.....&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Templates use &lt;a href="http://olado.github.io/doT/index.html" target="_blank" rel="noreferrer"&gt;DoT.js&lt;/a&gt; as template engine, so that the full expressiveness of JavaScript is available. The fish-pepper &lt;a href="https://github.com/fabric8io/fish-pepper#template-context" target="_blank" rel="noreferrer"&gt;context object&lt;/a&gt; &lt;code&gt;fp&lt;/code&gt; holds the configuration and more.&lt;/p&gt;
&lt;p&gt;The given configuration will lead to four Docker build directories:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;images/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---- openjdk7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | +--- jre -- Dockerfile, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | +--- jdk -- Dockerfile, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---- opendjk8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +--- jre -- Dockerfile, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +--- jdk -- Dockerfile, ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The generated build files can also be used directly to create the images with &lt;code&gt;fish-pepper build&lt;/code&gt;. This will reach out to a Docker daemon and create the images &lt;code&gt;java-openjdk7-jre&lt;/code&gt;, &lt;code&gt;java-openjdk7-jdk&lt;/code&gt;, &lt;code&gt;java-openjdk8-jre&lt;/code&gt; and &lt;code&gt;java-openjdk8-jdk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively these builds can be used as content for automated Docker Hub builds when checked into Github. The full example can be found on &lt;a href="https://github.com/fabric8io/fish-pepper/tree/master/example" target="_blank" rel="noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But wait, there is more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/fabric8io/fish-pepper#blocks" target="_blank" rel="noreferrer"&gt;Blocks&lt;/a&gt; can be used to reuse Dockerfile snippets and files to include across images. Blocks can be stored locally or referenced via a remote Git repository. Examples for blocks are generic &lt;a href="https://github.com/fabric8io/run-java-sh/tree/master/fish-pepper/run-java-sh" target="_blank" rel="noreferrer"&gt;startup scripts&lt;/a&gt; or other value add functionality like enabling agents like &lt;a href="https://github.com/fabric8io/agent-bond/tree/master/fish-pepper/agent-bond" target="_blank" rel="noreferrer"&gt;agent bond&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Flexible &lt;a href="https://github.com/fabric8io/fish-pepper#file-mappings" target="_blank" rel="noreferrer"&gt;file mappings&lt;/a&gt; allow multiple alternative templates.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/fabric8io/fish-pepper#defaults" target="_blank" rel="noreferrer"&gt;Defaults&lt;/a&gt; allow shared configuration between multiple parameter values.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;fish-pepper can be seen in its fully beauty in &lt;a href="https://github.com/fabric8io/base-images" target="_blank" rel="noreferrer"&gt;fabric8io/base-images&lt;/a&gt; where more than twenty five base images are maintained with fish-pepper.&lt;/p&gt;
&lt;p&gt;With node.js you can install fish-pepper super easy with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm -g install fish-pepper
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the following blogs I will show more usage examples, especially how &amp;ldquo;blocks&amp;rdquo; can be easily reused and shared.&lt;/p&gt;</description></item><item><title>Jmx4Perl for everyone</title><link>https://ro14nd.de/jmx4perl-docker/</link><pubDate>Tue, 28 Jul 2015 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jmx4perl-docker/</guid><description>&lt;p&gt;As you might know, &lt;a href="http://www.jmx4perl.org" target="_blank" rel="noreferrer"&gt;Jmx4Perl&lt;/a&gt; is the mother of &lt;a href="https://jolokia.org/" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt;. But what might be not so known is, that Jmx4Perl provides a set of nice CLI tools for accessing Jolokia agents. However, installing Jmx4Perl manually is cumbersome because of its many Perl and also native dependencies.&lt;/p&gt;
&lt;p&gt;However, if you are a Docker user there is now a super easy way to benefit from this gems.&lt;/p&gt;
&lt;p&gt;Even if Perl is not your cup of tea, you might like the following tool (for which of course no Perl knowledge is required at all):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/jmx4perl" target="_blank" rel="noreferrer"&gt;&lt;strong&gt;jmx4perl&lt;/strong&gt;&lt;/a&gt; is a command line tool for one-shot querying Jolokia agents. It is perfectly suited for shell scripts.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/j4psh" target="_blank" rel="noreferrer"&gt;&lt;strong&gt;j4psh&lt;/strong&gt;&lt;/a&gt; is a readline based, JMX shell with coloring and command line completion. You can navigate the JMX namespace like directories with &lt;code&gt;cd&lt;/code&gt; and &lt;code&gt;ls&lt;/code&gt;, read JMX attributes with &lt;code&gt;cat&lt;/code&gt; and execute operations with &lt;code&gt;exec&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/jolokia" target="_blank" rel="noreferrer"&gt;&lt;strong&gt;jolokia&lt;/strong&gt;&lt;/a&gt; is an agent management tool which helps you in downloading Jolokia agents of various types (war, jvm, osgi, mule) and versions. It also knows how to repackage agents e.g. for enabling security for the war agent by in-place modification of the web.xml descriptor.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/check_jmx4perl" target="_blank" rel="noreferrer"&gt;&lt;strong&gt;check_jmx4perl&lt;/strong&gt;&lt;/a&gt; is a full featured Nagios plugin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How can you now use these tools ? All you need is a running Docker installation. The tools mentioned above are all included within the Docker image &lt;a href="https://registry.hub.docker.com/u/jolokia/jmx4perl/" target="_blank" rel="noreferrer"&gt;jolokia/jmx4perl&lt;/a&gt; which is available from Docker Hub.&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Get some basic information of the server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --rm -it jolokia/jmx4perl \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jmx4perl http://localhost:8080/jolokia
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Download the current jolokia.war agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --rm -it -v `pwd`:/jolokia jolokia/jmx4perl \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jolokia
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Start an interactive JMX shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# server &amp;#34;tomcat&amp;#34; is defined in ~/.j4p/jmx4perl.config
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --rm -it -v ~/.j4p:/root/.j4p jolokia/jmx4perl \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; j4psh tomcat&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In these examples we mounted some volumes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you put your server definitions into &lt;code&gt;~/.j4p/jmx4perl.config&lt;/code&gt; you can use them by mounting this directory as volume with &lt;code&gt;-v ~/.j4p:/root/.j4p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the management tool &lt;code&gt;jolokia&lt;/code&gt; it is recommended to mount the local directory with &lt;code&gt;-v $(pwd):/jolokia&lt;/code&gt; so that downloaded artefacts are stored in the current host directory. (Note for boot2docker users: This works only when you are in a directory below you home directory)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is recommended to use aliases as abbreviations:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias jmx4perl=&amp;#34;docker run --rm -it -v ~/.j4p:/root/.j4p jolokia/jmx4perl jmx4perl&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias jolokia=&amp;#34;docker run --rm -it -v `pwd`:/jolokia jolokia/jmx4perl jolokia&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias j4psh=&amp;#34;docker run --rm -it -v ~/.j4p:/root/.j4p jolokia/jmx4perl j4psh&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As an additional benefit of using Jmx4Perl that way, you can access servers which are not directly reachable by you. The Jolokia agent must be reachable by the Docker daemon only. For example, you can communicate with a SSL secured Docker daemon running in a DMZ only. From there you can easily reach any other server with a Jolokia agent installed, so there is no need to open access to all servers from your local host directly.&lt;/p&gt;
&lt;p&gt;Finally, here&amp;rsquo;s a short appetiser with an (older) demo showing &lt;code&gt;j4psh&lt;/code&gt; in action.&lt;/p&gt;
&lt;iframe width="720" height="405" src="https://www.youtube.com/embed/y9TuGzxD2To" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;</description></item><item><title>docker:watch</title><link>https://ro14nd.de/maven-docker-watch/</link><pubDate>Tue, 30 Jun 2015 00:00:00 +0000</pubDate><guid>https://ro14nd.de/maven-docker-watch/</guid><description>&lt;p&gt;Ok, you know Docker. And since you are a Java developer you want to know how you can use this in your daily development workflow. You probably also heard about &lt;em&gt;the&lt;/em&gt; &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;docker-maven-plugin&lt;/a&gt; which seamlessly creates Docker images, starts and stops Docker containers and more all with a concise configuration syntax.&lt;/p&gt;
&lt;p&gt;And now there is this new goal &lt;code&gt;docker:watch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We developers are lazy, right ? We want our code to compile fast, we want the servers to start up fast. And we want to test changes quickly. That&amp;rsquo;s why we love &lt;a href="http://www.osgi.org/Main/HomePage" target="_blank" rel="noreferrer"&gt;OSGi&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; and &lt;a href="http://zeroturnaround.com/software/jrebel/" target="_blank" rel="noreferrer"&gt;JRebel&lt;/a&gt;. And we want this for Docker containers, too.&lt;/p&gt;
&lt;p&gt;Good news. &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;docker-maven-plugin&lt;/a&gt; will support hot rebuild of Docker images and hot restart of containers with a new Maven goal &lt;code&gt;docker:watch&lt;/code&gt;. It will be released with version 0.12.1. For the brave coder 0.12.1-SNAPSHOT is already out there, the documentation can be found &lt;a href="https://github.com/rhuss/docker-maven-plugin/blob/integration/doc/manual.md#dockerwatch" target="_blank" rel="noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But before losing more words, here&amp;rsquo;s a sneak preview.&lt;/p&gt;
&lt;iframe src="https://player.vimeo.com/video/132183699" width="720" height="405" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;That&amp;rsquo;s of course not entirely true. We love OSGi &amp;hellip; or we hate it with passion. But even the haters don&amp;rsquo;t hate it for its hot deployment abilities.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item><item><title>The Docker Wormhole Pattern</title><link>https://ro14nd.de/docker-wormhole-pattern/</link><pubDate>Wed, 17 Jun 2015 00:00:00 +0000</pubDate><guid>https://ro14nd.de/docker-wormhole-pattern/</guid><description>&lt;p&gt;Building a Docker wormhole is easy.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A wormhole is a special type of structure that some scientists think might exist, connecting parts of space and time that are not usually connected&lt;/p&gt;
&lt;p&gt;&amp;mdash; Cambridge Dictionaries Online&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;In Docker universe we have several uses cases, which require a Docker installation within a Docker container. For example the &lt;a href="https://github.com/openshift/origin/blob/master/docs/builds.md#openshift-builds" target="_blank" rel="noreferrer"&gt;OpenShift Builds&lt;/a&gt; use images whose container&amp;rsquo;s are meant to create application images. They include a whole development environment including possibly a compiler and a build tool. During the build a Docker daemon is accessed for creating the final application image.&lt;/p&gt;
&lt;p&gt;The question is now, &lt;em&gt;how&lt;/em&gt; a build can access the Docker daemon ? In general, there are two possibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jpetazzo/dind" target="_blank" rel="noreferrer"&gt;Docker in Docker&lt;/a&gt; is a project which allows you to run a Docker daemon within a Docker container. Technically this is quite tricky and there seems to be some issues with this approach, especially because you have to run this container in &lt;a href="http://blog.docker.com/2013/09/docker-can-now-run-within-docker/" target="_blank" rel="noreferrer"&gt;privileged mode&lt;/a&gt;. This is the &lt;strong&gt;Matryoshka doll pattern&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Or you use the &lt;strong&gt;Wormhole pattern&lt;/strong&gt; described in this post. The idea is to get access to the Docker daemon running a container from within the container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you know a Docker host can be configured to be accessible by two alternative methods: Via a Unix socket or via a TCP socket.&lt;/p&gt;
&lt;p&gt;Using the Unix socket of the surrounding docker daemon is easy: Simply share the path to the unix socket as a volume:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Map local unix socket into the container
docker run -it -v /var/run/docker.sock:/var/run/docker.sock ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then within the container you can use the Docker CLI or any tool that uses the Unix socket at usual.&lt;/p&gt;
&lt;p&gt;Running over the TCP socket is a bit more tricky because you have to find out the address of your Docker daemon host. This can best be done by examining the routing table within the container:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Lookup and parse routing table 
host=$(ip route show 0.0.0.0/0 | \
 grep -Eo 'via \S+' | \
 awk '{print $2}');
export DOCKER_HOST=tcp://${host}:2375
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works fine as long you are not using SSL. With SSL in place you need have access to the SSL client certificates. Of course this is achieved again with a volume mount. Assuming that you are using boot2docker this could look like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Mount certs into the container
docker run -ti -v ~/.boot2docker/certs/boot2docker-vm/:/certs ....
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will mount your certs at &lt;code&gt;/certs&lt;/code&gt; within the container and can be used to set the &lt;code&gt;DOCKER_HOST&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if [ -f /certs/key.pem ]; then
 # If certs are mounted, use SSL ...
 export DOCKER_CERT_PATH=/certs
 export DOCKER_TLS_VERIFY=1
 export DOCKER_HOST=tcp://${host}:2376
else
 # ... otherwise use plain http
 export DOCKER_TLS_VERIFY=0
 export DOCKER_HOST=tcp://${host}:2375
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is some final gotcha as that the server certificate can not be verified because it doesn&amp;rsquo;t contain the docker host IP as seen from the container. See this &lt;a href="https://github.com/docker/docker/issues/13922" target="_blank" rel="noreferrer"&gt;issue&lt;/a&gt; for details. As workaround you have to &lt;code&gt;unset DOCKER_TLS_VERIFY&lt;/code&gt; for the moment when using the docker client.&lt;/p&gt;
&lt;p&gt;Both ways are useful and are &lt;a href="https://github.com/openshift/origin/blob/master/docs/builds.md#why-not-docker-in-docker" target="_blank" rel="noreferrer"&gt;leaner and possibly more secure&lt;/a&gt; than having a Matryoshka doll approach.&lt;/p&gt;
&lt;p&gt;Finally there is still the question, why on earth &lt;em&gt;wormhole pattern&lt;/em&gt; ? Like in a wormhole (also known as &lt;a href="https://en.wikipedia.org/wiki/Wormhole" target="_blank" rel="noreferrer"&gt;Einstein-Rosen Bridge&lt;/a&gt;) you can reach through the wormhole a point (the outer docker daemon) in spacetime which is normally not reachable (because a container is supposed to be its &amp;ldquo;own&amp;rdquo; world). Another fun fact: If you create a container through a wormhole this container it&amp;rsquo;s not your daughter, its your sister. Feels a bit freaky, or ? Alternatively you could call it also &lt;strong&gt;Münchhausen pattern&lt;/strong&gt; because you create something with the exact the identically means you have been created yourself (like in the &lt;a href="https://en.wikipedia.org/wiki/M%C3%BCnchhausen_trilemma" target="_blank" rel="noreferrer"&gt;Münchhausen trilemma&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Or feel free to call it what you like ;-)&lt;/p&gt;</description></item><item><title>Jmx4Perl on OS X</title><link>https://ro14nd.de/jmx4perl-on-osx/</link><pubDate>Mon, 23 Mar 2015 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jmx4perl-on-osx/</guid><description>&lt;p&gt;The HTTP-JMX Bridge &lt;a href="http://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt; allows easy access to JMX. It exposes all JMX information and operations via an REST-like interface and has tons of nifty features. &lt;a href="http://search.cpan.org/~roland/jmx4perl/" target="_blank" rel="noreferrer"&gt;Jmx4Perl&lt;/a&gt; on the other side is a client for Jolokia, which beside Perl access modules also provides quite some nice CLI tools for accessing and installing Jolokia. This post explains how install these tools on OS X.&lt;/p&gt;
&lt;p&gt;Jmx4Perl provides some nice CLI commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/jmx4perl" target="_blank" rel="noreferrer"&gt;jmx4perl&lt;/a&gt; is a simple access tool which is useful for quick queries and ideal for inclusion in shell scripts.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/j4psh" target="_blank" rel="noreferrer"&gt;j4psh&lt;/a&gt; is a powerful interactive, readline based JMX shell with tab completion and syntax highlighting.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/jolokia" target="_blank" rel="noreferrer"&gt;jolokia&lt;/a&gt; is a tool for managing Jolokia agents (downloading, changing init properties etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All this tools are very helpful in order to explore the JMX namespace and installing the agent. They all are fairly good documented and each of them probably deserves an own blog post.&lt;/p&gt;
&lt;p&gt;However, the installation or Perl modules and programs is a bit tedious. Although &lt;a href="http://search.cpan.org/~andk/CPAN/scripts/cpan" target="_blank" rel="noreferrer"&gt;cpan&lt;/a&gt; helps here and also resolves transitive dependencies it&amp;rsquo;s still a lengthy process, which fails from time to time. Native Linux packages are planned, but don&amp;rsquo;t hold your breath ;-).&lt;/p&gt;
&lt;p&gt;For OS X users with &lt;a href="http://brew.sh/" target="_blank" rel="noreferrer"&gt;Homebrew&lt;/a&gt; can install Jmx4Perl quite easily, though:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ brew install cpanm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cpanm --sudo install JMX::Jmx4Perl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will do all the heavy lifting for you and at the end all the fine Jmx4Perl tools are installed and available under &lt;code&gt;/usr/local/bin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;j4psh&lt;/code&gt; uses &lt;code&gt;libreadline&lt;/code&gt; for the input handling. For the best user experience GNU ReadLine is recommended. Unfortunately, OS X doesn&amp;rsquo;t ship with a &lt;em&gt;true&lt;/em&gt; &lt;code&gt;libreadline&lt;/code&gt; but with &lt;code&gt;libedit&lt;/code&gt; which is a stripped down version of libreadline. In order to use GNU readline, some tricks are needed which are described in this &lt;a href="http://blogs.perl.org/users/aristotle/2013/07/easy-osx-termreadlinegnu.html" target="_blank" rel="noreferrer"&gt;recipe&lt;/a&gt;. For me, the following steps worked (but are probably a bit &amp;ldquo;dirty&amp;rdquo;):&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ brew install readline
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ brew link --force readline
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo mv /usr/lib/libreadline.dylib /tmp/libreadline.dylib 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cpanm --sudo Term::ReadLine::Gnu
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo mv /tmp/libreadline.dylib /usr/lib/libreadline.dylib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ brew unlink readline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These steps are really only necessary if you need advanced readline functionality (or a coloured prompt in j4psh ;-).&lt;/p&gt;</description></item><item><title>Health Checks with Jolokia</title><link>https://ro14nd.de/health-checks/</link><pubDate>Sat, 17 Jan 2015 00:00:00 +0000</pubDate><guid>https://ro14nd.de/health-checks/</guid><description>&lt;p&gt;A &lt;em&gt;health check&lt;/em&gt; is a useful technique for determining the overall operational state of a system in a consolidated form. It provides some kind of internal monitoring which collects metrics, evaluates them against some thresholds and provides a unified result. Health checks are now coming to &lt;a href="http://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt;. This post explains the strategy to include health checks into Jolokia without blowing up the agents to much.&lt;/p&gt;
&lt;p&gt;Health checks are different to classical monitoring solutions like Nagios, where external systems collect metrics and evaluate them against some threshold on their own. While monitoring with Nagios was and is always possible with Jolokia (and in fact was the original motivation for creating it), intrinsic health checks were avoided for the vanilla agent up to now because of the extra complexity they introduce into the agent. One of the major design goals of Jolokia is to keep it small and focussed.&lt;/p&gt;
&lt;p&gt;The upcoming release 1.3.0 (scheduled for the end of this month) will introduce a simple plugin architecture into Jolokia which allows to hook into the agent&amp;rsquo;s lifecycle. A so called &lt;a href="https://github.com/rhuss/jolokia/blob/master/agent/core/src/main/java/org/jolokia/backend/plugin/MBeanPlugin.java" target="_blank" rel="noreferrer"&gt;MBeanPlugin&lt;/a&gt; in Jolokia also allows access to the agent configuration and to the JMX system. Currently it is supported for the WAR and JVM agent, where plugins are created via a simple class path lookup. For the OSGi agent it is planned that it will pick up plugins as OSGi services.&lt;/p&gt;
&lt;p&gt;Having this new infrastructure in place, extra functionality like health checks can be added easily. The GitHub repository &lt;a href="https://github.com/rhuss/jolokia-extra" target="_blank" rel="noreferrer"&gt;jolokia-extra&lt;/a&gt; was created to host various extensions to the Jolokia agent, also to keep the original agent as lean as possible. Beside the new health checks there is already an extension &lt;em&gt;jsr77&lt;/em&gt; for simplifying the access to &lt;a href="https://jcp.org/en/jsr/detail?id=77" target="_blank" rel="noreferrer"&gt;JSR-77&lt;/a&gt; compliant JEE Servers like WebSphere.&lt;/p&gt;
&lt;p&gt;The new &lt;a href="https://github.com/rhuss/jolokia-extra/tree/master/addon/health" target="_blank" rel="noreferrer"&gt;health&lt;/a&gt; addon in &lt;em&gt;jolokia-extra&lt;/em&gt; has just been started. Currently it contains not much more as proof-of-concept with some hardcoded health checks, but it already illustrate the concept: A &lt;code&gt;MBeanPlugin&lt;/code&gt; registers a certain &lt;code&gt;SampleHealthCheckMBean&lt;/code&gt; during startup which exposes the health checks as JMX operations (and which can be executed as usual with Jolokia). These operations have access to JMX via the &lt;code&gt;MBeanPluginContext&lt;/code&gt; and can query any MBean in the system.&lt;/p&gt;
&lt;p&gt;But that is only the beginning. There are still a lot of design decisions to take:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How should health check specification look like ? Should it be done via JSON or should a more expressive DSL based e.g. on Groovy should be used ?&lt;/li&gt;
&lt;li&gt;How are the health check store on the agent side ?
&lt;ul&gt;
&lt;li&gt;Looking them up in the filesystem (from a configurable path with a sane default like &lt;code&gt;~/.jolokia_healthchecks&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Baking it into the agent jar&lt;/li&gt;
&lt;li&gt;Uploading it via an MBean operation (and then storing them in the filesystem as well)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What kind of meta data should be provided so that consoles like hawt.io can dynamically create their health check views ?&lt;/li&gt;
&lt;li&gt;How should the parameter and return value for the health checks look like ?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you would like to participate, the discussion about the implementation details will take place in issue &lt;a href="https://github.com/rhuss/jolokia-extra/issues/1" target="_blank" rel="noreferrer"&gt;#1&lt;/a&gt; and the current working state is summarized in this &lt;a href="https://github.com/rhuss/jolokia-extra/wiki/Health-Checks" target="_blank" rel="noreferrer"&gt;wiki page&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Real clean Maven builds with Docker</title><link>https://ro14nd.de/clean-maven-builds-with-docker/</link><pubDate>Fri, 07 Nov 2014 00:00:00 +0000</pubDate><guid>https://ro14nd.de/clean-maven-builds-with-docker/</guid><description>&lt;p&gt;A local Maven repository serves as a cache for artifacts and dependencies, we all know this. This helps in speeding up things but can cause subtle problems when doing releases. Docker can help here a bit for avoiding caching issues.&lt;/p&gt;
&lt;p&gt;Before doing a release I typically move &lt;code&gt;~/.m2/repository&lt;/code&gt; away to be really sure that everybody else can build the source as well and that any dependencies are also on the remote Maven repository. This is a bit tedious, because it is a manual process and you can forget to move the old directory back which will was a LOT of disk space over time.&lt;/p&gt;
&lt;p&gt;Docker can help here a bit: Since yesterday there is an &lt;a href="https://registry.hub.docker.com/_/maven/" target="_blank" rel="noreferrer"&gt;official Maven image&lt;/a&gt; which can be used to build your project. The nice thing for doing releases with this image is, that it always starts afresh with an empty local Maven repository.&lt;/p&gt;
&lt;p&gt;Assuming you are currently located in the top-level directory holding your &lt;code&gt;pom.xml&lt;/code&gt; you can use this single command for running a real clean build:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -it --rm \ 
	 -v &amp;quot;$(pwd)&amp;quot;:/usr/src/mymaven \ 
	 -w /usr/src/mymaven \ 
	 maven:3.2-jdk-7 \
	 mvn clean install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this call you mount your project directory into &lt;code&gt;/usr/src/mymaven&lt;/code&gt; on the container, change to this directory in the container and call &lt;code&gt;mvn clean install&lt;/code&gt;. At the end, your container will be removed (&lt;code&gt;--rm&lt;/code&gt;) so there is no chance that you might forget to clean up afterwards.&lt;/p&gt;
&lt;p&gt;Of course it will download all the artifacts each time, so it is not a good idea to use this approach for your daily developer business (especially if you using Maven central as remote Maven repository).&lt;/p&gt;
&lt;p&gt;You can also play around with various versions of Maven by changing the image tag so at the end you can be really sure, that your project will build everywhere. Please refer to the &lt;a href="https://registry.hub.docker.com/_/maven/" target="_blank" rel="noreferrer"&gt;Docker Hub page&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: As pointed out by &lt;a href="https://twitter.com/noahlz/status/530708791906807808" target="_blank" rel="noreferrer"&gt;Noah Zucker&lt;/a&gt; on Twitter you can redirect of course the local repository via &lt;code&gt;-Dmaven.repo.local=/tmp/clean-repo&lt;/code&gt; temporarily to a new location. Which is confessedly much simpler and I would prefer that one instead if you don&amp;rsquo;t need to check with different JDKs or Maven versions. Sometimes you don&amp;rsquo;t see the forest for the trees if you come from the wrong direction (e.g. looking for use case of a specific docker image).&lt;/p&gt;</description></item><item><title>Docker maven plugin rewrite</title><link>https://ro14nd.de/docker-maven-plugin-rewrite/</link><pubDate>Mon, 13 Oct 2014 00:00:00 +0000</pubDate><guid>https://ro14nd.de/docker-maven-plugin-rewrite/</guid><description>&lt;p&gt;My &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;docker-maven-plugin&lt;/a&gt; is undergoing a major refactoring. This post explains the motivation behind this and also what you can expect in the very near future.
The configuration syntax becomes much cleaner and implicit behavior was removed.&lt;/p&gt;
&lt;p&gt;Originally, I needed a &lt;em&gt;docker-maven-plugin&lt;/em&gt; for a very specific use case: To test &lt;a href="http://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt;, the HTTP-JMX bridge in all the JEE and non-JEE servers out there. This was a very manual process: Fire up the VirtualBox image with all those servers installed, start a server, deploy Jolokia, run integration tests, stop the server, start the next server &amp;hellip;. It takes easily half a day or more to do the tests before each release. That&amp;rsquo;s not the kind of QA you are looking for, really. But with docker there is finally the opportunity to automate all this: Deploy a single application on multiple different servers while controlling the lifecycle of theses servers from within the build.&lt;/p&gt;
&lt;p&gt;Early this year when I searched the Web, I couldn&amp;rsquo;t find a good Docker build integration, so I decided to write my own &lt;a href="http://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;docker-maven-plugin&lt;/a&gt; to back my use case. Today you find nearly a dozen of Maven plugins for your Docker business. However, only four plugins (&lt;a href="https://github.com/alexec/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;alexec&lt;/a&gt;, &lt;a href="https://github.com/wouterd/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;wouterd&lt;/a&gt;, &lt;a href="https://github.com/spotify/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;spotify&lt;/a&gt; and &lt;a href="https://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;rhuss&lt;/a&gt;) are still actively maintained. A later blog post will present a detailed comparison between those four plugins (or come to my &lt;a href="http://jax.de/wjax2014/sessions/docker-fuer-java-entwickler" target="_blank" rel="noreferrer"&gt;W-JAX&lt;/a&gt; session), but this post is about the evolution of the &lt;code&gt;rhuss&lt;/code&gt; plugin.&lt;/p&gt;
&lt;p&gt;It turned out that the plugin works quite well, people liked and starred it on GitHub. It provides also some unique features like creating Docker images from &lt;a href="http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html" target="_blank" rel="noreferrer"&gt;assembly descriptors&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I was not so happy.&lt;/p&gt;
&lt;p&gt;The reason is, that I started from a very special, probably very uncommon use case: A single application, multiple different servers for multiples tests. A much more common scenario is to have a fixed application server brand for the application, running with multiple linked backend containers like databases. My plugin doesn&amp;rsquo;t work well with running multiple containers at once. Or to state it otherwise: The plugin was not prepared for orchestration of multiple docker containers.&lt;/p&gt;
&lt;p&gt;Also, there was too much happening &lt;em&gt;magically&lt;/em&gt; behind the scenes: When pushing a data image, it was implicitly build. When starting a container for integration test, the data container is also build before.&lt;/p&gt;
&lt;p&gt;Two operational modes were supported: One with images holding the server and data separately in two containers (linked via &lt;code&gt;volumes&lt;/code&gt;) and one so called &lt;em&gt;merged&lt;/em&gt; image, holding both, the application and server together in one image. This is perfect for creating micro services. The mode is determined only by a configuration flag (&lt;code&gt;mergeData&lt;/code&gt;), but it is not really clear how many and what Docker images are created. And it was hard to document which is always a very bad smell.&lt;/p&gt;
&lt;p&gt;So I changed the configuration syntax completely.&lt;/p&gt;
&lt;p&gt;It is now much more explicit and you will know merely by looking at the configuration which and how many containers will be started during integration testing and what the container with the application will look like. I don&amp;rsquo;t want to go into much detail here, the post is already too long. Instead here is an example of the new syntax:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;plugin&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;groupId&amp;gt;org.jolokia&amp;lt;/groupId&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;artifactId&amp;gt;docker-maven-plugin&amp;lt;/artifactId&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;version&amp;gt;0.10.1&amp;lt;/version&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;configuration&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;images&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;image&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;name&amp;gt;consol/tomcat-7.0&amp;lt;/name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;run&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;volumes&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;from&amp;gt;jolokia/docker-jolokia-demo&amp;lt;/from&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/volumes&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;ports&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;port&amp;gt;jolokia.port:8080&amp;lt;/port&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/ports&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;wait&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;url&amp;gt;http://localhost:${jolokia.port}/jolokia&amp;lt;/url&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;time&amp;gt;10000&amp;lt;/time&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/wait&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/run&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/image&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;image&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;name&amp;gt;jolokia/docker-jolokia-demo&amp;lt;/name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;build&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;assemblyDescriptor&amp;gt;src/main/assembly.xml&amp;lt;/assemblyDescriptor&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/build&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/image&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/images&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/configuration&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This examples creates and starts &lt;strong&gt;two&lt;/strong&gt; containers during &lt;code&gt;docker:start&lt;/code&gt;, linked together via the &lt;code&gt;volumes&lt;/code&gt; directive. The &lt;strong&gt;&lt;code&gt;&amp;lt;run&amp;gt;&lt;/code&gt;&lt;/strong&gt; configuration section is used to describe the runtime behavior for &lt;code&gt;docker:start&lt;/code&gt; and &lt;code&gt;docker:stop&lt;/code&gt;, and &lt;strong&gt;&lt;code&gt;&amp;lt;build&amp;gt;&lt;/code&gt;&lt;/strong&gt; is for specifying how images are build up during &lt;code&gt;docker:build&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, a &lt;strong&gt;single&lt;/strong&gt; image could be created:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;plugin&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;groupId&amp;gt;org.jolokia&amp;lt;/groupId&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;artifactId&amp;gt;docker-maven-plugin&amp;lt;/artifactId&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;version&amp;gt;0.10.1&amp;lt;/version&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;configuration&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;images&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;image&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;name&amp;gt;jolokia/docker-jolokia-combined-demo&amp;lt;/name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;build&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;baseImage&amp;gt;consol/tomcat-7.0&amp;lt;/baseImage&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;assemblyDescriptor&amp;gt;src/main/assembly.xml&amp;lt;/assemblyDescriptor&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/build&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;run&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;ports&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;port&amp;gt;jolokia.port:8080&amp;lt;/port&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/ports&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;wait&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;url&amp;gt;http://localhost:${jolokia.port}/jolokia&amp;lt;/url&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/wait&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/run&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/image&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/images&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/configuration&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;code&gt;consol/tomcat-7.0&lt;/code&gt; is used as base for the image to build and the data referenced in the assembly descriptor is copied into the image. So there is no need to volume-link them together.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t repeat the old, more confusing syntax for this both use cases here, you find it in the current &lt;a href="http://github.com/rhuss/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;online documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Said all that, and since &lt;code&gt;rhuss/docker-maven-plugin&lt;/code&gt; is still pre-1.0, I take the liberty to change it without much thoughts on backwards compatibility (you can easily update old configurations). The new syntax is available since &lt;code&gt;0.10.1&lt;/code&gt;, the old syntax will still be used in the &lt;code&gt;0.9.x&lt;/code&gt; line. Everybody is encouraged to upgrade to &lt;code&gt;0.10.x&lt;/code&gt;, although the documentation still reflects the old syntax (will be fixed soon). Please refer to the &lt;a href="https://github.com/rhuss/docker-maven-plugin/tree/new-config/samples" target="_blank" rel="noreferrer"&gt;examples&lt;/a&gt; on the &lt;code&gt;new-config&lt;/code&gt; branch for more details. An upgrade path will be available soon, too.&lt;/p&gt;
&lt;p&gt;There will be a &lt;code&gt;1.0.0&lt;/code&gt; release before the end of this year.&lt;/p&gt;
&lt;p&gt;Please let me know your feedback on the new syntax and what features you would like to see. Everything is moving before the 1.0.0 freeze. You can open an &lt;a href="http://github.com/rhuss/docker-maven-plugin/issues" target="_blank" rel="noreferrer"&gt;issue&lt;/a&gt; for any suggestion or feature request.&lt;/p&gt;</description></item><item><title>Spicy Docker Java Images with Jolokia</title><link>https://ro14nd.de/jolokia-docker-image/</link><pubDate>Thu, 09 Oct 2014 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jolokia-docker-image/</guid><description>&lt;p&gt;While on the way of transforming the &lt;a href="http://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt; integration test suite from a tedious, manual, half-a-day procedure to a full automated process I ran into and felt in love with &lt;a href="http://docker.io" target="_blank" rel="noreferrer"&gt;Docker&lt;/a&gt;. As a byproduct a &lt;a href="https://registry.hub.docker.com/u/jolokia/java-jolokia/" target="_blank" rel="noreferrer"&gt;java-jolokia&lt;/a&gt; docker repository emerged, which can be easily used as a Java base image for enabling a Jolokia JVM agent during startup for any Java application.&lt;/p&gt;
&lt;p&gt;These images are variants of the official &lt;a href="https://registry.hub.docker.com/_/java" target="_blank" rel="noreferrer"&gt;java&lt;/a&gt; Java docker image. In order to use the Jolokia agent, a child image should call the script &lt;code&gt;jolokia_opts&lt;/code&gt; (which is in the path). This will echo all relevant startup options that should be included as argument to the Java startup command.&lt;/p&gt;
&lt;p&gt;Here is a simple example for creating a Tomcat 7 images which starts Jolokia along with Tomcat:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FROM jolokia/java-jolokia:7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ENV TOMCAT_VERSION 7.0.55
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ENV TC apache-tomcat-${TOMCAT_VERSION}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXPOSE 8080 8778
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RUN wget http://archive.apache.org/dist/tomcat/tomcat-7/v${TOMCAT_VERSION}/bin/${TC}.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RUN tar xzf ${TC}.tar.gz -C /opt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CMD env CATALINA_OPTS=$(jolokia_opts) /opt/${TC}/bin/catalina.sh run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;(&lt;em&gt;Don&amp;rsquo;t forget to use &lt;code&gt;$(jolokia_opts)&lt;/code&gt; or with backticks, but not &lt;code&gt;${jolokia_opts}&lt;/code&gt;&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;The configuration of the Jolokia agent can be influenced with various environments variables which can be given when starting the container:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JOLOKIA_OFF&lt;/code&gt; : If set disables activation of Jolokia. By default, Jolokia is enabled.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JOLOKIA_CONFIG&lt;/code&gt; : If set uses this file (including path) as Jolokia JVM agent properties (as described in Jolokia&amp;rsquo;s &lt;a href="http://www.jolokia.org/reference/html/agents.html#agents-jvm" target="_blank" rel="noreferrer"&gt;reference manual&lt;/a&gt;. By default this is &lt;code&gt;/opt/jolokia/jolokia.properties&lt;/code&gt;. If this file exists, it will automatically be taken as configuration&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JOLOKIA_HOST&lt;/code&gt; : Host address to bind to (Default: 0.0.0.0)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JOLOKIA_PORT&lt;/code&gt; : Port to use (Default: 8778)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JOLOKIA_USER&lt;/code&gt; : User for authentication. By default authentication is switched off.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JOLOKIA_PASSWORD&lt;/code&gt; : Password for authentication. By default authentication is switched off.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, if you start your tomcat with &lt;code&gt;docker run -e JOLOKIA_OFF&lt;/code&gt; no agent will be started.&lt;/p&gt;
&lt;p&gt;Currently this image is available from &lt;a href="https://registry.hub.docker.com/u/jolokia/java-jolokia/" target="_blank" rel="noreferrer"&gt;Docker Hub&lt;/a&gt; for the latest versions of Java 6,7 and 8, respectively, as they are provided by the official Docker &lt;a href="https://registry.hub.docker.com/_/java/" target="_blank" rel="noreferrer"&gt;java&lt;/a&gt; image.&lt;/p&gt;
&lt;p&gt;Other base images can be easily added by using the configuration and templates from a super simple node based &lt;a href="https://github.com/rhuss/docker-java-jolokia" target="_blank" rel="noreferrer"&gt;build system&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All appserver images from &lt;a href="https://github.com/ConSol/docker-appserver" target="_blank" rel="noreferrer"&gt;ConSol/docker-appserver&lt;/a&gt; (&lt;a href="https://registry.hub.docker.com/repos/consol/" target="_blank" rel="noreferrer"&gt;Docker Hub&lt;/a&gt;) are based now on this image, so Jolokia will always be by your side ;-)&lt;/p&gt;</description></item><item><title>Using NSEnter with Boot2Docker</title><link>https://ro14nd.de/nsenter-with-boot2docker/</link><pubDate>Mon, 01 Sep 2014 00:00:00 +0000</pubDate><guid>https://ro14nd.de/nsenter-with-boot2docker/</guid><description>&lt;p&gt;&lt;a href="https://github.com/jpetazzo/nsenter" target="_blank" rel="noreferrer"&gt;NSEnter&lt;/a&gt; is a nice way to connect to a running Docker container. This post presents a script to simplify the usage of &lt;code&gt;nsenter&lt;/code&gt; together with &lt;a href="https://github.com/boot2docker/boot2docker" target="_blank" rel="noreferrer"&gt;Boot2Docker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is still quite some dust around Docker and after gaining more and more experience, new patterns and anti-patterns are emerging.&lt;/p&gt;
&lt;p&gt;One of those anti-patterns is the usage of an SSH daemon inside an image for debugging, backup and troubleshooting purposes. Jérôme Petazzoni&amp;rsquo;s &lt;a href="https://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker/" target="_blank" rel="noreferrer"&gt;Blog Post&lt;/a&gt; explains this nicely. In addition it provides proper solutions for common use cases for which SSH is currently used.&lt;/p&gt;
&lt;p&gt;Nevertheless I still have this irresistible urge to login into a container. And if it is only for looking around and checking out the environment (call me old-fashioned, that&amp;rsquo;s ok ;-)&lt;/p&gt;
&lt;p&gt;Luckily Jérôme provides a perfect solution to satisfy this thirst: &lt;a href="https://github.com/jpetazzo/nsenter" target="_blank" rel="noreferrer"&gt;nsenter&lt;/a&gt;. This allows you to &lt;strong&gt;enter&lt;/strong&gt; into container &lt;strong&gt;n&lt;/strong&gt;ame&lt;strong&gt;s&lt;/strong&gt;paces. On the GitHub page you find the corresponding recipe for installing and using &lt;code&gt;nsenter&lt;/code&gt; on a Linux host.&lt;/p&gt;
&lt;p&gt;If you want to use it from OS X with e.g. &lt;a href="https://github.com/boot2docker/boot2docker" target="_blank" rel="noreferrer"&gt;Boot2Docker&lt;/a&gt; you need to login into the VM hosting the Docker daemon and then connect to a running container.&lt;/p&gt;
&lt;p&gt;As described in the &lt;a href="https://github.com/jpetazzo/nsenter#docker-enter-with-boot2docker" target="_blank" rel="noreferrer"&gt;NSenter README&lt;/a&gt; you can use a simple alias for doing this transparently&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	docker-enter&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 boot2docker ssh &lt;span style="color:#e6db74"&gt;&amp;#39;[ -f /var/lib/boot2docker/nsenter ] || docker run --rm -v /var/lib/boot2docker/:/target jpetazzo/nsenter&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 boot2docker ssh -t sudo /var/lib/boot2docker/docker-enter &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For a bit more comfort with usage information and error checking you can convert this to a small shell script like &lt;a href="https://gist.github.com/rhuss/a8a40bd143001fd5c83c#file-docker-enter" target="_blank" rel="noreferrer"&gt;docker-enter&lt;/a&gt; which needs to be installed within the path (on OS X). As arguments it expects a container id or name and optionally a command (with args) to execute in the container. This script also will automatically install &lt;code&gt;nsenter&lt;/code&gt; on the boot2docker VM if not already present (like the shell function above does this as well):&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	10:20 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;~&lt;span style="color:#f92672"&gt;]&lt;/span&gt; $ docker ps -q
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	5bf8a161cceb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	10:20 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;~&lt;span style="color:#f92672"&gt;]&lt;/span&gt; $ docker-enter 5bf8a161cceb bash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Unable to find image &lt;span style="color:#e6db74"&gt;&amp;#39;jpetazzo/nsenter&amp;#39;&lt;/span&gt; locally
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Pulling repository jpetazzo/nsenter
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Installing nsenter to /target
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Installing docker-enter to /target
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	root@5bf8a161cceb:/#&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you want even more comfort with bash completion you can add the small Bash completion script &lt;a href="https://gist.github.com/rhuss/a8a40bd143001fd5c83c#file-docker-enter_commands" target="_blank" rel="noreferrer"&gt;docker-enter_commands&lt;/a&gt; (inspired by and copied from &lt;a href="https://github.com/docker/docker/blob/master/contrib/completion/bash/docker" target="_blank" rel="noreferrer"&gt;Docker&amp;rsquo;s bash completion&lt;/a&gt;) to your &lt;code&gt;~/.bash_completion_scripts/&lt;/code&gt; directory (or wherever your completion scripts are located, e.g. &lt;code&gt;/usr/local/etc/bash_completion.d&lt;/code&gt; if you installed &lt;code&gt;bash-completion&lt;/code&gt; via brew). This setup completes on container names and ids on the arguments for &lt;code&gt;docker-enter&lt;/code&gt;. Alternatively you can put the commands together with the shell function code above directly into your &lt;code&gt;~/.bashrc&lt;/code&gt;, too.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;P.S. After writing this post, I&amp;rsquo;ve found out, that this topic has been already covered in another &lt;a href="http://blog.sequenceiq.com/blog/2014/07/05/docker-debug-with-nsenter-on-boot2docker/" target="_blank" rel="noreferrer"&gt;blog post&lt;/a&gt; previously by Lajos Papp. That&amp;rsquo;s also where the shell function definition in the &lt;code&gt;nsenter&lt;/code&gt; README originates from. Give credit to whom it’s due.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Docker for (Java) Developers</title><link>https://ro14nd.de/docker-for-developers/</link><pubDate>Mon, 25 Aug 2014 00:00:00 +0000</pubDate><guid>https://ro14nd.de/docker-for-developers/</guid><description>&lt;p&gt;Recently I gave a Meetup talk for the &lt;a href="http://www.meetup.com/Docker-Munich/" target="_blank" rel="noreferrer"&gt;Docker Munich&lt;/a&gt; Meetup Group which explained how Docker can help developers to improve integration tests and to ship applications.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://ro14nd.de/meetup-docker-developer-slides" target="_blank" rel="noreferrer"&gt;slides&lt;/a&gt; are online as well as the &lt;a href="https://github.com/rhuss/meetup-docker-demo" target="_blank" rel="noreferrer"&gt;demo project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During the demo I used &lt;a href="https://github.com/paradoxxxzero/butterfly" target="_blank" rel="noreferrer"&gt;Butterfly&lt;/a&gt; for an in-browser shell, which was quite cool, I guess ;-) (This is obviously not enabled in the online slides).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to continue to celebrate my Docker-♡ with another two talks in autumn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://onedaytalk.org/index.php/program?id=194" target="_blank" rel="noreferrer"&gt;Boosting your developer toolbox with Docker&lt;/a&gt; at JBoss One Day Talk, September, 29. in Germering (Munich, Germany)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jax.de/wjax2014/sessions/docker-fuer-java-entwickler" target="_blank" rel="noreferrer"&gt;Docker für Java Entwickler&lt;/a&gt; (in german) at W-JAX 14, November, 3. - 7. in Munich&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And there is a slight chance (since the CFP has not yet been declined ;-) to talk at &lt;a href="http://www.devoxx.be/" target="_blank" rel="noreferrer"&gt;Devoxx&lt;/a&gt; about Docker. &lt;a href="http://2014.javazone.no/" target="_blank" rel="noreferrer"&gt;JavaZone&lt;/a&gt; unfortunately declined my CFP, I guess there are already too many riding the docker horse (which is a good thing).&lt;/p&gt;
&lt;p&gt;Nevertheless I will attend both conferences with talks about &lt;a href="http://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt;, and I&amp;rsquo;m really looking forward to it.&lt;/p&gt;
&lt;p&gt;&amp;lsquo;guess it will become a hot autumn (hotter than this german 2014 summer for sure) &amp;hellip;.&lt;/p&gt;</description></item><item><title>Jolokia and CORS</title><link>https://ro14nd.de/jolokia-cors/</link><pubDate>Mon, 18 Aug 2014 00:00:00 +0000</pubDate><guid>https://ro14nd.de/jolokia-cors/</guid><description>&lt;p&gt;&lt;a href="http://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt; has configurable &lt;a href="http://www.w3.org/TR/cors/" target="_blank" rel="noreferrer"&gt;CORS&lt;/a&gt; support so that it plays nicely together with the Browser world when it comes to cross origin requests. However, Jolokia’s CORS support is not without gotchas. This post explains how Jolokias CORS supports works, what are the issues and how I plan to solve them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tldr;&lt;/strong&gt; &lt;em&gt;Jolokia CORS support is configured via &lt;code&gt;jolokia-access.xml&lt;/code&gt; but has issues with authenticated requests which are tackled for the next release 1.3.0&lt;/em&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;CORS Primer
 &lt;div id="cors-primer" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cors-primer" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.w3.org/TR/cors/" target="_blank" rel="noreferrer"&gt;CORS&lt;/a&gt; (Cross Origin Resource Sharing) is a specification for browsers to allow controlled access for JavaScript code to locations which are different than the origin of the JavaScript code itself.&lt;/p&gt;
&lt;p&gt;In simple cases, it works more or less like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A JavaScript code (coming from the original location &lt;em&gt;&lt;a href="http://a.com" target="_blank" rel="noreferrer"&gt;http://a.com&lt;/a&gt;&lt;/em&gt;) requests HTTP access via &lt;code&gt;XMLHttpRequest&lt;/code&gt; to &lt;em&gt;&lt;a href="http://b.com" target="_blank" rel="noreferrer"&gt;http://b.com&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Since the the origin of the script and target URL of the request differs, the browser adds some extract checking on the response of this request.&lt;/li&gt;
&lt;li&gt;The request to &lt;em&gt;b.com&lt;/em&gt; contains a header &lt;code&gt;Origin: http://a.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The server at &lt;em&gt;b.com&lt;/em&gt; answering the request has to decided upon this header whether it wants allow this request. The server decision is contained in the response header &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The value of this header can be either a literal URL (e.g. &lt;em&gt;&lt;a href="http://a.com" target="_blank" rel="noreferrer"&gt;http://a.com&lt;/a&gt;&lt;/em&gt;) or a wildcard like in &lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt; which allows access from any original location.&lt;/li&gt;
&lt;li&gt;The browser finally decides whether it returns the response to the JavaScript based on the returned access control header. If not, is throws an exception before handing out the response data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is it for &lt;em&gt;simple requests&lt;/em&gt;. A simple request has the following characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP method is either &lt;code&gt;GET&lt;/code&gt;,&lt;code&gt;HEAD&lt;/code&gt; or &lt;code&gt;POST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The request contains only the following headers
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Accept&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Accept-Language&lt;/code&gt; or &lt;code&gt;Content-Language&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Content-Type&lt;/code&gt; with the value &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;, &lt;code&gt;multipart/form-data&lt;/code&gt; or &lt;code&gt;text/plain&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If this criteria are not match for a request (e.g. because it uses a different method or additional headers), a so called &lt;a href="http://www.w3.org/TR/cors/#resource-preflight-requests" target="_blank" rel="noreferrer"&gt;preflight request&lt;/a&gt; is sent to the server before the actual request is performed. The preflight is an HTTP request with method &lt;code&gt;OPTIONS&lt;/code&gt; and contains the headers &lt;code&gt;Origin&lt;/code&gt; (&lt;em&gt;&lt;a href="http://a.com" target="_blank" rel="noreferrer"&gt;http://a.com&lt;/a&gt;&lt;/em&gt; in our case), &lt;code&gt;Access-Control-Request-Method&lt;/code&gt; for the HTTP method requested and &lt;code&gt;Access-Control-Request-Headers&lt;/code&gt; with a comma separated list of additional header names. The server in turn answers with the allowed request methods and headers, whether an authenticated request is allowed and how long the client might cache this answer. An important point is, that a preflight request &lt;a href="http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0" target="_blank" rel="noreferrer"&gt;must not be authenticated&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And in fact, browsers never sent an authentication header with the preflight request even when already authenticated against the target server. More on this later.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Jolokia CORS Support
 &lt;div id="jolokia-cors-support" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#jolokia-cors-support" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;By default, Jolokia allows any CORS request. For the preflight the agent answers with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Access-Control-Allow-Origin: http://a.com
Access-Control-Allow-Headers: accept, authorization, content-type
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The allowed headers returned are exactly the same headers as requested. For the real request with an origin header &lt;code&gt;Origin: http://a.com&lt;/code&gt; the answer is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Access-Control-Allow-Origin: http://a.com
Access-Control-Allow-Credentials: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For best computability Jolokia always answers with the provided &lt;code&gt;Origin:&lt;/code&gt; which is extracted from the request (except when the origin is &lt;code&gt;null&lt;/code&gt; in which case the wildcard &lt;code&gt;*&lt;/code&gt; is returned.&lt;/p&gt;
&lt;p&gt;This behavior can be tuned by adapting the &lt;code&gt;jolokia-access.xml&lt;/code&gt; policy as described in the &lt;a href="http://www.jolokia.org/reference/html/security.html#security-policy" target="_blank" rel="noreferrer"&gt;reference manual&lt;/a&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;cors&amp;gt;
 &amp;lt;allow-origin&amp;gt;http://www.jolokia.org&amp;lt;/allow-origin&amp;gt;
 &amp;lt;allow-origin&amp;gt;*://*.jmx4perl.org&amp;lt;/allow-origin&amp;gt;

 &amp;lt;strict-checking/&amp;gt;
&amp;lt;/cors&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a &lt;code&gt;&amp;lt;cors&amp;gt;&lt;/code&gt; section is present in &lt;code&gt;jolokia-access.xml&lt;/code&gt; then only those hosts declared in this sections are allowed. The Origin URLs to match against can be specified either literally or as pattern containing the wildcard &lt;code&gt;*&lt;/code&gt;. The optional declaration &lt;code&gt;&amp;lt;strict-checking/&amp;gt;&lt;/code&gt; is not really connected to CORS but helps in defending against &lt;a href="http://de.wikipedia.org/wiki/Cross-Site-Request-Forgery" target="_blank" rel="noreferrer"&gt;Cross-Site-Request-Forgery&lt;/a&gt; (CSRF). If this option is given, then the given patterns are used for &lt;strong&gt;every&lt;/strong&gt; request to compare it against the &lt;code&gt;Origin:&lt;/code&gt; or &lt;code&gt;Referer:&lt;/code&gt; header (not only for CORS requests).&lt;/p&gt;

&lt;h2 class="relative group"&gt;CORS and Authentication
 &lt;div id="cors-and-authentication" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cors-and-authentication" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Since &lt;code&gt;Authorization:&lt;/code&gt; is for CORS not a &lt;em&gt;simple&lt;/em&gt; header, when authentication is used, preflight checking is always applied. However, there is often a &lt;a href="https://code.google.com/p/twitter-api/issues/detail?id=2273" target="_blank" rel="noreferrer"&gt;catch 22&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The preflight check using the &lt;code&gt;OPTIONS&lt;/code&gt; HTTP Method &lt;strong&gt;must not be authenticated&lt;/strong&gt; as explained above, so browser doesn’t send the appropriate authentication headers when doing the preflight.&lt;/li&gt;
&lt;li&gt;The Jolokia agent is typically secured completely no matter which HTTP method is used.&lt;/li&gt;
&lt;li&gt;The preflight check fails, the request fails.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only clean solution is to setup Jolokia Authentication that way that &lt;code&gt;OPTIONS&lt;/code&gt; request are not secured.&lt;/p&gt;
&lt;p&gt;Let’s have a look at the individual Agents:&lt;/p&gt;

&lt;h3 class="relative group"&gt;JVM Agent
 &lt;div id="jvm-agent" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#jvm-agent" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Since the JVM agent does all the security stuff on its own, it is not a big deal to introduce this specific behavior. Next one.&lt;/p&gt;

&lt;h3 class="relative group"&gt;WAR Agent
 &lt;div id="war-agent" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#war-agent" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;The WAR agent use authentication and authorization as defined in the &lt;a href="https://jcp.org/aboutJava/communityprocess/final/jsr315/" target="_blank" rel="noreferrer"&gt;Servlet Specification&lt;/a&gt;, i.e. the appropriate &lt;code&gt;&amp;lt;security-constraint&amp;gt;&lt;/code&gt; must be added manually to the web.xml (&lt;a href="http://search.cpan.org/~roland/jmx4perl/scripts/jolokia" target="_blank" rel="noreferrer"&gt;jolokia&lt;/a&gt; is a CLI tool which helps in this repackaging). Unfortunately there is no way to secure the same &lt;code&gt;&amp;lt;url-pattern&amp;gt;&lt;/code&gt; differently for different HTTP Methods (i.e. secured with an &lt;code&gt;&amp;lt;auth-constraint&amp;gt;&lt;/code&gt; for &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;, but accessible for everybody for &lt;code&gt;OPTIONS&lt;/code&gt;). I tried hard by providing multiple &lt;code&gt;&amp;lt;security-constraint&amp;gt;&lt;/code&gt; but failed miserably (if you know how to this, please let me know).&lt;/p&gt;
&lt;p&gt;The only solution is to switch over to checking a given role on our own without relying on the declarative JEE security mechanism. Since we can check the role programmatically (&lt;code&gt;HttpServletRequest.isUserInRole()&lt;/code&gt;) this should not be that big deal. But it’s still some work ….&lt;/p&gt;

&lt;h3 class="relative group"&gt;OSGi Agent
 &lt;div id="osgi-agent" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#osgi-agent" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;When using an &lt;a href="http://www.osgi.org/javadoc/r4v42/org/osgi/service/http/HttpService.html" target="_blank" rel="noreferrer"&gt;OSGI HttpService&lt;/a&gt; adding this behavior should not be difficult since security is handled programmatically here as well (&lt;code&gt;HttpContext.handleSecurity()&lt;/code&gt;)&lt;/p&gt;

&lt;h3 class="relative group"&gt;Other Agent variants
 &lt;div id="other-agent-variants" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#other-agent-variants" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;This is the dark matter, because I don’t know where and how Jolokia is integrated directly into a bigger context. I know that &lt;a href="http://activemq.apache.org/rest.html" target="_blank" rel="noreferrer"&gt;ActiveMQ&lt;/a&gt;, &lt;a href="http://karaf.apache.org/manual/latest/users-guide/monitoring.html" target="_blank" rel="noreferrer"&gt;Karaf&lt;/a&gt; and &lt;a href="https://github.com/spring-projects/spring-boot/blob/master/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc" target="_blank" rel="noreferrer"&gt;Spring Boot&lt;/a&gt; uses Jolokia internally. In order to support authenticated CORS access they probably needs to be changed to allow unauthorized &lt;code&gt;OPTIONS&lt;/code&gt; access for everybody. Since this is not under my control I have no idea when and even whether it ever will happen. Generic purpose console like &lt;a href="http://hawt.io" target="_blank" rel="noreferrer"&gt;hawt.io&lt;/a&gt; rely in some setups on CORS access so it would be real cool if we can get it out there. Help with this is highly appreciated ;-)&lt;/p&gt;

&lt;h2 class="relative group"&gt;Roadmap
 &lt;div id="roadmap" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#roadmap" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Since 1.2.2 is already finished and about to be published today, the stuff I can do as described above will go into a 1.3.0. Looking back at my release history this will probably be ready approx. end of august.&lt;/p&gt;</description></item><item><title>Removing attachments with JavaMail</title><link>https://ro14nd.de/removing-attachments-with-javamail/</link><pubDate>Mon, 29 Mar 2010 00:00:00 +0000</pubDate><guid>https://ro14nd.de/removing-attachments-with-javamail/</guid><description>&lt;p&gt;If you have ever sent or received mail messages via Java, chances are high that you have used JavaMail for this task.
Most of the time JavaMail does an excellent job and a lot of use cases are described in the JavaMail FAQ.
But there are still some additional quirks you should be aware of when doing advanced mail operations like adding or removing attachments (or “Parts”) from existing mails retreived from some IMAP or POP3 store.
This post gives a showcase for how to remove an attachment from a mail at an arbitrary level which has been obtained from an IMAP store.&lt;/p&gt;
&lt;p&gt;It points to the pitfalls which are waiting and shows some possible solutions.
The principles laid out here are important for adding new attachments to a mail as well, but that’s yet another story.&lt;/p&gt;

&lt;h3 class="relative group"&gt;JavaMail objects
 &lt;div id="javamail-objects" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#javamail-objects" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Before we start manipulating mail messages it is important to understand how these are represented in the JavaMail world.&lt;/p&gt;
&lt;p&gt;The starting point is the &lt;code&gt;Message&lt;/code&gt;. It has a content and a content type. The content can be any Java object representing the mail content, like a plain text (&lt;code&gt;String&lt;/code&gt;) or raw image data. But it can also be a &lt;code&gt;Multipart&lt;/code&gt; object: this is the case when a message’s content consists of more than a single item. A &lt;code&gt;Multipart&lt;/code&gt; object is a container which holds one ore more &lt;code&gt;BodyPart&lt;/code&gt; objects. These &lt;code&gt;BodyParts&lt;/code&gt;, like a &lt;code&gt;Message&lt;/code&gt;, have a content and a content type (in fact, both &lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;BodyPart&lt;/code&gt; implement the same interface &lt;code&gt;Part&lt;/code&gt; which carries these properties).&lt;/p&gt;
&lt;p&gt;Beside plain content, A &lt;code&gt;BodyPart&lt;/code&gt; can contain another &lt;code&gt;Multipart&lt;/code&gt; or even another &lt;code&gt;Message&lt;/code&gt;, a so called &lt;em&gt;nested message&lt;/em&gt; (e.g. a message forwarded as attachment) with content type &lt;code&gt;message/rfc822&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you can see, the structure of a &lt;code&gt;Message&lt;/code&gt; can be rather heterogenous, a tree with nodes of different types. The following picture illustrates the tree structure for a sample message.&lt;/p&gt;
&lt;img src="https://ro14nd.de/images/removing-attachments-with-javamail/javamail-message.png" style="margin: auto;"/&gt;
&lt;p&gt;This object tree can be navigated in both directions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;getContent()&lt;/em&gt; on &lt;code&gt;Part&lt;/code&gt;s like &lt;code&gt;Message&lt;/code&gt; or &lt;code&gt;BodyPart&lt;/code&gt; to get to the child of this node. The return type is a &lt;code&gt;java.lang.Object&lt;/code&gt; and in case of a plain &lt;code&gt;BodyPart&lt;/code&gt; can be quite huge. Before calling &lt;code&gt;Part.getContent()&lt;/code&gt; be sure to check whether it contains a container by checking for its content type via &lt;code&gt;Part.isMimeType(&amp;quot;multipart/*&amp;quot;)&lt;/code&gt; or &lt;code&gt;Part.isMimeType(&amp;quot;message/rfc822&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;getParent()&lt;/em&gt; on &lt;code&gt;Multipart&lt;/code&gt; or &lt;code&gt;BodyPart&lt;/code&gt; returns the parent node, which is of type &lt;code&gt;BodyPart&lt;/code&gt;. Note that there is no way to get from a nested &lt;code&gt;Message&lt;/code&gt; to its parent &lt;code&gt;BodyPart&lt;/code&gt;. If you need to traverse the tree upwards with nested messages on the way, you first have to extract the path to this node from the top down. E.g. while identifying the part to remove you could store the parent &lt;code&gt;BodyPart&lt;/code&gt;s on a stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;First approach
 &lt;div id="first-approach" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#first-approach" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Back to our use case of removing an attachment at an arbitrary level within a mail. First, a &lt;code&gt;Message&lt;/code&gt; from the IMAP Store needs to be obtained, e.g. by looking it up in an &lt;code&gt;IMAPFolder&lt;/code&gt; via its UID:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Session session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Session.&lt;span style="color:#a6e22e"&gt;getDefaultInstance&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Properties());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Store store &lt;span style="color:#f92672"&gt;=&lt;/span&gt; session.&lt;span style="color:#a6e22e"&gt;getStore&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;imap&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;store.&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;imap.example.com&amp;#34;&lt;/span&gt;,&lt;span style="color:#f92672"&gt;-&lt;/span&gt;1,&lt;span style="color:#e6db74"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IMAPFolder folder &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (IMAPFolder) store.&lt;span style="color:#a6e22e"&gt;getFolder&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;INBOX&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IMAPMessage originalMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (IMAPMessage) folder.&lt;span style="color:#a6e22e"&gt;getMessageByUID&lt;/span&gt;(42L);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, the fetched message is copied over to a fresh &lt;code&gt;MimeMessage&lt;/code&gt; since the &lt;code&gt;IMAPMimeMessage&lt;/code&gt; obtained from the store is marked as read-only and can&amp;rsquo;t be modified:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Message message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; MimeMessage(originalMessage);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Mark original message for a later expunge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;originalMessage.&lt;span style="color:#a6e22e"&gt;setFlag&lt;/span&gt;(Flags.&lt;span style="color:#a6e22e"&gt;Flag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;DELETED&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now the part to be removed needs to be identified. The detailed code is not shown here, but it is straight forward: You need to traverse the cloned &lt;code&gt;Message&lt;/code&gt; top down to identify the &lt;code&gt;Part&lt;/code&gt;, e.g. by its part number (a positional index) or by its content id. Be careful, though, not to call &lt;code&gt;getContent()&lt;/code&gt; except for &lt;code&gt;BodyPart&lt;/code&gt;s of type &lt;code&gt;multipart/*&lt;/code&gt; or &lt;code&gt;message/rfc822&lt;/code&gt;, since this would trigger a lazy fetch of the part&amp;rsquo;s content into memory. Probably not something you want to do while looking up a part. I think, I already said this. ;-)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MimePart partToRemove &lt;span style="color:#f92672"&gt;=&lt;/span&gt; partExtractor.&lt;span style="color:#a6e22e"&gt;getPartByPartNr&lt;/span&gt;(message,&lt;span style="color:#e6db74"&gt;&amp;#34;2.1&amp;#34;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;rsquo;s time to remove the body part from its parent in the hierarchy and store the changed message back into the store. You can mark the original message as &lt;code&gt;DELETED&lt;/code&gt; and expunge it on the folder. If you have the &lt;em&gt;UIDEXTENSION&lt;/em&gt; available on your IMAP store, you can selectively delete this single message, otherwise your only choice is to remove all messages marked as deleted at once (&amp;ldquo;Empty Trash&amp;rdquo;).&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Multipart parent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; partToRemove.&lt;span style="color:#a6e22e"&gt;getParent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parent.&lt;span style="color:#a6e22e"&gt;removeBodyPart&lt;/span&gt;(partToRemove);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Update headers and append new message to folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;message.&lt;span style="color:#a6e22e"&gt;saveChanges&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;folder.&lt;span style="color:#a6e22e"&gt;appendMessages&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Message&lt;span style="color:#f92672"&gt;[]&lt;/span&gt; { message });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Mark as deleted and expunge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;originalMessage.&lt;span style="color:#a6e22e"&gt;setFlag&lt;/span&gt;(Flags.&lt;span style="color:#a6e22e"&gt;Flag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;DELETED&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;folder.&lt;span style="color:#a6e22e"&gt;expunge&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Message&lt;span style="color:#f92672"&gt;[]&lt;/span&gt;{ originalMessage });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We are done now.&lt;/p&gt;

&lt;h3 class="relative group"&gt;But wait, that&amp;rsquo;s not good enough &amp;hellip;
 &lt;div id="but-wait-thats-not-good-enough-" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#but-wait-thats-not-good-enough-" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;If you try the code above, you will probably be a bit surprised. If you fetch back the newly saved message from the folder, you will find that the attachment has &lt;strong&gt;not&lt;/strong&gt; been removed at all.&lt;/p&gt;
&lt;p&gt;Dragons are waiting here.&lt;/p&gt;
&lt;p&gt;The problem is that a JavaMail Part does heavy internal caching: it keeps a so called &lt;em&gt;content stream&lt;/em&gt; until a new &lt;em&gt;content&lt;/em&gt; is set for it.
So even if you modify the hierarchy of objects as described above, the original content is kept until you update the content of the parents yourself and the cache is thrown away.
Our part has not been removed because the cached content stream has not yet been invalidated. The solution is to get rid of the cached content stream (aka &amp;lsquo;refresh the message&amp;rsquo;).
You could set the content directly via &lt;code&gt;Part.setContent(oldPart.getContent(),oldPart.getContentType())&lt;/code&gt;, but this is dangerous in so far as it will load the part content into memory. (Did I already mention this?)
That&amp;rsquo;s really not something you are keen on if you want to remove this Britney Spears Video to save some IMAP space.
The alternative is to work on the wrapped &lt;code&gt;DataHandler&lt;/code&gt; only. A &lt;code&gt;DataHandler&lt;/code&gt; (defined in &lt;a href="http://java.sun.com/javase/technologies/desktop/javabeans/glasgow/javadocs/javax/activation/package-summary.html" target="_blank" rel="noreferrer"&gt;Java Activation&lt;/a&gt;) is not much more than a &lt;em&gt;reference&lt;/em&gt; to the content stream. Setting the &lt;code&gt;DataHandler&lt;/code&gt; on a &lt;code&gt;Part&lt;/code&gt; via &lt;code&gt;Part.setDataHandler()&lt;/code&gt; also causes it to invalidate its cached content, so a later &lt;code&gt;Part.writeTo()&lt;/code&gt; will stream out the new content.
Unfortunately, this has to be done on every parent up to the root. A brute force solution is to start from the top and refresh every content with&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Recursively go through and save all changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (message.&lt;span style="color:#a6e22e"&gt;isMimeType&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;multipart/*&amp;#34;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; refreshRecursively((Multipart) message.&lt;span style="color:#a6e22e"&gt;getContent&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Multipart part &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (Multipart) message.&lt;span style="color:#a6e22e"&gt;getContent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;message.&lt;span style="color:#a6e22e"&gt;setContent&lt;/span&gt;(part);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;message.&lt;span style="color:#a6e22e"&gt;saveChanges&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;refreshRecursively&lt;/span&gt;(Multipart pPart)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; MessagingException, IOException {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0;i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;pPart.&lt;span style="color:#a6e22e"&gt;getCount&lt;/span&gt;();i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MimeBodyPart body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (MimeBodyPart) pPart.&lt;span style="color:#a6e22e"&gt;getBodyPart&lt;/span&gt;(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (body.&lt;span style="color:#a6e22e"&gt;isMimeType&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;message/rfc822&amp;#34;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Refresh a nested message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Message nestedMsg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (Message) body.&lt;span style="color:#a6e22e"&gt;getContent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (nestedMsg.&lt;span style="color:#a6e22e"&gt;isMimeType&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;multipart/*&amp;#34;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Multipart mPart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (Multipart) body.&lt;span style="color:#a6e22e"&gt;getContent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; refreshRecursively(mPart);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nestedMsg.&lt;span style="color:#a6e22e"&gt;setContent&lt;/span&gt;(mPart);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nestedMsg.&lt;span style="color:#a6e22e"&gt;saveChanges&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (body.&lt;span style="color:#a6e22e"&gt;isMimeType&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;multipart/*&amp;#34;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Multipart mPart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (Multipart) body.&lt;span style="color:#a6e22e"&gt;getContent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; refreshRecursively(mPart);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; body.&lt;span style="color:#a6e22e"&gt;setDataHandler&lt;/span&gt;(body.&lt;span style="color:#a6e22e"&gt;getDataHandler&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;However, we can be smarter here: Since we already identified the part to remove, we can make our way upwards to the root message via the &lt;code&gt;getParent()&lt;/code&gt; method on &lt;code&gt;Multipart&lt;/code&gt; and &lt;code&gt;BodyPart&lt;/code&gt; (which, by the way are not connected via any interface or inheritance relationship).&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BodyPart bodyParent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Multipart multipart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; parent;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (multipart.&lt;span style="color:#a6e22e"&gt;getParent&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; BodyPart) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bodyParent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (BodyPart) multipart.&lt;span style="color:#a6e22e"&gt;getParent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bodyParent.&lt;span style="color:#a6e22e"&gt;setDataHandler&lt;/span&gt;(bodyParent.&lt;span style="color:#a6e22e"&gt;getDataHandler&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; multipart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bodyParent.&lt;span style="color:#a6e22e"&gt;getParent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// It&amp;#39;s a Message, probably the toplevel message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// but could be a nested message, too (in which&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// case we have to stop here, too)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bodyParent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (bodyParent &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally you need to update the uppermost message headers, too with a&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MimeMessage.&lt;span style="color:#a6e22e"&gt;saveChanges&lt;/span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As you might have noticed, this works as long as there is no nested message in the chain of &lt;code&gt;BodyPart&lt;/code&gt;s up to the root.
Since a &lt;code&gt;Message&lt;/code&gt; doesn&amp;rsquo;t have any parent, we need some other means to get the &lt;code&gt;BodyPart&lt;/code&gt; which is the parent of an enclosed &lt;code&gt;Message&lt;/code&gt;. One way is to keep track of the chain of parent &lt;code&gt;BodyPart&lt;/code&gt;s when identifying the part to remove e.g. by extending the part extractor to support a stack of parent &lt;code&gt;BodyParts&lt;/code&gt; which will be in:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Stack&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MimeBodyPart&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; parentBodys &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Stack&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MimeBodyPart&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MimePart partToRemove &lt;span style="color:#f92672"&gt;=&lt;/span&gt; partExtractor.&lt;span style="color:#a6e22e"&gt;getPartByPartNr&lt;/span&gt;(message,&lt;span style="color:#e6db74"&gt;&amp;#34;2.1&amp;#34;&lt;/span&gt;,parentBodys);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ....&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This example could be extended to remove multipart containers on the fly, if only one part is left after removal and replace the multipart with its then last child or remove an empty multipart altogether when its last child has been removed.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Summary
 &lt;div id="summary" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#summary" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Hopefully, I could sketch out that there are several points to take care of when manipulating existing JavaMail &lt;code&gt;Messages&lt;/code&gt; (it&amp;rsquo;s not that difficult if you build up one from scratch). The code shown above is only a starting point, but it hopefully saves you some time when you start wondering why on earth your nicely trimmed message isn&amp;rsquo;t stored correctly on the IMAP store.&lt;/p&gt;</description></item><item><title>About</title><link>https://ro14nd.de/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://ro14nd.de/about/</guid><description>&lt;p&gt;This site contains my thoughts and articles on computer related stuff. The content is probably a bit Kubernetes, cloud-native, and developer tooling biased, but this is shifting towards AI-first engineering and agentic coding.&lt;/p&gt;

&lt;h3 class="relative group"&gt;About me
 &lt;div id="about-me" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#about-me" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;I am Roland Huß, a developer and engineer, coding for over two decades (mostly in Java and Go), living and working in Franconia, loving chilis.&lt;/p&gt;
&lt;p&gt;I do Open Source. Among my projects are &lt;a href="https://www.jolokia.org" target="_blank" rel="noreferrer"&gt;Jolokia&lt;/a&gt;, the JSON/HTTP bridge to JMX, and a &lt;a href="https://github.com/fabric8io/docker-maven-plugin" target="_blank" rel="noreferrer"&gt;docker-maven-plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For information about my professional career, find me on &lt;a href="https://linkedin.com/in/ro14nd" target="_blank" rel="noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Contact
 &lt;div id="contact" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#contact" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Roland Huß, &lt;a href="mailto:blog@ro14nd.de" &gt;blog@ro14nd.de&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;Legal
 &lt;div id="legal" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#legal" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ro14nd.de/datenschutz/" &gt;Privacy Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ro14nd.de/license/" &gt;License&lt;/a&gt; (CC BY 4.0)&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>License</title><link>https://ro14nd.de/license/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://ro14nd.de/license/</guid><description>
&lt;h2 class="relative group"&gt;Content License
 &lt;div id="content-license" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#content-license" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Unless otherwise noted, the content on this blog is licensed under the &lt;a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer"&gt;Creative Commons Attribution 4.0 International License&lt;/a&gt; (CC BY 4.0).&lt;/p&gt;

&lt;h3 class="relative group"&gt;You are free to
 &lt;div id="you-are-free-to" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#you-are-free-to" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Share&lt;/strong&gt; — copy and redistribute the material in any medium or format&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapt&lt;/strong&gt; — remix, transform, and build upon the material for any purpose, even commercially&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;Under the following terms
 &lt;div id="under-the-following-terms" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#under-the-following-terms" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Attribution&lt;/strong&gt; — You must give appropriate credit, provide a link to the license, and indicate if changes were made.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;Code Examples
 &lt;div id="code-examples" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#code-examples" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Code snippets and examples in blog posts are provided under the &lt;a href="https://www.apache.org/licenses/LICENSE-2.0" target="_blank" rel="noreferrer"&gt;Apache License 2.0&lt;/a&gt; unless otherwise stated.&lt;/p&gt;</description></item><item><title>Privacy Policy</title><link>https://ro14nd.de/datenschutz/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://ro14nd.de/datenschutz/</guid><description>
&lt;h2 class="relative group"&gt;1. Data controller
 &lt;div id="1-data-controller" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1-data-controller" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Roland Huß, &lt;a href="mailto:blog@ro14nd.de" &gt;blog@ro14nd.de&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;2. Hosting
 &lt;div id="2-hosting" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2-hosting" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This website is hosted on GitHub Pages (GitHub Inc., USA). GitHub may process technical data such as IP addresses. For more information, see the &lt;a href="https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement" target="_blank" rel="noreferrer"&gt;GitHub Privacy Statement&lt;/a&gt;.&lt;/p&gt;

&lt;h2 class="relative group"&gt;3. Comments
 &lt;div id="3-comments" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3-comments" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Comments are powered by Giscus, which is based on GitHub Discussions. A GitHub account is required to participate. The &lt;a href="https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement" target="_blank" rel="noreferrer"&gt;GitHub Privacy Statement&lt;/a&gt; applies.&lt;/p&gt;

&lt;h2 class="relative group"&gt;4. Analytics
 &lt;div id="4-analytics" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#4-analytics" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This website does not use cookies or tracking. No personal data is collected for analytics purposes.&lt;/p&gt;

&lt;h2 class="relative group"&gt;5. Your rights
 &lt;div id="5-your-rights" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#5-your-rights" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;You have the right to access, rectification, erasure, restriction of processing, data portability, and objection. Contact me at the email address above.&lt;/p&gt;

&lt;h2 class="relative group"&gt;6. Social media links
 &lt;div id="6-social-media-links" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#6-social-media-links" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This website contains links to LinkedIn, Mastodon, and Bluesky. These are simple hyperlinks with no tracking or data transfer to these services when visiting this website.&lt;/p&gt;</description></item></channel></rss>