0
Обложка: Docker: что это и как используется в разработке

Docker: что это и как используется в разработке

Docker: что это и как используется в разработке

На дворе закат 2022-го, и большая часть IT-индустрии только и делает, что работает с контейнерами. Откуда они появились, как добились глобального признания и при чём тут Docker? Расскажет разработчица в команде инфраструктуры Яндекса, действующий автор курса «DevOps для эксплуатации и разработки» Дарья Меленцова.

  1. Начнём с основ
  2. Благодаря каким механизмам работает Docker
  3. Терминология
  4. Запуск и начальная настройка Docker
  5. Развёртывание веб-приложения
  6. Создание Docker Image
  7. Выводы
  8. Дополнительные материалы по Docker
Дарья Меленцова
Дарья Меленцова
разработчица в команде инфраструктуры Яндекса, действующий автор курса «DevOps для эксплуатации и разработки»

Из этой статьи вы узнаете:

  • что такое Docker и его главные возможности;
  • почему Docker стал де-факто современной индустрией программного обеспечения;
  • как создавать и развёртывать Docker-контейнеры.

Начнём с основ

Что такое Docker

Разработчики Docker дают ему такое определение: «Docker helps developers bring their ideas to life by conquering the complexity of app development», что можно перевести как «Docker помогает разработчикам воплощать свои идеи в жизнь, преодолевая сложность разработки приложений». Звучит многообещающе, не правда ли?

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

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

В отличие от виртуальных машин, контейнеры не требуют серьёзных мощностей, что позволяет более эффективно использовать ресурсы сервера.

Что такое контейнер

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

  1. Все серверы настраивались вручную (или почти вручную). Подключение сервера, установка ОС, настройка правильного окружения, сети и других параметров занимали много времени.
  2. Были проблемы с гибким масштабированием. Представьте, что у вас на сервере развёрнут интернет-магазин. В обычное время приложение справляется с потоком пользователей, но в канун Нового года аудитория возрастает, ведь все хотят закупиться подарками. И тут оказывается, что интернет-магазин не справляется с нагрузкой и надо либо добавить ресурсы на сервер, либо поднять ещё несколько экземпляров сервиса. Да, мы можем заранее подумать о празднике и предвидеть наплыв покупателей, но что делать с теми ресурсами, которые будут простаивать после Нового года?
  3. Требовалось эффективнее использовать ресурсы. Если на большом и мощном физическом сервере разместить какое-нибудь скромное приложение, которому нужно от силы 20% всех мощностей, что делать с остальным запасом? Может быть, подселить к этому приложению ещё одно или несколько? Казалось бы, вариант, пока вы не узнаете, что для работы приложений нужны разные версии одного и того же пакета.

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

Виртуализация — технология, которая позволяет создавать виртуальное представление ресурсов отдельно от аппаратных. Например, под операционную систему (далее — ОС) можно отдать не весь диск, а только часть, создав его виртуальное представление.

Есть много разных видов виртуализации, и один из них — аппаратная виртуализация.

Схема аппаратной виртуализации

Аппаратная виртуализация

Идея в том, чтобы взять сервер и разделить его на кусочки. Допустим, у вас есть сервер, на котором установлена хостовая ОС, и внутри неё запускаются виртуальные машины (далее — ВМ) с гостевыми ОС. Между хостовой ОС и ВМ есть прослойка — гипервизор, который управляет разделением ресурсов, а также изоляцией гостевых ОС.

У аппаратной виртуализации есть большой плюс: внутри ВМ можно запускать абсолютно разные ОС, отличные от хостовой, но ценой дополнительных расходов на гипервизор.

Казалось бы, проблемы с утилизацией ресурсов и изоляцией приложений решены, но как быть с установкой ОС и настройкой окружения: всё ещё делаем вручную и на каждой ВМ? Да и зачем платить за гипервизор, если не нужно держать на одном сервере Windows и Linux — достаточно ядра хостовой ОС?

На этот случай придумали контейнерную виртуализацию. При таком типе виртуализация происходит на уровне ОС: есть хостовая ОС и специальные механизмы, которые позволяют создавать изолированные контейнеры. В роли гипервизора выступает хостовая ОС — она отвечает за разделение ресурсов между контейнерами и обеспечивает их изолированность.

