Збираємо Docker контейнер з http-сервером за допомогою Gradle

image
Виникла така задача: Зробити простий web — сервер з мінімальним числом залежностей. При цьому деплоиться він буде у вигляді docker контейнера. Для реалізації самого сервера буду використовувати GrizzlyWebServer. Для складання Gradle c плагіном для docker від Benjamin Muschko (bmuschko).
Такий вибір інструментів не випадковий, я займаюся розробкою для android і мені ближче Java і Gradle ніж щось інше. У цій статті хочу детально описати процес від написання додатки до запуску в docker, можливі проблеми та їх вирішення.
І так, почнемо: сервер.

Створюємо новий Gradle проект в IntelliJ IDEA.

image

image
Порожній проект створений, додамо клас HabrWebServer з методом main().
У build.gradle в dependencies додаємо рядок.
compile group: 'org.glassfish.grizzly', name: 'grizzly-http server', version: '2.3.28'

Код нашої найпростішого сервера
public class HabrWebServer {

private static final Logger LOGGER = Grizzly.logger(HabrWebServer.class);

public static void main(String[] args) {
// create a basic server that listens 0.0.0.0:8080
final HttpServer server = HttpServer.createSimpleServer();
final ServerConfiguration config = server.getServerConfiguration();
// Map the path, '/', to the Handler
config.addHttpHandler(new HabrHandler(), "/");
try {
server.start();
System.out.println("The server is running. \nPress enter to stop...");
System.in.read();
} catch (IOException ioe) {
LOGGER.log(Level.SEVERE, ioe.toString(), ioe);
} finally {
server.shutdownNow();
}
}

private static class HabrHandler extends HttpHandler {
@Override
public void service(Request request, Response response) throws Exception {
response.setContentType("text/plain");
response.getWriter().write("Hello Habrahabr!");
}
}
}


Відкриваємо консоль в директорії проекту набираємо ./gradlew assemble — BUILD SUCCESSFUL.
Що то у нас вже зібралося.
Але є одна неприємна річ, ide імпорти не працюють і класики сервера підсвічені червоним.
image
Лікується це так — треба знайти чарівну кнопку refresh і натиснути її — Synchronizing Changes in Gradle Project and IntelliJ IDEA Project

Тепер запустимо додаток локально, для цього використовуємо плагін 'application' для Gradle.

У build.gradle додаємо рядків
apply plugin: 'application'
mainClassName = 'ua.test.HabrWebServer'

Збираємо і встановлюємо додаток
./gradlew installDist

Переходимо в папку /habrServer/build/install/habrServer/bin
Запускаємо додаток
./habrServer

Відкриваємо браузер, сервер відповідає, але не тим що чекаємо.
image
Виявляється при створенні сервера метод createSimpleServer() встановлює першим обробник який віддає статичний контент якого у нас немає, і до нашого обробника справа не доходить. Міняємо код створення сервера.
public static void main(String[] args) {
final HttpServer server = createServer("0.0.0.0", 8080);
...
}

public static HttpServer createServer(String host, int port) {
HttpServer server = new HttpServer();
NetworkListener listener = new NetworkListener("grizzly", host, new PortRange(port));
server.addListener(listener);
return server;
}

Залишилося зібрати додаток у вигляді docker контейнера.
Почнемо з локальної установки docker.
Після установки docker сервер слухає тільки на unix-сокет. Дозволимо локальний доступ tcp.
У файлі /lib/systemd/system/docker.service знаходимо і правимо рядок
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://127.0.0.1:2375
Не зовсім правильно змінювати цей файл, так як він змінює настройки для всіх користувачів, але в моєму випадку для тестів на моїй машині підходить.

Щоб зібрати контейнер використовуємо bmuschko Gradle Docker plugin

Остаточний варіант build.gradle
group 'habrServer'
version '1.0-SNAPSHOT'

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.bmuschko.docker-java application'
apply plugin: 'com.bmuschko.docker-remote-api'

import com.bmuschko.gradle.docker.tasks.container.DockerCreateContainer

mainClassName = 'ua.test.HabrWebServer'

buildscript {
repositories {
jcenter()
}

dependencies {
classpath 'com.bmuschko:gradle-docker-plugin:3.0.3'
}
}

docker {
url = 'http://127.0.0.1:2375'
javaApplication {
maintainer = 'Dmitry Barkalov "xxx@xxx.xxx"'
ports = [8080]
tag = 'habrwebserver'
}
}

task createDocker(type: DockerCreateContainer) {
dependsOn dockerBuildImage
targetImageId { dockerBuildImage.getImageId() }
portBindings = ['8080:8080']
}


repositories {
mavenCentral()
jcenter()
}

dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
compile group: 'org.glassfish.grizzly', name: 'grizzly-http server', version: '2.3.28'
}


Збираємо та встановлюємо контейнер
./gradlew createDocker

image
Запускаємо!
image
Відкриваємо в браузері.
image

Залишилася одна не вирішена завдання: додаток чекає в main потоці на System.in.read(); Тому docker запускаємо з ключем -i. Keep STDIN open even if not attached.) тобто stdin залишається приатаченым до контейнера. Робити додаток у вигляді демона швидше за все не потрібно, докер сам вміє демонізувати. Треба прибрати взаємодія з stdin, і вміти зупиняти додаток. Це треба ще дізнатися. Якщо хтось знає пишіть в коментарях, буду вдячний.

Спасибі за увагу, сподіваюся стаття була комусь корисна.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.