Эта статья является частью нашего курса Академии под названием Docker Tutorial для разработчиков Java .
В этом курсе мы предлагаем серию руководств, чтобы вы могли разрабатывать свои собственные приложения на основе Docker. Мы охватываем широкий спектр тем, от Docker через командную строку, до разработки, тестирования, развертывания и непрерывной интеграции. С нашими простыми учебными пособиями вы сможете запустить и запустить собственные проекты за минимальное время. Проверьте это здесь !
Содержание
1. Введение
В течение первых нескольких частей руководства мы рассмотрели основы Docker и множество способов взаимодействия с ним. Настало время применить полученные знания в реальных проектах Java, начав обсуждение с темы о том, как Docker влияет на хорошо отлаженные процессы и практики сборки.
Честно говоря, цель этого раздела двоякая. Сначала мы рассмотрим, как существующие инструменты сборки, а именно Apache Maven и Gradle , помогают упаковывать приложения Java в контейнеры Docker . Во-вторых, мы будем продвигать эту идею еще дальше и узнаем, как мы могли бы использовать Docker для полной инкапсуляции конвейера сборки наших Java-приложений и создания окончательных образов Docker в конце.
2. Под увеличительным стеклом
Чтобы поэкспериментировать, мы собираемся разработать два простых (но, тем не менее, значимых) веб-приложения на Java, которые бы реализовывали и представляли API REST (ful) для управления задачами.
Первое приложение будет разработано поверх Spring Boot и Spring Webflux с использованием Gradle в качестве инструмента управления сборкой и зависимостями. Что касается версий, мы будем использовать последнюю 2.0.0.M6
Spring Boot 2.0.0.M6
, последнюю 2.0.0.M6
Spring Webflux 5.0.1
и последнюю версию Gradle 4.3
.
Второе приложение, хотя и функционально эквивалентное первому, будет разработано поверх другой популярной платформы Java, Dropwizard , на этот раз с использованием Apache Maven для управления сборкой и зависимостями. Что касается версий, мы собираемся представить последний выпуск 1.2.0
Dropwizard и последний выпуск 3.5.2
Apache Maven .
Как мы уже упоминали, оба приложения будут реализовывать и предоставлять API-интерфейсы REST (ful) для управления задачами, по сути, заключая в себе операции CRUD (создание, чтение, обновление и удаление).
1
2
3
4
|
GET /tasks POST /tasks DELETE /tasks/ { id } GET /tasks/ { id } |
Сама задача моделируется как постоянный объект, который будет управляться Hibernate ORM и храниться в базе данных отношений MySQL .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@Entity @Table (name = "tasks" ) public class Task { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) @Column (name = "id" ) private Integer id; @Column (name = "title" , nullable = false , length = 255 ) private String title; @Column (name = "description" , nullable = true , columnDefinition = "TEXT" ) private String description; // Getters and setters are omitted ... } |
На этом сходство обоих приложений заканчивается, и каждое из них будет следовать своему идиоматическому пути развития.
3. Градл и Докер
Итак, все готово, давайте начнем путешествие с изучения того, что нужно для интеграции Docker в типичную сборку Gradle . Для этого подраздела вам понадобится установить Gradle 4.3
на ваш компьютер для разработки. Если у вас его еще нет, следуйте инструкциям по установке , выбрав любой предложенный метод, который вы предпочитаете.
Чтобы упаковать типичное приложение Spring Boot как образ Docker с помощью Gradle, нам просто нужно включить два дополнительных плагина в файл build.gradle
:
- Плагин Spring Boot Gradle
- Плагин Palantir Docker Gradle (но есть довольно много альтернативных вариантов )
Конвейер сборки в основном полагался бы на плагин Spring Boot Gradle для создания uber-jar (термин, который часто используется для описания техники создания единственного исполняемого JAR-архива приложения), который позже будет использоваться Palantir Docker Gradle для сборки образа Docker . Вот как выглядит определение сборки, файл build.gradle
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
buildscript { repositories { } dependencies { classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.M6" } } plugins { id 'com.palantir.docker' version '0.13.0' } apply plugin: "org.springframework.boot" apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'application' sourceCompatibility = 1.8 targetCompatibility = 1.8 dependencies { compile( "org.flywaydb:flyway-core:4.2.0" ) compile( "org.springframework.boot:spring-boot-starter-webflux:2.0.0.M6" ) compile( "org.springframework.boot:spring-boot-starter-data-jpa:2.0.0.M6" ) compile( "org.springframework.boot:spring-boot-starter-actuator:2.0.0.M6" ) compile( "mysql:mysql-connector-java:8.0.7-dmr" ) } repositories { maven { mavenCentral() } } springBoot { mainClassName = "com.javacodegeeks.spring.AppStarter" } jar { mainClassName = "com.javacodegeeks.spring.AppStarter" baseName = 'spring-boot-webapp ' version = project.version } bootJar { baseName = 'spring-boot-webapp ' version = project.version } docker { name "jcg/spring-boot-webapp:$project.version" tags 'latest' dependsOn build files bootJar dockerfile file( 'src/main/docker/Dockerfile' ) buildArgs([BUILD_VERSION: project.version]) } |
Это на самом деле довольно просто, все мясо в основном находится в разделе build.gradle
файла build.gradle
. Вы также можете заметить, что мы используем наш собственный Dockerfile , src/main/docker/Dockerfile
, чтобы предоставить Docker инструкции по созданию образа.
01
02
03
04
05
06
07
08
09
10
11
|
FROM openjdk:8-jdk-alpine ARG BUILD_VERSION ENV DB_HOST localhost ENV DB_PORT 3306 ADD spring-boot-webapp-${BUILD_VERSION}.jar spring-boot-webapp.jar EXPOSE 19900 ENTRYPOINT exec java $JAVA_OPTS -Ddb.host=$DB_HOST -Ddb.port=$DB_PORT -jar /spring-boot-webapp .jar |
Действительно, так просто, как только можно. Обратите внимание, как мы используем инструкцию ARG (и настройку build.gradle
файле build.gradle
) для передачи аргументов в изображение. В этом случае мы передаем версию проекта, чтобы найти окончательные артефакты сборки. Еще одна интересная деталь, на которую стоит обратить внимание, — это использование инструкций ENV для соединения хоста и порта экземпляра MySQL для подключения. И, как вы уже догадались, инструкция EXPOSE информирует Docker о том, что контейнер прослушивает порт 19900
во время выполнения.
Круто, а что дальше? Ну, нам просто нужно запустить нашу сборку Gradle , вот так:
1
2
3
4
|
> gradle clean docker dockerTag ... BUILD SUCCESSFUL in 12s 15 actionable tasks: 14 executed, 1 up-to- date |
Задача dockerTag
самом деле не нужна, но из-за этой проблемы, о которой сообщалось в отношении плагина Palantir Docker Gradle, мы должны явно вызвать его, чтобы правильно dockerTag
наше изображение. Давайте проверим, есть ли у нас изображение, доступное локально.
1
2
3
4
5
|
> docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE jcg /spring-boot-webapp 0.0.1-SNAPSHOT 65057c7ae9ba 21 seconds ago 133MB jcg /spring-boot-webapp latest 65057c7ae9ba 21 seconds ago 133MB ... |
Хорошо, новый образ есть прямо из духовки. Мы можем запустить его немедленно, используя инструмент командной строки docker , но сначала нам нужно, чтобы где-то был доступен контейнер MySQL . К счастью, мы делали это уже столько раз, что это нас не озадачит.
1
2
3
4
5
6
|
docker run -- rm -d \ --name mysql \ -e MYSQL_ROOT_PASSWORD= 'p$ssw0rd' \ -e MYSQL_DATABASE=my_app_db \ -e MYSQL_ROOT_HOST=% \ mysql:8.0.2 |
Теперь мы готовы запустить наше приложение в виде контейнера Docker . Есть несколько способов, которыми мы могли бы ссылаться на контейнер MySQL , при этом определяемая пользователем сеть является предпочтительным вариантом. Для простых случаев, подобных нашему, мы можем просто обратиться к нему, назначив DB_HOST
среды DB_HOST
IP-адрес работающего контейнера MySQL , например:
1
2
3
4
5
|
docker run -d -- rm \ --name spring-boot-webapp \ -p 19900:19900 \ -e DB_HOST=`docker inspect -- format '{{ .NetworkSettings.IPAddress }}' mysql` \ jcg /spring-boot-webapp :0.0.1-SNAPSHOT |
Сопоставив порт 19900
от контейнера к хосту, мы могли общаться с нашим приложением, получая доступ к его REST (ful) API из curl, используя localhost
качестве имени хоста. Давайте сделаем это прямо сейчас.
01
02
03
04
05
06
07
08
09
10
11
|
$ curl -X POST http: //localhost :19900 /tasks \ -d '[{"title": "Task #1", "description": "Sample Task"}]' \ -H "Content-Type: application/json" [ { "id" :1, "title" : "Task #1" , "description" : "Sample Task" } ] |
1
2
3
4
5
6
7
8
9
|
$ curl http: //localhost :19900 /tasks [ { "id" :1, "title" : "Task #1" , "description" : "Sample Task" } ] |
1
2
3
4
5
6
7
|
$ curl http: //localhost :19900 /tasks/1 { "id" :1, "title" : "Task #1" , "description" : "Sample Task" } |
Под капотом много движущихся частей, например, автоматическая миграция базы данных с использованием Flyway и встроенная поддержка проверки работоспособности с помощью Spring Boot Actuator . Некоторые из них появятся в следующих разделах руководства, но посмотрите, насколько просто и естественно создать и упаковать свои приложения Spring Boot в виде образов Docker с помощью Gradle .
4. Gradle на докере
Оказывается, что создание образов Docker с помощью Gradle совсем не больно. Но все же, для того, чтобы Gradle был установлен в целевой системе вместе с JDK / JRE, требуется некоторая предварительная работа. Это может быть не проблема, скажем, для разработки, так как очень вероятно, что вы все равно (и многие другие) были бы установлены.
Однако в случае облачных развертываний или конвейеров CI / CD это может быть проблемой, что может повлечь за собой дополнительные затраты с точки зрения работы и / или обслуживания. Можем ли мы найти способ избавиться от таких издержек и полностью положиться на Docker ? Да, фактически мы можем, приняв многоэтапные сборки , одно из недавних дополнений в наборе функций Docker .
Если вам интересно, как это может помочь нам, вот идея. По сути, мы собираемся следовать обычной процедуре создания образа из Dockerfile . Но Dockerfile на самом деле будет содержать два определения изображений. Первый (основанный на одном из официальных образов Gradle ) инструктирует Docker запустить сборку Gradle нашего приложения Spring Boot . Второй выбрал бы двоичные файлы, созданные первым изображением, и создал окончательный образ Docker с нашим приложением Spring Boot, запечатанным внутри (так же, как мы делали раньше).
Возможно, лучше один раз увидеть, чем пытаться объяснить. Файл Dockerfile.build
ниже иллюстрирует эту идею в действии, используя инструкции многоступенчатой сборки .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
FROM gradle:4.3.0-jdk8-alpine ADD src src ADD build.gradle . ADD gradle.properties . RUN gradle build FROM openjdk:8-jdk-alpine ARG BUILD_VERSION ENV DB_HOST localhost ENV DB_PORT 3306 COPY --from=0 /home/gradle/build/libs/spring-boot-webapp- ${BUILD_VERSION}.jar spring-boot-webapp.jar EXPOSE 19900 ENTRYPOINT exec java $JAVA_OPTS -Ddb.host=$DB_HOST -Ddb.port=$DB_PORT -jar /spring-boot-webapp .jar |
Первая часть определения Dockerfile описывает изображение на основе gradle:4.3.0-jdk8-alpine
. Поскольку наш проект довольно мал, мы просто копируем все источники внутри образа и запускаем gradle build
(эта команда будет выполняться Docker во время gradle build
образа). Результатом сборки будет uber-jar, который мы openjdk:8-jdk-alpine
в другое определение изображения, на этот раз на основе openjdk:8-jdk-alpine
. Это составило бы наше окончательное изображение, которое мы могли бы создать, используя инструмент командной строки docker .
1
2
3
4
5
|
docker image build \ --build-arg BUILD_VERSION=0.0.1-SNAPSHOT \ -f Dockerfile.build \ -t jcg /spring-boot-webapp :latest \ -t jcg /spring-boot-webapp :0.0.1-SNAPSHOT . |
После командного соревнования мы должны увидеть наше недавно испеченное изображение в списке доступных изображений Docker .
1
2
3
4
5
|
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE jcg /spring-boot-webapp 0.0.1-SNAPSHOT 02abf724da64 10 seconds ago 133MB jcg /spring-boot-webapp latest 02abf724da64 10 seconds ago 133MB ... |
Многоуровневые сборки имеют большой потенциал, но даже для такого простого приложения, как наше, они заслуживают внимания.
5. Мавен и Докер
Давайте немного переключимся и посмотрим, как Apache Maven использует управление сборкой для приложений Dropwizard . Для этого подраздела вам потребуется установить Apache Maven 3.2.5
на компьютере разработчика (однако, если у вас уже установлен Apache Maven 3.2.1
или более поздней версии, вы можете просто придерживаться его).
Шаги, которые мы должны выполнить, в основном идентичны тем, что мы обсуждали для сборок Gradle , изменения в основном только в плагинах:
- Плагин Maven Shade
- Плагин Spotify Docker Maven
Плагин Maven Shade создает uber-jar, который позже будет использоваться плагином Spotify Docker Maven для создания образа Docker . Без суеты, давайте посмотрим на файл pom.xml
.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
< project xmlns = http ://maven.apache.org/POM/4.0.0 xmlns:xsi = http ://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 < modelVersion >4.0.0</ modelVersion > < groupId >com.javacodegeeks</ groupId > < artifactId >dropwizard-webapp</ artifactId > < version >0.0.1-SNAPSHOT</ version > < packaging >jar</ packaging > < properties > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > </ properties > < dependencyManagement > < dependencies > < dependency > < groupId >io.dropwizard</ groupId > < artifactId >dropwizard-bom</ artifactId > < version >1.2.0</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > < dependencies > < dependency > < groupId >io.dropwizard</ groupId > < artifactId >dropwizard-core</ artifactId > </ dependency > < dependency > < groupId >io.dropwizard</ groupId > < artifactId >dropwizard-hibernate</ artifactId > </ dependency > < dependency > < groupId >mysql</ groupId > < artifactId >mysql-connector-java</ artifactId > < version >8.0.7-dmr</ version > </ dependency > < dependency > < groupId >io.dropwizard.modules</ groupId > < artifactId >dropwizard-flyway</ artifactId > < version >1.2.0-1</ version > </ dependency > < dependency > < groupId >com.google.guava</ groupId > < artifactId >guava</ artifactId > </ dependency > < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < scope >test</ scope > </ dependency > </ dependencies > < build > < plugins > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-compiler-plugin</ artifactId > < version >3.1</ version > < configuration > < source >1.8</ source > < target >1.8</ target > </ configuration > </ plugin > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-jar-plugin</ artifactId > < version >3.0.2</ version > < configuration > < archive > < manifest > < mainClass >com.javacodegeeks.docker.AllApiApp</ mainClass > </ manifest > </ archive > </ configuration > </ plugin > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-shade-plugin</ artifactId > < version >3.1.0</ version > < configuration > < filters > < filter > < artifact >*:*</ artifact > < excludes > < exclude >META-INF/*.SF</ exclude > < exclude >META-INF/*.DSA</ exclude > < exclude >META-INF/*.RSA</ exclude > </ excludes > </ filter > </ filters > </ configuration > < executions > < execution > < phase >package</ phase > < goals > < goal >shade</ goal > </ goals > < configuration > < transformers > < transformer implementation = "org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" /> < transformer implementation = "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" > < mainClass >com.javacodegeeks.dw.AppStarter</ mainClass > </ transformer > </ transformers > </ configuration > </ execution > </ executions > </ plugin > < plugin > < groupId >com.spotify</ groupId > < artifactId >docker-maven-plugin</ artifactId > < version >1.0.0</ version > < configuration > < imageName >jcg/dropwizard-webapp:${project.version}</ imageName > < dockerDirectory >src/main/docker</ dockerDirectory > < resources > < resource > < targetPath >/</ targetPath > < directory >${project.build.directory}</ directory > < include >${project.build.finalName}.jar</ include > </ resource > < resource > < targetPath >/</ targetPath > < directory >${project.basedir}</ directory > < include >application.yml</ include > </ resource > </ resources > < buildArgs > < BUILD_VERSION >${project.version}</ BUILD_VERSION > </ buildArgs > < imageTags > < tag >latest</ tag > </ imageTags > </ configuration > </ plugin > </ plugins > </ build > </ project > |
Честно говоря, это выглядит значительно более многословно, чем сборка Gradle , но если мы на секунду представим, что все теги XML пропали, мы получим в основном идентичное определение, по крайней мере, в случае плагинов Docker . Dockerfile немного отличается, хотя:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
FROM openjdk:8-jdk-alpine ARG BUILD_VERSION ENV DB_HOST localhost ENV DB_PORT 3306 ADD dropwizard-webapp-${BUILD_VERSION}.jar dropwizard-webapp.jar ADD application.yml application.yml ADD docker-entrypoint.sh docker-entrypoint.sh RUN chmod a+x /docker-entrypoint .sh EXPOSE 19900 19901 ENTRYPOINT [ "/docker-entrypoint.sh" ] |
Из-за особенностей приложения Dropwizard , мы должны связать файл конфигурации, в нашем случае application.yml
, вместе с приложением. Вместо того, чтобы выставлять только один порт 19900
, мы должны выставить другой, 19901
, для административных задач. И последнее, но не менее важное: мы предоставляем скрипт для инструкции ENTRYPOINT , docker-entrypoint.sh
.
01
02
03
04
05
06
07
08
09
10
|
#!/bin/sh set -e java $JAVA_OPTS -DDB_HOST=$DB_HOST -DDB_PORT=$DB_PORT -jar /dropwizard-webapp .jar db migrate application.yml if [ ! $? - ne 0 ]; then exec java $JAVA_OPTS -DDB_HOST=$DB_HOST -DDB_PORT=$DB_PORT -jar /dropwizard-webapp .jar server application.yml fi exec "$@" |
Причиной добавления некоторой сложности здесь является то, что по умолчанию пакет дополнений Dropwizard Flyway не выполняет автоматическую миграцию схемы базы данных. Мы могли бы обойти это, но самый простой способ — запустить команду db migrate
перед запуском приложения Dropwizard . Это именно то, что мы делаем внутри сценария оболочки выше. Теперь пришло время запустить сборку!
01
02
03
04
05
06
07
08
09
10
11
12
|
> mvn clean package docker:build ... Successfully tagged jcg /dropwizard-webapp :0.0.1-SNAPSHOT [INFO] Built jcg /dropwizard-webapp :0.0.1-SNAPSHOT [INFO] Tagging jcg /dropwizard-webapp :0.0.1-SNAPSHOT with latest [INFO] --------------------------------------------------------- [INFO] BUILD SUCCESS [INFO] --------------------------------------------------------- ... |
Давайте посмотрим, будет ли наше изображение доступно локально на этот раз.
1
2
3
4
5
|
> docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE jcg /dropwizard-webapp 0.0.1-SNAPSHOT fa9c310683b1 20 seconds ago 128MB jcg /dropwizard-webapp latest fa9c310683b1 20 seconds ago 128MB ... |
Отлично, предполагая, что контейнер MySQL запущен и работает (эта часть не меняется вообще, мы могли бы использовать ту же команду из предыдущего раздела ), мы могли бы просто запустить наш контейнер приложения Dropwizard .
1
2
3
4
5
6
|
docker run -d -- rm \ --name dropwizard-webapp \ -p 19900:19900 \ -p 19901:19901 \ -e DB_HOST=`docker inspect -- format '{{ .NetworkSettings.IPAddress }}' mysql` \ jcg /dropwizard-webapp :0.0.1-SNAPSHOT |
Мы также отображаем порты 19900
и 19901
из контейнера на хост, чтобы мы могли использовать localhost
качестве имени хоста в curl .
01
02
03
04
05
06
07
08
09
10
11
|
$ curl -X POST http: //localhost :19900 /tasks \ -d '[{"title": "Task #1", "description": "Sample Task"}]' \ -H "Content-Type: application/json" [ { "id" :1, "title" : "Task #1" , "description" : "Sample Task" } ] |
1
2
3
4
5
6
7
8
9
|
$ curl http: //localhost :19900 /tasks [ { "id" :1, "title" : "Task #1" , "description" : "Sample Task" } ] |
1
2
3
4
5
6
7
|
$ curl http: //localhost :19900 /tasks/1 { "id" :1, "title" : "Task #1" , "description" : "Sample Task" } |
Обратите внимание, что при сопоставлении портов хоста мы можем запустить либо jcg/dropwizard-webapp:0.0.1-SNAPSHOT
либо контейнер jcg/spring-boot-webapp:0.0.1-SNAPSHOT
, но не оба одновременно, так как к неизбежным конфликтам портов. Мы просто используем один и тот же порт для удобства, но в большинстве случаев вы будете использовать динамические привязки портов и не увидите, что эта проблема происходит.
6. Maven на докере
Та же техника использования многоэтапных сборок в равной степени применима к проектам, которые используют Apache Maven для сборки и управления зависимостями (к счастью, существуют официальные изображения Apache Maven, опубликованные на Docker Hub ).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
FROM maven:3.5.2-jdk-8-alpine ADD src src ADD pom.xml . RUN mvn package FROM openjdk:8-jdk-alpine ARG BUILD_VERSION ENV DB_HOST localhost ENV DB_PORT 3306 COPY --from=0 /target/dropwizard-webapp- ${BUILD_VERSION}.jar dropwizard-webapp.jar ADD application.yml application.yml ADD src /main/docker/docker-entrypoint .sh docker-entrypoint.sh RUN chmod a+x /docker-entrypoint .sh EXPOSE 19900 19901 ENTRYPOINT [ "/docker-entrypoint.sh" ] |
Немного добавить сюда, когда мы взломали работу многоступенчатых сборок , поэтому давайте создадим окончательный образ с помощью инструмента командной строки docker .
1
2
3
4
5
|
docker image build \ --build-arg BUILD_VERSION=0.0.1-SNAPSHOT \ -f Dockerfile.build \ -t jcg /dropwizard-webapp :latest \ -t jcg /dropwizard-webapp :0.0.1-SNAPSHOT . |
И убедитесь, что изображение появляется в списке доступных изображений Docker .
1
2
3
4
5
|
> docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE jcg /dropwizard-webapp 0.0.1-SNAPSHOT 5b006fcc9a1d 26 seconds ago 128MB jcg /dropwizard-webapp latest 5b006fcc9a1d 26 seconds ago 128MB ... |
Это довольно круто, если честно. Прежде чем закончить обсуждение многоэтапных сборок , давайте коснемся варианта использования, с которым вы наверняка столкнетесь: проверка проекта из системы контроля версий. Примеры, которые мы видели до сих пор, предполагают, что проект доступен локально, но мы могли бы клонировать его из удаленного репозитория как часть определения многоступенчатых сборок .
7. Выводы
В этом разделе руководства мы увидели несколько примеров того, как популярные инструменты управления сборкой и зависимостями, а именно Apache Maven и Gradle , поддерживают упаковку приложений Java в виде образов Docker . Мы также потратили некоторое время на обсуждение многоэтапных сборок и возможностей, которые они открывают для реализации переносимых конвейеров сборки с нулевой зависимостью (буквально!).
8. Что дальше
В следующем разделе руководства мы рассмотрим, как Docker может упростить процессы и практики разработки, особенно в отношении работы с хранилищами данных и внешними (или даже внутренними) сервисами.
Полные исходные коды проекта доступны для скачивания .