Docker и Kotlin: контейнеризация приложений от А до Я

Онлайн-тренажер Python для начинающих

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

Начать курс

Docker и Kotlin: контейнеризация приложений от А до Я

Контейнеризация стала стандартом де-факто для современной разработки. Она решает проблему "на моей машине работает" и упрощает CI/CD. В этой статье мы разберем, как эффективно контейнеризировать Kotlin-приложения с помощью Docker — от создания простого Dockerfile до продакшн-оптимизаций и оркестрации.

1. Основы: Dockerfile для Kotlin-приложения

Сердце контейнеризации — Dockerfile. Для Kotlin-приложений, которые компилируются в JVM байт-код, мы используем многоступенчатую сборку (multi-stage build). Это позволяет отделить среду сборки от среды выполнения, уменьшая размер финального образа.

Рассмотрим типовое приложение на Kotlin с использованием Gradle (файл build.gradle.kts упрощен):

// build.gradle.kts
plugins {
    kotlin("jvm") version "1.9.0"
    application
    id("com.google.cloud.tools.jib") version "3.4.0" // опционально
}

application {
    mainClass.set("com.example.MainKt")
}

Создадим Dockerfile с двумя стадиями:

# Стадия 1: Сборка
FROM gradle:8.5-jdk21 AS builder
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
COPY src ./src
RUN gradle build --no-daemon

# Стадия 2: Запуск
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/my-app-*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Команды для сборки и запуска:

docker build -t my-kotlin-app .
docker run -p 8080:8080 my-kotlin-app

Рекомендации:

  • Используйте eclipse-temurin (OpenJDK) вместо полного JDK — образ меньше.
  • Кэшируйте зависимости: сначала копируйте build.gradle.kts, затем src.
  • Для Spring Boot приложений можно использовать layers для инкрементальной сборки.

2. Оптимизация с помощью Jib и Gradle

Ручное написание Dockerfile — это классика, но есть инструменты, которые автоматизируют процесс. Jib (от Google) интегрируется с Maven/Gradle и собирает оптимизированные Docker-образы без Docker daemon.

Добавьте плагин Jib в build.gradle.kts:

plugins {
    id("com.google.cloud.tools.jib") version "3.4.0"
}

jib {
    from {
        image = "eclipse-temurin:21-jre-alpine"
    }
    to {
        image = "my-registry/my-kotlin-app:latest"
    }
    container {
        ports = listOf("8080")
        jvmFlags = listOf("-Xms512m", "-Xmx1024m")
    }
}

Сборка одной командой:

./gradlew jibDockerBuild

Преимущества Jib:

  • Автоматическое разделение на слои (зависимости, ресурсы, классы).
  • Не требует Dockerfile.
  • Работает без Docker daemon — идеально для CI/CD.

Пример Kotlin-приложения (простой HTTP-сервер):

// src/main/kotlin/com/example/Main.kt
package com.example

import com.sun.net.httpserver.HttpServer
import java.net.InetSocketAddress

fun main() {
    val server = HttpServer.create(InetSocketAddress(8080), 0)
    server.createContext("/") { exchange ->
        val response = "Hello from Kotlin in Docker!"
        exchange.sendResponseHeaders(200, response.length.toLong())
        exchange.responseBody.write(response.toByteArray())
        exchange.close()
    }
    server.start()
    println("Server started on port 8080")
}

3. Docker Compose: многоконтейнерные приложения

Реальные проекты редко состоят из одного сервиса. Docker Compose позволяет описать и запустить несколько контейнеров (например, приложение + база данных + Redis).

Создадим docker-compose.yml для Kotlin-приложения с PostgreSQL:

version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=mydb
      - DB_USER=user
      - DB_PASSWORD=pass
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  pgdata:

Запуск одной командой:

docker compose up --build

В Kotlin-коде можно использовать библиотеку Exposed для работы с БД:

// Пример подключения к PostgreSQL через Exposed
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.transactions.transaction

fun initDb() {
    Database.connect(
        url = "jdbc:postgresql://${System.getenv("DB_HOST")}:${System.getenv("DB_PORT")}/${System.getenv("DB_NAME")}",
        driver = "org.postgresql.Driver",
        user = System.getenv("DB_USER"),
        password = System.getenv("DB_PASSWORD")
    )
    transaction {
        // Создание таблиц и миграции
    }
}

4. Best Practices и продакшн-настройки

Чтобы контейнеры работали стабильно и безопасно, следуйте этим рекомендациям:

  • Не запускайте от root. Создайте пользователя в Dockerfile:
    RUN addgroup -S appgroup && adduser -S appuser -G appgroup
    USER appuser
  • Минимизируйте слои. Объединяйте команды RUN (например, RUN apt-get update && apt-get install -y --no-install-recommends ... && rm -rf /var/lib/apt/lists/*).
  • Используйте .dockerignore. И

Блоги

Рекомендаций по книгам