Как преобразовать веб-сервис Spring-Boot в образ Docker?

Вот еще один оптимизированный способ сделать это:

import org.apache.spark.sql.functions._

val cols = freq.columns.drop(1).toSeq
val selections = Seq(col("id")) ++ cols.map(c => when(col(c).isNotNull, lit(1)).otherwise(col(c)).alias(c))
val freq2 = freq.select(selections : _*)
freq2.show
// +---+----+----+----+----+
// | id|  a1|  a2|  a3|  a4|
// +---+----+----+----+----+
// |101|null|   1|   1|null|
// |102|   1|null|   1|   1|
// |103|   1|   1|null|   1|
// |104|   1|null|   1|null|
// +---+----+----+----+----+

Вы можете попытаться сравнить планы выполнения для обоих:

scala> newfreq.explain(true)
== Parsed Logical Plan ==
'Project [id#10, a1#20, a2#26, a3#32, CASE WHEN isnotnull('a4) THEN 1 ELSE 'a4 END AS a4#38]
+- AnalysisBarrier
      +- Project [id#10, a1#20, a2#26, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#32, a4#14]
         +- Project [id#10, a1#20, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#26, a3#13, a4#14]
            +- Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#20, a2#12, a3#13, a4#14]
               +- Relation[id#10,a1#11,a2#12,a3#13,a4#14] csv

== Analyzed Logical Plan ==
id: int, a1: int, a2: int, a3: int, a4: int
Project [id#10, a1#20, a2#26, a3#32, CASE WHEN isnotnull(a4#14) THEN 1 ELSE a4#14 END AS a4#38]
+- Project [id#10, a1#20, a2#26, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#32, a4#14]
   +- Project [id#10, a1#20, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#26, a3#13, a4#14]
      +- Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#20, a2#12, a3#13, a4#14]
         +- Relation[id#10,a1#11,a2#12,a3#13,a4#14] csv

== Optimized Logical Plan ==
Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#20, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#26, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#32, CASE WHEN isnotnull(a4#14) THEN 1 ELSE a4#14 END AS a4#38]
+- Relation[id#10,a1#11,a2#12,a3#13,a4#14] csv

== Physical Plan ==
*(1) Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#20, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#26, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#32, CASE WHEN isnotnull(a4#14) THEN 1 ELSE a4#14 END AS a4#38]
+- *(1) FileScan csv [id#10,a1#11,a2#12,a3#13,a4#14] Batched: false, Format: CSV, Location: InMemoryFileIndex[file:.../test.data], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<id:int,a1:int,a2:int,a3:int,a4:int>

scala> freq2.explain(true)
== Parsed Logical Plan ==
'Project [unresolvedalias('id, None), CASE WHEN isnotnull('a1) THEN 1 ELSE 'a1 END AS a1#46, CASE WHEN isnotnull('a2) THEN 1 ELSE 'a2 END AS a2#47, CASE WHEN isnotnull('a3) THEN 1 ELSE 'a3 END AS a3#48, CASE WHEN isnotnull('a4) THEN 1 ELSE 'a4 END AS a4#49]
+- AnalysisBarrier
      +- Relation[id#10,a1#11,a2#12,a3#13,a4#14] csv

== Analyzed Logical Plan ==
id: int, a1: int, a2: int, a3: int, a4: int
Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#46, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#47, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#48, CASE WHEN isnotnull(a4#14) THEN 1 ELSE a4#14 END AS a4#49]
+- Relation[id#10,a1#11,a2#12,a3#13,a4#14] csv

== Optimized Logical Plan ==
Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#46, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#47, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#48, CASE WHEN isnotnull(a4#14) THEN 1 ELSE a4#14 END AS a4#49]
+- Relation[id#10,a1#11,a2#12,a3#13,a4#14] csv

== Physical Plan ==
*(1) Project [id#10, CASE WHEN isnotnull(a1#11) THEN 1 ELSE a1#11 END AS a1#46, CASE WHEN isnotnull(a2#12) THEN 1 ELSE a2#12 END AS a2#47, CASE WHEN isnotnull(a3#13) THEN 1 ELSE a3#13 END AS a3#48, CASE WHEN isnotnull(a4#14) THEN 1 ELSE a4#14 END AS a4#49]
+- *(1) FileScan csv [id#10,a1#11,a2#12,a3#13,a4#14] Batched: false, Format: CSV, Location: InMemoryFileIndex[file:.../test.data], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<id:int,a1:int,a2:int,a3:int,a4:int>

Оптимизированный логический логический планы одинаковы для обоих, но это более чистый способ сделать.

2
задан ErikMD 21 February 2019 в 21:46
поделиться

2 ответа

Чтобы полностью ответить на ваш вопрос (докеризировать проект Spring Boot и просмотреть соответствующее веб-приложение в локальном браузере, скажем, на этапе разработки), необходимо выполнить три независимых задачи:

  1. [1127 ] Использовать сборку образа Docker с помощью Dockerfile, который использует механизм кэширования Docker (чтобы избежать повторной загрузки зависимостей Maven с нуля каждый раз и тем самым ускорить сборку)

  2. Убедитесь, что приложение Spring Boot прослушивает указанный порт для 0.0.0.0 специального IP , а не localhost;

  3. И, наконец, опубликуйте данный порт, чтобы вы могли запустить, например:

    $ xdg-open http://localhost:8080/index
    

Шаг 3 хорошо объяснен в ответе @ Poger's, поэтому я подробнее остановлюсь только на шагах 1 и 2:

  1. Я предложил Dockerfile в этой теме SO: Как кэшировать зависимости maven в Docker , вдохновленный этой статьей в блоге , это применимо для проектов Java / Maven в гене ral (не только проекты Spring Boot):

    # our base build image
    FROM maven:3.5-jdk-8 as maven
    
    WORKDIR /app
    
    # copy the Project Object Model file
    COPY ./pom.xml ./pom.xml
    
    # fetch all dependencies
    RUN mvn dependency:go-offline -B
    
    # copy your other files
    COPY ./src ./src
    
    # build for release
    # NOTE: my-project-* should be replaced with the proper prefix
    RUN mvn package && cp target/my-project-*.jar app.jar
    
    
    # smaller, final base image
    FROM openjdk:8u171-jre-alpine
    # OPTIONAL: copy dependencies so the thin jar won't need to re-download them
    # COPY --from=maven /root/.m2 /root/.m2
    
    # set deployment directory
    WORKDIR /app
    
    # copy over the built artifact from the maven image
    COPY --from=maven /app/app.jar ./app.jar
    
    # set the startup command to run your binary
    CMD ["java", "-jar", "/app/app.jar"]
    

    , но для дальнейшего уточнения обратите внимание, что рекомендуется передать дополнительное системное свойство java.security.egd :

    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
    

    или, если вы предпочитаете ENTRYPOINT, чем CMD:

    ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
    
  2. Как упомянуто в ветке SO Как получить доступ к приложению Spring, запущенному в докере container? , в контексте контейнерного приложения, localhost следует избегать и заменять на 0.0.0.0 большую часть времени (а именно, если приложение должно действовать как веб-служба, отвечающая на входящие запросы извне контейнера ).

    Подводя итог, вы должны просто попытаться добавить следующую строку в ваш файл application.properties:

    server.address=0.0.0.0
    
0
ответ дан ErikMD 21 February 2019 в 21:46
поделиться

Когда вы запускаете Docker-контейнер, все порты, которые прослушиваются в нем любым приложением, по умолчанию не публикуются.

Чтобы опубликовать порт, вам нужно указать его при запуске контейнера с использованием вашего изображения. Для получения более подробной информации о том, как это сделать, вы можете проверить раздел «EXPOSE» в документации команды docker run : https://docs.docker.com/engine/reference/run /

Короче говоря, вы хотите добавить еще одну опцию во время работы вашего контейнера:

docker run --name mycontainer1 -p 8080:8080 myimage1

Я не уверен, что вы хотите добиться этого, добавив

[ 111]

в вашем Dockerfile. На самом деле это не означает, что порт будет открыт, когда образ используется для запуска контейнера. Как вы можете найти в Справочник по Dockerfile :

Инструкция EXPOSE фактически не публикует порт. Он функционирует как тип документации между человеком, который создает образ, и человеком, который запускает контейнер, о том, какие порты предназначены для публикации. Чтобы фактически опубликовать порт при запуске контейнера, используйте флаг -p на панели запуска Docker, чтобы опубликовать и сопоставить один или несколько портов, или флаг -P, чтобы опубликовать все открытые порты и сопоставить их с портами высокого порядка.

0
ответ дан Poger 21 February 2019 в 21:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: