📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Docker и Kubernetes глазами разработчика

Eugene Suleimanov2:46:22

Transcription

Всем привет! С вами Евгений Сулейманов, и это курс "Докер и Кубернетес с глазами разработчика".

Дисклеймер: Всё сказанное в данном видео является оценочным суждением автора и ни коим образом не связано с компаниями, с которыми автор сотрудничает. Цель данного видео — это дать теоретические основы и практические навыки работы с Докер и Кубернетес.

Немного о себе: более 10 лет опыта в разработке, занимаюсь созданием промышленных систем, написанием кода, и также публикую обучающие материалы, статьи, видео.

План нашего курса будет следующим: сначала будет введение в курс, в рамках которого мы ознакомимся с небольшими правилами, которые позволят проходить данный курс более эффективно. Далее мы разберём модули, которые будут в рамках нашего курса. После этого мы с вами разберём, что такое Докер образы, что такое контейнеры, поработаем с волюмами, а же томами. Далее мы перейдём к сетевому взаимодействию контейнеров. Далее мы с вами создадим Compose, разберём детальнее докеризацию Spring Boot REST API и попробуем всё это задеплоить в AWS.

После этого мы перейдём к Кубернетес. У нас будет введение в Кубернетес, разбор основных концепций. Далее будет развёртывание и работа с Кубер кластером на локальной машине. Далее работа с томами, которые относятся уже к Кубернетес. Рассмотрим сетевое взаимодействие в рамках Кубера, и потом будет небольшое заключение, рекомендации по работе с курсом.

Весь курс разбит на небольшие части, которые отмечены таймкодами. Я рекомендую просмотреть конкретный раздел видео, после этого скачать исходный код учебного проекта, который рассмотрен в рамках данной части, далее повторить действия, которые были выполнены в видео. Каждый этап, кроме того, что это есть на видео, он отмечен и находится в отдельной ветке Git репозитория, который мы рассматриваем. Там будет Step 1, Step 2, Step 3 и коммит сообщение, которое описывает, что было сделано. Ссылки на все Git репозитории будут в описании к этому видео. Далее мы проверяем работоспособность приложения после выполнения задания каждого модуля и подмодуля. И если у вас всё-таки будут вопросы, то ответ на них вы можете увидеть в комментариях после того, как вы их туда зададите.

Что будет изучено в курсе? То есть мы с вами разберём ещё раз детальнее основы Докера, использование Докера в промышленной разработке с точки зрения именно разработчика, как инженера, не DevOps, не тестировщика, а именно разработчика. Далее мы перейдём к основам Кубернетес, и после этого мы рассмотрим использование Кубернетес в промышленной разработке, как это выглядит схематично. То есть основы Докера, здесь мы будем рассматривать с вами образы и контейнеры. Далее будет работа с данными, волюмы, и потом будет сетевое взаимодействие контейнеров. После этого мы рассмотрим, как же Докер используется в промышленной разработке, то есть мы посмотрим, как мы можем настроить приложение, в котором мы работаем с несколькими контейнерами. После этого мы перейдём к использованию Docker Compose. И далее мы попробуем задеплоить эти Docker контейнеры.

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

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

Что же такое Docker? Docker — это технология контейнеризации, которая обеспечивает нам создание и управление контейнерами. То есть это очень важный момент, чтобы вы не думали, что Docker может что-то за пределами этого. Далее, когда мы говорим о контейнере, мы подразумеваем какую-то стандартную рабочую единицу. То есть, например, Java JDK, какое-то Java приложение и JDK, которое есть вместе с этим приложением. Контейнер также имеет одинаковое поведение в любом окружении, которое способно его запустить. То есть, если я запущу на своей машине какой-то контейнер, вы запустите, у нас будет с вами абсолютно одинаковое поведение. Далее, большинство современных операционных систем, они как раз и поддерживают работу с контейнерами. То есть Docker — это крайне популярная технология, которая решает целый ряд задач. То есть очень часто, когда вы рассматриваете Docker, вы можете видеть либо такую картинку, либо ещё используют как контейнер, потому что очень хорошая аналогия, что есть какая-то коробка, которую можно переместить куда угодно, переместить много на чём, как на корабле, на самолёте, на грузовике, и потом его использовать, открыть и уже работать с ним.

Какие преимущества есть у контейнеров? То есть контейнеры, во-первых, позволяют нам задавать детали окружения так, как мы хотим. Тестировать работу нашего приложения на том же окружении, на котором оно будет запущено. То есть мы можем воссоздать абсолютно всё: операционную систему, версии каких-то средств сборки, версии языка и прочее. Далее, Docker даёт нам возможность поделиться нашим рабочим окружением как с членами команды, так и в компании, так и с другим разработчиком, если вы публикуете какой-то публичный артефакт и прочее. Далее, Docker даёт нам возможность легко переключаться между подпроектами, потому что более зрелые проекты могут работать на более старых версиях, и также в рамках одного большого проекта могут быть приложения, которые написаны как на разных версиях одного языка или фреймворка, так и вообще на разных системах. То есть, например, у вас есть какой-то большой проект, на котором используется в одних проектах Java 8, а на других проектах используется уже 21 Java. И чтобы вам это всё не ставить, вы можете это всё поднять через Docker и использовать готовый модуль. То есть, например, есть какой-то проект, вам не обязательно даже скачивать исходники этого проекта, вы взяли Docker образ этого проекта, вы подняли его, и уже можете с ним взаимодействовать. Это действительно очень и очень удобно.

Рассмотрим виртуальную машину как некую в кавычках альтернативу Докера, потому что очень часто и на собеседованиях спрашивают, чем отличается виртуалка от Докера, и также на форумах вы можете часто видеть сравнения. Опять-таки, все пару статей я оставлю в описании к видео. Но если в общем и целом мы можем разобрать базовые концепции, то есть виртуальная машина — это система, которая эмулирует некоторую платформу и создавать на ней среды. То есть, например, мы можем создать вообще новую машинку, которая поверх моей OS X платформы работает с Windows или с другой операционной системой. Далее, как это выглядит: есть операционная система OS X, мы устанавливаем, например, на мою машинку VirtualBox, и мы создаём две виртуальные машины. То есть у меня два компьютера: один на Debian, который я использую для работы с PostgreSQL и Redis, и я также свою другую виртуальную машинку, которая имеет у себя Windows как операционную систему, и там есть какой-то WSL.

Какие преимущества даёт нам виртуальная машина? То есть первое — это, конечно же, защита через изоляцию, потому что виртуальные машины они функционируют полностью в изолированном режиме, и они защищены от потенциальных атак. То есть, если у нас есть одна машинка, допустим, Windows, с ней что-то пошло не так, это никак не повлияет на машинку, на которой стоит Debian. Далее, интерактивное развитие. То есть контейнеры обычно представляют собой некие статические определения и требуют конфигурации и зависимостей для их запуска, а виртуальные машины они более гибкие и могут настраиваться уже в интерактивном режиме. То есть после того, как мы указали ключевые параметры виртуальной машины, её можно рассматривать как компьютер без операционной системы.

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

Docker в свою очередь позволяет нам создавать и управлять контейнерами. Как это выглядит: у нас с вами есть наша операционная система, поверх операционной системы, то есть встроенной либо установленной поверх, есть слой поддержки контейнеров, то есть нативный либо эмулятор. Далее уже поверх этого слоя поддержки контейнеров стоит движок Docker, то есть он же Docker Engine, и уже благодаря Docker Engine мы можем с вами создавать именно контейнеры. Опять-таки, детальнее, что такое контейнер и прочее, мы разберём немного далее. И соответственно, уже поверх этого Docker Engine я создаю два контейнера: первый — это PostgreSQL, второй — это Redis для моего Security.

Какие преимущества даёт нам Docker? Первое — это скорость итерации. То есть в большинстве контейнерных средств выполнения существует некий общедоступный размещённый репозиторий с готовыми контейнерами. Эти репозитории содержат много популярных приложений, баз данных, систем обмена сообщениями, брокеров и прочее, что поможет сэкономить затраты по времени наших разработчиков. И также это надёжная экосистема. То есть экосистема становится более надёжной благодаря тому, что есть общедоступный репозиторий, который можно увидеть, образы можно просканировать, и все понимают, кто, когда и что заливал.

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

Какие же ключевые компоненты Docker у нас есть? То есть первое — это Docker Engine, который мы уже только что затронули. Это как бы ядро, сердце Docker, которое нам необходимо для того, чтобы вообще всё это запустилось. Далее идёт Docker Desktop — это приложение, юзерский клиент, который упрощает нам работу с Docker. Далее компонент Docker Compose позволяет нам управлять более сложными и многоконтейнерными приложениями. То есть, если вам нужно поднять не только приложение, допустим, Java API, но и базу данных, и какой-то ещё что-то. И также Docker Hub — это компонент, который позволяет хранить наши образы не только локально на нашей машинке, а и удалённо. То есть это некий аналог GitHub для Docker образов.

Перейдём к установке Docker на вашу локальную машину. На этом слайде вы видите три ссылки, которые соответствуют ссылкам с инструкциями по установке для каждой из трёх операционных систем: это Mac, Windows и Linux. В зависимости от вашей ОС, вы переходите по нужной ссылке, выполняете простые инструкции, которые здесь указаны. Здесь вы можете видеть примерно, как это выглядит для Docker на Mac, для чипа Intel и для чипа Silicon. В зависимости от вашей конфигурации, вы выполняете эти простые команды, которые есть здесь. И после этого вам необходимо выполнить простую команду `docker --version`, которая позволит вам понять, есть ли установленный Docker на вашей машине и всё ли корректно здесь работает.

Итак, мы с вами открываем терминал, и здесь в терминале мы с вами выполняем простую команду `docker --version`. И если всё корректно и всё хорошо работает, то здесь вы видите версию Docker, которая стоит на вашей машинке. В моём случае на текущий момент это версия 2.0.0. С этого момента вы можете сказать, что на вашей машинке установлен Docker, и теперь мы с вами можем перейти к разбору сейчас ключевых компонентов Docker, и после этого вы увидите, как довольно-таки легко и быстро, без усилий, вы можете запустить практически любое приложение на вашей машине с помощью Docker.

Давайте посмотрим, как это будет выглядеть. Уверен, что вы часто слышали такой термин, как Docker образ. То есть образ — это некий шаблон в кавычках для контейнеров, на основании которого мы уже создаём с вами рабочие единицы. Данный шаблон состоит из исходного кода приложения и среды, которая необходима для его исполнения: библиотеки, инструменты, средства сборки и прочее, и прочее. Docker контейнер — это уже рабочая единица приложения, которое создаётся на основе нашего Docker образа. Как это выглядит: у нас с вами есть некий образ, который состоит из двух ключевых компонентов. В нашем случае это исходный код и среда исполнения. И потом уже на основании Docker образа мы создаём рабочий контейнер, где будет рабочее приложение. То есть, например, если мы будем рассматривать с вами следующий пример, там, где мы пишем простое Node App приложение, то там это будет исходный код нашего приложения и сама Node, которая нужна, чтобы всё это красиво взлетело. Также на основании образа может быть создано много контейнеров. То есть Docker образ один, а контейнеров рабочих юнитов будет много. То есть, например, если у нас с вами будет образ, у которого есть код Spring Boot приложения, REST API, также есть среда, которая будет состоять из Gradle как средства сборки и JDK для того, чтобы всё это работало, и мы можем создать независимых контейнера, которые будут, ну, в данном случае, просто копировать инстанс нашего приложения.

Итак, ещё поговорим про сторонние образы. Помимо наших приложений, которые мы сами пишем, существует огромная база, огромная коллекция образов популярных систем. Как я говорил раньше, это базы данных, брокеры сообщений и прочее. Для того, чтобы это использовать, мы с вами можем использовать команду `docker pull` для того, чтобы подтянуть нужный нам образ. Мы это будем повторять много раз и дальше рассмотрим детальнее. И после этого условный `docker run`, который позволяет нам запустить наше приложение. Но перед тем, как мы перейдём к этому, к сторонним образам, давайте с вами рассмотрим простой пример Node App приложение. Ветка Step 1. То есть ссылка для приложения, которое видите в описании, это Node App, и также там будет ветка Step 1. Вам стоит перейти на неё и повторить все последующие шаги, которые я сейчас буду делать.

Итак, мы с вами подтянули наш проект, мы с вами переключились на ветку Step 1. Как видите, в будущем тут будет много веток, с которыми будем плотно работать, но сейчас это ветка Step 1. Здесь у нас есть файл `gitignore`, стандартный, знакомый всем. Есть файл `package.json` для тех, кто знаком, они знают, что это файл для того, чтобы очень грубо говоря, подтянуть нужные нам зависимости и какие-то дополнительные данные, прописать описание, версию, прочее. И есть файлик `server.js`, который и запускает наше приложение. То есть в общем и целом данный проект позволит мне увидеть какую-то страничку, и на ней будет какая-то манипуляция. То есть что я вижу: я вижу, что я здесь подтягиваю сущность `body-parser`, подтягиваю какой-то непонятный `express`, то есть ну, Express по названию, то, что позволяет быстро запустить приложение. Далее вижу переменную `username`, John Doe. Далее строка 8 — это `app.listen`. Это значит, что после старта моего приложения, перейдя в браузер на страницу `localhost:4200`, я смогу увидеть наше приложение. После этого я вижу, что у меня есть какой-то `app.get('/exit')`. Это значит, что при переходе на `localhost:4200/exit` сработает метод `process.exit()`, который завершит работу моего приложения. На странице `GET`, то есть на главной странице приложения, мы увидим что-то наподобие "Привет, username". Далее, username у нас, как мы видим, это пока John Doe. Далее мы сможем опубликовать в формочке какое-то новое сообщение, то есть задать новое имя, и соответственно, мы ожидаем, что потом это имя изменится на то, которое мы с вами заменили. Также здесь есть метод `setUsername`, который здесь используется, вот `action: setUsername`, который как раз и позволяет нам, во-первых, вывести в консоль сообщение определённое и задать это имя, которое изменится. В данный момент мы не знаем ничего про Docker, мы не работали с ним, у нас нет такой возможности для того, чтобы стартовать. Даже мы с вами должны выполнить следующие команды. То есть первая команда — это `npm install`. Давайте пока закрою другие табы. То есть тут выбрали Clear. Давайте ещё раз переоткроем. После того, как мы выполнили `npm install` для того, чтобы всё это стартовать, я должен выполнить команду `npm start`. И что очень важно, для того, чтобы это выполнить, npm должен стоять на моей локальной машине. То есть, если у вас не стоит npm, то есть Node не установлена, и вы хотите запустить, вам теперь придётся это всё поднять своими руками, чтобы всё это заработало. Как понимаете, это не всегда удобно.

Итак, мы с вами стартовали приложение. Теперь давайте с вами перейдём в наш браузер. Итак, мы с вами перешли в наш браузер, и мы видим, что у нас есть `localhost:4200`. Здесь у меня есть надпись "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всёссмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция, которая говорит Docker: "Запусти на порту 4200 то, что будет на порту 4200 у этого образа". То есть у нас в Docker образе мы создаём приложение на порту 4200, но это внутренний порт, и мы хотим его сопоставить с портом, который в нашей системе. Соответственно, мы выполнив эту команду и перейдя по ссылке `localhost:4200`, должны получить наше рабочее приложение. Потом мы с вами выполним вторую команду: `docker run -p 5050:4200 node-app:latest`. Это значит, что мы увидим то же самое, то есть будет новая нода, точнее, новый под на порту `localhost:5050`, то есть то же самое, но на другом порту. Давайте попробуем это сделать. Мы переходим с нами в наш проект, и здесь я выполняю данную команду. То есть я пишу `docker run -p 4200:4200 node-app:latest`, нажимаю Enter, и мы видим, что здесь мы с вами вошли в какой-то терминал. То есть у меня пока не свободен терминал, я где-то пока заблокирован. Давайте посмотрим, что же у нас происходит сейчас на `localhost`. Если мы перейдём в браузер на нашу ссылку на порт 4200, и вот теперь, перейдя на `localhost:4200`, мы видим то же самое. У нас появляется "Привет, John Doe". И теперь я пишу "Set username", допустим, "Private". Нажимаю кнопочку "Введите имя". И теперь у меня моя надпись сменилась. То есть довольно-таки простое, примитивное приложение. Тут будет ещё какой-то тест 10000. Введём какой-то "Введите имя". Всё поменялось. Очень примитивно, очень просто. Если приду на `/exit`, то у меня моё приложение упадёт. То есть всё, не работает. Извините, приехали. Соответственно, мы бы хотели теперь сделать так, чтобы мне не нужно было устанавливать на свою локальную машину вот все моменты, вот все библиотеки, которые нам сейчас нужны. Как раз для этих целей мы и можем использовать с вами Docker.

Итак, что мы с вами сделали? Мы с вами выполнили локальный старт, где прогнали команды `npm install`, `npm start`. После этого мы можем перейти к запуску средствами Docker. Для этого я перехожу на ветку Step 2 внутри нашего проекта Node App. Для того, чтобы перейти на нашу ветку Node App, давайте мы тут всё почистим. Я делаю `git checkout Step 2`.