Схема контейнерной виртуализации

Контейнерная виртуализация

Контейнер — это изолированный процесс, который использует основное ядро ОС. Работа с контейнерами помогает решить следующие проблемы:

  • утилизации ресурсов (на одном сервере можно запустить несколько контейнеров);
  • изоляции приложений;
  • установки ОС (по сути, мы используем хостовую ОС);
  • настройки окружения для приложения (можно один раз настроить окружение и быстро клонировать его между контейнерами).

Почему контейнеры и Docker

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

Все механизмы для создания контейнеров заложены в ядро Linux, но на практике обычно используют готовые среды выполнения вроде Docker, containerd и cri-o, которые помогают автоматизировать развёртывание и управление контейнерами.

Особенности контейнеров:

  • Короткий жизненный цикл. Любой контейнер можно остановить, перезапустить или удалить. Данные, которые содержатся в контейнере, тоже пропадут. Поэтому при проектировании приложений, которые подходят для контейнеризации, используют правило: не хранить важные данные в контейнере. Такой подход проектирования называют Stateless.
  • Контейнеры маленькие и лёгкие, их объём измеряется в мегабайтах. Так получается, потому что в контейнер упаковывают лишь те процессы и зависимости ОС, которые необходимы для приложения. Легковесные контейнеры занимают мало места на диске и быстро запускаются.
  • Контейнеризация обеспечивает изоляцию процессов. Приложения, которые работают внутри контейнера, не имеют доступа к основной ОС.
  • Благодаря контейнерам можно перейти с монолита на микросервисную архитектуру.
  • Не нужно тратиться на гипервизор, и можно запустить больше контейнеров, чем ВМ на одних и тех же ресурсах.
  • Контейнеры хранятся в специальных репозиториях, и каждый контейнер содержит всё необходимое окружение для запуска приложения, благодаря чему можно автоматизировать развёртывание приложения на разных хостах.

Теперь обсудим, какие преимущества даёт Docker.

  • Сообщество. Существует огромное хранилище контейнеров с открытым исходным кодом, и вы можете скачать готовый образ для конкретной задачи.
  • Гибкость. Docker позволяет создавать базовые шаблоны контейнеров (image) и использовать их повторно на различных хостах. Docker-контейнеры можно легко запустить как на локальном устройстве, так и в любой облачной инфраструктуре.
  • Скорость развёртывания. Шаблон контейнера содержит всё необходимое окружение и настройки для работы приложения, нам не нужно настраивать всё это каждый раз с нуля.
  • Нет проблемы с зависимостями и версиями пакетов. Docker позволяет упаковывать различные языки программирования и стек технологий в контейнер, чем избавляет от проблемы несовместимости разных библиотек и технологий в рамках одного хоста.

Благодаря каким механизмам работает Docker

Как вы уже знаете, в ядре Linux из коробки есть все необходимые механизмы для создания контейнеров:

  • capabilities — позволяет выдать процессу часть расширенных прав, которые доступны только root. Например, разрешить удалять чужие файлы, завершать другие процессы (команда kill) или изменять атрибуты у файлов (команда chown);
  • namespace — это абстракция в Linux, с помощью которой можно создавать своё изолированное окружение в ОС. То есть такую коробочку, в которой свои пользователи, своя сеть, свои процессы и всё остальное. При этом изменения в namespace видны только членам этого namespace. Есть шесть типов пространств имён (namespaces): IPC, Network, Mount, PID, User, UTS.

Например:

  • Network namespace отвечает за ресурсы, связанные с сетью. У каждого namespace будут свои сетевые интерфейсы, свои таблицы маршрутизации.
  • User namespace специализируется на пользователях и группах в рамках namespace.
  • PID namespace заведует набором ID процессов. Первый процесс, созданный в новом namespace, имеет PID = 1, а дочерним процессам назначаются следующие PID.
  • cgroup объединяет несколько процессов в группу и управляет ресурсами для этой группы.

Традиционно лимиты в Linux можно задавать для одного процесса, и это неудобно: вы могли задать какому-то процессу не больше n мегабайт памяти, но как указывать лимиты на приложение, если у него больше одного процесса? Поэтому появились cgroups, позволяющие объединить процессы в группу и навесить на неё лимиты.

Давайте разберёмся, как Docker создаёт контейнер из capabilities, namespace и cgroup.

Docker — это очень тонкая прослойка вокруг ядра. Он создаёт контейнер на основе docker image c заданными настройками. Когда вы попросите Docker создать контейнер, он автоматически создаст набор namespaces и cgroup для этого контейнера.

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

Network namespace — контейнер получит свой сетевой стек, а значит, он не сможет получить доступ к сокетам или сетевым интерфейсам другого контейнера.

Аналогичная история со всеми остальными пространствами имён — для каждого контейнера своё дерево каталогов, хостнеймы и прочее.

При создании Docker-контейнера мы можем указать, сколько памяти или cpu выдать конкретному контейнеру, и ОС будет следить за этим лимитом. Такой контроль нужен, чтобы один контейнер случайно не убил всю систему, съев всю память или перегрузив процессор.

По умолчанию Docker при создании контейнера урезает все capabilites внутри него, оставляя только часть возможностей — смену атрибутов UID и GID (chown), kill, chroot и несколько других. Это сделано в целях безопасности, чтобы злоумышленнику не достались все root-права, если бы он смог выбраться из контейнера.

Терминология

Прежде чем начать работу с Docker, нужно изучить несколько терминов.

Устройство архитектуры Docker

Архитектура Docker

Docker Image

Образ — это шаблон для ваших будущих контейнеров. В образе описывается, что должно быть установлено в контейнере и какие действия нужно выполнить при старте контейнера.

В практической части вы будете использовать команду docker pull, чтобы загрузить busybox image из специального хранилища Docker образов — docker hub.

Docker Container

Контейнер — это исполняемый экземпляр образа (image). Его можно создавать, запускать, останавливать и удалять. Также можно подключать к контейнеру хранилище, объединять контейнеры одной или несколькими сетями и общаться с контейнерами, используя Docker API или CLI.

Увидеть список запущенных контейнеров можно через команду docker ps.

Docker Daemon

Docker-демон (dockerd) — фоновый процесс в операционной системе, который обрабатывает запросы Docker API и управляет объектами Docker: образами, контейнерами, сетями и томами.

Docker Client

Docker-клиент — инструмент командной строки (Comand Line Interface — CLI), через который пользователь взаимодействует с демоном.

Когда вы используете команду docker run, то Docker-клиент отправляет команду dockerd. Аналогичная история с другими командами docker <команда>.

Docker Hub

Docker Hub — это общедоступный Docker registry, то есть хранилище всех доступных Docker-образов. При необходимости можно разворачивать свои приватные Docker registry, размещать собственные реестры Docker и использовать их для извлечения образов.

Запуск и начальная настройка Docker

Для работы потребуются:

  • базовые навыки работы с командной строкой;
  • Git;
  • Docker.

Docker — довольно популярный инструмент, и установить его на любую ОС не составит труда. В руководстве «Начало работы с Docker» есть подробные инструкции по настройке Docker на Mac, Linux и Windows.

После установки Docker стоит проверить, что он работает.

Для этого выполните:

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:62af9efd515a25f84961b70f973a798d2eca956b1b2b026d0a4a63a3b0b6a3f2
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly
**....**

Запускаем Busybox

Теперь, когда Docker установлен, запустим в нём первый контейнер. За основу контейнера возьмите Busybox image. Введите в терминале команду:

$ docker pull busybox

ПримечаниеВы можете увидеть ошибку permission denied после выполнения команды. Если вы работаете на Mac, убедитесь, что ядро Docker (engine) запущено. Если вы работаете в Linux, добавьте к командам docker префикс sudo. Кроме того, вы можете создать docker group, чтобы избавиться от этой проблемы.

Команда pull скачает (спулит) busybox image из Docker registry и сохранит его в вашей системе.

Чтобы увидеть список всех образов в вашей системе, используйте команду docker images:

$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
busybox       latest    ff4a8eb070e1   2 days ago      1.24MB=

Docker Run

Отлично! Давайте теперь запустим Docker-контейнер на основе этого образа. Используйте команду docker run:

$ docker run busybox
$

Пусть вас не смущает, что ничего не произошло. Ошибки здесь нет, и всё идёт по плану. Когда вы вызываете run, Docker-клиент находит образ (в нашем случае busybox), загружает контейнер и запускает в нём команду.

Когда вы запустили docker run busybox, то не передали команду, поэтому контейнер загрузился, выполнил ничего и затем вышел.

Давайте передадим команду и посмотрим, что будет:

$ docker run busybox echo "hello from busybox"
hello from busybox

Ура, хоть какой-то результат! Docker клиент выполнил команду echo в busybox-контейнере, а затем вышел из него. И всё это произошло довольно быстро.

Хорошо, контейнер вы запустили, а как посмотреть, какие контейнеры запущены на сервере прямо сейчас? Для этого есть команда docker ps:

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Сейчас нет запущенных контейнеров, и вы видите пустую строку. Попробуйте более полезный вариант — docker ps -a:

$ docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                      PORTS     NAMES
c3368945dc3a   busybox       "echo 'hello from bu…"   7 minutes ago    Exited (0) 7 minutes ago              zealous_hugle

Появился список всех контейнеров, которые вы запускали. Заметьте, столбец STATUS показывает, что эти контейнеры были закрыты несколько минут назад.

Итак, вы запустили контейнер, выполнили одну команду, и контейнер завершился. Какой в этом смысл? Может быть, есть способ запускать больше одной команды?

Конечно, есть! Давайте выполним docker run -it busybox sh:

$ docker run -it busybox sh
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # uptime
 22:34:42 up 35 min,  0 users,  load average: 0.02, 0.01, 0.00
/ #

run с флагами -it подключит вас к интерактивному терминалу в контейнере. Теперь можно запускать в контейнере столько команд, сколько захотите.

Попробуйте выполнить ваши любимые команды в контейнере. А ещё стоит потратить немного времени на изучение возможностей команды run, так как именно её вы будете использовать чаще всего.

Чтобы увидеть список всех флагов, которые поддерживает run, выполните docker run --help.

Docker rm

Раз вы научились создавать контейнеры, нужно потренироваться их удалять. Вы сами видели, что даже после остановки контейнера информация о нём остаётся на хосте. Можно запускать docker run несколько раз и получать бесхозные контейнеры, которые будут занимать место на диске.

Место на диске нерезиновое, поэтому надо прибираться и удалять ненужные контейнеры. В этом поможет команда docker rm:

# какие есть контейнеры  
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                       PORTS     NAMES
f3776be78165   busybox       "sh"                     17 minutes ago   Exited (130) 3 seconds ago             optimistic_elion
c3368945dc3a   busybox       "echo 'hello from bu…"   33 minutes ago   Exited (0) 33 minutes ago              zealous_hugle

# удаление контейнеров по CONTAINER ID
$ docker rm f3776be78165 c3368945dc3a

# проверка, что контейнеры удалились
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                       PORTS     NAMES

Если на хосте много контейнеров, которые надо удалить, то придётся копировать много CONTAINER ID, а это может быть утомительно. Чтобы облегчить себе жизнь, можно использовать docker container prune:

$ docker container prune                                                     
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
f3776be78165721b1e7e00234a29eb962ee7d678821f7632b538540cfa537701

Команда удалит все остановленные контейнеры.

Чтобы удалить образы, которые больше не нужны, запустите docker image prune.

Развёртывание веб-приложения

Static-site

Итак, вы рассмотрели запуск docker и поиграли с контейнером. Настало время перейти к более реальным вещам и развернуть веб-приложение с помощью Docker.

Первым делом запустите очень простой статический сайт. Для этого заберите Docker-образ из Docker Hub, запустите его и проверьте, что у вас есть рабочий веб-сервер.

Образ, который вы будете использовать, — одностраничный веб-сайт, специально созданный для демонстрации и размещённый в registryifireice/static-site.

Вы можете загрузить и запустить образ сразу, используя docker run, флаг --rm автоматически удалит контейнер при выходе из него, а флаг -it запустит интерактивный терминал, из которого можно выйти с помощью Ctrl+C. Контейнер при этом будет уничтожен.

$ docker pull ifireice/static-sitedocker run --rm -it ifireice/static-site

Так как образа ещё нет на хосте, Docker-клиент сначала скачает образ с registry, а потом запустит его. Если всё пойдёт по сценарию, вы должны увидеть сообщение Nginx is running... в терминале.

Сервер запущен, но как увидеть сайт? На каком порту работает сайт? Как получить доступ к контейнеру?

