Разработка контейнеров с помощью Dockerfiles

1. Обзор

Docker — это открытая платформа для разработки, распространения и запуска приложений. С помощью Docker вы можете отделить свои приложения от инфраструктуры и рассматривать инфраструктуру как управляемое приложение. Docker помогает быстрее распространять код, быстрее тестировать, быстрее развертывать и сокращать цикл между написанием и запуском кода.

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

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

Что вы узнаете

В этой лабораторной работе вы научитесь выполнять следующие действия:

  • Создайте Dockerfile для тестового приложения.
  • Создать изображение
  • Запустите образ локально в качестве контейнера.
  • Изменение поведения контейнера
  • Загрузите образ в реестр артефактов.

Предварительные требования

Это лабораторная работа начального уровня. Предполагается минимальный или нулевой опыт работы с Docker и контейнерами. Знание Cloud Shell и командной строки желательно, но не обязательно.

Настройка среды для самостоятельного обучения

  1. Войдите в консоль Google Cloud и создайте новый проект или используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Название проекта — это отображаемое имя участников данного проекта. Это строка символов, не используемая API Google, и вы можете изменить её в любое время.
  • Идентификатор проекта должен быть уникальным для всех проектов Google Cloud и неизменяемым (его нельзя изменить после установки). Консоль Cloud автоматически генерирует уникальную строку; обычно вам неважно, какая она. В большинстве практических заданий вам потребуется указать идентификатор проекта (обычно он обозначается как PROJECT_ID ), поэтому, если он вам не нравится, сгенерируйте другой случайный идентификатор или попробуйте свой собственный и посмотрите, доступен ли он. Затем он "замораживается" после создания проекта.
  • Существует третье значение — номер проекта , который используется некоторыми API. Подробнее обо всех трех значениях можно узнать в документации .
  1. Далее вам потребуется включить оплату в консоли Cloud, чтобы использовать ресурсы/API Cloud. Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Чтобы отключить ресурсы и избежать дополнительных расходов после завершения этого урока, следуйте инструкциям по «очистке», приведенным в конце практического задания. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .

2. Пример приложения

Для упрощения выполнения этого лабораторного задания предоставлен пример приложения. В этом разделе вы получите исходный код и соберете приложение в его нативном виде, прежде чем перейти к процессу контейнеризации.

Исходный код

Исходный код для этой лабораторной работы доступен в репозитории GoogleCloudPlatform/container-developer-workshop вместе с документацией к примеру приложения .

Настройка Git

git config --global user.name ${USER}
git config --global user.email ${USER}@qwiklabs.net

Клонируйте репозиторий исходного кода демонстрационного приложения Cloud Source Repository.

gcloud source repos clone sample-app ${HOME}/sample-app &&
cd ${HOME}/sample-app &&
git checkout main

Выход

Cloning into '/home/student_03_49720296e995/sample-app'...
remote: Finding sources: 100% (16/16)
remote: Total 16 (delta 0), reused 16 (delta 0)
Receiving objects: 100% (16/16), 47.23 KiB | 681.00 KiB/s, done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.

Project [qwiklabs-gcp-02-4327c4e03d82] repository [sample-app] was cloned to [/home/student_03_49720296e995/sample-app].
Branch 'main' set up to track remote branch 'main' from 'origin'.
Switched to a new branch 'main'

Соберите демонстрационное приложение

cd ${HOME}/sample-app
./mvnw compile

Выход

[INFO] Scanning for projects...
...
[INFO] Compiling 1 source file to /home/student_03_49720296e995/sample-app/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.080 s
[INFO] Finished at: 2022-02-23T17:14:30Z
[INFO] ------------------------------------------------------------------------

Запустите демонстрационное приложение

cd ${HOME}/sample-app
./mvnw exec:java

Выход

[INFO] Scanning for projects...
...
Listening at http://localhost:8080

Предварительный просмотр работающего приложения

  • Нажмите кнопку «Предварительный просмотр веб-версии Cloud Shell».
  • Нажмите «Предварительный просмотр» на порту 8080.

Когда закончите

  • Нажмите CTRL + c в Cloud Shell, чтобы остановить запущенное приложение.

3. Dockerfile

Контейнеризация приложения с помощью Dockerfile

Один из способов упаковки приложения в контейнер — использование Dockerfile. Dockerfile похож на скрипт, который инструктирует демона, как собрать образ контейнера. Дополнительную информацию см. в справочной документации по Dockerfile .

Создайте пустой Dockerfile в репозитории примера приложения.

touch ${HOME}/sample-app/Dockerfile

Откройте Dockerfile в любом удобном для вас редакторе.

vi ${HOME}/sample-app/Dockerfile

Выберите начальное изображение