Итак, мы видим, что у нас есть Step 2. Смотрим `git log`. Мы видим, что мы добавили здесь Dockerfile для гибкого старта. Хорошо, пока звучит отлично. Можем пока из терминала выйти и посмотрим, что же у нас здесь есть. У нас с вами появился какой-то файл под названием `Dockerfile`. И что мы здесь видим? Мы видим с вами какие-то команды. Давайте попробуем разобрать, что же это такое. То есть здесь на строке 1 мы видим, что мы используем какой-то `FROM node:alpine AS builder`. Это означает, что я хочу подтянуть некий образ или пакет, и пока непонятно, зависимость под названием `node`, которая обзывается переменной `builder`. И мы видим значок `builder`. Это значит, что это этап сборки, то есть сборки нашего приложения, это `npm install`. Далее мы говорим, что у нас появляется некая рабочая директория уже внутри Docker с `/app`. То есть появляется `/app`. После этого мы делаем `COPY . .`. Это значит, я копирую всё, что есть здесь в моём проекте, то, что получится, внутрь этой папки `/app`. Далее я выполняю команду `npm install`. Выполнить я её могу, потому что я уже подтянул Node как средство сборки. После этого я говорю, что я хочу прокинуть наружу порт 4200, то есть экспортировать его. И после этого я говорю, что теперь для того, чтобы войти в моё приложение, мне нужно выполнить команду `npm start`. Иногда ещё используется здесь вместо `ENTRYPOINT` `CMD`, но мы будем использовать с вами `ENTRYPOINT`. То есть вроде понятно, но возникает вопрос: как же мы теперь всё это можем запустить?

Здесь мы видим какую-то команду `docker build --tag=node-app:latest`. Данная команда нужна для того, чтобы мы могли собрать Docker образ на основании того, что находится в текущей директории и добавить тег нашему образу. То есть это грубо говоря, некий аналог имени и версии, называется тег, который будет равен `node-app:latest`. После этого идут какие-то команды `docker run`, но их давайте рассмотрим немного позже. Давайте перейдём в наш проект и попробуем выполнить эту команду. Здесь я нахожусь в этой директории, в которой находится `Dockerfile`. То есть я нажимаю `ls`, вижу, что здесь появился `Dockerfile`, `node_modules` и прочее. И что теперь я делаю? Я пишу `docker build .` то есть собери всё, что находится здесь в этой директории, и дай ему тег `node-app:latest`.

Итак, происходит сборка моего проекта. Что мы видим? Что здесь прошла сборка. Детальнее мы всё рассмотрим чуть позже, вот эти все сообщения, которые мы увидели. Но теперь мы понимаем, что у нас где-то появится наш Docker образ. Пока мы не умеем работать с консолью, мы перейдём с вами в наш Docker Desktop, то, что мы установили при установке по инструкциям на сайте Docker. Смотрим, что мы здесь увидим.

Итак, здесь мы с вами видим некий образ. Есть такая вкладка `Images`, и здесь в `Images` мы видим `node-app`, который был создан буквально вот-вот. Его сейчас никто не использует, его размер 1.1 ГБ, и это как раз образ, который мы с вами создали здесь только что, используя нашу команду.

Итак, теперь давайте попробуем запустить наше приложение. То есть мы говорили о том, что у нас есть Docker образ, и на основании Docker мы уже можем с вами создавать контейнеры. Давайте посмотрим, как это будет выглядеть. Здесь мы видим команду `docker run -p 4200:4200 node-app:latest`. Что это значит? Это инструкция

Чтобы применить наши изменения, которые мы произвели, нам необходимо пересобрать наш образ, то есть создать новый образ. Для того, чтобы продемонстрировать это, мы с вами перейдём в проект и переключимся на ветку `step 3`, в которой есть некоторые минорные изменения в коде. После этого мы с вами стартанем старый образ, попытаемся создать новый и его запустить.

Переходим в проект. Итак, мы с вами переходим на ветку `git checkout`. Давайте пересоберём ещё раз образ, чтобы всё было аккуратно. То есть `docker build --tag nodeApp:latest`, чтобы убедиться, что данный образ собран на основании ветки `step 2`.

Теперь мы с вами делаем `git checkout step 3`. Мы перешли на третью ветку, и мы видим, что здесь есть некоторые минорные изменения. То есть добавилась здесь строка 18, версия 2.0, и добавилась "Привет, многоуважаемый юзернейм!".

Итак, давайте почистим консоль. И теперь я смотрю, что сейчас у меня код вот такой, то есть должны изменения быть. И теперь я пытаюсь стартануть наш Docker образ. То есть я пишу `docker run -p 42:4200 nodeApp:latest` и перейду в наш браузер.

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

Возвращаемся в наш проект. Мы снова чистим консоль. И теперь я снова делаю `docker build --tag nodeApp:2.0`. Происходит сборка. И теперь я попытаюсь запустить новый контейнер. То есть здесь я пишу не 42, давайте это будет у нас 6060 или 7070. `docker run -p 7070:4200 --name nodeApp_v2 nodeApp:2.0`. И давайте перейдём теперь в браузер на порт 7070.

И вот уже перейдя в версию 2.0, то есть в контейнер на порту 7070, который был собран на основании образа `nodeApp:2.0`, мы видим эти наши изменения, которые у нас были.

Давайте теперь ещё перейдём в наш Docker Desktop и посмотрим, что же у нас там происходит с образами. И вот здесь вы видите, что у нас есть сейчас два образа `nodeApp`. То есть первый с тегом `latest`, а второй с тегом `v2.0`. Каждый из которых сейчас у нас находится в работе. И у нас есть два контейнера: первый контейнер на основании `latest` тега, и второй на основании `v2.0` тега. Оба работают, и у нас проблем здесь никаких нет.

Таким образом, мы с вами увидели, что для того, чтобы применить изменения в коде, просто их добавить в код недостаточно. Их нужно применить с помощью пересборки.

Каждая строка нашего Docker файла - это упорядоченная инструкция по сборке, и каждая инструкция преобразуется в слой. Он называется Image Layer. Как это выглядит у нас с вами? На левой стороне вы видите Dockerfile, в котором есть `FROM`, `RUN`, `WORKDIR` и прочее. Далее сборщик преобразует каждую строку в отдельный слой, и, соответственно, у нас появляется такой слоёный образ. То есть каждая команда - это отдельный слой. Слои могут быть кэшированы.

Максимально детально по кэшированию Docker'а с официальной документацией. Там все варианты, все кейсы, которые только могут произойти, описаны довольно-таки подробно. Если говорить в общем, то при запуске сборки строитель пытается повторно использовать слои из предыдущих сборок. То есть, если слой образа не изменён, то есть не было, то есть чексум не поменялся, то сборщик берёт его из кэша сборки. Если же слой изменился с момента последней сборки, этот слой и все последующие слои должны быть пересобраны.

Быть кэшированным, поскольку она определяет самый базовый образ, с которого начинается сборка. Базовый образ может быть закэширован на локальной машинке, если он ранее был загружен, но он не кэшируется в рамках сборки конкретного Docker файла Docker образа. Далее строка `WORKDIR /app` - это слой установки рабочей директории. Далее идёт копирование текущего всего текущего, то есть слой копирования файлов проекта в контейнер, и он будет кэширован в файлах проекта. Далее команда `RUN npm install`. Здесь слой с установкой зависимости Node.js. Этот слой будет кэширован только тогда, когда зависимости не менялись с момента последней сборки. Остальные команды, такие как `EXPOSE`, `ENTRYPOINT`, не создают отдельных слоёв и не будут кэшированы.

Рассмотрим концепцию утилит контейнера, то есть контейнеры, которые представляют собой только окружение, в отличие от стандартного контейнера, который является приложением с окружением. То есть, если в предыдущем примере у нас с вами было некое приложение `nodeApp`, которое с окружением вместе запускалось, мы могли посмотреть, существуют образы и контейнеры на их основании, которые просто представляют нам либо Node, либо какой-то язык. В данном примере, соответственно, мы с вами попробуем подтянуть образ из общего артефакта образов под названием Rust. То есть это язык программирования.

После этого мы запустим данный образ в интерактивном режиме. То есть мне будет доступен терминал, я смогу выполнять команды терминала здесь. И после этого я попытаюсь выполнить команду внутри этого контейнера. То есть я создам контейнер с именем `rust_container` в интерактивном режиме на основании образа `rust`. А после этого я попытаюсь внутри контейнера `rust` выполнить команду `--version`, то есть вывести версию данного языка.

Итак, переходим в терминал и выполняем команду `docker pull rust`. Происходит подтягивание этого образа. Мы видим, что всё подтянулось. Теперь выполним следующую команду для старта этого контейнера. Итак, здесь мы копируем эту команду, делаем запуск. Мы видим, что у меня стартовал новый контейнер. Давайте перейдём в наш Docker Desktop и убедимся, что он у нас там появился в контейнерах. Мы видим, что у меня появился `rust_container` от образа `rust`, и он сейчас у нас запущен.

Выполним следующую команду, которая позволит мне получить версию данного Rust. Мы копируем данную команду, выполняем `docker exec rust_container rustc --version`. Запускаем, и мы видим, что здесь у нас появилась версия Rust. Если же я пытаюсь просто это выполнить, видим, что на моей машине ничего связанного с Rust нет. Таким образом, мы с вами смогли поработать с утилитой контейнера, и теперь давайте рассмотрим ключевые команды Docker'а в терминале, так как до этого мы использовали Docker Desktop, это не всегда удобно и не всегда правильно. Поэтому мы можем посмотреть с вами, что же нам предоставляет Docker.

Итак, первая команда - это `docker ps`, который возвращает нам список всех наших контейнеров, которые активны. То есть мы видим, что здесь такая колонка, как статус, и мы видим, что мы сейчас получили все три контейнера. Итак, здесь мы выполним команду `docker ps --help`. Здесь будет список команд и опций, которые мы можем добавлять сюда. И также здесь есть такая штука, как `-a` или `--all`, которая показывает все контейнеры, а по дефолту показывает только те, которые запущены.

Итак, я делаю `docker ps -a`. Видим, что у меня есть контейнеры, которые уже были здесь. И теперь я попытаюсь сначала убить контейнер Rust. То есть я беру его ID, копирую и выполняю команду `docker kill` и вбиваю ID. Теперь, если выполняю команду `docker ps -a`, мы видим, что у меня есть некоторые контейнеры, которые в статусе `Up`, а есть контейнеры, которые либо в статусе `created`, либо в статусе `Exited`. Хорошо.

Далее мы с вами можем также остановить контейнеры. Снова делаем `docker ps`. Мы видим, что у меня есть два контейнера. Первый контейнер, я беру и выполняю команду `stop`, то есть `docker stop` от ID. Отличненько. Теперь при выполнении `docker ps` у меня остался только один контейнер.

Далее мы также можем убить все контейнеры. То есть для этого я выбираю команду `docker stop $(docker ps -q)`, которые вернут только ID. Всё есть. И теперь мы с вами смотрим, что же у нас есть. Я делаю `docker ps -a`. У меня есть контейнеры в статусе `created` и прочее. Соответственно, теперь я могу использовать команду `remove`. Давайте сначала удалим контейнер в статусе `created`. То есть я беру `docker rm created` первый. Далее `docker rm created` второй. И теперь `docker rm created` третий. Снова делаем `docker ps` - ничего. Делаем `docker ps -a` - видим, что у меня есть три контейнера в статусе `Exited`. И есть очень интересная полезная команда под названием `docker container prune`, который удалит все неактивные контейнеры. То есть все стопнутые. Что было удалено три контейнера. Теперь снова, если вы `docker ps` - ничего. `docker ps -a` - тоже всё пусто, ничего нет.

Далее мы с вами попробуем сейчас запустить снова наш контейнер. То есть я делаю `docker run -p` точнее `-p 4200:4200 nodeApp:latest`. Мы видим, что мы как бы заблокировали, то есть терминал для нас потерян. Мы можем выйти отсюда, но это не всегда удобно. Давайте сейчас его пнём. `docker ps` соответственно `docker kill` вот этот контейнер. И после этого `docker container prune`, то есть мы почистили все наши контейнеры. Всё хорошо, всё отлично. И теперь для того, чтобы мы не блокировали, мы можем использовать detached mode. То есть я здесь выполняю `docker run -d` и здесь у меня будет снова мой контейнер запущенный. То есть смотрим `docker ps` - всё работает. Делаем снова `docker kill`, передаём нужный ID сюда. И давайте ещё выполним `prune`, чтобы всё было аккуратно. Чистим консоль.

И теперь мы с вами попробуем ещё задать имя нашему контейнеру. То есть мы здесь с вами создавали контейнер, и теперь мы после порта можем задать флаг `--name`, зададим `nodeApp`, чтобы было понятно. Итак, теперь мы снова с вами делаем `docker ps`, и здесь мы видим `NAMES nodeApp`, то есть не то, что мы по дефолту получали, а что-то, ну, по несколько другому.

Итак, мы теперь видим, что у нас есть некий контейнер, который находится в detached mode. Но я хотел бы к нему подключиться. Для этих целей я беру, копирую ID данного контейнера и используя команду `docker attach` сюда. И соответственно, теперь мы видим, что здесь ничего не происходит. И если мы сейчас с вами вернёмся в браузер на порт 4200 и там попытаемся получить username логи, то мы их здесь увидим. Давайте это сделаем.

Итак, здесь мы с вами сделаем `test10000`, далее `test2800`. И сейчас, когда мы вернёмся с вами в терминал, мы увидим наши логи. Итак, снова мы тут выходим отсюда. Делаем `clear`, чтобы почистить всё. Давайте ещё разберём пару команд. Это команда `docker logs`. То есть для этих целей мы используем ID нашего контейнера. Получили. Теперь можем использовать флаг `-f` и получать наши логи как бы стримингово. `-n` `--tail` и вбить какую-то цифру, какое количество логов нам необходимо получить.

Так, давай теперь ещё раз убьём все наши контейнеры, которые были. То есть контейнер ID. Я делаю `docker kill`. Есть. И теперь `docker container prune`. Убили всё. На этом можно сказать, что практически все команды ключевые с Docker'ом мы разобрали.

Итак, здесь у нас остаются только команды для работы с образами. Итак, мы можем использовать команду `docker image ls`, где мы увидим с вами, какие образы у нас есть в списке, чтобы мы не обращались к этим образам через Docker Desktop. Далее мы можем проинспектировать образы. Для этих целей я делаю `docker image inspect` и задаю сюда образ. И здесь мы видим очень много данных по нашему образу, что здесь используется, то есть откуда, что, когда мы тянули. Там, опять-таки, слои же можно посмотреть. Здесь вот мы видим, что есть `RootFS`, и тут пошли `layers`. Соответственно, вот это контрольная сумма наших слоёв, с которым мы работаем.

Далее мы можем с вами также удалить наши образы. То есть я снова делаю `docker image ls` и, допустим, хочу удалить вот непонятные мне пока образы. То есть для этих целей я делаю `docker rmi` первый. Далее `docker rmi` второй. И тут `docker rmi` третий. Снова делаем `docker image ls`, видим, что этих образов уже нет. Давайте это тоже снесём. `docker rmi` убрали. И также мы можем использовать команду такую, как `docker image prune`, которая позволяет нам удалить все как бы ненужные, там какие-то мусорные образы, которые мы сейчас не юзаем, и почистить какое-то место в нашем дисковом пространстве.

На этом мы можем завершить пока работу с Docker образами локально на какое-то время. И теперь давайте перейдём с вами к публикации наших Docker образов в регистре.

Перейдём к публикации Docker образа. Docker образы хранятся в хранилищах. Тавтология, но так оно и есть. Registry. Хранилища бывают публичными и бывают приватными. Наиболее популярным хранилищем является Docker Hub, где вы можете создать как приватные образы, так и публичные образы. Но кроме Docker Hub, есть такие сервисы, как GitLab Container Registry, Amazon ECR, Red Hat Quay, GitHub Registry, то есть различные сервисы. Уже в этих registry хранятся различные образы: это база данных, JDK, Gradle, Cassandra, Node и прочие и прочие сервисы.

Мы с вами будем работать с Docker Hub как с одним из наиболее популярных стрей в мире. На текущий момент, в первую очередь, вам необходимо будет зарегистрироваться на Docker Hub, перейдя по ссылке, которая есть здесь, то есть `hub.docker.com`, и после этого создать репозиторий. Давайте с вами пройдемся по этим шагам. Регистрацию я оставлю на вас, а вот уже создание репозитория и прочая манипуляция мы попытаемся сделать вместе. Результатом нашей работы будет создание локально Docker образа и публикация его на Docker Hub, и, соответственно, возможность получить этот Docker образ из публичного хранилища. А потом мы уже запустим наше приложение на основании образа, который не локально, а на удалённом регистре.

Давайте начнём. Итак, вы переходите по ссылке, регистрируетесь, и после регистрации начинаете создавать ваш первый репозиторий. После создания своего аккаунта на Docker Hub, вы переходите на страницу Repositories. Здесь у вас, если ничего ранее не было, будет пусто. Здесь вы видите свои namespace. По дефолту будет только ваш аккаунт. В моём случае это `prays`. Далее вы нажимаете кнопочку `Create repository`. Здесь вы сейчас, это будет User API. Посмотрите внимательно, чтобы здесь была видимость `Public`. После создания вы нажимаем кнопку `Create`. После этого у вас будет создан репозиторий.