Клиент не предоставляет никаких портов, поэтому вам нужно повторно запустить docker run и опубликовать порты. Нажмите Ctrl+C, чтобы остановить контейнер.

Также вам надо сделать так, чтобы работающий контейнер не был привязан к терминалу. Это нужно для того, чтобы после закрытия терминала контейнер продолжил работать, — принцип действия detached mode:

$ docker run -d -P --name static-site ifireice/static-site
9c9e7a8a552795c0312bcdf3cb8949ddeea7bdd60bbf683140b99abf3b43bff1
  • -d — отсоединить терминал,
  • -P — опубликовать все открытые порты на случайные порты,
  • --name — задать имя контейнеру.

Теперь вы можете увидеть порты, запустив команду docker port [CONTAINER]:

$ docker port static-site
80/tcp -> 0.0.0.0:55000

Откройте http://localhost:55000 в браузере. Также можно указать собственный порт, на который Docker-клиент будет перенаправлять подключения к контейнеру.

$ docker run -p 8888:80 ifireice/static-site
Nginx is running...
«Hello Docker!» в localhost

Если вы устали писать «Hello world!», самое время перейти на «Hello Docker!»

Чтобы остановить контейнер, запустите docker stop, указав идентификатор контейнера. В этом случае можно использовать имя static-site, которое вы задали контейнеру при запуске.

$ docker stop static-site
static-site

Чтобы развернуть этот же сайт на удалённом сервере, вам нужно установить Docker и запустить указанную выше команду.

Создание Docker Image

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

Помните команду docker images, которая выводит список образов, располагающихся локально?

$ docker images
REPOSITORY             TAG       IMAGE ID       CREATED          SIZE
ifireice/django-app    latest    07f6ba4cc25b   23 seconds ago   945MB
ifireice/static-site   latest    b237e7cf6bd2   27 minutes ago   142MB
ubuntu                 18.04     71cb16d32be4   2 days ago       63.1MB
busybox                latest    ff4a8eb070e1   2 days ago       1.24MB

Перед вами список образов, скачанных из registry, а также образы, которые созданы нами:

  • TAG — относится к конкретному снимку изображения;
  • IMAGE ID — уникальный идентификатор этого image.

Образы могут быть зафиксированы с изменениями и иметь несколько версий. Если вы не укажете конкретный номер версии, по умолчанию для клиента будет установлена последняя — latest. Например, вы можете вытащить конкретную версию образа ubuntu:

$ docker pull ubuntu:18.04

Новый образ можно или скачать из registry, или создать собственный.

Первый image

Допустим, вы хотите создать образ, который засунет в контейнер простое приложение на Django, отображающее случайную картинку с котиком. Для начала клонируйте это приложение к себе на локальный компьютер (не в Docker-контейнер):

$ git clone https://github.com/ifireice/docker-article.git
$ cd docker-article

Теперь это приложение нужно упаковать в image. Здесь пригодятся определения про образы.

  • Базовые образы — это образы, у которых нет родительского образа. Обычно это образы ОС — ubuntu, busybox или debian;
  • Дочерние образы — это образы, созданные на основе базовых образов с дополнительной функциональностью.

Также есть такие понятия, как официальный и пользовательский образы.

  • Официальные образы поддерживаются Docker-сообществом. Обычно их имя состоит из одного слова, например, python, ubuntu, busybox и hello-world.
  • Пользовательские образы созданы пользователями. Они строятся на основе базового и содержат дополнительную функциональность. Только поддерживаются уже не сообществом, а пользователем, который его создал. Имя у таких образов обычно имеет вид имя пользователя/изображения.

Вы будете создавать пользовательский образ, основанный на Python, потому что используете приложение на Django. Также вам понадобится Dockerfile.

Dockerfile

Dockerfile — это простой текстовый файл со списком команд, которые Docker-клиент вызывает при создании образа. Команды почти как в Linux, а значит, не нужно изучать ещё один язык для создания Dockerfile.

В директории приложения уже есть Dockerfile, но вы будете создавать его с нуля. Поэтому переименуйте его и создайте пустой файл с именем Dockerfile в директории Django-приложения.

Начните с определения базового image. Для этого используйте ключевое слово FROM:

FROM python:3.8

