Проект SBT не смонтирован в Docker контейнер с использованием docker -compose - PullRequest
1 голос
/ 30 апреля 2020

Когда я запускаю docker-compose up --build контейнер БД работает нормально, но контейнер приложения существует с

[error] java.lang.RuntimeException: No main class detected.
[error]     at scala.sys.package$.error(package.scala:30)
[error] stack trace is suppressed; run 'last Compile / bgRun' for the full output
[error] (Compile / bgRun) No main class detected.
[error] Total time: 3 s, completed Apr 30, 2020 10:07:31 AM
ERROR: Service 'app' failed to build: The command 'sbt run' returned a non-zero code: 1

Мой Dockerfile:

FROM        hseeberger/scala-sbt:8u222_1.3.5_2.13.1
MAINTAINER  <HIDDEN>
EXPOSE      8080 8000

WORKDIR     /www/app

VOLUME /www/app

RUN ["sbt", "run"]

Мой docker -compose.yml :

version: "3.3"
services:
  db:
    image: postgres:latest
    ports:
      - "5432:5432"
  app:
    build: .
    ports:
     - "8080:8080"
     - "8000:8000"
    volumes:
     - ..:/www/app

Моя Scala структура проекта:

Project structure

Main.scala просто содержит супер простой Hello World как вы можете видеть:

object Main extends App {
  println("Hello from main scala object")
}

Если я запускаю контейнер, используя RUN ["sbt"] в Dockerfile, контейнер продолжает работать. Я подключился через docker exec -it adcc9897d1fc bash и увидел, что папка /www/app пуста (кроме папок, созданных sbt). Есть идеи, почему он пустой и не содержит проект?

1 Ответ

2 голосов
/ 30 апреля 2020

Файл Docker рассматривается и обрабатывается полностью до того, как будут рассмотрены большинство других параметров в файле docker-compose.yml. В частности, сборка образа никогда не видит volumes: из Docker Compose setup (он также не может видеть environment: переменные или любые сетевые настройки, включая default network).

Это означает, что во время сборки (потому что это директива RUN), вы пытаетесь запустить sbt run на пустом анонимном томе. Это приводит к ошибке «no main class», которую вы получаете.

Для языков на основе JVM типичной настройкой является компиляция приложения на хосте, а затем COPY (переносимый) .jar файл в ваше изображение. Плагин sbt-native-packager может на самом деле сделать все это за вас ; если вы предпочитаете делать это вручную, плагин sbt-assembly может создать «толстый» .jar, содержащий все зависимости приложения. Затем вы получаете типичный минимальный Dockerfile JVM

FROM openjdk:8
COPY target/scala-2.13/my-app-*.jar /my-app.jar
CMD ["java", "-jar", "/my-app.jar"]

Если вы хотите скомпилировать приложение в Dockerfile, вам нужно COPY приложение в нем и установить CMD для запуска приложения, когда контейнер запускается (не во время сборки).

FROM hseeberger/scala-sbt:8u222_1.3.5_2.13.1
WORKDIR /www/app

# Copy the application source in.
COPY ./ ./

# Build it.
RUN sbt compile

# Set the command to run and other metadata when the container starts.
EXPOSE 8000 8080
CMD sbt run

(Вы также можете использовать многоступенчатую сборку , чтобы объединить эти два файла Docker: первый COPY исходное дерево и sbt compile это, затем на втором этапе COPY --from=build только файл jar в образе JRE-only.)

Из-за инструкции COPY необходимо установить контекст сборки равным root исходного дерева. (Возможно, было бы легче переместить Dockerfile и docker-compose.yml в хранилище root рядом с файлом build.sbt.)

version: "3.3"
services:
  app:
    build:
      context: ..
      dockerfile: docker/Dockerfile
    ports:
     - "8080:8080"
     - "8000:8000"
    # No need for volumes:, source code is already in the image

В принципе, вы можете привязать код приложения к вашему компьютеру. как у вас было в вопросе, и команда sbt run перекомпилирует его. Вам не нужна директива VOLUME в вашем Dockerfile. Вероятно, вам будет проще выполнять повседневную разработку в среде JDK / sbt хоста.

...