И теперь мы с вами можем перейти к нашему проекту, который есть по ссылке в описании к видео. Это проект под названием `User API`, и нас пока интересует `branch step 1`. Итак, здесь что мы видим? Мы видим простое приложение Spring Boot API с одним endpoint'ом, который возвращает список всех пользователей. Есть DTO, которая имеет ID, имя, фамилия, email, и есть стартовый класс. Здесь есть `application.yaml`, в котором есть `server.port`, который можно передать через переменную среды, и при этом у него есть ещё `spring.application.name: User API`. Мы можем запустить наше приложение, если у вас установлено всё, что необходимо, и после этого мы можем перейти в Postman и попробовать выполнить запрос.

Итак, мы выполняем наш запрос `localhost:8880/api/v1/users`, и мы получаем в ответ наших пользователей, наших юзеров. Видим, что запрос нормально работает, проблем никаких у нас нет. Теперь мы можем выключить наше приложение, пнуть сервер, перейдя на ветку `step 2`, мы увидим, что был добавлен Dockerfile. Здесь мы видим, что есть этап сборки, в рамках которого мы используем Gradle и JDK 21. Как после этого у нас есть этап создания артефакта. То есть здесь мы с вами используем OpenJDK 21, JDK Slim, начинаем создавать артефакт. Далее мы задаём переменную `server.port` 9200, чтобы работать с ним. После этого мы копируем всё, что было собрано в рамках сборки, в директорию `/app/UserAPI/100J`. И после этого у нас появляется `ENTRYPOINT`, которая запускает наш артефакт с помощью команды `java -jar app.jar` и передаём директорию нашего джарника.

Итак, для того, чтобы это проверить, что это всё работает, для начала мы с вами выполним сборку нашего образа. Для этих целей мы выполняем команду `docker build --tag UserAPI:latest`. Итак, происходит сборка нашего проекта, и в результате сборки появляется образ. То есть мы делаем `docker image ls` и видим здесь, что у нас появился новый образ под названием `UserAPI:latest`, который создан 6 секунд назад. Отличненько.

Теперь попробуем запустить наш образ. Для этих целей я выполняю команду `docker run --port 9200:9200 UserAPI:latest`. Итак, происходит запуск приложения на порту 9200. Теперь мы можем перейти с вами в Postman и при попытке выполнить запрос на 8880 - ошибка, потому что мы стопнули наш сервер локальный. Но если мы пропишем `localhost:9200` и выполним запрос, мы увидим, что всё отработало корректно. То есть мы получили наших юзеров. Это значит, что мы запустили успешно наше приложение в Docker. Соответственно, теперь перед нами стоит задача сделать так, чтобы мы смогли закинуть этот Docker образ с нашей локальной машины в наш публичный артефакт.

Для этих целей мы выполняем следующую команду. Это `docker tag UserAPI:latest prays/UserAPI:latest`. То есть я говорю, что мой локальный образ `UserAPI:latest` я тегаю на `prays/UserAPI:latest`. И здесь, если вы хотите публиковать в ваш артефакт, вместо `prays` должно быть ваше имя. Итак, мы выполнили данную команду. И теперь я делаю `docker push prays/UserAPI:latest`. Итак, происходит push нашего образа в артефакт.

Теперь мы можем перейти в наш Docker Hub и посмотреть, что мы там увидим. Здесь мы видим, что несколько секунд назад появился новый образ с тегом `latest`, где вы видите его детали. Теперь давайте проверим, что мы действительно можем этот образ и как-то работать с ним, то есть публичным образом на своей локальной машине. Итак, сначала мы удалим образы с локальной машины. Итак, я делаю `docker image ls`. Мы видим, что у нас нет наших образов. Если они у вас ещё остались, вы их удаляете. То есть мы видим, что образов `UserAPI:prays` у нас нет.

Теперь я делаю следующее: я пишу `docker pull prays/UserAPI:latest`. И мы теперь как бы тянем этот образ на свою локальную машину. Здесь теперь мы выполняем команду `docker image ls`, и мы видим, что образ был подтянут к нам сюда на локальную машину. Итак, теперь мы его... Давайте ещё раз удалим. То есть я пишу `docker rmi prays/UserAPI:latest`. То есть всё, его больше нет. Перепроверяем `docker image ls`. Убрали.

И теперь давайте запустим его. То есть я пишу `docker run -p 9200:9200` и запускаю уже как бы с образа, который удалённый. То есть пишу `prays/UserAPI:latest`. Итак, происходит запуск. Он говорит, что он не может найти данный образ на локальной машине. Соответственно, произойдёт `pull` этого образа к себе. И когда мы его запустим с удалённого репозитория, мы видим, что наше приложение стартануло на порту 9200. Давайте ещё раз перепроверим, что это приложение работает.

Итак, мы снова в нашем Postman. Я выполняю данный запрос, и у нас всё работает корректно. Таким образом, мы с вами смогли опубликовать наш образ в публичном артефакте, смогли подтянуть этот образ и запустить на основании этого образа новый контейнер.

Теперь поговорим про работу с переменными среды. Перед этим в нашем проекте `User API` мы передавали переменную среды `port` через Dockerfile, используя ключевое слово `ENV`. Далее имя переменной `PORT`, мы передали значение `9200`. Также можем это сделать с помощью флага `-e` и выполнив команду, которую видите ниже, мы сможем это сделать. То есть мы запустим приложение на порту 9000. Давайте попробуем перейти в наш проект и выполнить эти действия.

Итак, мы берём эту команду и выполняем её. Смотрим, что у нас получается. Здесь при старте мы видим, что приложение было на порту 9000. И теперь мы можем перейти в Postman и попробовать выполнить данный запрос. Итак, теперь мы берём порт 7878, отправляем запрос, и мы видим, что всё отработала корректно, штатно, без ошибок.

Попробуем ещё один вариант для работы с переменными среды. Мы также можем использовать так называемый `.env` файл. То есть файл - это файл, в котором мы храним наши переменные. И здесь мы говорим, что у нас появится какая-то переменная `PORT`, скорее всего, и мы будем работать с ней. Для этих целей мы используем флаг `--env-file`. Далее мы указываем, где он у нас появится. У нас это будет в корне проекта файл с названием `.env`. Задаём новое имя нашему контейнеру и запускаем его. И мы должны будем его увидеть на порту 4848. Перейдём в наш проект.

Итак, здесь давайте мы пока потушим наши контейнеры. То есть я делаю `docker kill` наш контейнер. Теперь делаю `docker container prune`, чтобы лишнего ничего не было. И теперь мы с вами попробуем переключиться на ветку номер `step 3`. В ветке `step 3` мы видим, что у нас появился новый файл под названием `.env`. И теперь мы можем выполнить следующую команду: `docker run --env-file .env -p 4848:9100 --name user_api_env_file UserAPI:latest`. Как я говорил ранее, указать, где находится файл, и запустить его.

Итак, происходит старт проекта. Мы видим, что приложение стартануло на порту 9100. И соответственно, теперь, перейдя на порт 4848, который мапится на порт 9100, мы должны получить корректный ответ. Переходим в Postman. В Postman'е мы прописали новый порт, выполняем запрос, и у нас всё отрабатывает штатно, без ошибок.

Таким образом, мы с вами научились работать с переменными среды: Dockerfile, это флаг `-e`, и это использование файла `.env`. На этом мы заканчиваем разбор именно основ работы с Docker'ом. Это что такое Docker. Далее предлагается вспомнить, какие преимущества даёт нам Docker в сравнении с обычным запуском на локальной машине. Далее, в чём отличие между образом и контейнером, и что такое Image Layers, то есть слои нашего образа. Далее предлагается вспомнить, как работает кэширование слоёв при сборке. Вы также можете изучить материалы, которые будут по ссылке. Вопрос следующий: как войти в интерактивный режим при запуске контейнера? И далее вопрос: что такое стриминг?

Наш следующий раздел - это работа с данными. Мы рассмотрим в рамках этого подмодуля работу с данными как таковыми, работу с томами и работу с переменными среды. Когда мы говорим про данные в контексте Docker'а, то данные можно разбить на три большие группы. Первая группа - это исходный код и окружение. Вторая группа - это временные данные, и третья группа - это постоянные данные. И у нас есть характеристики: этапы получения данных, типы данных и место их хранения.

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

Следующий этап - это временные данные. Они получаются нами на этапе работы приложения. Они изменяемые в Docker контейнере. Хороший пример таких данных - это `username` в `nodeApp`. То есть во время работы приложения мы могли изменять переменную `username`, и она у нас была изменчива, получалась на этапе работы приложения и хранилась в Docker контейнере. То есть, если контейнер удаляется, то данные теряются.

И финальный тип данных - это постоянные данные, которые также получены на этапе работы приложения, которые также изменяемые. Место хранения - это некая постоянное хранилище. Пока написано в кавычках, потому что мы разберём более детально позже, что же это за хранилище. Файловая система каждого контейнера изолирована от файловой системы других контейнеров. Соответственно, если мы удаляем контейнер, то все данные теряются. Для этих ситуаций существует такая штука, как Volumes, он же Vol. - это папка в файловой системе рабочей машины, то есть железяки, на которой мы работаем, который доступен внутри нашего Docker контейнера. То есть сама директория, которая создаётся для тома, она не доступна за пределами Docker. То есть у неё есть свой путь, но если вы попытаетесь найти этот путь просто на операционной системе, вы не получите к ней доступа, потому что это идёт исключительно через Docker. Эта директория доступна как на чтение, так и на запись. И даже когда контейнер уничтожен, сам Vol продолжает существовать.

Как это выглядит? У нас с вами появляется наша рабочая машина, у нас есть некий контейнер, который находится в какой-то директории `/home/app`, и у нас появляется некий том хранилища в файловой системе, допустим, `/user/pr/docker/vol1`. И соответственно, получить доступ вот к этой папочке из-за пределов Docker мы не можем. Но Docker контейнер хранит данные здесь, и соответственно, когда том создан, к нему можно подключиться как из этого контейнера, так и из других контейнеров.

Работа с томами. Для того, чтобы мы разобрались, что же это такое и как с этим работать на практике, мы можем рассмотреть приложение `file-service`. `file-service-1`. Перейдём в наш проект. Итак, мы с вами делаем обзор нашего проекта `file-service`. Что у нас есть здесь? Мы видим простой проект, это Java приложение.

которое держит в себе, во-первых, `build.gradle` в котором можем видеть с вами `Starter Tim`. То есть, это для работы с UI, это Web, для того чтобы мы могли подключить контроллеры и прочее, то есть взаимодействие с этим UI. И `test`, который у нас просто идёт по дефолту.

Далее, мы заходим с вами в пакет `src/main/resources`. Здесь идут формочки `page`. То есть, это будет страничка для ввода каких-то данных под названием `content`. Эти данные у нас будут попадать в текстовый файл, к которому мы будем иметь доступ через страницу `page`. То есть, здесь будет иметь доступ к содержимому какого-то файлика. И `success` будет просто страничка, в которой у нас будет информация о том, что при публикации данных на странице `forms` всё произошло у нас успешно.

Если мы пойдём с вами по коду, то здесь мы увидим следующее. То есть, это у нас просто стартер. Здесь мы с вами видим `file`, который делает что у нас есть какая-то `fileLocation`, `filePath`, то есть файлик, куда мы будем писать данные. Далее, при получении данных, то есть `writeToFile`, мы получаем `PostDto` — это обычный `Record`, у которого есть `string title` и есть `string content`. Далее, содержимое этого поста попадает в наш файлик `filePath`, о котором мы говорим. Выводит какое-то сообщение нам в консоль. Если произошла ошибка, мы получим сообщение об ошибке. И далее у нас есть метод `readFromFile`, который вычитывает содержимое нашего файла, который указан по этой ссылке.

Далее, у нас есть `postController`, у которого есть контроллеры для работы с формой. Здесь мы принимаем данные, и потом эти данные у нас попадают в методе `postMapping form` в наш файл через вызов метода `writeToFile`. `Success` просто вводит `Success`. `Exit` для того, чтобы потушить наше приложение. И `page` показывает нам, вычитывает данные из файла через метод `readFromFile`, добавляет их в атрибуты `page`, и потом уже этот `page` мы видим здесь в HTML файле. Вот примерно так.

Давайте попробуем запустить наше приложение. Мы вот видим, что по дефолту у нас есть какой-то `storageLocation`. И если у нас есть какой-то `stage`, мы его давайте возьмём, скопируем `copyPath`. Я беру `copyAbsolutePath`. Здесь я перехожу в наш `FileWriterApplication`, здесь беру `runConfiguration`, и здесь я добавляю. Давайте их тут добавим `environmentVariables`. Здесь мы вбиваем переменную, пока рандомное имя, вбиваем наши данные, жмём `OK`. `OK`. Возвращаемся сюда, и у нас есть `storageLocation` переменной среды. Соответственно, мы снова идём сюда, `modifyRunConfiguration`, и в переменной среды мы меняем имя на нужную нам переменную. Делаем `OK`. И теперь попытаемся запустить наше приложение в режиме дебага. Посмотрим, что же произойдёт.

Мы переходим по ссылке `localhost:880/form` и здесь мы видим страницу для заполнения, то есть для ввода данных. Мы здесь вводим `test10000` в `title`, в `content`. Нажимаем `submit`. Идёт редирект на страницу `success`. После этого переходим на `payload` и видим, что в конце нашего файлика мы добавили следующие данные: `title: test10000`, `content: 10000`. Давайте для теста ещё раз добавим, наверное, запись `test200800`, чтобы убедиться, что всё работает корректно. Жмём `submit`, `go to payload`. И здесь мы видим `test200800`, `test200800`. То есть, сейчас всё работает корректно так, как мы хотим.

Но теперь давайте попробуем запустить наше приложение с помощью Docker, а не просто через локальный старт. Для этих целей мы тушим наш сервер, переходим в терминал и давайте ещё откроем наш Docker файл. Здесь мы уже видим знакомый нам, где мы с помощью `openjdk` и `jdk21` делаем сборку. После этого у нас следующий этап — упаковка и запуск. И потом уже идёт `entryPoint`, в котором мы вызываем `java` и запуск артефакта, который будет собран на этапе сборки. И эта `jar`.

Теперь мы можем, во-первых, собрать сам Docker образ. Для этих целей выполняю команду `docker build -t file-service:latest`. Начинается сборка нашего приложения. И теперь мы должны получить наш новый образ. Я выполняю команду `docker image ls`. И здесь мы видим, что у нас появился `file-service` — новый образ, с которым можем работать. Давайте почистим консоль. И теперь мы постараемся запустить наше приложение. Для этих целей я буду использовать команду `docker run -p 8070:8070 --rm --name file-service -e STORAGE_LOCATION=/app/data file-service:latest`. Итак, происходит старт нашего приложения. Мы видим, что всё у нас запустилось, всё аккуратно. Пока.

И давайте в соседнем терминале мы выполним команду `docker volume ls`. То есть, я хочу видеть список всех наших волюмов. Появился какой-то волюм с именем `file-service-storage`, и у него драйвер — это `local`. Теперь я делаю следующее: я выполняю команду `docker volume inspect file-service-storage`. И задаю сюда имя нашего волюма. И здесь мы видим, что же произошло. Я получаю здесь данные, что он был создан какое-то время, что драйвер у него `local`, лейблов нет, точка его монтирования вот такая. Но при этом, если вы попытаетесь, как я говорил, перейти по этой ссылке, вы не получите к ней доступа. У неё есть имя, скоуп — локальный, и никаких опций мы с вами не создавали. Соответственно, теперь мы делаем с вами что: `docker volume rm file-service-storage`. Если нам необходимо это сделать. То есть, `docker volume rm file-service-storage`. И мы получаем ошибку, потому что он сейчас используется в нашей машинке.

Теперь мы понимаем, что мы с вами создали новый Docker контейнер, который запущен на порту 8070. Я предлагаю сейчас перейти в браузере по этой ссылке и посмотреть, что же у нас сейчас произойдёт. Итак, здесь мы видим, что перейдя по ссылке `localhost:8070/form`, мы вбиваем, допустим, `test3600` сюда, `3600`. Нажимаем `submit`, получили `success`. И после этого переходим на `payload` и видим, что в конце нашего файлика мы добавили следующие данные: `title: test3600`, `content: 3600`. Потому что это не было связано с тем файликом, который у нас находится внутри кода. Я снова перехожу в форму, тут вбиваю `test10000`, `submit`, `go to payload`. Всё хорошо, всё работает, всё отлично.

Теперь я предлагаю нам перезапустить наш контейнер. То есть, давайте сейчас выключим приложение, перезапустим. Что же у нас произойдёт после удаления контейнера? Итак, для этих целей я выполняю `docker ps`, смотрю, что ничего нет, всё было удалено. Далее, я смотрю `docker ps -a` на всякий случай. Выполняю `docker container prune`, чтобы всё было по-честному. Итак, всё удалено. И теперь давайте мы ещё раз попробуем запустить наш контейнер. Итак, я его запускаю. Смотрим, что происходит. Всё работает корректно. И мы снова идём в браузер на порт 8070. Итак, здесь мы видим, что всё работает. И давайте сразу пойдём на страницу `payload`, и мы видим, что данные у нас не были потеряны, даже после того, как мы перезапустили наш контейнер. Это как раз связано с тем, что у нас есть отдельный волюм, где данные хранятся.