Потом задайте рабочую директорию и скопируйте все файлы приложения:

# установить каталог для приложения
WORKDIR /usr/src/app

# копировать все файлы в контейнер
COPY . .

Теперь, когда у вас есть файлы, можете установить зависимости:

# установка зависимостей
RUN pip install --no-cache-dir -r requirements.txt

Добавьте порт, который нужно открыть. Приложение работает на порту 5000, его и укажите:

EXPOSE 5000

Последний шаг — написать очень простую команду для запуска приложения: python ./manage.py runserver 0.0.0.0:5000. Для этого используйте команду CMD. Она говорит, какую команду должен запустить контейнер при старте.

CMD ["python", "./manage.py", "runserver", "0.0.0.0:5000"]

Теперь ваш Dockerfile готов и выглядит вот так:

FROM python:3.8

# установить каталог для приложения
WORKDIR /usr/src/app

# копировать все файлы в контейнер
COPY . .

# установка зависимостей
RUN pip install --no-cache-dir -r requirements.txt

# какой порт должен экспоузить контейнер
EXPOSE 5000

# запуск команды
CMD ["python", "./manage.py", "runserver", "0.0.0.0:5000"]

Раз у вас есть Dockerfile, нужно собрать образ. Для этого используйте docker build и передайте необязательный флаг -t — имя тега и расположение каталога, содержащего Dockerfile.

Чтобы сохранить (запушить) готовый image на Docker Hub, нужно создать там учётную запись. Сохранитесь, чтобы потом вы могли получить образ и развернуть контейнер на его основе на любом сервере.

В теге yourusername должно быть имя вашей учетной записи в Docker Hub, иначе ничего не сработает.

$ docker build -t yourusername/cats .
[+] Building 8.4s (10/10) FINISHED                                                                                                                                                                                                      
 => [internal] load build definition from Dockerfile                                                                                                                                                                               0.0s
 => => transferring dockerfile: 354B                                                                                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                  0.0s
 => => transferring context: 2B
....
 => => writing image sha256:398306665e853e7c8cbe1f6456951ca63e782bb286dff5dc9361b191260e0ce3                                                                                                                                       0.0s
 => => naming to docker.io/yourusername/cats

Если на локальной машине нет образа python:3.8, Docker-клиент сначала скачает образ, а затем создаст ваш. Тогда вывод команды может отличаться.

Если всё прошло хорошо, то image готов! Запустите его, не забыв изменить yourusername на правильный:

$ docker run -p 8888:5000 yourusername/cats

Команда взяла порт 5000 внутри контейнера и сопоставила его с портом 8888 на хосте. И теперь, если вы обратитесь на порт 8888 хостовой машины, запрос будет перенаправлен в контейнер на порт 5000. Узнать, что вернёт приложение на запрос, можно с помощью пути: http://0.0.0.0:8888.

Docker-образ кота

Котик дня

Поздравляем! Вы успешно создали свой первый Docker-образ.

Docker push

Осталось дело за малым — сохранить ваш образ в registry. Сначала авторизуйтесь в Docker Hub? Не забудьте про логин из yourusername.

$ docker login --username yourusername                                                                                                         1  1772  04:12:45 
Password: 
Login Succeeded

Logging in with your password grants your terminal complete access to your account. 
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/

 

Когда будете вводить пароль, он не отобразится в консоли. Это норма, он и не должен быть виден всем подряд.

Чтобы сохранить образ в registry, просто введите docker push yourusername/cats. Важно, чтобы тег имел формат yourusername/image_name. Тогда Docker-клиент будет знать, куда сохранять образ:

$ docker push yourusername/cats

Как только образ сохранится в registry, его можно увидеть в Docker Hub по адресу https://hub.docker.com/r/yourusername/cat.

Ну а забирать и запускать image с registry вы уже умеете!

Выводы

Главные мысли этой работы:

  • разобрались с виртуальными машинами, контейнерами и поняли, чем они отличаются;
  • узнали, что такое Docker, и обсудили основную терминологию: image, container, docker daemon, docker client, registry;
  • запустили Hello Docker;
  • запустили контейнер на базе образа из Docker Hub;
  • создали свой контейнер и сохранили на Docker Hub.

Дополнительные материалы по Docker

Если хочется изучить Docker глубже, отправляйтесь по ссылкам: