
Содержание статьи
от Мигеля Лопеса

Использование Docker сегодня является данностью. В этом учебнике мы расскажем, как научиться докеризировать наши HTTP-приложения Scala и Akka без даже создавая файл Docker самостоятельно.
Для целей данного руководства мы предполагаем, что Docker уже установлен на машине. Если это не так, соблюдайте официальную документацию.
Для автоматизации создания Dockerfile для нашего проекта, мы будем использовать плагин sbt-native-packager.
Вы можете использовать любой проект HTTP Scala или Akka для этого учебника. Мы будем использовать следующее хранилище, не стесняйтесь клонировать его и не забудьте проверить ветку 6.5-testing-directives
.
Добавление плагина
Сначала нам нужно добавить плагин к нашему проекту в файле project/plugins.sbt
файл. Если файл не существует, нам нужно его создать, а затем добавить следующую строку:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.6")
Затем нам нужно включить плагин в нашем build.sbt
файл. Добавьте следующую строчку вверху:
enablePlugins(JavaAppPackaging)
Включение этого плагина позволяет нам создать исполняемый файл для нашей программы. Беги sbt stage
в корневом каталоге проекта.
Теперь мы можем выполнить нашу программу, запустив ./target/universal/stage/bin/akkahttp-quickstart
. Вы должны увидеть a Success!
сообщения. Если вы посылаете запрос GET на адрес localhost:9000/todos
вы получите пару задач.

Докеризация нашей программы
Пора начать играть с Docker.
Давайте начнем с создания файла Docker для нашего приложения. Беги sbt docker:stage
потом беги cat target/docker/stage/Dockerfile
чтобы увидеть его содержимое:
FROM openjdk:latestWORKDIR /opt/dockerADD --chown=daemon:daemon opt /optUSER daemonENTRYPOINT ["/opt/docker/bin/akkahttp-quickstart"]CMD []
Это достаточно просто. В итоге он запускает двоичный файл, подобный тому, который мы создали и запустили раньше.
Мы можем создать образ Docker с помощью этого Dockerfile вручную, но есть более удобный способ сделать это. Давай бежать sbt docker:publishLocal.
Как следует из названия, он опубликует образ Docker нашей программы в нашем локальном реестре.
Беги docker images
и вы должны увидеть следующую запись:
REPOSITORY TAG IMAGE ID CREATED SIZEakkahttp-quickstart 0.1 d03732dd0854 42 seconds ago 774MB
Теперь мы можем запустить наше приложение с помощью Docker.
Беги docker run akkahttp-quickstart:0.1
вы должны увидеть Success!
сообщение еще раз.
Но на этот раз, если мы попытаемся запросить нашу программу, мы получим ошибку:

Давай бежать docker ps
чтобы получить некоторую информацию о нашем запущенном процессе Docker (сокращен вывод):
CONTAINER ID IMAGE PORTS NAMES9746162d4723 akkahttp-quickstart:0.1 serene_agnesi
Как видим, нет открытых портов, поэтому нет возможности связаться с нашим приложением.
Программы по умолчанию в Docker запускаются в своей сети. Существует несколько способов разрешить связь между процессами Docker и хост-машиной. Самый простой способ – открыть порт.
Остановите запущенную программу, нажав Ctrl-C
или бегом docker stop $CONTAINER_ID
.
В этот раз, когда мы его запустим, мы также откроем порт.
docker run -p 9000:9000 akkahttp-quickstart:0.1
Теперь мы можем спрашивать нашу докеризированную программу:

Настройка нашей настройки
Есть несколько вещей, которые мы можем захотеть сделать с текущими настройками:
- Что делать, если мы хотим другое название изображения?
- Что делать, если мы хотим использовать другой порт?
- Можем ли мы иметь более светлый образ?
Давайте рассмотрим эти распространенные случаи использования.
Изменение названия изображения
Если мы заглянем в официальную документацию плагина, то мы увидим, что существует ряд параметров, которые мы можем изменить.
Прочтите и посмотрите, что еще можно настроить.
Чтобы изменить название изображения, мы можем изменить файл packageName
имущество в нашей build.sbt
файла, добавьте следующую строку после scalaVersion
собственность:
packageName in Docker := "dockerised-akka-http"
Давайте снова опубликуем изображение. Беги sbt docker:publishLocal
. Мы можем проверить, имеем ли новое изображение, запустив docker images
:
REPOSITORY TAG IMAGE ID CREATED SIZE akkahttp-quickstart 0.1 d03732dd0854 42 minutes ago 774MB dockerised-akka-http 0.1 d03732dd0854 42 minutes ago 774MB
Теперь у нас есть два изображения, оригинальные и новые. Прекрасно!
Смена порта
Мы не можем изменить порт, который прослушивает наша программа, не внеся изменения в код. Порт жестко закодирован в нашей программе. В идеале мы читаем это по изменяющейся среде и, возможно, имеем ее по умолчанию.
Но это нормально. Поскольку наша программа работает в другой сети, мы можем сравнить другой порт с внутренним портом 9000.
Когда мы указываем флаг -p 9000:9000
мы говорим, что порт 9000 на хост-машине будет сопоставлен с портом 9000 в сети нашего процесса. Давайте попробуем поменять это.
Беги docker run -p 5000:9000 dockerised-akka-http:0.1
чтобы запустить наш новый образ с другим портом.
Мы можем спросить todos
чтобы убедиться, что он работает должным образом:

Делаем наш образ более светлым
Для нашего последнего эксперимента мы постараемся сделать наше изображение более светлым. В настоящее время он использует более 700 МБ.
Сначала давайте увеличим версию, чтобы получить другой тэг и сравнить их. Затем добавьте dockerBaseImage := "openjdk:8-jre-alpine"
выше, где мы меняем packageName
. Наши build.sbt
сейчас выглядит так:
enablePlugins(JavaAppPackaging)
name := "akkahttp-quickstart"version := "0.2"scalaVersion := "2.12.6"
dockerBaseImage := "openjdk:8-jre-alpine"packageName in Docker := "dockerised-akka-http"
val akkaVersion = "2.5.13"val akkaHttpVersion = "10.1.3"val circeVersion = "0.9.3"
libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % akkaVersion, "com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test, "com.typesafe.akka" %% "akka-stream" % akkaVersion, "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % Test, "com.typesafe.akka" %% "akka-http" % akkaHttpVersion, "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test, "io.circe" %% "circe-core" % circeVersion, "io.circe" %% "circe-generic" % circeVersion, "io.circe" %% "circe-parser" % circeVersion, "de.heikoseeberger" %% "akka-http-circe" % "1.21.0", "org.scalatest" %% "scalatest" % "3.0.5" % Test)
Мы используем другой тег openjdk
базовое изображение, чтобы указать, что мы хотим использовать alpine
который является лёгким дистрибутивом Linux.
Публикуйте изображение, запустив sbt docker:publishLocal
. Получите изображение с помощью docker images
. Мы видим, что изображение стало светлее:
REPOSITORY TAG IMAGE ID CREATED SIZE dockerised-akka-http 0.2 4688366e70bb 32 seconds ago 119MB akkahttp-quickstart 0.1 d03732dd0854 2 hours ago 774MBdockerised-akka-http 0.1 d03732dd0854 2 hours ago 774MB
Давайте убедимся, что это все еще работает.
Беги docker run -p 5000:9000 dockerised-akka-http:0.2
, учитывая номер тега. Это не работает, мы получаем такую ошибку:
env: can't execute 'bash': No such file or directory
Очевидно, наше докеризированное приложение требует bash бежать. Читая документацию плагина, мы можем сказать, что он генерирует скрипт bash, выполняющий нашу программу.
Давайте установим bash в наш образ и попробуем еще раз.
Добавьте следующие строки ниже, где мы меняем packageName
в нашем build.sbt
файл:
import com.typesafe.sbt.packager.docker._dockerCommands ++= Seq( Cmd("USER", "root"), ExecCmd("RUN", "apk", "add", "--no-cache", "bash"))
Мы добавляем дополнительные команды в наш Dockefile. Мы меняем пользователя на root
чтобы установить пакет, а затем мы устанавливаем bash.
Попробуем снова запустить программу, docker run -p 5000:9000 dockerised-akka-http:0.2
. И сейчас работает, здорово!
Если мы проверим изображение еще раз, альпийский-базированный чуть больше, например 10 МБ. Это ничто по сравнению с примерно 770 МБ других.
Установка bash в альпийский это не самое плохое в мире. Некоторые люди все равно добавляют его из-за своих преимуществ и настройки.
Создание Ash-совместимого исполняемого файла
Установка bash на наш образ – это немного обходной путь. Давайте используем дополнительный плагин для создания исполняемого файла, совместимого с Alpine. Спасибо продавцу Muki за то, что он сообщил нам об этом решении!
Согласно официальной документации, нам нужно включить дополнительный плагин AshScriptPlugin
.
Изменить build.sbt
файл, чтобы включить оба плагина, и удалить предыдущий обходной путь:
enablePlugins(JavaAppPackaging, AshScriptPlugin)
name := "akkahttp-quickstart"version := "0.3"scalaVersion := "2.12.6"
dockerBaseImage := "openjdk:8-jre-alpine"packageName in Docker := "dockerised-akka-http"
val akkaVersion = "2.5.13"val akkaHttpVersion = "10.1.3"val circeVersion = "0.9.3"
libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % akkaVersion, "com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test, "com.typesafe.akka" %% "akka-stream" % akkaVersion, "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % Test, "com.typesafe.akka" %% "akka-http" % akkaHttpVersion, "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test,
"io.circe" %% "circe-core" % circeVersion, "io.circe" %% "circe-generic" % circeVersion, "io.circe" %% "circe-parser" % circeVersion, "de.heikoseeberger" %% "akka-http-circe" % "1.21.0",
"org.scalatest" %% "scalatest" % "3.0.5" % Test)
Мы также расширили версию, чтобы мы могли сравнивать и избегать замены предыдущей.
Беги sbt docker:publishLocal
и затем docker run dockerised-akka-http:0.3
.
Вы должны увидеть сообщение об успехе и, если вы спросите задания, вы также должны увидеть их. Прекрасно!
Вывод
В этом руководстве мы доправили HTTP-приложение Scala и Akka. Специально для этой программы ничего не было сделано, а это значит, что настройка будет работать почти так, как есть.
Затем мы рассмотрели, как выполнить некоторые распространенные случаи использования, настроив файл Docker с помощью плагина.
Нам даже удалось снизить размер изображения почти в семь раз!
Странно, не правда ли?
Если вам понравилось это руководство и вы хотите узнать, как создать API для программы Todo, просмотрите наш новый бесплатно конечно! ???
Первоначально опубликовано на www.codemunity.io.