Теперь давайте попробуем сделать следующий шаг, и мы снова вырубим наше приложение, удалим волюм. Итак, для этих целей снова `docker ps`, `docker container prune` — всё вырубили. Теперь у нас с вами есть `docker volume ls`. Видим, что он есть. Далее, мы удалим наш волюм. То есть, я пишу `docker volume rm file-service-storage`. Имя передали, всё удалено. И давайте теперь мы снова постараемся запустить наше приложение той же командой, которая была до этого. Я снова запускаю наши апки. Снова переходим в браузер на порт 8070. И здесь, нажимая `payload`, мы видим, что ничего нет. То есть, данные были потеряны, потому что мы удалили волюм.

Теперь снова `test1500`. Мы сюда видим данные. Здесь возвращаемся в наш контейнер. Здесь мы снова делаем `docker ps` — проверка, что у нас есть всё-таки здесь образ. Давайте мы это всё удалим сейчас. То есть, `docker kill` — убили данный контейнер. Теперь мы смотрим, что `docker ps` — ничего нет. На всякий случай `docker container prune`. Сохранились, потому что теперь волюм мы не удаляли. Итак, мы обновляем страничку и видим, что данные у нас есть. То есть, наш `test1500`, как был, так и остался.

После того, как мы разобрали работу с данными, мы перейдём к сетевому взаимодействию. Здесь мы рассмотрим работу контейнера с внешним миром. Мы рассмотрим работу контейнера с локальным хостом `localhost`, и также работу контейнера с другим контейнером. Как это будет выглядеть? Мы с вами создадим новое приложение, которое в нашем случае будет взаимодействовать с базой данных `MongoDB`, которая будет находиться у нас в Docker, как Docker контейнер. Она будет взаимодействовать. Эта оплеуха у нас ещё с `Postgres` с базой данных, которая реально установлена на физической машине. И также наш контейнер будет взаимодействовать со сторонним API, который будет возвращать не список стран. Тут хост немножко другой, но здесь просто для понимания, что есть внешний ресурс, который отвечает за взаимодействие с внешним миром. Есть внутренний контейнер `MongoDB` — Docker контейнер. Есть `Postgres`, которая поднята как сервер на локальной машинке.

Итак, сетевое взаимодействие. Мы сейчас с вами переходим к проекту `Country API Step 1`, в рамках которого мы попытаемся его запустить. Если у вас на текущий момент не установлено `Postgres` как базу данных на локальной машине, у вас есть время как раз немножко поставить на паузу и установить эту базу данных как сервер себе на свою машину. После этого вам нужно будет подтянуть образ `MongoDB`. То есть, это база данных, документо-ориентированная. И дальше мы уже с вами попытаемся всё это запустить и посмотреть, как же всё это у нас будет работать. Переходим к нашему проекту.

Итак, мы с вами скачали наш проект по ссылке, которую вы нашли. Это проект `Country`. Внутри этого проекта `Country` вы видите две папки: это `Country API`, `Country Client`. `Country Client` сейчас не интересен. `Country API` интересен. Это оплеуха, цель которой — взаимодействовать с внешним ресурсом и получать данные по странам. То есть, есть эндпоинт `process`, который получает данные со стороннего ресурса и сохраняет их в нашей базе данных. То есть, одна база данных — это у нас `MongoDB`, вторая база данных — это `Postgres`. В `Postgres` хранятся все данные, в `MongoDB` хранятся не все данные. Соответственно, мы запросили, получили все данные. Потом есть эндпоинт для получения всех стран. Есть эндпоинт для получения страны по альфа-коду. При получении страны по альфа-коду, что мы делаем? Мы сначала пытаемся найти эту страну в `MongoRepository`. Если там получили, то мы её и вернули. Если не нашли, то мы обращаемся к `Postgres` и выгребаем данные из этой `Postgres`. Есть репозитории, которые `MongoRepository` — получаем, работающие с `MongoDB`. Есть `PostgresRepository`, который работает с `Postgres`. Есть `Entity` как `MongoEntity`, то есть документ. Есть `Entity`, которая для `Postgres`. И есть `Dto`, чтобы привести это всё к одному виду. И тут есть маппинг-методы, которые преобразуют `Dto` в `JpaEntity` и в `MongoEntity` соответственно. Вот так это всё должно работать.

Теперь, что мы можем сделать? Давайте сейчас с вами ещё обратим внимание на наш пакет `resources` и тут есть `application.properties`. Здесь все данные мы передаём через переменные среды. То есть, у нас, во-первых, с вами есть тут `server.port`, который дефолт 9090, либо получить извне. Есть `datasource`, который по дефолту работает с локальной `Postgres` через `localhost` и именно `Postgres`, но можно передать их через переменные среды. Далее, у нас есть таблицы, создаются автоматически. И `MongoDB` у нас, опять-таки, можно передать по дефолту — это `localhost`, порт 27017, и имя базы данных — это `mongo`. Думаю, по проекту в целом по API понятно. Давайте попробуем сейчас это всё докеризировать и запускать на локальной машинке.

Мы завершили обзор нашего приложения. Теперь давайте подтянем на нашу локальную машину образ `MongoDB` и постараемся эту `MongoDB` также и запустить. Итак, для этих целей я перехожу в терминал моего проекта. Здесь я выполняю команду `docker pull mongo`. После того, как образ мы подтянули, давайте запустим наш контейнер `MongoDB`. То есть, мы запускаем `MongoDB` на порту 27017. Итак, происходит запуск. Теперь, если мы выполним команду `docker ps`, мы видим, что есть `mongo`. И давайте попробуем подключиться к ней через клиент. В моём случае это будет `DataGrip`. Для этих целей я здесь выбираю новый datasource, здесь я выбираю `MongoDB`. Соответственно, здесь нажимаем `Test Connection`, видим, что всё подключилось, всё корректно. Соответственно, здесь мы видим, что у нас появился новый datasource — это `mongo`, в которой, конечно же, на данный момент не будет никаких данных. То есть, тут пустая схема. Отличненько. Делаем следующий шаг.

Теперь мы с вами соберём образ нашего `Country API` с помощью команды `docker build -t country-api:latest .` и потом попытаемся запустить данный контейнер на основании этого образа. Переходим в наш проект. Для того, чтобы собрать наш образ, мы смотрим наш Docker файл. Здесь небольшие изменения от того, что есть уже на гите. Здесь мы используем сначала `openjdk:17-jdk-slim`. И для `MongoDB` мы также используем. Теперь давайте соберём наш образ. Я пишу `docker build -t country-api:latest .`. Происходит сборка образа. Образ собран. Давайте перепроверим, что он появился. Я пишу `docker image ls`. Видим, что у нас появился вот наш `country-api`. И теперь я попробую запустить это всё на локальной машине. То есть, я пишу `docker run -p 9200:9200 country-api:latest`. Происходит старт нашего приложения. И давайте посмотрим, что же здесь произойдёт при попытке стартануть. Мы видим, что у нас посыпались ошибки. То есть, мы видим, что мы не можем подключиться ни к `Postgres`, ни также мы не можем подключиться к нашей `MongoDB`. То есть, что же произошло? Почему это так? Давайте выполним следующую команду. Мы опять-таки посмотрим, какие контейнеры есть. Мы видим, что есть контейнер `mongo`. Соответственно, теперь что мы сделаем? Я пишу `docker inspect mongo`. И здесь нас очень интересует такая штука, как `IPAddress`. Мы видим, что у `mongo` появился вот такой IP-адрес. Давайте мы его сейчас скопируем. И вот в `mongo` сюда мы передадим вместо `localhost` вот этот IP-адрес. Теперь мы снова попробуем пересобрать наш образ. После сборки, давайте попробуем её стартануть. И что мы здесь с вами увидим? Мы с вами увидим, что к `mongo` коннект у нас происходит, но коннекта к `Postgres` у нас нет. То есть, что я здесь наблюдаю? То есть, вот пошёл старт. Здесь `Connection refused` `localhost:5432`. А вот коннект к `mongo` ошибок не выдал.

Теперь мы с вами немножко откорректируем наши изменения. И теперь вместо хоста мы пропишем вот такую запись: `host.docker.internal`. Давайте снова попробуем пересобрать наш образ уже с этим Docker файлом. Сборка произошла, всё успешно. И попробуем теперь снова стартануть наше приложение. Смотрим, что происходит. И мы видим, что сейчас ошибок у нас не наблюдается. Давайте теперь проверим через Postman, как у нас всё это работает. Мы выполняем запрос `POST` на `/api/v1/countries/process`. Происходит процессинг. Мы видим, что произошёл `OK`. Теперь мы попытаемся получить наши страны с помощью метода `GET`. Итак, мы делаем обращение и видим, что у нас пошли страны. Теперь, допустим, мы сделаем запрос поиска страны по альфа-коду. То есть, `cc2`, и пусть это будет `MD` — Молдова. То есть, идёт запуск. Мы получаем полные данные, потому что у нас в `Postgres` хранятся полные данные. А вот если мы, допустим, запросим `PL`, то мы получим коротенькие данные, потому что не хранятся в `MongoDB`. То есть, теперь у нас всё заработало. Мы можем сказать, что мы реализовали приложение и докеризировали его, и мы можем сейчас взаимодействовать как с внешним миром, так и с `MongoDB` в контейнере, и с `Postgres`, которая стартует на локальной машинке.

Теперь нам интересно, почему же это не сработало с `localhost`, сработало с каким-то IP-адресом, но к `Postgres` мы не подключились. Давайте разбираться. В теоретической базе причина ошибки описана в нашей документации. То есть, тут говорится, что хост для контейнеров, с которым мы работаем, он может изменяться. И если мы хотим, чтобы мы не были зависимы от этих изменений, мы можем использовать стандартный хост `host.docker.internal`. То есть, внутри Docker Desktop есть несколько DNS-серверов. DNS-запросы от контейнеров сначала обрабатываются вот этим сервером внутри `dockerd`, который распознаёт имена других контейнеров в этой же внутренней сети. Это позволяет нашим контейнерам работать друг с другом даже без знания конкретных внутренних IP-адресов. То есть, каждый раз, когда приложение запускается, внутренняя IP-шка может меняться динамически, но контейнеры всё равно смогут обратиться по этому имени `host.docker.internal` благодаря внутреннему встроенному DNS-серверу внутри нашего `dockerd`. То есть, остальные поисковые запросы они отправятся в `CoreDNS`, а потом, в зависимости от домена, запросы перенаправятся в один из двух DNS-серверов на хосте. То есть, домен `docker.internal` он считается как бы исключительным, особенным и включает в себя DNS-имя `host.docker.internal`, которое преобразуется в IP-адрес для текущего хоста. То есть, конечно, когда всё желательно, когда всё у нас контринизировано, но иногда `host.docker.internal` позволяет нам обращаться к любому `localhost` и не заботиться о хэш-конге наших адресов. То есть, чтобы этого избежать, опять-таки, у нас может быть создана отдельная единая сеть, в которой все контейнеры смогут легко друг к другу обращаться. То есть, мы можем создать новую сеть. То есть, у нас есть такая возможность, как создание нового `network`, который может быть создан с помощью `docker run --network` и мы даём имя этой сети. Далее, внутри этой единой Docker сети все контейнеры смогут общаться друг с другом, и их IP-адреса будут определены автоматически на основании только имени нашего контейнера. То есть, мы можем создать нашу сеть, потом увидеть её, либо создать и потом, когда мы будем стартовать заново наш контейнер, например, `mongo`, мы при старте укажем, что данный контейнер он принадлежит к конкретной сети. В данном случае `network: country-net`.

Итак, давайте для начала проверим, что все контейнеры, которые были, они убиты. То есть, у нас больше нет контейнеров. Если у вас что-то работает, попрошу их удалить и потушить. И теперь давайте проверим, какие сети у нас есть. То есть, я использую команду `docker network ls`. Мы видим, что у нас есть какие-то системные сети, но никакой `country-net` у нас пока нет. Теперь я выполняю команду `docker network create country-net`. Теперь мы снова выполняем команду, видим, что у нас `country-net` появилась. `docker network inspect country-net`. `driver: bridge`. По драйверам немного попозже пройдемся, какие они бывают и какие мы используем. Теперь я хочу запустить наш контейнер `mongo`, дав ему конкретное имя и присоединив его к нашей сети `country-net`. Для этих целей я использую команду `docker run -p 27017:27017 --name mongo-container --network country-net mongo:latest`. Итак, происходит запуск. Всё запустилось, всё супер. Теперь мы можем посмотреть, что у нас есть `docker ps mongo-container`. И теперь можем ещё выполнить команду `docker inspect mongo-container` и посмотреть, что у нас здесь есть `Networks`. `country-net`. И `IPAddress`. То есть, мы можем обратиться теперь к этому контейнеру либо по вот этому имени, либо по его ID. Что довольно-таки удобно. Вот здесь есть `Networks: country-net`. И вот DNS-имена нашего контейнера `mongo-container`. Отличненько. Думаю, с этим пока понятно.

И теперь предлагаю запустить уже наше приложение, передав ему вот через переменные среды нужные данные. То есть, что мы можем сделать? То есть, мы можем использовать следующую команду. Она у меня тут подготовлена заранее. Запустить `docker run -p 9200:9200 --name country-api-container --network country-net -e POSTGRES_HOST=host.docker.internal -e POSTGRES_PORT=5432 -e POSTGRES_DB=postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e MONGO_HOST=mongo-container -e MONGO_PORT=27017 -e MONGO_DB=mongo country-api:latest`. То есть, тут идёт `datasource URL` `Postgres` используется `host.docker.internal`, потому что это не контейнер, а реальный сервис, поэтому данный хост остаётся. Имена понятны. И потом мы говорим, что у меня есть `mongo_host`, и тут идёт `mongo-container`. Это возможно как раз потому, что внутри `country-net` `network` у нас есть DNS-имя `mongo-container`. Задали порт, задали базу данных и указали, на основании какого образа это всё у нас будет происходить. Итак, мы запускаем наше приложение и смотрим, что произойдёт. Видим, что у нас полетела ошибка по Docker. То есть, давайте разберёмся, почему так случилось. Потом это случилось по той причине. Давайте это сейчас топнем пока. По той причине, что мы не указали сеть, к которой нам нужно подключиться. Это очень критично. Теперь же, если мы с вами сделаем следующий шаг, и теперь мы выполним такую команду, где мы в конце укажем `--network country-net` и `country-api:latest`, и запустим ещё раз. То в этот раз никаких ошибок уже не будет, потому что данное имя интерпретируется и оно находится в единой сети. Давайте теперь перейдём в наш Postman. Итак, здесь у нас сейчас происходит процессинг. Теперь мы берём `countries/cc2/MD` — то есть, мы получаем данные из `Postgres`. И тут мы получаем данные из `MongoDB`. То есть, всё работает, всё корректно, всё аккуратненько. Давайте переходить к следующему этапу.

Теперь давайте подытожим. Только что мы с вами создали API, который был запущен в нашем контейнере, и он взаимодействовал с внешним миром, из которого он получал данные по странам. Он взаимодействовал с `MongoDB` — базой данных, которая была запущена в контейнере, и он взаимодействовал с `Postgres`, которая была поднята на нашей локальной машинке. Теперь давайте поговорим про драйверы. То есть, вот когда мы с вами создавали `network`, там было опция `driver`, и там по умолчанию используется `bridge`. То есть, это значит, что если мы используем `bridge`, то контейнеры будут искать друг друга по имени внутри одной сети. Если мы используем `host`, то у нас нет изоляции между контейнером и нашей системой. То есть, весь `localhost` в этом случае становится сетью. Далее, есть драйвер `overlay`. Он считается, и в этом случае несколько Docker могут работать друг с другом. То есть, несколько Docker инстансов, то есть машинок. Далее, `macvlan` задаётся MAC-адрес для контейнера, который используется для связи с ним. И также есть сторонние плагины, которые обеспечивают различные варианты взаимодействия, допустим, `Calico` и прочее. И это значит, что сети у нас будут отключены полностью.

Теперь давайте с вами поговорим про такую штуку, как всё, что мы с вами собрали во что-то единое. То есть, у нас с вами есть сервис, у сервиса есть какие-то тома, у него есть сети, есть переменные среды, есть порты, с которыми он работает. И для того, чтобы всё это объединить, нам было бы намного удобнее работать с чем-то единым. Вот таким единым является компонент `docker-compose`, который позволяет нам объединить вот различные сервисы, имеется в виду базу данных и прочее, и запустить вместе. То есть, у `docker-compose` есть целый ряд тегов, с которыми будем работать. Сейчас мы рассмотрим в нашем же `Country API Step 4`, как мы сможем это всё поднять в `docker-compose`. То есть, здесь у нас, во-первых, есть версия `docker-compose`, с которой работаем. Есть `services`, от которого будут зависеть наши контейнеры или контейнер. Далее, у нас есть `images`. Мы также можем задавать имя контейнера, указывать, как происходит сборка, задавать переменные среды, задавать порты и пользоваться `depends_on`, то есть указать, от каких сервисов зависит наше приложение, без которых мы не можем стартануть.

