как создать образ Docker All-In-One с помощью sbt-docker и sbt-assembly

Я использую sbt-assembly для получения толстых банок и использую sbt-docker для создания и отправки образов докеров. Мой проект состоит из нескольких модулей с несколькими веб-службами, пользовательским интерфейсом, базой данных и т. д. Поскольку мой базовый образ докера большой (800 МБ), я хочу создать образ докера, содержащий все толстые банки, чтобы я мог легко протестировать его в облаке, используя одна скромная машинка. Я называю это решение All-FatJars-in-One (AFIO). У меня возникли проблемы с созданием такого образа докера AFIO, поэтому этот пост.

Предположим, что этот многомодульный проект имеет корневой модуль и mod1, ниже находится build.scala:

val exeProjs = Seq(mod1)

lazy val root = Project("root", file(".")).
  enablePlugins(DockerPlugin).
  aggregate(exeProjs.map(_.project): _*).
  dependsOn(exeProjs.map(_ % "compile->test"): _*).
  settings(basicSettings: _*).
  settings(
    docker <<= docker dependsOn assembly,
    dockerfile in docker := {
      //get root artifact path like 
      // /home/me/root/target/scala-2.11/root-assembly-0.1-SNAPSHOT.jar 
      val parentArtifact = (assemblyOutputPath in assembly).value

      new Dockerfile {
        from("java:8")
        exeProjs.map(proj => {
          val projName = proj.id

          // fullPathToMod1Art will be like
          // /home/me/root/mod1/target/scala-2.11/mod1-assembly-0.1-SNAPSHOT.jar 
          fullPathToMod1Art = { NASTY parsing to get mo1 artifact }               

          val artifactTargetPath = s"/app/$projName/$artifact"
          addRaw(fullPathArt, artifactTargetPath)
      })
    }
  }

  imageNames in docker := Seq(
    ImageName("myaccount/root:v1")
  )
)

lazy val mod1 = Project("mod1", file("mod1")).
  enablePlugins(DockerPlugin).
  settings(basicSettings: _*).
  settings(
  libraryDependencies ++= Seq(spray_can, spray_routing, akka_actor, junit),

  docker <<= docker dependsOn assembly,

  dockerfile in docker := {
    val artifact = (assemblyOutputPath in assembly).value
    val artifactTargetPath = s"/app/${artifact.name}"
    new Dockerfile {
      from("java:8")
      add(artifact, artifactTargetPath)
      entryPoint("java", "-jar", artifactTargetPath)
    }
  },

  imageNames in docker := Seq(
    ImageName("myaccount/mod1:v1")
  )
)

Проблемы:

  1. приведенный выше код не работает, потому что корневой модуль не может найти артефакт mod1, даже если я проверил, что fullPathToMod1Art верен для сгенерированного артефакта mod1. Я указал root dependOn mod1 с помощью compile->test, так как я не знаю, какие другие конфигурации лучше подходят для описания необходимости: создание образа докера root зависит от генерации толстых jar-файлов mod1.

  2. Как видите, в настройках корневого модуля происходит неприятный анализ пути для получения пути артефакта mod1. Должен быть лучший способ.

Вопросы:

Если решение sbt-docker + sbt-assembly поддерживает модель AFIO, как это сделать правильно, чтобы решить две вышеуказанные проблемы элегантно? Если не поддерживают, то какие еще плагины могут помочь?

Благодарю за любую подсказку.


person jiangok    schedule 21.05.2015    source источник


Ответы (1)


Поскольку вы хотите использовать выходные данные сборки из своих подпроектов, вы должны сделать задачу docker в корневом проекте зависимой от задачи assembly в ваших подпроектах:

docker <<= docker.dependsOn(assembly in mod1, assembly in mod2)

На данный момент у вас есть docker <<= docker dependsOn assembly, который будет генерировать толстый JAR для корневого проекта.

Вы также можете получить выходной путь сборки для своих подпроектов следующим образом:

val jarFile = (outputPath in assembly in mod1).value

Надеюсь, это решит вашу проблему.

person Marcus Lönnberg    schedule 25.05.2015
comment
‹‹= устарело в более новых sbt, поэтому мне пришлось добавить следующее: dockerfile в docker := { val Artifact: File = Assembly.value val ArtifactTargetPath = (assemblyOutputPath в Assembly).value - person alex; 16.08.2019