Для сборки контейнера с помощью Dockerfile требуется непосредственное знание приложения. Первый шаг к созданию Dockerfile — выбор образа, который будет использоваться в качестве основы для вашего контейнера. Этот образ должен быть родительским или базовым образом, поддерживаемым и публикуемым надежным источником, обычно вашей компанией.

Инструкция FROM инициализирует новый этап сборки и устанавливает базовый образ для последующих команд. Таким образом, инструкция FROM обычно является первой инструкцией в Dockerfile и может предшествовать только необязательной инструкцией ARG для поддержки переменных.

Синтаксис: FROM <image>[:<tag> | @<digest>] [AS <name>]

Формат образа — <image>:<tag> или <image>@<digest> . Если тег или дайджест не указаны, по умолчанию используется тег :latest . Формат <image> зависит от используемого реестра для хранения образа. Для Artifact Registry формат <image><region>-docker.pkg.dev/<project ID>/<repository name>/<image name>:<image tag> .

Для этой лабораторной работы мы используем общедоступный образ openjdk:11.0-jdk . Добавьте следующую строку в свой Dockerfile.

FROM openjdk:11.0-jdk

Укажите рабочий каталог

Инструкция WORKDIR задает рабочий каталог для всех последующих инструкций в Dockerfile. Дополнительную информацию см. в разделе WORKDIR справочной документации по Dockerfile.

Синтаксис: WORKDIR <path>

Для этой лабораторной работы мы используем каталог /app в качестве рабочей директории WORKDIR . Добавьте следующую строку в конец вашего Dockerfile.

WORKDIR /app

Скопируйте файлы приложения.

Инструкция COPY копирует каталоги или файлы из расположения <source> в путь <destination> файловой системы образа. Можно указать несколько ресурсов <source> , и все они являются относительными к контексту сборки. Контекст сборки будет более подробно рассмотрен в разделе «Сборка». Для получения дополнительной информации см. раздел COPY в справочной документации Dockerfile.

Синтаксис: COPY <source>... <destination>

Для этой лабораторной работы мы скопируем все файлы из репозитория в файловую систему образа. Добавьте следующую строку в конец вашего Dockerfile.

COPY . /app

Скомпилируйте приложение

Инструкция RUN выполняет команды в новом слое образа поверх текущего образа и фиксирует результаты. Полученный зафиксированный образ будет использоваться для последующих шагов в Dockerfile. Для получения дополнительной информации см. раздел RUN в справочной документации по Dockerfile.

Синтаксис: RUN <command>

Для этой лабораторной работы мы будем использовать Maven для компиляции приложения в JAR-файл. Добавьте следующую строку в конец вашего Dockerfile.

RUN ./mvnw compile assembly:single

Запустите приложение

Инструкция CMD задает команду по умолчанию для запущенного контейнера. В Dockerfile может быть только одна инструкция CMD; если указано несколько инструкций CMD, то будет действовать только последняя. Более расширенные возможности доступны при использовании инструкций CMD и ENTRYPOINT, но они не рассматриваются в данной лабораторной работе. Для получения дополнительной информации см. раздел CMD в справочной документации по Dockerfile.

Синтаксис: CMD ["executable","param1","param2"]

Для выполнения этой лабораторной работы мы запустим скомпилированный JAR-файл. Добавьте следующую строку в конец вашего Dockerfile.

CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

Итоговый Dockerfile

Итоговый Dockerfile будет выглядеть следующим образом:

FROM openjdk:11.0-jdk
WORKDIR /app
COPY . /app
RUN ./mvnw compile assembly:single
CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

Зафиксируйте изменения в Dockerfile локально.

cd ${HOME}/sample-app
git add Dockerfile
git commit -m "Added Dockerfile"

4. Построить

Теперь мы соберем образ из Dockerfile, используя команду docker build . Эта команда указывает демону Docker собрать образ, используя инструкции из нашего Dockerfile. Дополнительную информацию см. в справочной документации по команде `docker build` .

Создайте образ

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker build --tag sample-app:${IMAGE_TAG} .

Выход

Sending build context to Docker daemon  221.2kB
Step 1/4 : FROM openjdk:11.0-jdk
11.0-jdk: Pulling from library/openjdk
0c6b8ff8c37e: Pull complete
412caad352a3: Pull complete
e6d3e61f7a50: Pull complete
461bb1d8c517: Pull complete
e442ee9d8dd9: Pull complete
542c9fe4a7ba: Pull complete
41de18d1833d: Pull complete
Digest: sha256:d72b1b9e94e07278649d91c635e34737ae8f181c191b771bde6816f9bb4bd08a
Status: Downloaded newer image for openjdk:11.0-jdk
---> 2924126f1829
Step 2/4 : WORKDIR /app
---> Running in ea037abb273d
Removing intermediate container ea037abb273d
---> bd9b6d078082
Step 3/4 : COPY . /app
---> b9aec2b5de51
Step 4/4 : RUN ./mvnw compile jar:jar
---> Running in 3f5ff737b7fd
[INFO] Scanning for projects...
...
[INFO] Building jar: /app/target/sample-app-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  22.952 s
[INFO] Finished at: 2022-02-23T18:09:08Z
[INFO] ------------------------------------------------------------------------
Removing intermediate container 331443caebd3
---> 152f65cc441e
Step 5/5 : CMD ["java", "-jar", "/app/target/sample-app-1.0.0.jar"]
---> Running in 3d595a72231c
Removing intermediate container 3d595a72231c
---> 0e40d7548cab
Successfully built 0e40d7548cab
Successfully tagged sample-app:aaa8895

5. Бег

После успешной сборки образа контейнера мы можем запустить наше приложение и убедиться, что оно работает должным образом, используя команду `docker run`. Эта команда запустит наш контейнер в фоновом режиме командной строки для тестирования или отладки. Дополнительную информацию см. в справочной документации по команде `docker run` .

Запустите контейнер, используя образ.

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG}

Выход

Listening at http://localhost:8080

Предварительный просмотр приложения, работающего в контейнере.

  • Нажмите кнопку «Предварительный просмотр веб-версии Cloud Shell».
  • Нажмите «Предварительный просмотр» на порту 8080.
  • Нажмите CTRL + c в Cloud Shell, чтобы остановить контейнеры.

Изменение поведения контейнера

При выполнении команды `docker run` используется конфигурация по умолчанию, указанная в файле Dockerfile. Для изменения этого поведения можно добавить дополнительные инструкции и параметры.

Включить трассировочное логирование

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG} \
  java -Dorg.slf4j.simpleLogger.defaultLogLevel=trace -jar /app/target/sample-app-1.0.0-jar-with-dependencies.jar

Предварительный просмотр приложения, работающего в контейнере.

  • Нажмите кнопку «Предварительный просмотр веб-версии Cloud Shell».
  • Нажмите «Предварительный просмотр» на порту 8080.
  • Перейдите на вкладку Cloud Shell и посмотрите дополнительные записи в журнале.
  • Нажмите CTRL + c в Cloud Shell, чтобы остановить контейнер.

Изменить порт

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
--rm \
-e PORT=8081 \
-p 8081:8081 \
sample-app:${IMAGE_TAG}

Предварительный просмотр приложения, работающего в контейнере.

  • Нажмите кнопку «Предварительный просмотр веб-версии Cloud Shell».
  • Нажмите «Изменить порт».
  • Введите 8081
  • Нажмите «Изменить» и «Предварительный просмотр».
  • Нажмите CTRL + c в Cloud Shell, чтобы остановить контейнер.

6. Толчок

Убедившись, что образ контейнера работает корректно, и желая сделать этот контейнер доступным для запуска в других средах и/или другими пользователями, необходимо загрузить образ в общий репозиторий. Это должно происходить в рамках автоматизированного конвейера сборки, но в нашей тестовой среде репозиторий уже настроен, и мы можем загрузить образ вручную.

Отправьте коммит с Dockerfile в репозиторий sample-app.

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
git push

Добавьте изображение в реестр артефактов.

docker tag sample-app:${IMAGE_TAG} \
    us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

Настройте учетные данные для реестра артефактов.

gcloud auth configure-docker us-central1-docker.pkg.dev

Когда появится запрос Do you want to continue (Y/n)? ответьте y и нажмите Enter

Загрузите образ в реестр артефактов.

docker push us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

Выход

 The push refers to repository [us-central1-docker.pkg.dev/qwiklabs-gcp-04-b47ced695a3c/apps/sample-app]
  453b97f86449: Pushed
  e86791aa0382: Pushed
  d404c7ee0850: Pushed
  fe4f44af763d: Pushed
  7c072cee6a29: Pushed
  1e5fdc3d671c: Pushed
  613ab28cf833: Pushed
  bed676ceab7a: Pushed
  6398d5cccd2c: Pushed
  0b0f2f2f5279: Pushed
  aaa8895: digest: sha256:459de00f86f159cc63f98687f7c9563fd65a2eb9bcc71c23dda3351baf13607a size: 2424

7. Поздравляем!

Поздравляем, вы завершили практическое занятие!

Что вы уже рассмотрели

  • Создан Dockerfile для тестового приложения.
  • Создан образ
  • Запустил образ локально в качестве контейнера.
  • Изменено поведение контейнера.
  • Образ загружен в реестр артефактов.