Давайте вернёмся к коду и посмотрим `Country API Step 4`. Давайте мы с вами перейдём на `Step 2`, и здесь вы видите, что мы с вами добавили наш `Country Client`, который тоже имеет Docker образ. Это простой React клиент для нашего сервиса. Проверяем, во-первых, что у нас все остальные контейнеры работают. То есть, работает `mongo`, работает `Country API`. Теперь мы с вами создадим Docker образ для `Country Client`. То есть, я выполняю `docker build -t country-client:latest .`. После этого произойдёт сборка нашего образа. Когда сборка завершена, мы теперь стартанем контейнер на основании этого образа. То есть, я пишу `docker run -p 4200:3000 --name country-client-container --network country-net country-client:latest`. Происходит запуск. После успешного запуска мы перейдём в браузер на `localhost:4200`. Итак, здесь мы нажимаем кнопочку `process`, чтобы запустить процессинг. Мы видим, что процессинг успешный, `200 OK`, и у нас появились наши страны. Далее, я могу посмотреть детали по какой-то стране, вернуться обратно. И уже после этого мы можем переключиться на бранч `Step 4`, потому что в рамках `Step 3` мы только добавили наш мишк. То есть, здесь.

Я делаю переключение на Step 4 и уже здесь, в рамках п. 4, вы увидите, что мы добавили файл под названием docker-compose. Давайте посмотрим, что же здесь есть. Мы используем версию 3. Далее мы говорим, что у нас есть сервис Database, который создаётся на основании образа mongo:latest. Hostname у него будет mongo, порты у него будут 27017 на 27017. Далее мы говорим, что мы хотим создать после этого новый образ Country API, который будет создан на основании образа country-api:latest. Порт будет 9200 на 9200. Задаём переменные среды, которые нам нужны. Мы также говорим, что App зависит от Database, и только после этого мы начинаем выполнять сборку C Client, его образа и работы с ними. И по итогу я рассчитываю, что он будет запущен на порту 3000, и мы говорим, что наш клиент зависит от API.

Для того чтобы мы могли запустить наше приложение, нам достаточно выполнить одну простую команду: это команда `docker-compose up -d --build`. После этого мы должны с вами получить три Docker образа и также получить с вами три рабочих контейнера. После этого, когда мы перейдём в нашем браузере на ссылку localhost:3000, мы должны получить всё, что мы видели перед этим при запуске поэтапно.

Давайте проверим наш браузер. Итак, мы находимся с вами в браузере, порт 3000, localhost. Я нажимаю кнопочку "Process". После этого у нас должен стартовать backend processing. Мы видим, что все данные были получены. Теперь, если я посмотрю сюда, то данные все есть. Соответственно, мы здесь можем сказать, что благодаря Docker Compose мы смогли с помощью только одной команды запустить все три сервиса в нужном нам порядке.

Теперь, если мы с вами выполним команду `docker ps`, то здесь мы видим, что у нас есть, во-первых, у нас с вами есть наш API, и у нас с вами есть наш backend. Таким образом, благодаря Docker, а в частности Docker Compose, мы можем с вами получить возможность иметь такое же абсолютно окружение, как на локальной машине, так и на продакшене. То есть это означает, что мы будем иметь одинаковое поведение. То есть у нас есть локальная машина, у нас есть окружение, которое мы можем поделиться и воспроизвести, и также продакшн, поделиться и его же воспроизвести.

Теперь давайте рассмотрим следующую ситуацию. У нас с вами есть некоторый разработчик, который хотел бы этим всем поделиться. То есть он поднял какой-то локально Docker, у него всё работает. Теперь он хотел бы, чтобы с этим могли воспользоваться другие пользователи или другие разработчики. Соответственно, этот разработчик должен взять наш Docker образ, закинуть его в регистр, как мы делали, допустим, в Docker Hub. А далее уже на основании образа из этого регистра мы могли бы поднять это всё на каком-то сервере. То есть простая железяка. И уже если у этой железяки публичный доступ, то мы сможем получить доступ к этому функционалу API, что бы там ни было. И очень хорошо бы, чтобы этот процесс был более налажен и более настроен. Но это следующий этап.

А пока мы попробуем с вами развернуть всё это на каком-то облачном сервисе. Давайте мы с вами попробуем это всё развернуть на AWS облаке. Для этих целей мы создадим EC2 instance, VPC, то есть это железяка, которая находится у Амазона, к которой мы сможем получить доступ. Мы дальше сможем сконфигурировать этот сервер, настроить определённые группы безопасности, чтобы наш сервер был доступен для внешнего мира. После этого мы сможем подключиться к данной машинке по SSH. Далее мы устанавливаем Docker на нашу машинку. После этого запускаем наш контейнер. Для примера возьмём наше приложение Node App, чтобы мы могли обратиться по API, поправка, по IP-адресу к этой машинке и в нашем браузере увидеть, что же там происходит.

Для этих целей вам необходимо перейти по ссылке, которую видите здесь. Регион можете выбрать не us-east, а любой другой. И соответственно, после этого нам необходимо будет запустить instance. Нужно будет выбрать ему конфигурацию. В нашем случае мы выберем конфигурацию Linux 2 AMI. Далее мы выберем T2 Micro, это как бы бесплатный уровень нашей машинки T2 Micro, потому что он входит в бесплатный tier. Но опять-таки, очень внимательно следите за расходами, потому что здесь могут быть какие-то косты. И также вы можете взять любую машинку у любого провайдера, а не только у Амазона.

Далее, после этого мы создадим новую пару ключей для того, чтобы мы могли подключиться. К этому мы перейдём к запуску нашего instance. При переходе по ссылке, которая указана в презентации, вы попадёте на такой дашборд EC2 сервиса. Здесь нажимаем кнопочку "Запуск инстанса". После этого мы должны с вами выбрать instance, то есть какой тип машинки мы будем использовать. Здесь нас интересует Amazon Linux 2 AMI, HVM kernel 5.10. Далее мы с вами выбрали архитектуру, это будет 64-бита. Далее instance type, то есть как бы уровень нашей машинки, это будет T2 Micro. Это очень важно, потому что он подлежит к бесплатному использованию. То есть, если вы только зарегистрировались на сервисе Amazon, то первое время вы сможете бесплатно пользоваться каким-то количеством ресурсов.

Далее у нас такая важная секция — это Key Pair, то есть логин, как мы будем коннектиться к нашей машинке. Здесь важно сгенерировать новую пару. То есть мы нажимаем здесь "Create New Key Pair" и здесь я делаю какую-то пару, пусть называется `private-kubernetes`. Далее тут выбираем RSA, здесь выбираем PEM, и после этого мы нажимаем кнопочку "Create Key Pair". Это очень важный шаг, который нельзя пропустить. Когда мы нажимаем создание, мы получим скачанный этот файл, к которым мы немножко позже перейдём с вами. Далее мы должны выбрать здесь эту пару, которую мы с вами создали. После этого мы можем нажимать на кнопочку "Launch Instance". Здесь мы ничего не трогаем. Network settings: мы разрешаем весь трафик. Здесь ничего не меняем. Выбираем "Create Security Group", чтобы группа безопасности была создана автоматически, и остальное остаётся по дефолту. Нам здесь не критичны никакие изменения. Мы нажимаем кнопку "Launch Instance".

После этого начинается процесс создания нашей машинки, виртуальной машинки, с которой мы будем работать. Когда машина будет создана, мы с вами можем перейти на вкладку "Instances" и здесь в "Instances" вы увидите, что у вас была создана машинка, которая в моём случае сейчас находится в статусе "pending". И когда состояние изменится на уже созданную машину, тогда мы можем будем считать, что наша машинка готова к использованию.

Итак, мы видим, что наша машинка была запущена. Теперь для того, чтобы мы могли подключиться к нашей машинке, мы можем нажать на неё, то есть на instance ID, и здесь у нас есть такая кнопочка, как "Connect". Мы нажимаем на кнопку "Connect", и здесь есть инструкция для подключения к нашему instance, как с помощью, например, встроенного клиента Амазона, так и через SSH Client. Мы нажимаем кнопочку "SSH Client", что позволит нам, по сути, через терминал подключиться к нашей машинке. Здесь есть детальные инструкции того, что нужно сделать. И важно теперь перейти в терминал и попасть в ту директорию, в которой у вас находится вот наш файл `private-kubernetes.pem`. В вашем случае, если вы дали другое имя ключу, соответственно, подставить имя своего ключа.

Итак, мы с вами находимся в нашей директории. Здесь видите, что именно в этой директории находится `private-kubernetes.pem`. И соответственно, в первую очередь, нам необходимо изменить права доступа к этому файлу. И здесь я вбиваю `chmod 400 private-kubernetes.pem`. Отлично, то есть мы это сделали. Теперь нам нужно выполнить команду `ssh -i private-kubernetes.pem ec2-user@<IP-адрес нашей машинки>`. То есть мы можем сейчас вернуться с вами снова в наш браузер, здесь мы копируем вот эту строку и выполняем эту команду. Далее здесь мы нажимаем "Yes", потому что это первое подключение к нашей машинке. И теперь мы находимся уже внутри нашей железяки. То есть это уже не ваша консоль, это как раз вот SSH консоль нашей машинки.

Теперь можем выполнить команду `sudo yum update -y`, что позволит нам проапдейтить всё. Теперь далее мы можем установить Docker. Для этих целей мы выполняем команду `sudo yum -y install docker`. После этого вы должны запустить Docker. Так как он уже был установлен, соответственно, выполняю команду `sudo service docker start`. Соответственно, мы теперь видим, что Docker стартанул. И теперь мы ещё должны выполнить команду `sudo usermod -a -G docker ec2-user`. Всё, теперь можем сказать, что наша машинка готова для того, чтобы мы могли с ней работать.

Теперь мы должны проверить, что у нас в нашем Docker Hub, в стринге, который мы с вами создавали ранее, есть наш образ `node-app`. Если его там ещё нет, то нам необходимо сделать так, чтобы он туда попал. Давайте вернёмся в проект с `node-app`. Итак, что мы здесь видим? Мы, во-первых, прописали здесь есть Dockerfile. То есть, в первую очередь, мы делаем сборку. То есть я нахожусь сейчас в проекте, делаю `docker build -t node-app:latest`. Происходит сборка нашего образа. Далее, после того, как образ был собран, мы перепроверяем данное приложение. Для этого я пишу `docker run -p 4200:4200` и здесь я запускаю `node-app:latest`. Мы перешли в браузер, здесь мы видим, что всё работает корректно, проблем никаких нет. Нажимаем "Введите имя", всё работает, всё отлично. Теперь давайте сделаем `docker tag node-app:latest` и далее проверяю, что он публичный. Нажимаю кнопочку "Create". Отлично, мы видим, что сейчас у нас образ собран. Теперь нам нужно его запушить с нашей локальной машины. Для этих целей здесь мы должны затегать репозиторий на удалённый. Соответственно, я пишу команду `docker tag node-app:latest <ваш_логин>/node-app:latest`. После этого я должен запушить свой локальный образ `<ваш_логин>/node-app:latest` в мой стринг для этих целей я использую команду `docker push <ваш_логин>/node-app:latest`. Мы видим, что push произошёл. Давайте перейдём в браузер и убедимся, что наш образ находится сейчас в стринге.

Итак, мы обновили нашу страничку и видим, что несколько секунд назад мы действительно запушили наш образ `<ваш_логин>/node-app` в наш публичный стринг. Теперь давайте попробуем запустить этот образ в нашем EC2 instance с помощью SSH. Здесь важное уточнение: если вы работаете на какой-то специфической ARM машинке, в моём случае это OS X M1, вам желательно ещё указать платформу образа, который вы собираете. То есть здесь мы указываем не просто `docker build`, но также указываем `linux/amd64`, потому что по умолчанию в моём случае это будет ARM 64, который не запустится на машинке, которая у нас поднята. Соответственно, здесь мы собираем наш образ. Происходит сборка. После этого мы делаем `docker tag node-app:latest <ваш_логин>/node-app:latest`. Мы тегаем на `<ваш_логин>/node-app:latest`. И после этого мы делаем `docker push node <ваш_логин>/node-app:latest`.

Теперь, когда произойдёт пуш, нам необходимо будет перейти в нашу машинку EC2 через SSH и попытаться запустить наше приложение уже там. Давайте посмотрим, как это будет выглядеть. Итак, сейчас мы находимся внутри нашей машинки. Теперь для того, чтобы запустить наше приложение, мы для начала проверяем, что у нас нет никаких запущенных контейнеров, то есть ни обычных, ни выключенных. Теперь мы вводим команду `docker run -p 4200:4200 <ваш_логин>/node-app:latest`. Итак, происходит сейчас запуск. Мы видим, что запуск произошёл без каких-либо проблем. Но теперь давайте попробуем зайти на наш сервер по IP-адресу через адрес.

Теперь, если мы попытаемся пингануть наш IP-адрес через `ping`, то здесь вы увидите, что у нас идёт потеря данных, то есть мы по какой-то причине не можем подключиться. Давайте же разберёмся, почему так происходит. Если мы вернёмся в наш instance, то здесь мы увидим такую вкладку "Networking" и "Security". И здесь, если мы нажмём на "Security", то мы увидим такую штуку, как "Inbound Rules". Соответственно, если мы посмотрим сюда, то мы видим, что мы сейчас разрешаем подключение к нашей машинке откуда угодно, но только по протоколу TCP на порту 22. Соответственно, это значит, что можем подключиться только через консоль. А вот исходящий трафик идёт куда угодно. Но для того, чтобы подключиться через браузер к этому, или через просто любой пинг, любой клиент к нашей железяке, нам необходимо немного модифицировать наши правила.

Для этих целей мы находим такую вкладку "Security Groups", заходим сюда, и здесь нам необходимо добавить новое правило. Мы нажимаем кнопочку "Edit inbound Rules" или "Edit". Здесь нажимаю "Add Rule" и здесь я указываю следующую вещь: то есть я говорю, что у меня есть "Custom TCP" и я разрешаю кому угодно, на любом порту, по любому протоколу подключаться к моей машинке. Конечно же, вы не можете делать подобное во всех случаях в реальной жизни, но для учебного проекта это подойдёт. Теперь мы нажимаем "Save Rules". Соответственно, это означает, что на данный момент мы можем подключиться откуда угодно к нашему IP-адресу.

Давайте теперь перейдём по ссылке в браузере, где у нас будет IP-адрес и порт 4200. И теперь, когда мы с вами перешли на порт 4200 вот по этому IP-адресу, мы видим, что у нас на данный момент всё работает корректно, то есть всё, как мы хотели, так и работает уже не на нашей локальной машине, а на удалённой железяке, то есть на удалённой машинке, которая запустила под капотом у себя Docker приложения.

Крайне и крайне важный момент, который нужно не забыть сделать, — это остановить нашу машинку, чтобы мы больше не тратили деньги на наш instance. Для этих целей вы подключаетесь из другого окна терминала к нашей машинке. Здесь мы выполняем команду `docker ps`. Далее мы выполняем команду `docker kill` для того, чтобы убить наш контейнер. Далее мы выполняем команду `docker container prune`. Мы видим, что теперь у нас нет никаких контейнеров, ни таких, ни выключенных, ничего подобного. И теперь мы должны выключить саму машинку в консоли AWS. Для этих целей мы идём на наш EC2 dashboard. Здесь у нас есть наши инстансы, и здесь я выбираю такую штуку, как "Actions", точнее "Instance State", и здесь я нажимаю кнопочку "Terminate Instance". То есть тут предупреждение, что мы всё это вышибем, но мы всё равно нажимаем "Terminate". И теперь мы видим, что теперь статус будет "Shutting-down" и потом он будет "terminated". То есть убедитесь, что вы удалили ваш instance и больше вам не идёт, как бы не капают косты на вашу машинку.

Отлично, то есть на этом мы можем сказать, что наша работа с Docker.

Итак, мы с вами увидели пример так называемого ручного деплоймента, развернуть на сервере нужно было руками, идти в консоль, что-то делать, всё это мониторить. Соответственно, вы уже поняли, что такой подход сложно поддерживать, особенно если у нас более чем один сервис, с которым нам нужно работать. У нас возрастает кратно вероятность ошибки. То есть я где-то что-то не то написал, прописал не те конфиги, возникли проблемы. Далее тратится много времени на всё это. У нас возможны проблемы как с безопасностью, так и с конфигурацией. По следующий этап — это процесс мониторинга, который у нас вызывает много сложностей. То есть, например, у меня 50 сервисов, как мне понимать, кто работает, кто не работает? Если они масштабированы, кто работает, на кого направлять нагрузку, если такая необходимость возникла? То есть целый ряд проблем промышленных возникает, которые нам пока трудно решать.

Для того чтобы решить эти проблемы, используется очень часто такая технология, как Kubernetes. Kubernetes — это инструмент для оркестрации контейнеров. Это Open Source система для автоматического деплоймента, масштабирования и управления контейнеризированными приложениями. То есть она позволяет нам вот все эти проблемы решить: и мониторинг, и деплоймент, и масштабирование, и балансировка нагрузки. То есть это очень такая серьёзная система, которую мы рассмотрим сейчас именно как разработчики, потому что система очень обширная, и если рассматривать как DevOps, то на это потребуется очень много времени. Но как разработчики, мы с вами рассмотрим ключевые компоненты и попробуем что-то поднять своими руками.

Итак, Kubernetes — это экосистема, которая решает для нас следующие задачи: первое — это мониторинг состояния и автоматический деплоймент, автоматическое масштабирование, когда мне необходимо поднять несколько инстансов, это балансировка нагрузки, если у меня мои сервисы горизонтально масштабированы. Провайдеру мы можем использовать как GCP, Azure, AWS, так и свою какую-то железяку, на которую мы накатим Kubernetes, или Kube, с которым мы и будем работать. Kube — это такая аналогия, как бы уменьшенная версия Kube, как K3s и прочее. И также решает проблему коммуникации между узлами кластера. То есть в кластере может быть много машин, то есть, допустим, у нас 10 железяк, они все объединятся в единый кластер, и между ними нужно как-то настраивать коммуникацию. Таким образом, мы конфигурируем эту конфигурацию на кластер, с которым работает у нас получается рабочее железо.

То есть, как это выглядит, если брать верхнее приближение: у нас есть всегда какой-то главный узел, он же Master Node, у которого есть управляющий слой, который называется Control Plane, и уже этот управляющий слой он распределяет нагрузку и делает вызовы на так называемые Worker Nodes или Worker Nodes, рабочие узлы. Внутри этих уже рабочих узлов у нас находятся наши Pods, то есть контейнеры и конфиги, на основании которых наши контейнеры и работают и взаимодействуют друг с другом.

Если брать более такое близкое приближение, то у нас есть некий главный узел Master Node, у которого есть управляющий слой и ещё какие-то магические компоненты, которые нам пока непонятны и не ясны. Давайте попытаемся их разобрать. То есть, если посмотреть немножко по-другому, как выглядит Kubernetes, то мы видим, что у нас есть Control Plane, в котором у нас есть как бы в центре всего так называемый `kube-apiserver`, который и взаимодействует с нашими рабочими узлами. То есть у нас есть сервер, он шлёт какие-то команды, пока непонятно какие, на наши рабочие узлы, на наши рабочие машинки. Внутри Control Plane есть ещё такие компоненты, как etcd — это некое хранилище, сейчас разберём детальнее, что это такое. `kube-controller-manager`, который отвечает как бы ну за менеджмент всей этой красоты. У нас есть `kube-scheduler`, который отвечает за поднятие, опускание наших нодов. И `cloud-controller-manager`, который отвечает за работу с облачными сервисами.

Рабочие узлы, ноды, они состоят каждый нод состоит из `kubelet` и `kube-proxy`. Сейчас посмотрим, что же это такое более детально. Если мы с вами говорим про `kube-api`, то это наш сервер, это компонент Kubernetes управления, который представляет как бы API Kubernetes. То есть это клиентская часть панели управления нашим кластером. `kube-apiserver` предназначен для горизонтального масштабирования и деплоймента трафика между этими экземплярами. Далее, etcd — это распределённое и очень надёжное хранилище наших данных в формате ключ-значение, такая key-value storage, которое используется как основное хранилище всех данных кластера в Kubernetes. Если наш кластер Kubernetes использует etcd в качестве основного хранилища, нужно убедиться, что у нас настроено резервное копирование данных.

`kube-scheduler` — это компонент нашей плоскости управления. Тут может меняться вот Control Plane, пытался переводить, поэтому разные термины используются. И он отслеживает созданные поды без привязанного узла. То есть есть под, но она не привязана к какому-то ноду. И вот именно он выбирает ноду, на котором эта под должна работать. При скелировании нашего деплоймента на узлах учитывается много факторов, и тут включаются требования к ресурсам, ограничения, связанные с аппаратными политиками, и прочее.

`kube-controller-manager` запускает процессы контроллера. То есть, э, логично, что каждый контроллер представляет собой отдельный процесс, и для упрощения все такие процессы скомпилированы в один файл и выполняются в одном процессе. Контроллеры включают себя: контроллеры узла — это Node Controller, контроллер репликации — поддерживает количество подов для каждого объекта, контроллер `endpoints` — он заполняет объект конечных точек, то есть endpoints, и связывает сервисы и поды. Что такое сервис, рассмотрим чуть дальше. И контроллер учётных записей и токенов — токенов, то есть Account и Token Controller, они создают стандартные учётки и токены для доступа там для для новых пространств имён.

`cloud-controller-manager` он запускает контроллеры, которые взаимодействуют с основными облачными провайдерами. Это бинарный файл, альфа, альфа функциональность, которая появилась в Kube 1.6, и `cloud-controller-manager` запускает только циклы контроллера, которые относятся к облачному провайдеру.

`kubelet` — это агент, который работает на каждом узле в нашем кластере, на каждой ноде. Он следит за тем, чтобы контейнеры были запущены в нашей в поде и работали. Ута `kubelet` принимает набор под спецификацию и гарантирует, что всё будет работать и исправно с точки зрения контейнеров. Агент `kubelet` не отвечает за сами контейнеры, которые не созданы Kubernetes.

`kube-proxy` — это сетевой прокси, который работает на каждом узле в кластере и реализует часть концепции сервиса. Далее, Kubernetes отвечает за создание, управление контейнерами, за использование ресурсов, которые представляет инфраструктура, чаще всего облачный провайдер, мониторинг состояния клиентов и за масштабирование сервисов.

Как это выглядит с точки зрения другой схемы: вот у нас с вами есть некий кластер, внутри которого есть три ноды. То есть кластер — это группа нод, на которых работают наши Docker приложения. Далее у нас есть нода, и нода — это физическая или виртуальная машина, которая взаимодействует с нашим кластером и которая является по сути хостом для worker Notes. Далее есть такая штука, как Pods. Pods — это рабочие приложения, которым были выделены определённые ресурсы. И есть такая сущность, как Services. То есть это логически объединённая группа подов, под которую выделяется отдельный IP-адрес. Теперь мы можем перейти к установке Kubernetes на наш локальную машину. Мы будем с вами устанавливать Minikube, потому что он хорошо подходит для нашего именно одноузлового кластера.

На машинке на ней будет кластер Kubernetes. Вы выбираете свою операционную систему, следуйте инструкциям, выбираете свой гипервизор, который вам будет нужен. А далее у нас есть необходимость ещё установить `kubectl`. Вы также выбираете вашу операционную систему. Здесь очень подробная инструкция. Когда вы это выполните, мы можем перейти к продолжению к проверке того, как шла установка. Для проверки мы сначала проверим, что у нас установился `kubectl`. Для этих версий я выполняю для этих целей я выполняю команду `kubectl version --client`. И здесь я вижу, что установка прошла хорошо. После этого мне необходимо стартовать мой Minikube. Для этих целей я выполняю команду `minikube start --driver=docker`. Я выбираю в данном случае Docker и также вбиваю команду `no-vtx-check`, которая поможет мне избежать ряда проблем на Маке.

Итак, сейчас происходит подтягивание Docker образа для Minikube. И когда он будет подтянут, начнётся этап старта контейнера Minikube. Итак, после старта нашего Minikube, мы можем выполнить команду `minikube status`. Здесь мы увидим, что у нас используется Control Plane, HVM запущен, API сервер запущен, `kubeconfig` сконфигурирован. Соответственно, мы скачали образ Kube, и мы подняли контейнер, в котором у нас сейчас Kube и крутится. Соответственно, теперь мы можем с вами запустить дашборд нашего Minikube. То есть для этих целей я использую команду `minikube dashboard`.

Итак, после этого в браузере мы увидим консоль нашего Minikube. Здесь мы видим, что на данный момент у нас ничего не отображается. То есть у нас нет Jobs, у нас нет Pods, у нас не настроены ни сервисы, ничего. То есть у нас чистый Minikube, с которым мы сейчас можем начинать нашу работу. После проверки мы можем перейти уже к основам работы с Kubernetes, более практически. То есть, когда мы говорим про Kubernetes, то у нас есть три ключевых компонента: это Pods — наши рабочие контейнеры, то есть рабочие юниты; это Deployment, которые описывают то, каким образом мы поднимаем эти Pods, на основании чего, как они работают и прочее; и это Service, который предоставляет доступ внешнему миру к нашим Pods. То есть мы смотрим сюда. То есть Pod — наименьшая рабочая единица с внутренним IP-адресом, который недоступен наружу. Далее, Deployment определяет, какие Pods и какое количество запускать. Service группирует Pods под одним каким-то общим IP-адресом и позволяет обратиться к Pod по IP-адресу мира.

Теперь мы можем с вами перейти к созданию Deployment. Мы уже с вами создали наш наше приложение Node App. И теперь мы будем создавать наш Deployment. То есть посмотрим, что это такое. Главное, чтобы вы понимали, что в этом случае мы работаем ни в коем случае не с локальным образом, а с образом, который у нас находится в регистре. И здесь в терминале мы начинаем выполнять команду `kubectl`. То есть я прошу `kubectl` создать мне Deployment `kubectl create deployment` и далее даю ему имя. То есть я назову его `private-node-app`. И после этого я указываю, на основании какого образа это сделать. То есть я говорю, что мне нужен образ `<ваш_логин>/node-app`. И нажимаю Enter.

То есть теперь мы видим, что у нас наш Deployment был создан. Я выполняю следующую команду `kubectl get deployments`. Здесь мы видим, что у нас появился Deployment, у которого сейчас состояние 0, то есть мы понимаем, что ни один Pod не запущен ещё. Теперь выполняю команду.

qp ctl get pods. Мы видим, что контейнер всё ещё создаётся. То есть, он на этапе создания. Вероятнее всего, это связано с тем, что мы ещё подтягиваем наш образ. В какой-то момент вы увидите, что у вас Get pods отдаёт вам адрес вашего пода, точнее, его имя и говорит, что он готов.

Теперь, если мы ещё раз выполним команду Get deployments, то здесь вы видите, что у него состояние "ready" один из одного. То есть, что у нас всего подразумевается один под, и этот под уже находится в рабочем состоянии.

Теперь, если мы с вами вернёмся снова в наш minic дашборд, давайте откроем отдельную вкладку здесь, чтобы мы не заблокировали основной консоль. Min Cube дашборд, то здесь вы увидите, что уже у нас появился, во-первых, один деплоймент, который рабочий. У нас есть один под, который рабочий, и у нас реплика сет одна. То есть, мы видим деплоймент, поды, реплика сеты. Отличненько.

Теперь давайте попробуем перейти по нашей ссылке localhost:4200, на которую мы обычно переходили перед этим, когда запускали это всё локально. При попытке перейти на localhost:4200, мы видим, что мы не можем обратиться сюда. Это связано с тем, что в данном случае это уже что-то внутреннее. Как я говорил ранее, у пода есть внутренний IP-адрес, к которому мы не можем обратиться из-за пределов.

То есть, что здесь произошло? Мы с вами выполнили команду и прочее. Далее, Ctrl Plane выбирает рабочий узел по ряду параметров. В нашем случае у нас один узел, но если было два, то он бы сделал какой-то выбор. Далее, отвечает за управление подом, и на основании образа деплой создаётся наш под.

Теперь, для того чтобы мы получили доступ к нашему поду, нам нужно сделать очень много усилий. Сейчас нужно каким-то образом прокинуть внутренний айпишник наружу. У нас есть типы прокидывания: это ClusterIP, это NodePort, или LoadBalancer. Про каждый из них вы можете почитать в документации. Я оставлю ссылку. Но мы с вами будем использовать NodePort. То есть, соответственно, мы говорим, что сейчас я хочу экспортить deployment prl-node-app и заэкспортить его на порт 4200. На основании этого у нас появится новый сервис.

Давайте вернёмся в наше приложение, посмотрим, как это будет происходить. Соответственно, здесь мы выполняем команду: `kubectl expose deployment prl-node-app --type=NodePort --port=4200`. То есть, теперь мы говорим, что у меня по App, который является, то есть, прокинуть наружу.

Теперь команду `kubectl get services`, то есть либо `services`, и мы здесь увидели, что у нас появился. Ну, Kubernetes - это понятно. Но здесь нас интересует `prl-node-app`. Либо мы можем использовать команду `get svc`, и вот мы с вами видим, что у нас появился какой-то сервис.

Теперь, для того чтобы мы могли получить доступ к нашей системе, мы должны подключить ещё minicube. То есть, в этом случае я выполняю команду: `minikube service prl-node-app`. Нажимаю Enter. И теперь у нас есть уже готовая ссылка. То есть, вот она появилась у нас. Перейдя по этой ссылке, мы увидим наше рабочее приложение. Давайте это проверим.

Итак, перейдя по этой ссылке, мы с вами увидели наше рабочее приложение, к которому мы привыкли. Да, то есть тут вбиваем `prl-node-app`, видите имя, всё работает, всё отлично. И теперь интересный момент. Давайте с вами сейчас нажмём Exit, чтобы проверить, что приложение сейчас потухнет и что будет происходить далее. Мы сейчас подождём какое-то время, и мы увидим, что наш под был пересоздан. О котором мы и говорили, что если даже с подом что-то случается, мы по какой-то причине выключили, то Kubernetes нам обеспечит как бы работоспособность этого пода. То есть, он увидел, что произошла какая-то беда, что под сейчас не отвечает, и, соответственно, его нужно пересоздать.

Давайте сейчас ещё зайдём с вами в наш куб дашборд, и здесь мы сейчас видим, что у нас всё работает, всё корректно. И теперь, если мы ещё обратимся к нашим подам, и здесь зайдём в наш конкретный под, мы ещё можем посмотреть Events. И здесь вы всегда видите, что происходило, на каком этапе. То есть, как всё планировалось, как запускалось и прочее. То же самое у нас есть по деплой, по деплоймент, где расписывается, что когда происходило. И основная мысль заключается в том, что, как вы увидели, сам отслеживает работоспособность наших подов, и если с подом что-то случилось, то в этом случае мы просто его перезапустим, и он будет работоспособен.

Теперь мы переключаем на новый бранч. Это ветка `p5`. Здесь, в ветке `p5`, вы видите, что у нас есть версия Kubernetes `dev`. То есть, это как бы изменение в код, с которым мы хотим поработать. Сейчас мы с вами соберём новый образ для этой версии. Соответственно, `docker build --tag prl-node-app:dev .`. Мы ждём, пока образ будет собран. И по завершении сборки мы можем его теперь тегнуть и запушить в наш registry. То есть, соответственно, теперь я пишу `docker tag prl-node-app:dev prl/prl-node-app:dev`. И после этого мы пушим образ. Соответственно, я делаю `docker push prl/prl-node-app:dev`. Происходит пуш нашего образа на сторонний сервер, на registry. И когда образ запущен, мы делаем следующие изменения. То есть, здесь я пишу: `kubectl set image deployment prl-node-app prl-node-app=prl/prl-node-app:dev`. То есть, мы как бы для нашего существующего деплой хотим применить новый образ. Мы выполняем эту команду. Мы видим, что имидж для данного деплоймент был изменён. И теперь, если я выполню команду `kubectl get pods`, то в этом случае вы увидите, что у нас создаётся новый контейнер для этого же пода. То есть, сейчас будет происходить пул нашего образа, а после пула мы запустим новый и потушим старый.

Итак, мы видим, что мы перезапустили под. У нас есть новый рабочий под, который был стартован минуту назад. И теперь, если мы перейдём с вами по той же ссылке, где мы проверяли наше приложение, мы увидим, что наши изменения были применены. Итак, здесь мы теперь видим, что у нас есть версия `k8s dev`. Она рабочая. То есть, все изменения отрабатывают, и проблем никаких нет. Таким образом, мы научились с вами применять новые изменения для уже существующего деплоймент.

Теперь, по такой же аналогии, мы переключаем на наш следующий бранч. Это `p6`. Мы делаем checkout и видим, что здесь из изменений - это изменение версии `k8s prod` вместо `dev`. Соответственно, теперь мы снова собираем новый образ. То есть, я делаю `docker build --tag prl-node-app:prod .`. Происходит сборка нашего образа. После этого мы должны создать тег. То есть, я тегаю `prl-node-app:prod` на `prl/prl-node-app:prod`. Происходит тег. И теперь я пушу этот образ в наш registry. То есть, `docker push prl/prl-node-app:prod`. То есть, теперь происходит аплоад нашего образа. И теперь мы меняем для нашего деплоймент. Пожалуйста, новые изменения для моего деплой. Теперь мы вбиваем `kubectl get pods`. Мы видим, что изменения применились моментально. 8 секунд прошло. Давайте теперь проверим, что же происходит сейчас в нашей системе. Здесь мы видим, что теперь у нас версия `k8s prod`. Проверяем, что всё работает по классике. `prl-node-app`, введите имя, всё. Таким образом, мы с вами применили первую версию и применили вторую.

И выполним ещё одну интересную команду. Мы попробуем создать два пода. То есть, как вы видите, сейчас у нас есть только один под для нашего деплоймент. Он работает, всё корректно. И теперь я выполняю команду `kubectl scale deployment prl-node-app --replicas=2`. Соответственно, теперь, когда мы проверяем, мы видим, что сейчас у нас создаётся второй контейнер. Он довольно-таки быстро создан. И теперь мы с вами попробуем перейти сначала в наш браузер и выполнить несколько команд, а потом проверим логи на подах. Как видите, здесь всё работает. То есть, тут будет, например, 1, 2, 3, 4, 5 и так до 10. Посчитаем и потом посмотрим, какие из этих вызовов полетели на один под, а какие на другой под.

