Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alpine-consul-openjdk image #77

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions alpine-consul-openjdk/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM smebberson/alpine-consul-base:4.1.0
MAINTAINER James Ousby (https://github.com/smebberson/docker-alpine)

# Taken from openjdk/8-jdk/alpine/Dockerfile
# (https://github.com/docker-library/openjdk/blob/master/8-jdk/alpine/Dockerfile)
#
# A few problems with compiling Java from source:
# 1. Oracle. Licensing prevents us from redistributing the official JDK.
# 2. Compiling OpenJDK also requires the JDK to be installed, and it gets
# really hairy.

# Default to UTF-8 file.encoding
ENV LANG C.UTF-8

# add a simple script that can auto-detect the appropriate JAVA_HOME value
# based on whether the JDK or only the JRE is installed
RUN { \
echo '#!/bin/sh'; \
echo 'set -e'; \
echo; \
echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
} > /usr/local/bin/docker-java-home \
&& chmod +x /usr/local/bin/docker-java-home

ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
ENV PATH $PATH:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin

# See the Dockerfile linked at the top for latest version numbers to put here
ENV JAVA_VERSION 8u111
ENV JAVA_ALPINE_VERSION 8.111.14-r0

RUN set -x \
&& apk add --no-cache \
openjdk8="$JAVA_ALPINE_VERSION" \
&& [ "$JAVA_HOME" = "$(docker-java-home)" ]
12 changes: 12 additions & 0 deletions alpine-consul-openjdk/OPENJDK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# alpine-openjdk

This file contains a map between [openjdk][openjdk] versions and the version of [alpine-openjdk][alpineopenjdk] that you should pull.

You can [read more about how these images are versioned here](https://github.com/smebberson/docker-alpine#versioning).

## OpenJDK 8.x

- OpenJDK v8.111.14: [v8.111.14](VERSIONS.md#v100)

[openjdk]: http://openjdk.java.net/
[aplineopenjdk]: https://github.com/smebberson/docker-alpine/tree/master/alpine-openjdk
138 changes: 138 additions & 0 deletions alpine-consul-openjdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# alpine-consul-openjdk

A Docker image for running [OpenJDK][openjdk] with [Consul][consul], based on Alpine Linux.
This image belongs to a suite of images [documented here][dockeralpine].

Image size is ~188 MB.

## Features

This image features:

- [Alpine Linux][alpinelinux]
- [s6][s6] and [s6-overlay][s6overlay]
- [OpenJDK][openjdk]
- [consul][consul]

## Versions

- `1.0.0`, `latest` [(Dockerfile)](https://github.com/smebberson/docker-alpine/blob/alpine-consul-openjdk-v1.0.0/alpine-consul-openjdk/Dockerfile)

[See VERSIONS.md for image contents.](https://github.com/smebberson/docker-alpine/blob/master/alpine-consul-openjdk/VERSIONS.md)
[Looking for a particular version of OpenJDK? See OPENJDK.md for more information.](https://github.com/smebberson/docker-alpine/blob/master/alpine-consul-openjdk/OPENJDK.md)

## Usage

To use this image include `FROM smebberson/alpine-consul-openjdk` at the top of your `Dockerfile`. Inheriting from `smebberson/alpine-consul-openjdk` provides you with the ability to easily start your OpenJDK application using [s6][s6].

This container has been setup to automatically connect to a Consul cluster, created with a service name of `consul`. [Read more about it here](https://github.com/smebberson/docker-alpine/tree/master//alpine-consul).

You have two options for process management:

- s6 can keep it running for you, restarting it when it crashes.
- The entire container can exit allowing the host machine to kick in and restart it.

To start your app, with automatic restarts:

- create a folder at `/etc/services.d/app` (or name it whatever you like, just make sure it lives within `/etc/services.d`)
- create a file in your new folder called `run` and give it execute permissions
- inside that file start your openjdk application, for example:

```
#!/usr/bin/env sh

# cd into our directory
cd /app

# start our openjdk application
java -jar app.jar;
```

When you run this container, s6 will automatically restart your application and make sure it stays running for you.

You'll also need to make sure you go through the usual process of exposing the necessary ports for your application (usually within your Dockerfile).

### Service registration with Consul

If you're using this image, chances are, you want to register this application as a service with Consul so that other containers can discover this service and use it as required (i.e. an Nginx container that will configure itself as a proxy for your app).

To do so, create a file at `/etc/consul/conf.d/app.json` (or call it whatever you want, as long as you create a `.json` file within `/etc/consul/conf.d/`) and add it to your image:

```
{
"service": {
"name": "app",
"tags": ["app","java"],
"port": 4000,
"check": {
"id": "app",
"name": "Java app on port 4000"
"http": "http://localhost/ping",
"interval": "10s",
"timeout": "1s"
}
}
}

```

This file registers your app with Consul, giving it a service name of `app`. It also defines a health check that will respond to a `GET / HTTP/1.1 Host: localhost:4000` request. Consul will use this health check to broadcast the status of your application.

### Configuration generation with consul-template

This container also features consul-template which allows you to easily generate configuration files based on Consul services. You can [read more about this feature here](https://github.com/smebberson/docker-alpine/tree/master/alpine-consul-base#customisation).

### Container exits

To start your app in a fashion that will exit the container when your app dies, add something like the following to your Dockerfile:

```
CMD ["java", "-jar", "/app/app.jar"]
```

The container will execute the command and your app will start running. When it suddenly dies, your container will exit so you'll need processes on your host machine to restart it (i.e. `docker run --autorestart`).

#### Taking advantage of s6

The above method has the benefit of exiting the container when your app dies, but it doesn't really allow you to take advantage of s6. With s6, you can have processes that are executed after your app dies. For example, in case there is something you need to clean up before your host restarts the container. To take advantage of this, create the executable `run` file at `/etc/services.d/app` as described in **Automatic restarts**.

Now, create an executable file named `finish` at `/etc/services.d/app`. In this file do any clean up you need to, and then use s6 to kill the container, for example:

```
#!/usr/bin/env sh

# perform clean-up here

# use s6 to exit the container
s6-svscanctl -t /var/run/s6/services

```

You can simply remove the last line, if you want s6 to automatically restart your app again.

### Logging

If you're logging to stdout then you'll be able to review your logs using the standard [Docker process][dockerlogs].

### Handling uncaught exceptions

The best way to handle exceptions is to:

1. Capture them.
1. Log them.
1. Exit the process and let s6 restart your app, or exit the container.

This will ensure that your errors aren't going un-noticed, but that your application stays up and in proper functioning order.

## Example

An example of using this image can be found in [examples/user-consul-openjdk][example].

[dockeralpine]: https://github.com/smebberson/docker-alpine
[s6]: http://www.skarnet.org/software/s6/
[s6overlay]: https://github.com/just-containers/s6-overlay
[alpinelinux]: https://www.alpinelinux.org/
[consul]: https://consul.io/
[opendjdk]: http://openjdk.java.net
[dockerlogs]: https://docs.docker.com/reference/commandline/cli/#logs
[example]: https://github.com/smebberson/docker-alpine/tree/master/examples/user-consul-nodejs
18 changes: 18 additions & 0 deletions alpine-consul-openjdk/VERSIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# alpine-consul-openjdk

This file contains all software versions, that correspond to a version of this image itself. Read more about the [alpine-consul-openjdk image here][alpineconsulopenjdk].

Looking for a particular version of OpenJdk? [See OPENJDK.md for more information.](https://github.com/smebberson/docker-alpine/blob/master/alpine-consul-openjdk/OPENJDK.md)

## Latest

Same as v1.0.0

Usage: `smebberson/alpine-consul-openjdk` or `smebberson/alpine-consul-openjdk:latest`.

## v1.0.0

- [OpenJdk: v8.111.14][openjdk]
- [smebberson/alpine-consul-base: v4.1.0][smebbersonalpineconsulbase410]

Usage: `smebberson/alpine-consul-openjdk:1.0.0`.
1 change: 1 addition & 0 deletions alpine-consul-openjdk/build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker build -t smebberson/alpine-consul-openjdk /vagrant/alpine-consul-openjdk
25 changes: 25 additions & 0 deletions examples/user-consul-openjdk/app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM smebberson/alpine-consul-openjdk
MAINTAINER James Ousby (https://github.com/smebberson/docker-alpine)

# original sample from https://github.com/deis/example-java-jetty

# NOTE: This example actually builds the Java application with Maven, which means that the
# final image includes both build and runtime dependencies - this is not meant as a
# production-ready example.

RUN MAVEN_VERSION=3.3.9 \
&& cd /usr/share \
&& wget http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz -O - | tar xzf - \
&& mv /usr/share/apache-maven-$MAVEN_VERSION /usr/share/maven \
&& ln -s /usr/share/maven/bin/mvn /usr/bin/mvn

ENV MAVEN_HOME /usr/share/maven

ADD root /

RUN apk add --update curl && \
rm -rf /var/cache/apk/* && \
cd /app && \
mvn -V -U -B -DskipTests clean dependency:list install

EXPOSE 8081
13 changes: 13 additions & 0 deletions examples/user-consul-openjdk/app/root/app/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2012 Engine Yard, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
45 changes: 45 additions & 0 deletions examples/user-consul-openjdk/app/root/app/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>helloworld</artifactId>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.3.9.v20160517</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Healthcheck extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setStatus(200);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class HelloWorld {
public static void main(String[] args) throws Exception{
String portEnv = System.getenv("PORT");
int port = 8081;
if (portEnv != null) {
port = Integer.valueOf(portEnv);
}

Server server = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(new ServletHolder(new Healthcheck()),"/healthz");
context.addServlet(new ServletHolder(new Index()),"/*");
server.start();
server.join();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class Index extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String message = System.getenv("POWERED_BY");
if (message == null) {
message = "Deis";
}

String release = System.getenv("WORKFLOW_RELEASE");
if (release == null) {
release = "unknown";
}

String container = "unknown";
Process proc = Runtime.getRuntime().exec("hostname");
InputStream is = proc.getInputStream();
Scanner s = new Scanner(is);
if (s.hasNext()) {
container = s.next();
}

resp.getWriter().print(String.format("Powered by %s\nRelease %s on %s\n", message, release, container));
}
}
13 changes: 13 additions & 0 deletions examples/user-consul-openjdk/app/root/etc/consul/conf.d/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"service": {
"name": "app",
"tags": ["app","java"],
"port": 8081,
"checks": [
{
"script": "curl -s -o /dev/null localhost:8081 2>&1",
"interval": "5s"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env sh

# perform clean-up here
curl -s -o /dev/null localhost:8500/v1/agent/service/deregister/app 2>&1

# use s6 to exit the container
s6-svscanctl -t /var/run/s6/services

5 changes: 5 additions & 0 deletions examples/user-consul-openjdk/app/root/etc/services.d/app/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/with-contenv sh

cd /app

java -cp target/classes:target/dependency/* HelloWorld
Loading