Я возвращаюсь в нашу борду. Здесь у меня есть поды. Я смотрю, что у меня есть `node-app-1`. Здесь у нас есть такая кнопочка посмотреть логи. И видно, что сюда пошли вызовы 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. То есть, пока пошли все пром. Пока второй `node-app-2`. Здесь мы видим, что сюда пришло только `prl-node-app`. Давайте ещё в объём что-нибудь проверим, что придёт сюда. То есть, и здесь мы видим, что часть обращений пошла сюда, а часть обращений пошла на другую поду.

Таким образом, мы увидели, что с помощью команд в консоли мы можем задавать конфигурацию нашего окружения. Но использование только команд создаёт ряд сложностей с поддержкой рабочего окружения, потому что мы можем вбить, потом забыли, потом не понимаем, на основании чего применялись такие прочие изменения. Это сложно контролировать, мы не понимаем историю изменений и прочее. В реальной жизни чаще всего применяется подход использования конфигурационных файлов. То есть, инфраструктура как код (Infrastructure as Code). Для этих целей мы с вами можем сейчас сначала удалить все наши деплоймент, удалить наши сервисы, посмотреть, что нет никаких подов. И после этого перейти к написанию наших деплой с помощью формата YAML.

Сначала мы проявим. У нас есть `kubectl get deployments`. Далее, мы можем удалить этот deployment. Отмечу, я использую команду `kubectl delete deployment prl-node-app`. После этого я смотрю, какие у меня есть сервисы. То есть, `kubectl get services`. Теперь я использую команду `delete service` и задаём имя нашего, который мы хотим удалить. Далее, мы проверяем, какие у нас есть поды. `kubectl get pods`. Мы видим, что никаких подов сейчас у нас нет. И теперь мы с вами можем переключить `step 7`. То есть, мы переключились на `step 7`. Здесь мы смотрим, что был добавлен deployment файл. И давайте посмотрим, что же это за `node-app-deployment.yaml`. То есть, это у нас файл, который описывает, какой что должно быть в нашем деплой. То есть, здесь мы пишем, что мы используем версию `apps/v1`. В документации, по которой есть ссылка, вы сможете ознакомиться со всеми возможными опциями. Далее, мы говорим, что у меня есть метаданные с таким-то именем `prl-node-app-deployment`. Далее, указываем количество реплик - их четыре. Далее, у нас с вами есть `node-app` - имя `prl-node-app`. Label `app: client`. То, что это не back, а front. Далее, мы задаём шаблон. Тут опять-таки `label app: client`. И далее, мы указываем по контейнерам. Я говорю, что я хочу создать контейнер с именем `prl-node-app` на основании образа `prl/prl-node-app:latest`.

Итак, теперь, что я должен сделать для того, чтобы это у меня применилось? Я прихожу опять в консоль и использую команду: `kubectl apply -f node-app-deployment.yaml`. То есть, я говорю: "Kubectl, пожалуйста, примени файл `node-app-deployment.yaml`". После этого мы получаем информацию о том, что был создан новый deployment. Я проверяю это командой `kubectl get deployments`. И теперь мы видим, что у меня появилась появился деплой, у которой четыре пода. Проверяем, что есть действительно четыре пода. То есть, и они действительно все работают.

Таким образом, мы с вами смогли создать `deploy` файл. Теперь мы должны с вами сконфигурировать сервис, чтобы это у нас корректно работало. Соответственно, мы можем с вами теперь переключиться на шаг номер 8. И здесь вы увидите, что был добавлен сервисный файл. Мы зайдём в него, то мы здесь видим следующие данные. Мы говорим, что у нас есть `api_version: v1`. Тип этого файла - это `service`. Метаданные - это `node-app-service`. Далее, я хочу работать с приложением `node-node-app`. И далее, я говорю, что у меня есть `port: tcp`. Порт на 80-й, `targetPort: 4200`. Соответственно, теперь, давайте и здесь, что мы здесь тоже поставим 4200, чтобы было `NodePort`, то что мы забивали в консоли. Теперь происходит здесь. Соответственно, теперь мы пере проверяем, что никаких сервисов сейчас у нас нет. Идёт `kubectl get services`. У нас есть только `kubernetes`. Теперь мы делаем следующее: `kubectl apply -f node-app-service.yaml`. Отличненько. Соответственно, Теперь мы проверяем, что у меня есть уже мои сервисы. Я выбиваю команду `kubectl get services`. Здесь я вижу, что есть `prl-node-app` и `kubernetes`. И теперь мне осталось только запустить с помощью `minikube`. Я пишу `minikube service node-app-service`. Происходит запуск. И соответственно, перейдя по ссылке, я смогу увидеть, что же у меня здесь есть. И здесь мы видим код, который был у нас в версии `latest`, не `dev` и не `prod`, а именно `latest`. Здесь, давайте просто в объём тоже `prl-node-app`. Проверим, что всё работает.

Таким образом, мы понимаем, что сейчас у меня уже есть deployment, у меня есть сервис, которые были созданы на основании наших конфигурационных файлов. И остался только один момент - это применение изменений к нашему деплоймент. Например, я смотрю, что сейчас у меня есть четыре пода. То есть, делаю `kubectl get pods`. Четыре пода, всё работает. И я хочу изменить, чтобы их стало два. В этом случае я просто меняю их в файле. Если нужно, я это коммичу. И после этого использую команду `kubectl apply -f node-app-deployment.yaml`. Отлично. Теперь, если мы сделаем `kubectl get deployments`, что у меня два пода останавливаются. И в какой-то момент, когда они остановятся, у меня останется только два пода. Отличненько.

Теперь мы с вами можем переключиться на бранч номер 9, где мы с вами добавим новые файлы. Это будут файлы `node-app-deployment.yaml`, который будет работать на основании образа `prl/prl-node-app:prod`. Это будет `node-app-service-dev.yaml`, который соответственно на проде. И два сервиса `client-dev` и `client-prod`, который будет взаимодействовать со своим деплой для дева и для прода. Здесь единственный момент, что мы забьём другие порты. То есть, тут тоже поставлю 4200, и тут поставлю 4200. Далее, что нам необходимо сделать? Давайте для начала снесём все деплой, которые у нас есть, и все сервисы, чтобы проверить, что подов пока не осталось. То есть, тут я пишу `kubectl get deployments`. Теперь этот deployment я удаляю. `kubectl delete deployment node-app`. Далее, `kubectl delete service prl-node-app-service`. Такого нет. Соответственно, `node-app-service`. Да, скорее всего. Отлично. И проверяем, что у меня больше подов нет. Всё, подов в данном у нас нет.

Теперь мы можем перейти к нашим файликам `node-dev-deployment.yaml` и `node-app-deployment.yaml`, и также сервисы для дева для прода. Всё это находится у нас в бранч под номером 9. `kitch`. Мы находимся в `step 9`, финальный `step` для этого приложения. Соответственно, что мы теперь делаем? Мы увидели, что у нас никаких подов, никаких деплой, никаких сервисов нет. И теперь мы с вами можем запустить наши изменения. То есть, соответственно, теперь мы делаем следующее: `kubectl apply -f`. То есть, я могу прямо несколько файлов применить сюда: `node-app-deployment-dev.yaml`, `-f node-app-deployment-prod.yaml`, `-f node-app-service-dev.yaml`, и `-f node-app-service-prod.yaml`. Так, у нас есть наши файлики. Смотрим, что произошло. Теперь мы выполняем команду `kubectl get deployments`. У нас есть два деплой. Теперь у нас есть два наших сервиса. И теперь, соответственно, мы делаем `minikube service client-dev` и в соседнем окне мы делаем `minikube service client-prod`. Итак, их запустили. Да, давайте нас появилась. Итак, здесь мы видим, что на одном порту у нас поднялся сервис и рабочее приложение для дева. На другом порту поднялся сервис и есть рабочее приложение для прода. Таким образом, мы теперь можем переключаться между окружения на уровне кода.

Итак, мы переходим в наш проект `fil-service` и переключаем на бранч `step 2`. Здесь у нас есть `docker-compose.yaml` файл, в котором мы запускаем наше приложение и создаём volume. Соответственно, для того, чтобы это всё стартануть, мы используем команду `docker-compose up -d --build`. Итак, команда запускается. У нас подтягивается образ. Всё запущено. Теперь, если мы с вами перейдём на порт 8989, то здесь, если мы с вами в объём данные, то есть `test 1`, `test 1`, `submit payload`, мы видим эти данные. Теперь, давайте мы с вами выключим наше приложение и удалим контейнеры. Соответственно, здесь выполняем команду `docker-compose down`. Теперь мы удаляем наши контейнеры. То есть, я пишу `docker container prune`. Контейнеры удалены. И теперь мы попробуем снова поднять наше приложение через `docker-compose up`. И теперь, если мы снова обновим, то мы увидим, что данные у нас не потеряны.

Перейдём к томам в Kubernetes, потому что до этого момента мы работали с томами контейнеров. Kubernetes в свою очередь представляет нам свои тома, которые дают нам ряд преимуществ. Они имеют различные типы, не всегда персистентные. Они имеют различные драйверы, то есть могут быть локальными на ноде и облачными через облачные драйвера. Более детально мы можем ознакомиться с ними, перейдя по ссылке, которую вы видите здесь. То есть, здесь у нас есть разные типы: volumes, AWS, для Azure, есть локальный, есть cinder, configMap и прочее. EmptyDir, с которым мы немножко поработаем. Соответственно, изучив эту документацию и зная свою ситуацию на проекте, то есть, что вам необходимо, вы всегда можете выбрать себе корректный тип volume для Kubernetes.

Теперь, давайте мы снова вернёмся в наше приложение и попробуем поработать уже с томами Kubernetes. Для начала мы переключимся на новый бранч и попробуем запустить наше приложение с помощью уже Kubernetes, с помощью файлов deployment и сервисов. Итак, мы переключаемся на бранч `step 3`. И здесь вы видите, что у нас появились файлы `fil-service-deployment.yaml` и `fil-service-service.yaml`. Соответственно, что мы с вами видим здесь? Мы добавили стандартный наш deploy файл. Но самое интересное нам. Мы видим с вами здесь, у нас есть спецификация, есть контейнер, и тут есть такой раздел `volumeMounts`. То есть, мы говорим, что мы хотим смонтировать наш volume в наш контейнер с volume, который будет расположен вот по такому пути `/app/storage`, и имя этого volume `fil-service-volume`. А здесь мы создадим сам volume. И здесь мы видим, что у него тип идёт `emptyDir`.

Теперь, давайте мы соберём новый Docker образ на основании текущего кода, используя команды `docker build --tag fil-service:latest .`. Пока идёт создание образа, мы с вами создадим наш новый репозиторий. То есть, здесь появляется репозиторий с именем `fil-service`. Здесь я его пере проверяю, что он является публичным. Я создаю данный репозиторий и возвращаюсь в наш проект. Внутри проекта мы видим, что образ уже был создан. Теперь нам нужно его тегнуть. То есть, мы используем стандартную команду `docker tag fil-service:latest prl/fil-service:latest`. Нажимаем Enter. И теперь мы пушим наш образ в наш удалённый арфа. `docker push prl/fil-service:latest`. Печатка. И теперь должно быть всё хорошо. Итак, идёт пуш нашего registry, нашего образа. И мы также видим, что в наш удалённый артефакт мы загрузили несколько секунд назад наш новый образ.

Теперь можем вернуться в проект и попробовать применить наши deployment и наш сервис. Для этих целей я пишу: `kubectl apply -f fil-service-deployment.yaml` и `-f fil-service-service.yaml`. Итак, мы видим, что у нас были созданы новые deployment, новый сервис. И теперь выполняю команду `minikube service fil-service-service`. На данный получили ошибку, потому что ещё образ не подтянулся. Если мы сейчас выполним с вами `kubectl get pods`, то здесь мы видим, что у нас есть `fil-service-deployment`, и контейнер всё ещё создаётся. Такая ситуация бывает. Нам стоит подождать, пока под будет создан.

Итак, теперь видим, что под был создан. И давайте ещё раз выполним команду `minikube service fil-service-service`. Теперь мы видим, что ошибок мы не получили. И теперь, если мы с вами перейдём снова на страницу формы, и тут мы в объём `test`, `test`, `submit`, `go to payload`, видим, что данные у нас здесь есть. То есть, мы ничего не потеряли, всё корректно работает. Но если сейчас мы с вами сделаем следующее: то есть, я беру под `kubectl get pods` и попытаюсь удалить данный под, чтобы Kubernetes сам его пересоздал. Соответственно, теперь мы видим, что мы создаём новый под. На текущий момент снова `get pods`, он запущен. У нас всё хорошо. И сейчас я вернусь в наш браузер и посмотрю, что же там происходит. Сейчас на данный момент мы видим здесь `test`. Но как только я обновлю страницу, я увижу, что данные были потеряны, потому что мы с вами использовали `emptyDir`.

Давайте вернёмся в код. То есть, здесь мы с вами видим, что мы использовали тип volume `emptyDir`. Это значит, что при пересоздании нашего пода мы получим пустой volume, в котором ничего не будет. Текущий вид томов Kubernetes не поддерживает кластерную модель, то есть наличие нескольких связанных узлов. Для решения нашей задачи существуют персистентные тома (Persistent Volumes). Более детально о них вы можете прочитать в официальной документации. Персистентные тома делятся на: то есть, есть у нас стандартные, которые определяются, создаются и работают на уровне именно пода. Их администрировать довольно-таки сложно. А персистентные тома - они определяются, создаются и работают на уровне уже кластера и управляются они через Claims. Они крайне просты и понятны в администрировании.

Итак, мы переключились на бранч `step 4`. И здесь мы с вами видим следующие файлы. То есть, это `local-volume.yaml`, в котором мы с вами создадим. То есть, мы видим `api_version: v1`. Далее, мы даём имя `local-persistent-volume`. Ему мы выделяем ему 2 Гб в нашей файловой системе. `storageClassName: standard`. Доступ `ReadWriteMany`. Это значит, что можем записывать, читать и записывать. Этот файл мы создаём. `/path/storage`. И директория или создание. То есть, если такой директории нет, то мы её создадим. Далее, у нас есть `claims`, которые работают с нашим `local-persistent-volume`, и они говорят, какие ресурсы мы здесь можем использовать. То есть, это уже как бы сами claims.

Теперь, давайте перейдём в наш браузер, почистим консоль и выполним команду `kubectl get pv`. Мы видим, что сейчас у нас `persistent-volume` есть только для нашего Minikube. То есть, ничего связанного с нами у нас нет. Теперь, вы поняв, выполняю команду `kubectl apply -f local-volume.yaml` и `-f local-volume-claim.yaml`. Отличненько. Теперь мы с вами создали наши volumes. Теперь ещё напишу `kubectl get scc`. Ничего пока не поменялось. А далее, мы с вами идём в наш `fil-service-deployment.yaml`. И здесь мы видим, что есть некоторые изменения. То есть, вот здесь мы в `volumes` указали, что наш volume `fil-service-volume` теперь `persistentVolumeClaim`, который ссылается на этот claim. А claim в свою очередь ссылается на `local-volume`. Соответственно, Теперь мы можем ещё выполнить следующую команду: `kubectl get persistent volumes`. Видим. Так, они уже были созданы. Далее, я могу ещё вбить `get persistent volume claims`. И теперь ещё `kubectl get pods`. Мы видим, что наши поды сейчас крутятся. Соответственно, сейчас мы можем с вами применить те изменения, которые у нас были. Соответственно, мы сейчас делаем. Что я могу создать? То есть, я пишу `kubectl apply -f fil-service-deployment.yaml`. То есть, мы видим, что всё было сконфигурировано. Теперь мы смотрим `kubectl get pods`. Видим, что под был запущен наш. И соответственно, давайте сейчас снова вернёмся в наш браузер. Добавим туда какие-то данные. Перезапустили. Здесь мы видим, что пока payload пустой. Я вбиваю `test 1`, `test 1`. Смотрю, добавились. Давайте ещё добавим `test 2`. Тоже submit. Данные есть, всё хорошо. Возвращаемся сейчас в наш проект. Соответственно, я вбиваю команду `kubectl delete pod` вбиваем её имя. Почистим. `kubectl get pods`. Видим, что уже под была запущена. Возвращаемся браузер. И здесь, если мы обновим страницу, мы видим, что данные никуда не делись, они остались, потому что теперь мы используем именно персистентный volume.

Теперь мы можем переключиться на бранч `step 5`. И здесь мы видим, что в этом бранчевский файлы нам нужны для того, чтобы мы не забивали руками вот в деплоймент себе данные сами, а чтобы мы могли брать эти данные непосредственно из переменной среды. То есть, у нас с вами появляется какой-то `configMap`. То есть, мапа с переменными. То есть, у меня появляется какая-то переменная `FILE_SERVICE_STORAGE_LOCATION`, и здесь её значение как key-value. Теперь мы смотрим, где используется данный файл. Мы видим, что у нас теперь здесь есть `fil-service-deployment-configmap.yaml`, где вместо хардкода используем `FILE_SERVICE_STORAGE_LOCATION`. Теперь, после этого мы с вами что можем сделать? У нас который у нас уже есть.

и удалим сервис, который у нас уже есть, и потом передним новый и создадим Новый сервис для этих целей. Давайте почистим консоль. То есть, я снова пишу: "Далее мы фас сносим Del". Давайте заодно ещё вот это снесём аккуратненько. То что осталось от прошлых проектов. Отлично. Теперь мы делаем Cu ctl Get. Опять-таки, мы можем снести прошлое, то есть Cu ctl Delete serv Client Client и также снес ещё и F serv serv. То есть здесь serv. Отличненько.

Теперь что мы делаем? Мы с вами начинаем применять наши фай. То есть, япи при config Map наш. После этого я применяю наш dey F dey volumes config Map и дальше я применяю ещё наш сервис File serv serv Y, в котором также у нас есть изменение, что мы работаем с этим деплой. Итак, мы нажимаем Enter. Мы видим, что были созданы и деплой, и config, и сервис. Далее я выполняю команду Min Cube serv фа Service Service. Некорректно скопировал. Так происходит запуск. И давайте теперь Переключи в нашу в наш браузер. Здесь мы видим, что мы создали наш файл. Здесь мы видим старые данные, потому что мы подключились всё к тому же persistent во, потому что независимо от того, кто к нему подключается, Vol остаётся всё таким же, данные там хранятся, и мы получаем к ним доступ.

Итак, давайте сейчас удалим текущий deployment. Снова делаем Cub ctl Get deployment. Удаляем его, то есть Cub ctl Delete deployment. Удалим наши сервис. Cube ctl Get Service. Соответственно, его тоже нужно снести. Cube ctl Delete Service. Далее мы проверяем, что у нас никаких подов не осталось. Cub C Get pods. Да, подов тоже нет. Всё хорошо. И теперь давайте мы Переключи на следующий бранч. Это branch Step 6. Шестой бранч. И здесь у нас с вами появляется новый файл fil serv Secret. То есть здесь мы можем хранить различные данные, пароли и прочее. Здесь данные закодированы с помощью кодировки Base 64. Это значит, что если мы с вами пойдём и сделаем декод вот этой строки, то мы с вами получим наш App storage storage txt. И далее мы можем применить наш fil Service Secret. И дальше у нас появился с вами ещё новый deployment File Service deployment Volume Secret. И здесь мы видим, что у нас появляются данные о нашем value From отсюда. То есть у нас появляется какой-то storage Location, и storage Location у нас берётся из File Service Secret файла, и он берётся из значение File servers storage. Соответственно, в данном случае это не так критично. Но если бы это были пароли к базе данных или прочем, это было бы более удобно.

Хорошо. Теперь давайте мы с вами сделаем следующее. То есть, мы применим все эти файлы. То есть apply - F fil Service deployment volumes Secret. И, конечно же, сначала нужно бы ещё прикрепить сами секреты. То есть F Secret. И в конце мы е перем. То есть тут будет serv serv YAM. Отлично. Нажимаем здесь. Теперь Enter. Всё создано. Теперь нажимаю команду Min Cube Service fil Service Service. Происходит запуск. И здесь мы видим, что приложение работает. Давайте тут в объём тест 8. Тест 8. Нажимаем submit. Go to payload. И видим, что и старые данные остались, и текущие данные у нас всё также сохранились.

Таким образом, мы с вами рассмотрели разли виды люмов и также рассмотрели варианты передачи данных в нашу систему через config Map и через Secret. Какие же преимущества даёт нам Такая сущность как Secret? Первая безопасность. То есть, даже если значения в секрете кодируется просто в b64, они всё равно не хранятся в открытом виде и не отображается в ял файлах манифестов кубера. Это может быть крайне Полезно, если значение секретов содержит чувствительные данные, такие как пароли Или ключи доступа. Далее управление доступом. Секреты могут использоваться для ограничени доступа к чувствительным данным на нашем кластере, и Мы также можем управлять правами доступа к секретам с помощью ролей и разрешений в кубе. Ещё следующий момент - интеграция с инструментами управления секретами. То есть, кубер имеет возможность интегрироваться с таким инструментами как aws sec Man и прочее. Это позволяет нам более безопасно управлять этими секретами, также автоматически их обновлять и производить ротацию ключей, не задействуя какую-то ручную работу. Глубокую простота обновления. Потому что ЕС нам нужно заменить Като значени, мы просто берём в конкретном файле меняем, и потом всё это будет применено. И дальше, хотя b64 кодирование не обеспечивает полной безопасности, использование секретов кубе представляет дополнительный уровень безопасности и управления данными в нашем клас.

Таким образом, что мы видим? У нас с вами есть некий прецедентный Том. У нас с вами Может быть несколько узлов, в рамках которых У нас есть сколько угодно под. В данном случае три штуки. И через То есть через настройки доступа к стент вому, который есть на данном узле, мы можем подн к одному и тому же тому. И мы переходим к сетевому взаимодействию в кубес. Мы будем рассматривать детали в сервисе persons. Там будет у нас три под проекта. Детально всё есть на гитхабе, и мы это всё сейчас разберём. То есть, что мы будем делать? У нас будет некий кластер, в котором будет два пода. Один под будет содержать один сервис API Gateway, который будет доступен внешне, и он будет обращаться к сервису Person serv внутри другого пода. И также у нас будет ещё под Address сес, и с ним вместе в поде будет Person серс. И опять-таки, Address сервис будет доступен для вызова из внешнего мира, а Person сес нет. И соответственно, мы будем как бы иметь защищённый ресурс, к которому нельзя Достучаться Извне, но к нему можно будет Достучаться через другие сервисы, то есть API Gate и Add.

Для этих целей мы с вами переходим в наш проект Person. И здесь мы находимся на ветке branch Step 1. То есть, я делаю git branch. И тут вижу П 1. Все остальные Давайте вкладок, чтобы они нам не мешали. Итак, что мы здесь делаем? У нас есть три сервиса. Это Address Service, это AP Gateway, и это Person Service. Person serv это просто все эти сервисы. Это просто springboot приложение, которое предоставляет а то есть в базу данных никуда не ходят, просто генерируют какие-то данные под капотом, и к этим данным можно обратиться. В Михе очень детально всё описано, как это работает. Тоже самое примерно происходит и в Address Service, и IP Gateway. Но при этом IP Gateway имеет следующую штуку. То есть, тут внутри него содержится такая штука Как Person Client, который с помощью обычного телета может обратиться к другому сервису по этой Ур. То есть, у нас есть какая-то переменная Person Service URL, которая находится здесь. То есть, она либо именуется Person Service, либо по дефолту это Local Host 8080. И то же самое у нас находится внутри Address сервис, который также содержит в себе клиент, который обращается к нашему Person Client. У него есть свои нпои, но под капотом он вызывает другой сервис.

Давайте пока всё это свернём аккуратненько и посмотрим на файл docker compose. Здесь что мы видим? Мы видим, что у нас есть docker compose версия 3. У нас есть три сервиса. То есть, первый - это Person. Мы здесь будем собирать образ на основании докер файла, который находится внутри Person Service. Для гевея на основании docker файла здесь. И для Add сервис настане docker файла там. И каждый мы запускаем на своём порту. То есть, у всех из трёх этих сервисов используется дефолтный порт 8080 под капотом. Но мы его мапи для Person Service на 8070, для AP Gateway 8080, и для Address Service для на 8090. Соответственно, что мы делаем? Мы сейчас выполняем команду docker compose Up - D - - Build. Теперь мы проверяем, что у нас были созданы наши образы. То есть, я пишу docker Image LS. И мы видим, что здесь Мы создали три образа: Person Gateway, persons Gateway, persons, persons, и persons Address.

Давайте теперь мы запушил arf. То есть, я создаю три репозитория: Person Gateway, Person, и persons Address. Итак, здесь появляется первый сервис - это persons Address публичный. Создали. Далее мы добавляем ещё один репозиторий - это Person Gateway. Тоже публичный. И третий - это Service persons Person. Таким образом, мы с вами сейчас видим, что у нас появились три новые репозитория: это Person, Person, Person Gateway, Person Address. Для каждого сервиса свой отдельный artfactory. Теперь уже самом коде. Мы сначала создаём теги. То есть, я пишу Dock Tag persons Person. Давайте Person Address начнём. Person Address тегаем на prite Person. Это сделали. Теперь мы запу это на наш artifactory. То есть, docker Push Address. Теперь мы выполняем команду следующую. Теперь выполняем команду г Person Gateway и тегаем его на prite persons Gateway. Происходит пуш нашего образа. Далее мы делаем ещё один тег. И соответственно, и этот образ Мы пушим в наш артефакто. Таким образом, мы с вами видим, что у нас есть первый репозиторий addresses, в котором уже есть образ latest. У нас есть второй репозиторий, в котором есть образ latest, и есть третий репозиторий, в котором также есть образ latest.

Итак, мы 2. Здесь мы видим, что были добавлены следующие файлы. У нас есть пакет и внутри него у нас есть два файлика. То есть, пер и Давайте посмотрим. Здесь мы создаём стандартный. Даём ему имя. Далее. После этого у нас есть интересная вещь вот здесь, где идут контейнеры. Мы создаём не один контейнер, а два. То есть, первый контейнер - это Address. Далее, у него идёт образ persons Address latest. Далее мы передаём переменный среды, в которой мы отдаём Person Service URL localhost 8080 и Север Port мы даём 8090. Далее у нас появляется здесь Person. И мы ему даём образ Person Person late. Соответственно, сервис работает с этим дейм. Прокиды нам порт 890 по tcp и прокиды тип прокиды - это соответственно.

Теперь можем сделать что? Мы с вами Заходим в консоль и выполняем команду apply ми F. Лучше будет даже зайти в кубете сначала, а теперь нажать F Add serv. Итак, происходит запуск. Что ий были созданы. Теперь мы проверяем, что у нас поднялись поды. Cu ctl Get pods. Смотрим, что контейнеры пока создаются. Итак, мы видим, что поды были подняты, и у нас всё сейчас работает. Соответственно, теперь мы можем проверить, во-первых, работу самого Add. Для этих целей я перехожу в наш postman. И здесь я делаю вызов API Address какая-то цифра. Нажимаю кнопочку S. Происходит запрос. И здесь мы видим, что данные были получены. И как вы помните, по логике в коде, Address обращается к Person. То есть, здесь у нас всё работает. То есть, к адресу мы Обращаемся без каких-либо проблем. Теперь Давайте попробуем обратиться к самому Person сервису. И как вы видите, если мы Обращаемся Local Host 880 API V1 Person, к которому мы и Обращаемся здесь, то у нас ничего не получается. Это из-за того, что у нас есть только сетевое взаимодействие внешнее проки для Add сервиса, но уже AD с взаимодействует внутри нашего пода.

Итак, мы переключаем на ветку п 3. Здесь вы видите, что у нас добавились новые файлы. Это добавление ресов и нов отдельных файлив. То есть, соответственно, давайте для начала снем де, который уже у на есть. То есть, я делаю сонно. Мы делаем удаление Delete deployment. Этот далее. У нас идёт ql Get serv. Мы снес Address Service. Cub C Delete serv Address. Отлично. И соответственно, теперь проверяем ql Get pods. Подов нет. Супер. Соответственно, теперь у нас с вами есть следующие фалы. То есть, первый фай - это Person dey. В этом случае у нас здесь есть. У нас создаётся deployment, который взаимодействует с нашим Person Person образом. На основании него поднимается одна реплика. Далее у нас с вами есть Person Service. И здесь мы видим, что у нас появляется тоже Application Person. Но здесь тип у нас идёт cler IP. То есть, это как раз значит, что внутри кластера мы доступны. Далее мы с вами идём в Address deployment File. И здесь мы опять-таки взаимодействуем с нашим Address деплоймент. Мы создадим и берём точнее на основании образа Person Address latest. И вот здесь мы используем переменно среды следующую. То есть, тут идёт Person serv default 880. Интересная вещь. Потом посмотрим, откуда она у нас всё-таки берётся. И сервер пор будет 8090, чтобы мы сам Add сер запустили на порту 890. Отличненько. Далее идём в Address. Тут уже прокиды идёт. Соответственно, мы сможем об к нашему Address сервису.

Теперь делаем следующее. То есть, я теперь снова делаю Cub ctl apply - F. М что мы сделаем? Здесь мы берём Address deployment yel. Здесь мы берём Address Service yaml. Здесь мы берём Person deployment yaml. И ми F Person Service Person Service yaml. Отлично. Мы видим, что всё было создано. Ошибок сейчас нет. Соответственно, теперь мы выполняем команду minic Service Person serv. И в соседнем окошке Мы тоже выполняем команду minic сес Address сес. Cube Address поправка сес Address Service. Итак, всё. Теперь мы запускаем его тоже. Отличненько. И теперь мы ещё можем проверить, какие сервисы У нас есть. Давайте Cu C Get Services. Отлично.

Какая же здесь особенность? Итак, теперь мы берём наш порт, который у нас появился для нашего Address сервиса. То есть, здесь мы берём наш Address сервис. Копируем вот этот порт. И переходим в postman. Итак, теперь мы делаем вызов на новый порт. И видим, что здесь мы получили данные. У нас всё корректно работает. Всё отлично. Теперь Давайте попробуем сделать обращение на наш Person. И ВМ мы уже получаем доступ, потому что мы находимся внутри единого кластера. Наша машинка, и мы можем сюда обратиться. То есть, таким образом, мы с вами подняли уже приложение Person, к которому можем обратиться и Извне, и из нашего кластера, и также через Address сес.

Итак, здесь важный момент, что обратиться к сервису Мы можем по такому имени. То есть, имя сервиса, потом точка Деол. Кроме этого, мы можем здесь использовать следующую запись. То есть, вместо вот Person можем поставить здесь переменную окружение под названием Person Service serv Host. Почему это должно заработать? Это должно заработать по следующей причине. Мы делаем с вами Cub ctl gets. У нас с вами есть Address. Здесь я делаю следующее. Я зайду в интерактивном режиме и посмотрю переменный среды нашего Address деплой. Соответственно, Cub ctl EX мину it интерактивный диник Нашего Нашего пода минус Минус ф мы запускаем. И здесь, если мы постараемся найти вот эту переменную. То есть, я вбил вот наш хост. То есть, здесь внутренний айпишник смап с нашим сес Host. Соответственно, это будет у нас корректно всё работать.

Итак, мы с вами переключаем на бранч Step 5. В рамках этого бранча мы с вами добавили в пакет kubernetes два файла. Это Gateway deployment, который по классике стартует на основании об своего. То есть, Gateway мы передам ему переменные среды Person serv URL и Server 8070. И в Gateway serv Мы видим, что у нас ста на основании приложения Gateway. Прокиды через и протокол tcp. Соответственно, теперь мы с вами Заходим в пакет cuber. Делаем apply - F Gateway Fate. Проверяем, что поды уже подняты. Cub ctl Get pods. Стартанул. И теперь мы можем запустить это через куб. Соответственно, идёт Мику сервис Gateway сервис. Так происходит Старт. Мы скопировали вот этот порт, который у нас здесь есть, и идём в наш postman. Здесь мы делаем запрос. Соответственно, мы можем получить данные от персона по одному персону и также по всем. Соответственно, мы с вами смогли поднять приложение Gateway, которое также взаимодействует с нашим Person сервисом, потому что у него идёт тип прокиды Нея через кластер IP. А так как Gateway находится в том же кластере, соответственно, Мы можем с ним взаимодействовать.

Вывод. В данном курсе Мы изучили теоретические основы и получили практические навыки работы с docker и кубес. Мы научились работать не только с локальным окружением, но и взаимодей с облачными сервисами, такими как dockerhub и aws. Опять-таки, вместо Reg dockerhub можете использовать любой другой. Концепция не изменится. AWS можно использовать другой Облачный сервис, который даёт вам возможность поднять eas 2 instance, то есть какую-то машинку и подключиться к ней по ssh. Далее мы разобрали с вами внутренние устройства как Докера, так и курне, и также научились настраивать. Что я хочу посоветовать тем рекомендациям, которые были в начале? То есть, не просто просмотреть залпом, а просматривать внимательно, повторять то, что было сделано в коде, выполнять все команды, смотреть, что всё работает, и дальше переключаться на следующую ветку. Потому что все репозитории Они будут залиты на github. У вас будут ссылки на эти репозитории, и соответственно, вы сможете любой из них подтянуть и работать. Если что-то не можете поднять локально без Докера, то это не критично. Это было просто показано для того, чтобы вы видели, что поведение при локальном старте и через докер не особо отличается, а местами не отличается совсем.

Также я очень рекомендую ознакомиться с документацией. Ссылку ссылки на которую Также будут под этим видео. Потому что в документации описание наиболее полное и наиболее актуальное. Там же оно постоянно обновляется. Обратная связь. Если у вас возникнут вопросы, предложения, жалобы, пожелания, то Пожалуйста пишите комментарии под видео. И также по любым вопросам Можете написать мне на эту почту prl a& yahoo.com. Я благодарен вам за ваш время. Желаю вам успехов и до новых встреч. Всем пока.