В чем разница между версиями Docker, и какую мне ставить?
В чём между ними разница? Какую мне лучше установить?
Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 5 фев 2018 в 11:05
Medvedev Alexandr Medvedev Alexandr
145 1 1 серебряный знак 10 10 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
docker-engine и docker.io это устаревшие версии.
На данный момент актуальные версии это платная корпоративная версия (EE — Enterprise Edition) и бесплатная комьюнити-версия (CE — Сommunity Edition).
Собственно docker-ce это бесплатная актуальная версия и устанавливать следует ее.
Если уже были установлены старые пакеты, то желательно удалить их перед установкой.
Удаление старых версий и установка новой:
Отслеживать
ответ дан 5 фев 2018 в 11:14
2,018 1 1 золотой знак 13 13 серебряных знаков 22 22 бронзовых знака
Бесплатную версию можно юзать в коммерческом ПО? Какие плюхи в коммерческой версии?
19 окт 2020 в 9:20
@doox911 docker-ce OpenSource под лицензией Apache-2.0 . Можно использовать в коммерческом ПО, а так же изменять и распространять, но необходимо указывать авторство. Возможно есть какие-то юридические подводные камни, но в целом лицензия позволяет. С точки зрения основного функционала коммерческая версия ничем не отличается. Разница в том, что коммерческая версия включает в себя поддержку и сертифицированные решения, например: сканер уязвимостей, LDAP/AD управление доступом с ролями и т.д. Более подробное сравнение по ссылке
20 окт 2020 в 12:08
Что такое Docker: краткий экскурс в историю и основные абстракции
В этой статье поговорим об истории появления Docker и его основных абстракциях: Image, Cli, Dockerfile. Лекция рассчитана на новичков, поэтому вряд ли будет интересна опытным пользователям. Здесь не будет крови, аппендикса и глубокого погружения. Самые основы.
10 августа в Слёрм стартовал видеокурс по Docker , в котором мы разбираем его полностью — от основных абстракций до параметров сети.
Что такое Docker
Посмотрим на определение Docker из Википедии.
Docker — это программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации.
Из этого определения ничего непонятно. Особенно непонятно, что значит «в средах с поддержкой контейнеризации». Чтобы разобраться, вернёмся в прошлое. Начнём с эпохи, которую я условно называю «Монолитной эрой».
Монолитная эра
Монолитная эра — это начало 2000-х, когда все приложения были монолитными, с кучей зависимостей. Разработка шла долго. При этом серверов было не так много, мы все их знали по именам и мониторили. Есть такое забавное сравнение:
Контейнер не подходит для изолирования процессов: в системах виртуализации на уровне ядра находят уязвимости, которые позволяют вылезти из контейнера на хост. Поэтому если вам нужно что-то изолировать, то лучше использовать виртуалку.

Различия между виртуализацией и контейнеризацией можно увидеть на схеме.
Бывают аппаратные гипервизоры, гипервизоры поверх ОС и контейнеры.
«Железные» гипервизоры — это крутая штука, если вы действительно хотите что-то изолировать. Потому что там есть возможность изолировать на уровне страниц памяти, процессоров.
Есть гипервизоры как программа, и есть контейнеры, о них мы и будем говорить дальше. В системах контейнеризации гипервизора нет, но есть Container Engine, который создаёт контейнеры и управляет ими. Штука это более легковесная, поэтому за счет работы с ядром оверхед меньше, или его нет совсем.
Что используется для контейнеризации на уровне ядра
Основные технологии, которые позволяют создавать изолированный от других процессов контейнер, — это Namespaces и Control Groups.
Namespaces: PID, Networking, Mount и User. Есть ещё, но для простоты понимания остановимся на этих.
PID Namespace ограничивает процессы. Когда мы, например, создаём PID Namespace, помещаем туда процесс, то он становится с PID 1. Обычно в системах PID 1 — это systemd или init. Соответственно, когда мы помещаем процесс в новый namespace, он тоже получает PID 1.
Networking Namespace позволяет ограничить/изолировать сеть и внутри уже размещать свои интерфейсы. Mount — это ограничение по файловой системе. User — ограничение по юзерам.
Control Groups: Memory, CPU, IOPS, Network — всего около 12 настроек. Иначе их ещё называют Cgroups («Cи-группы»).
Control Groups управляют ресурсами для контейнера. Через Control Groups мы можем сказать, что контейнер не должен потреблять больше какого-то количества ресурсов.
Чтобы контейнеризация полноценно работала, используются дополнительные технологии: Capabilities, Copy-on-write и другие.
Capabilities — это когда мы говорим процессу, что он может делать, а чего не может. На уровне ядра это просто битовые карты со множеством параметров. Например, пользователь root имеет полные привилегии, может делать всё. Сервер времени может изменять системное время: у него есть capabilities на Time Capsule, и всё. С помощью привилегий можно гибко настроить ограничения для процессов, и тем самым обезопасить себя.
Система Copy-on-write позволяет нам работать с образами Docker, использовать их более эффективно.
На данный момент Docker имеет проблемы с совместимостью Cgroups v2, поэтому в статье рассматриваются именно Cgroups v1.
Но вернёмся к истории.
Когда появились системы виртуализации на уровне ядра, их начали активно применять. Оверхед на гипервизор пропал, но некоторые проблемы остались:
- большие образы: в ту же OpenVZ толкают операционку, библиотеки, кучу разного софта, и в итоге образ всё равно получается немаленьким;
- нет нормального стандарта упаковки и доставки, поэтому остаётся проблема зависимостей. Бывают ситуации, когда два куска кода используют одну библиотеку, но с разными версиями. Между ними возможен конфликт.
Эра контейнеров
Когда наступила Эра контейнеров, сменилась философия работы с ними:
- Один процесс — один контейнер.
- Все нужные процессу зависимости доставляем в его контейнер. Это требует распиливать монолиты на микросервисы.
- Чем меньше образ, тем лучше — меньше возможных уязвимостей, быстрее раскатывается и так далее.
- Инстансы становятся эфемерными.
В 2014-2015 годах случился расцвет Docker — той технологии, о которой мы и будем сейчас говорить.
Docker изменил философию и стандартизировал упаковку приложения. С помощью Docker мы можем упаковать приложение, отправить его в репозиторий, скачать оттуда, развернуть.
В Docker-контейнер мы закладываем всё необходимое, поэтому решается проблема зависимостей. Docker гарантирует воспроизводимость. Я думаю, многие сталкивались с невоспроизводимостью: у тебя всё работает, пушишь на продакшен, там это перестает работать. С Docker эта проблема уходит. Если твой Docker-контейнер запускается и делает то, что требуется делать, то с большой долей вероятности он запустится на продакшене и там сделает то же самое.
Отступление про оверхед
По поводу оверхед постоянно идут споры. Кто-то считает, что Docker не несёт дополнительную нагрузку, так как использует ядро Linux и все его процессы, необходимые для контейнеризации. Мол, «если вы говорите, что Docker — это оверхед, то тогда и ядро Linux оверхед».
С другой стороны, если углубиться, то в Docker и правда есть несколько вещей, про которые с натяжкой можно сказать, что это оверхед.
Первое — это PID namespace. Когда мы в namespace помещаем какой-то процесс, ему присваивается PID 1. В то же время у этого процесса есть ещё один PID, который находится на хостовом namespace, за пределами контейнера. Например, мы запустили в контейнере Nginx, он стал PID 1 (мастер-процесс). А на хосте у него PID 12623. И сложно сказать, насколько это оверхед.
Вторая штука — это Cgroups. Возьмём Cgroups по памяти, то есть возможность ограничивать контейнеру память. При её включении активируются счётчики, memory accounting: ядру надо понимать, сколько страниц выделено, а сколько ещё свободно для этого контейнера. Это возможно оверхед, но точных исследований о том, как он влияет на производительность, я не встречал. И сам не замечал, что приложение, запущенное в Docker, вдруг резко теряло в производительности.
И ещё одно замечание о производительности. Некоторые параметры ядра прокидываются с хоста в контейнер. В частности, некоторые сетевые параметры. Поэтому если вы хотите запустить в Docker что-то высокопроизводительное, например то, что будет активно использовать сеть, то вам, как минимум, надо эти параметры подправить. Какой-нибудь nf_conntrack, к примеру.
О концепции Docker
Docker состоит из нескольких компонентов:

- Docker Daemon — то самое Container Engine; запускает контейнеры.
- Docker CII — утилита по управлению Docker.
- Dockerfile — инструкция по тому, как собирать образ.
- Image — образ, из которого раскатывается контейнер.
- Container.
- Docker registry — хранилище образов.
Схематично это выглядит примерно вот так:
На Docker_host работает Docker daemon, запускает контейнеры. Есть Client, который передаёт команды: собери образ, скачай образ, запусти контейнер. Docker daemon ходит в registry и выполняет их. Docker-клиент может обращаться и локально (к юникс-сокету), и по TCP с удалённого хоста.
Пройдёмся по каждому компоненту.
Docker daemon (демон) — это серверная часть, она работает на хост-машине: скачивает образы и запускает из них контейнеры, создаёт сеть между контейнерами, собирает логи. Когда мы говорим «создай образ», этим тоже занимается демон.
Docker CLI — клиентская часть Docker, консольная утилита для работы с демоном. Повторю, она может работать не только локально, но и по сети.
Базовые команды:
docker ps — показать контейнеры, которые сейчас запущены на Docker-хосте.
docker images — показать образы, скачанные локально.
docker search <> — поиск образа в registry.
docker pull <> — скачать образ из registry на машину.
docker build > — собрать образ.
docker run <> — запуск контейнер.
docker rm <> — удалить контейнер.
docker logs <> — логи контейнера
docker start/stop/restart <> — работа с контейнером
Если вы освоите эти команды и будете уверенно ими пользоваться, то считайте, что на 70% освоили Docker на уровне пользователя.

Dockerfile — инструкция для создания образа. Почти каждая команда инструкции — новый слой. Посмотрим на примере.
Примерно так выглядит Dockerfile: слева команды, справа — аргументы. Каждая команда, что здесь есть (и вообще пишется в Dockerfile), создаёт новый слой в Image.
Даже глядя на левую часть, можно примерно понять, что происходит. Мы говорим: «создай нам папку» — это один слой. «Сделай папку рабочей» — это ещё один слой, и так далее. Слоёный пирог упрощает жизнь. Если я создам ещё один Dockerfile и в последней строчке что-то изменю — запущу не «python» «main.py», а что-нибудь другое, или установлю зависимости из другого файла — то предыдущие слои будут переиспользованы, как кеш.
Image — это упаковка контейнера, из образа запускаются контейнеры. Если смотреть на Docker с точки зрения пакетного менеджера (как будто мы работаем с deb или rpm-пакетами), то image — это по сути rpm-пакет. Через yum install мы можем поставить приложение, удалить его, найти в репозитории, скачать. Здесь примерно то же самое: из образа запускаются контейнеры, они хранятся в Docker registry (по аналогии с yum, в репозитории), и каждый image имеет хеш SHA-256, имя и тег.
Image собирается по инструкции из Dockerfile. Каждая инструкция из Dockerfile создаёт новый слой. Слои могут использоваться повторно.
Docker registry — это репозиторий образов Docker. По аналогии с ОС, у Docker есть общедоступный стандартный реестр — dockerhub. Но можно собрать свой репозиторий, свой Docker registry.
Container — то, что запускается из образа. По инструкции из Dockerfile собрали образ, затем мы его из этого образа запускаем. Этот контейнер изолирован от остальных контейнеров, он должен содержать в себе всё необходимое для работы приложения. При этом один контейнер — один процесс. Случается, что приходится делать два процесса, но это несколько противоречит идеологии Docker.
Требование «один контейнер — один процесс» связано с PID Namespace. Когда в Namespace запускается процесс с PID 1, если он вдруг умрёт, то весь контейнер тоже умирает. Если же там запущено два процесса: один живёт, а второй умер, то контейнер всё равно продолжит жить. Но это к вопросу Best Practices, мы про них поговорим в других материалах.
Более детально изучить особенности и полную программу курса можно по ссылке: «Видеокурс по Docker».
Автор: Марсель Ибраев, сертифицированный администратор Kubernetes, практикующий инженер в компании Southbridge, спикер и разработчик курсов Слёрм.
Может быть интересно:
- Интенсив по Python для инженеров и разработчиков
- Курс по GoLang для инженеров
Как и для чего использовать Docker
Docker — программа, позволяющая операционной системе запускать процессы в изолированном окружении на базе специально созданных образов. Несмотря на то, что технологии, лежащие в основе Докера появились до него, именно Докер произвел революцию в том, как сегодня создается инфраструктура проектов, собираются и запускаются сервисы.
(В статье намеренно опущены многие детали, чтобы не грузить информацией, которая не нужна для ознакомления).
- Установка
- Запуск
- Зачем все это?
- Приложение в контейнере
- Работа с образами
- Управление контейнерами
- Взаимодействие с другими частями системы
- Подготовка собственного образа
- Docker Compose
- В бою
- Докер под капотом
- Дополнительные ссылки
Установка
Чтобы начать пользоваться Докером, необходимо установить движок — Docker Engine. На странице https://docs.docker.com/engine/install/ доступны ссылки для скачивания под все популярные платформы. Выберите вашу и установите Докер.
В работе Докера есть одна деталь, которую важно знать при установке на Mac и Linux. По умолчанию Докер работает через unix сокет. В целях безопасности сокет закрыт для пользователей, не входящих в группу docker. И хотя установщик добавляет текущего пользователя в эту группу автоматически, Докер сразу не заработает. Дело в том, что если пользователь меняет группу сам себе, то ничего не изменится до тех пор, пока пользователь не перелогинится. Такова особенность работы ядра. Для проверки того, в какие группы входит ваш пользователь, можно набрать команду id .
Проверить успешность установки можно командой docker info :
$ docker info Containers: 22 Running: 2 Paused: 0 Stopped: 20 Images: 72 Server Version: 17.12.0-ce Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs ...
Она выдаёт довольно много информации о конфигурации самого Докера и статистику работы.
Запуск
На этом этапе команды на выполнение даются «как есть» без объяснения деталей. Подробнее о том, как их формировать и что в них входит разбирается позже.
Начнем с самого простого варианта:
$ docker run -it nginx bash root@a6c26812d23b:/ #
При первом вызове данная команда начнет скачивать образ (image) nginx, поэтому придется немного подождать. Когда образ скачается, запустится bash, и вы окажетесь внутри контейнера (container).
Побродите по файловой системе, посмотрите директорию /etc/nginx. Как видите, её содержимое не совпадает с тем, что находится у вас на компьютере. Эта файловая система появилась из образа nginx. Всё, что вы сделаете здесь внутри, никак не затронет вашу основную файловую систему. Вернуться в родные скрепы можно командой exit .
Теперь посмотрим вариант вызова команды cat , выполненной уже в другом контейнере, но тоже запущенном из образа nginx:
$ docker run nginx cat /etc/nginx/nginx.conf user nginx ; worker_processes 1; error_log /var/log/nginx/error.log warn ; pid /var/run/nginx.pid ; ... $
Команда выполняется практически мгновенно, так как образ уже загружен. В отличие от предыдущего старта, где запускается баш и начинается интерактивная сессия внутри контейнера, запуск команды cat /etc/nginx/nginx.conf для образа nginx выведет на экран содержимое указанного файла (взяв его из файловой системы запущенного контейнера) и вернет управление в то место, где вы были. Вы не окажетесь внутри контейнера.
Последний вариант запуска будет таким:
# Обратите внимание на то, что после имени образа не указана никакая команда. # Такой подход работает в случае если команда на запуск прописана в самом образе $ docker run -p 8080:80 nginx
Данная команда не возвращает управление, потому что стартует nginx. Откройте браузер и наберите localhost:8080 . Вы увидите как загрузилась страница Welcome to nginx!. Если в этот момент снова посмотреть в консоль, где был запущен контейнер, то можно увидеть, что туда выводится лог запросов к localhost:8080 . Остановить nginx можно командой Ctrl + C .
Несмотря на то, что все запуски выполнялись по-разному и приводили к разным результатам, общая схема их работы — одна. Докер при необходимости автоматически скачивает образ (первый аргумент после docker run ) и на основе него стартует контейнер с указанной командой.
Образ — самостоятельная файловая система. Пока мы используем готовые образы, но потом научимся создавать их самостоятельно.
Контейнер — запущенный процесс операционной системы в изолированном окружении с подключенной файловой системой из образа.
Повторюсь, что контейнер — всего лишь обычный процесс вашей операционной системы. Разница лишь в том, что благодаря возможностям ядра (о них в конце) Докер стартует процесс в изолированном окружении. Контейнер видит свой собственный список процессов, свою собственную сеть, свою собственную файловую систему и так далее. Пока ему не укажут явно, он не может взаимодействовать с вашей основной операционной системой и всем, что в ней хранится или запущено.
Попробуйте выполнить команду docker run -it ubuntu bash и наберите ps auxf внутри запущенного контейнера. Вывод будет таким:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.1 0.1 18240 3300 pts/0 Ss 15:39 0:00 /bin/bash root 12 0.0 0.1 34424 2808 pts/0 R+ 15:40 0:00 ps aux
Как видно, процесса всего два, и у Bash PID равен 1. Заодно можно посмотреть в директорию /home командой ls /home и убедиться, что она пустая. Также обратите внимание, что внутри контейнера по умолчанию используется пользователь root .
Зачем все это?
Докер — универсальный способ доставки приложений на машины (локальный компьютер или удаленные сервера) и их запуска в изолированном окружении.
Вспомните, когда вам приходилось собирать программы из исходников. Этот процесс включает в себя следующие шаги:
- Установить все необходимые зависимости под вашу операционную систему (их список еще надо найти).
- Скачать архив, распаковать.
- Запустить конфигурирование make configure .
- Запустить компиляцию make compile .
- Установить make install .
Как видите, процесс нетривиальный и далеко не всегда быстрый. Иногда даже невыполнимый из-за непонятных ошибок. И это не говоря про загрязнение операционной системы.
Докер позволяет упростить эту процедуру до запуска одной команды причем с почти 100% гарантией успеха. Посмотрите на вымышленный пример, в котором происходит установка программы Tunnel на локальный компьютер в директорию /usr/local/bin используя образ tunnel:
docker run -v /usr/local/bin:/out tunnel
Запуск этой команды приводит к тому, что в основной системе в директории /usr/local/bin оказывается исполняемый файл программы, находящейся внутри образа tunnel. Команда docker run запускает контейнер из образа tunnel, внутри происходит компиляция программы и, в конечном итоге, она оказывается в директории /usr/local/bin основной файловой системы. Теперь можно стартовать программу, просто набрав tunnel в терминале.
А что если программа, которую мы устанавливаем таким способом, имеет зависимости? Весь фокус в том, что образ, из которого был запущен контейнер, полностью укомплектован. Внутри него установлены все необходимые зависимости, и его запуск практически гарантирует 100% работоспособность независимо от состояния основной ОС.
Часто даже не обязательно копировать программу из контейнера на вашу основную систему. Достаточно запускать сам контейнер, когда в этом возникнет необходимость. Предположим, что мы решили разработать статический сайт на основе Jekyll. Jekyll — популярный генератор статических сайтов, написанный на Ruby. Например, гайд который вы читаете прямо сейчас, находится на статическом сайте, сгенерированном с его помощью. И при его генерации использовался Докер (об этом можно прочитать в гайде: как делать блог на Jekyll).
Старый способ использования Jekyll требовал установки на вашу основную систему как минимум Ruby и самого Jekyll в виде гема (gem — название пакетов в Ruby). Причем, как и всегда в подобных вещах, Jekyll работает только с определенными версиями Ruby, что вносит свои проблемы при настройке.
С Докером запуск Jekyll сводится к одной команде, выполняемой в директории с блогом (подробнее можно посмотреть в репозитории наших гайдов):
docker run --rm --volume =" $PWD:/srv/jekyll" -it jekyll/jekyll jekyll server
Точно таким же образом сейчас запускается огромное количество различного софта. Чем дальше, тем больше подобный способ захватывает мир. На этом месте можно немного окунуться в происхождение названия Docker.
Как вы знаете, основной способ распространения товаров по миру — корабли. Раньше стоимость перевозки была довольно большая, по причине того, что каждый груз имел собственную форму и тип материала.

Загрузить на корабль мешок с рыбой или машину — разные задачи, требующие разных процессов и инструментов. Возникали проблемы со способами погрузки, требовались разнообразные краны и инструменты. А эффективно упаковать груз на самом корабле, с учетом его хрупкости — задача нетривиальная.
Но в какой-то момент все изменилось. Картинка стоит тысячи слов:

Контейнеры уравняли все виды грузов и стандартизировали инструменты погрузки и разгрузки во всем мире. Что в свою очередь привело к упрощению процессов, ускорению и, следовательно, уменьшению стоимости перевозок.
То же самое произошло и в разработке ПО. Docker стал универсальным средством доставки софта независимо от его структуры, зависимостей и способа установки. Всё, что нужно программам, распространяемым через Докер, находится внутри образа и не пересекается с основной системой и другими контейнерами. Важность этого факта невозможно переоценить. Теперь обновление версий программ никак не задействует ни саму систему, ни другие программы. Сломаться больше ничего не может. Всё, что нужно сделать, это скачать новый образ той программы, которую требуется обновить. Другими словами, Докер убрал проблему dependency hell и сделал инфраструктуру immutable (неизменяемой).
Больше всего Docker повлиял именно на серверную инфраструктуру. До эры Докера управление серверами было очень болезненным мероприятием даже несмотря на наличие программ по управлению конфигурацией (chef, puppet, ansible). Основная причина всех проблем — изменяемое состояние. Программы ставятся, обновляются, удаляются. Происходит это в разное время на разных серверах и немного по-разному. Например, обновить версию таких языков, как PHP, Ruby или Python могло стать целым приключением с потерей работоспособности. Проще поставить рядом новый сервер и переключиться на него. Идейно Докер позволяет сделать именно такое переключение. Забыть про старое и поставить новое, ведь каждый запущенный контейнер живет в своем окружении. Причем, откат в такой системе тривиален: всё что нужно — остановить новый контейнер и поднять старый, на базе предыдущего образа.
Приложение в контейнере
Теперь поговорим о том, как приложение отображается на контейнеры. Возможны два подхода:
- Всё приложение — один контейнер, внутри которого поднимается дерево процессов: приложение, веб сервер, база данных и всё в этом духе.
- Каждый запущенный контейнер — атомарный сервис. Другими словами каждый контейнер представляет из себя ровно одну программу, будь то веб-сервер или приложение.
На практике все преимущества Docker достигаются только со вторым подходом. Во-первых, сервисы, как правило, разнесены по разным машинам и нередко перемещаются по ним (например, в случае выхода из строя сервера), во-вторых, обновление одного сервиса не должно приводить к остановке остальных.
Первый подход крайне редко, но бывает нужен. Например, Хекслет работает в двух режимах. Сам сайт с его сервисами использует вторую модель, когда каждый сервис отдельно, но вот практика, выполняемая в браузере, стартует по принципу «один пользователь — один контейнер». Внутри контейнера может оказаться всё что угодно в зависимости от практики. Как минимум, там всегда стартует сама среда Хекслет IDE, а она в свою очередь порождает терминалы (процессы). В курсе по базам данных в этом же контейнере стартует и база данных, в курсе, связанном с вебом, стартует веб-сервер. Такой подход позволяет создать иллюзию работы на настоящей машине и резко снижает сложность в поддержке упражнений. Повторюсь, что такой вариант использования очень специфичен и вам вряд ли понадобится.
Другой важный аспект при работе с контейнерами касается состояния. Например, если база запускается в контейнере, то ее данные ни в коем случае не должны храниться там же, внутри контейнера. Контейнер как процесс операционной системы, может быть легко уничтожен, его наличие всегда временно. Docker содержит механизмы, для хранения и использования данных лежащих в основной файловой системе. О них будет позже.
Работа с образами
Docker — больше, чем просто программа. Это целая экосистема со множеством проектов и сервисов. Главный сервис, с которым вам придется иметь дело — Registry. Хранилище образов.
Концептуально оно работает так же, как и репозиторий пакетов любого пакетного менеджера. Посмотреть его содержимое можно на сайте https://hub.docker.com/, кликнув по ссылке Explore.
Когда мы выполняем команду run docker run , то Docker проверяет наличие указанного образа на локальной машине и скачивает его по необходимости. Список образов, уже скачанных на компьютер, можно посмотреть командой docker images :
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE workshopdevops_web latest cfd7771b4b3a 2 days ago 817MB hexletbasics_app latest 8e34a5f631ea 2 days ago 1.3GB mokevnin/rails latest 96487c602a9b 2 days ago 743MB ubuntu latest 2a4cca5ac898 3 days ago 111MB Ruby 2.4 713da53688a6 3 weeks ago 687MB Ruby 2.5 4c7885e3f2bb 3 weeks ago 881MB nginx latest 3f8a4339aadd 3 weeks ago 108MB elixir latest 93617745963c 4 weeks ago 889MB postgres latest ec61d13c8566 5 weeks ago 287MB
Разберемся с тем, как формируется имя образа, и что оно в себя включает.
Вторая колонка в выводе выше называется TAG. Когда мы выполняли команду docker run nginx , то на самом деле выполнялась команда docker run nginx:latest . То есть мы не просто скачиваем образ nginx, а скачиваем его конкретную версию. Latest — тег по умолчанию. Несложно догадаться, что он означает последнюю версию образа.
Важно понимать, что это всего лишь соглашение, а не правило. Конкретный образ вообще может не иметь тега latest, либо иметь, но он не будет содержать последние изменения, просто потому, что никто их не публикует. Впрочем, популярные образы следуют соглашению. Как понятно из контекста, теги в Докере изменяемы, другими словами, вам никто не гарантирует, что скачав образ с одним и тем же тегом на разных компьютерах в разное время вы получите одно и то же. Такой подход может показаться странным и ненадежным, ведь нет гарантий, но на практике есть определенные соглашения, которым следуют все популярные образы. Тег latest действительно всегда содержит последнюю версию и постоянно обновляется, но кроме этого тега активно используется семантическое версионирование. Рассмотрим https://hub.docker.com/_/nginx
1.13.8, mainline, 1, 1.13, latest 1.13.8-perl, mainline-perl, 1-perl, 1.13-perl, perl 1.13.8-alpine, mainline-alpine, 1-alpine, 1.13-alpine, alpine 1.13.8-alpine-perl, mainline-alpine-perl, 1-alpine-perl, 1.13-alpine-perl, alpine-perl 1.12.2, stable, 1.12 1.12.2-perl, stable-perl, 1.12-perl 1.12.2-alpine, stable-alpine, 1.12-alpine 1.12.2-alpine-perl, stable-alpine-perl, 1.12-alpine-perl
Теги, в которых присутствует полная семантическая версия (x.x.x) всегда неизменяемы, даже если в них встречается что-то еще, например, 1.12.2-alphine. Такую версию смело нужно брать для продакшен-окружения. Теги, подобные такому 1.12, обновляются при изменении path версии. То есть внутри образа может оказаться и версия 1.12.2, и в будущем 1.12.8. Точно такая же схема и с версиями, в которых указана только мажорная версия, например, 1. Только в данном случае обновление идет не только по патчу, но и по минорной версии.
Как вы помните, команда docker run скачивает образ, если его нет локально, но эта проверка не связана с обновлением содержимого. Другими словами, если nginx:latest обновился, то docker run его не будет скачивать, он использует тот latest, который прямо сейчас уже загружен. Для гарантированного обновления образа существует другая команда: docker pull . Вот она всегда проверяет, обновился ли образ для определенного тега.
Кроме тегов имя образа может содержать префикс: например, etsy/chef . Этот префикс является именем аккаунта на сайте, через который создаются образы, попадающие в Registry. Большинство образов как раз такие, с префиксом. И есть небольшой набор, буквально сотня образов, которые не имеют префикса. Их особенность в том, что эти образы поддерживает сам Docker. Поэтому если вы видите, что в имени образа нет префикса, значит это официальный образ. Список таких образов можно увидеть здесь: https://github.com/docker-library/official-images/tree/master/library
Удаляются образы командой docker rmi .
$ docker rmi Ruby:2.4 Untagged: Ruby:2.4 Untagged: Ruby@sha256:d973c59b89f3c5c9bb330e3350ef8c529753ba9004dcd1bfbcaa4e9c0acb0c82
Если в Докере присутствует хоть один контейнер из удаляемого образа, то Докер не даст его удалить по понятным причинам. Если вы всё же хотите удалить и образ, и все контейнеры, связанные с ним, используйте флаг -f .
Управление контейнерами

Картинка описывает жизненный цикл (конечный автомат) контейнера. Кружками на нём изображены состояния, жирным выделены консольные команды, а квадратиками показывается то, что в реальности выполняется.
Проследите путь команды docker run . Несмотря на то, что команда одна, с точки зрения работы Докера выполняется два действия: создание контейнера и запуск. Существуют и более сложные варианты исполнения, но в этом разделе мы рассмотрим только базовые команды.
Запустим nginx так, чтобы он работал в фоне. Для этого после слова run добавляется флаг -d :
$ docker run -d -p 8080:80 nginx 431a3b3fc24bf8440efe2bca5bbb837944d5ae5c3b23b9b33a5575cb3566444e
После выполнения команды Докер выводит идентификатор контейнера и возвращает управление. Убедитесь в том, что nginx работает, открыв в браузере ссылку localhost:8080 . В отличие от предыдущего запуска, наш nginx работает в фоне, а значит не видно его вывода (логов). Посмотреть его можно командой docker logs , которой нужно передать идентификатор контейнера:
$ docker logs 431a3b3fc24bf8440efe2bca5bbb837944d5ae5c3b23b9b33a5575cb3566444e 172.17.0.1 - - [19/Jan/2018:07:38:55 +0000 ] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
Вы также можете подсоединиться к выводу лога в стиле tail -f . Для этого запустите docker logs -f 431a3b3fc24bf8440efe2bca5bbb837944d5ae5c3b23b9b33a5575cb3566444e . Теперь лог будет обновляться каждый раз, когда вы обновляете страницу в браузере. Выйти из этого режима можно набрав Ctrl + C , при этом сам контейнер остановлен не будет.
Теперь выведем информацию о запущенных контейнерах командой docker ps :
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 431a3b3fc24b nginx "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 80/tcp wizardly_rosalind
- CONTAINER_ID — идентификатор контейнера. Так же, как и в git, используется сокращенная запись хеша.
- IMAGE — имя образа, из которого был поднят контейнер. Если не указан тег, то подразумевается latest.
- COMMAND — команда, которая выполнилась на самом деле при старте контейнера.
- CREATED — время создания контейнера
- STATUS — текущее состояние.
- PORTS — проброс портов.
- NAMES — алиас. Докер позволяет кроме идентификатора иметь имя. Так гораздо проще обращаться с контейнером. Если при создании контейнера имя не указано, то Докер самостоятельно его придумывает. В выводе выше как раз такое имя у nginx.
( Команда docker stats выводит информацию о том, сколько ресурсов потребляют запущенные контейнеры).
Теперь попробуем остановить контейнер. Выполним команду:
# Вместо CONTAINER_ID можно указывать имя $ docker kill 431a3b3fc24b # docker kill wizardly_rosalind 431a3b3fc24b
Если попробовать набрать docker ps , то там этого контейнера больше нет. Он удален.
Команда docker ps выводит только запущенные контейнеры. Но кроме них могут быть и остановленные. Причем, остановка может происходить как и по успешному завершению, так и в случае ошибок. Попробуйте набрать docker run ubuntu ls , а затем docker run ubuntu bash -c «unknown» . Эти команды не запускают долгоживущий процесс, они завершаются сразу после выполнения, причем вторая с ошибкой, так как такой команды не существует.
Теперь выведем все контейнеры командой docker ps -a . Первыми тремя строчками вывода окажутся:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 85fb81250406 ubuntu "bash -c unkown" Less than a second ago Exited (127) 3 seconds ago loving_bose c379040bce42 ubuntu "ls" Less than a second ago Exited (0) 9 seconds ago determined_tereshkova
Здесь как раз два последних наших запуска. Если посмотреть на колонку STATUS, то видно, что оба контейнера находятся в состоянии Exited. То есть запущенная команда внутри них выполнилась, и они остановились. Разница лишь в том, что один завершился успешно (0), а второй с ошибкой (127). После остановки контейнер можно даже перезапустить:
docker start determined_tereshkova # В вашем случае будет другое имя
Только в этот раз вы не увидите вывод. Чтобы его посмотреть, воспользуйтесь командой docker logs determined_tereshkova .
Взаимодействие с другими частями системы
Запускать изолированный контейнер, который живет весь внутри себя — малополезно. Как правило, контейнеру нужно взаимодействовать с внешним миром, принимать входящие запросы на определенный порт, выполнять запросы на другие сервисы, читать общие файлы и писать в них. Все эти возможности настраиваются при создании контейнера.
Interactive mode
Самый простой вариант использования Докера, как мы уже убедились — поднять контейнер и выполнить внутри него какую-либо команду:
$ docker run ubuntu ls /usr bin games include lib local sbin share src $
После выполнения команды Docker возвращает управление, и мы снова находимся вне контейнера. Если попробовать точно так же запустить баш, то мы получим не то, что хотим:
$ docker run ubuntu bash $
Дело в том, что bash запускает интерактивную сессию внутри контейнера. Для взаимодействия с ней нужно оставить открытым поток STDIN и запустить TTY (псевдо-терминал). Поэтому для запуска интерактивных сессий нужно не забыть добавить опции -i и -t . Как правило их добавляют сразу вместе как -it . Поэтому правильный способ запуска баша выглядит так: docker run -it ubuntu bash .
Ports
Если запустить nginx такой командой docker run nginx , то nginx не сможет принять ни один запрос, несмотря на то, что внутри контейнера он слушает 80 порт (напомню, что каждый контейнер по умолчанию живет в своей собственной сети). Но если запустить его так docker run -p 8080:80 nginx , то nginx начнет отвечать на порту 8080.
Флаг -p позволяет описывать как и какой порт выставить наружу. Формат записи 8080:80 расшифровывается так: пробросить порт 8080 снаружи контейнера в контейнер на порт 80. Причем, по умолчанию, порт 8080 слушается на 0.0.0.0 , то есть на всех доступных интерфейсах. Поэтому запущенный таким образом контейнер доступен не только через localhost:8080 , но и снаружи машины (если доступ не запрещен как-нибудь еще). Если нужно выполнить проброс только на loopback, то команда меняется на такую: docker run -p 127.0.0.1:8080:80 nginx .
Docker позволяет пробрасывать столько портов, сколько нужно. Например, в случае nginx часто требуется использовать и 80 порт, и 443 для HTTPS. Сделать это можно так: docker run -p 80:80 -p 443:443 nginx Про остальные способы пробрасывать порты можно прочитать в официальной документации.
Volumes
Другая частая задача связана с доступом к основной файловой системе. Например, при старте nginx-контейнера ему можно указать конфигурацию, лежащую на основной фс. Докер прокинет её во внутреннюю фс, и nginx сможет её читать и использовать.
Проброс осуществляется с помощью опции -v . Вот как можно запустить баш сессию из образа Ubuntu, подключив туда историю команд с основной файловой системы: docker run -it -v ~/.bash_history:/root/.bash_history ubuntu bash . Если в открытом баше понажимать стрелку вверх, то отобразится история. Пробрасывать можно как файлы, так и директории. Любые изменения производимые внутри volume меняются как внутри контейнера, так и снаружи, причем по умолчанию доступны любые операции. Как и в случае портов, количество пробрасываемых файлов и директорий может быть любым.
При работе с Volumes есть несколько важных правил, которые надо знать:
- Путь до файла во внешней системе должен быть абсолютным.
- Если внутренний путь (то, что идет после : ) не существует, то Докер создаст все необходимые директории и файлы. Если существует, то заменит старое тем, что было проброшено.
Кроме пробрасывания части фс снаружи, Докер предоставляет еще несколько вариантов создания и использования Volumes. Подробнее — в официальной документации.
Переменные окружения
Конфигурирование приложения внутри контейнера, как правило, осуществляется с помощью переменных окружения в соответствии с 12factors. Существует два способа их установки:
- Флаг -e . Используется он так: docker run -it -e «HOME=/tmp» ubuntu bash
- Специальный файл, содержащий определения переменных окружения, который пробрасывается внутрь контейнера опцией —env-file .
Подготовка собственного образа
Создание и публикация собственного образа не сложнее его использования. Весь процесс делится на три шага:
- Создается файл Dockerfile в корне проекта. Внутри описывается процесс создания образа.
- Выполняется сборка образа командой docker build
- Выполняется публикация образа в Registry командой docker push
Рассмотрим процесс создания образа на примере упаковки линтера eslint (не забудьте повторить его самостоятельно). В результате сборки, мы получим образ, который можно использовать так:
$ docker run -it -v /path/to/js/files:/app my_account_name/eslint /app/index.js 3:6 error Parsing error: Unexpected token 1 | import path from 'path'; 2 | > 3 | path (;) | ^ 4 | ✖ 1 problem (1 error, 0 warnings )
То есть достаточно запустить контейнер из этого образа, подключив каталог с файлами js для проверки как Volume во внутреннюю директорию /app.
1. Конечная структура директории, на основе файлов которой соберется образ, выглядит так:
eslint-docker/ Dockerfile eslintrc.yml
Файл eslintrc.yml содержит конфигурацию линтера. Он автоматически прочитывается, если лежит в домашней директории под именем .eslintrc.yml. То есть этот файл должен попасть под таким именем в директорию /root внутрь образа.
2. Создание Dockerfile
# Dockerfile FROM node:9.3 WORKDIR /usr/src RUN npm install -g eslint babel-eslint RUN npm install -g eslint-config-airbnb-base eslint-plugin-import COPY eslintrc.yml /root/.eslintrc.yml CMD ["eslint", "/app"]
Dockerfile имеет довольно простой формат. На каждой строчке указывается инструкция (директива) и её описание.
FROM
Инструкция FROM нужна для указания образа, от которого происходит наследование. Здесь необходимо оговориться, что образы строятся на базе друг друга и все вместе образуют большое дерево.
В корне этого дерева находится образ busybox. В прикладных задачах напрямую его не используют, так как Докером предоставляются подготовленные образы под каждую экосистему и стек.
RUN
Основная инструкция в Dockerfile. Фактически здесь указывается sh команда, которая будет выполнена в рамках окружения, указанного во FROM при сборке образа. Так как по умолчанию всё выполняется от пользователя root, то использовать sudo не нужно (и скорее всего его нет в базовом образе). К тому же учтите, что сборка образа — процесс не интерактивный. В тех ситуациях, когда вы используете команду, которая может запросить что-то от пользователя, необходимо подавлять этот вывод. Например, в случае пакетных менеджеров делают так: apt-get install -y curl . Флаг -y как раз говорит о том что нужно производить установку без дополнительных вопросов.
Технически образ Докера — это не один файл, а набор так называемых слоев. Каждый вызов RUN формирует новый слой, который можно представить как набор файлов, созданных и измененных (в том числе удаленных) командой, указанной в RUN. Такой подход позволяет значительно улучшить производительность системы, задействовав кеширование слоев, которые не поменялись. С другой стороны, Докер переиспользует слои в разных образах если они идентичны, что сокращает и скорость загрузки и занимаемое пространство на диске. Тема кеширования слоев довольно важная при активном использовании Докера. Для её эффективной работы нужно понимать как она устроена и как правильно описывать инструкции RUN для максимальной утилизации.
COPY
В соответствии со своим названием команда COPY берет файл или директорию из основной файловой системы и копирует её внутрь образа. У команды есть ограничение. То, что копируется, должно лежать в той же директории, где и Dockerfile. Именно эту команду используют при разработке когда необходимо упаковать приложение внутрь образа.
WORKDIR
Инструкция, устанавливающая рабочую директорию. Все последующие инструкции будут считать, что они выполняются именно внутри неё. По инструкция WORKDIR действует, как команда cd . Кроме того, когда мы запускаем контейнер, то он также стартует из рабочей директории. Например, запустив bash, вы окажетесь внутри неё.
CMD
Та самая инструкция, определяющая действие по умолчанию при использовании docker run . Она используется только в том случае, если контейнер был запущен без указания команды, иначе она игнорируется.
3. Сборка
Для сборки образа используется команда docker build . С помощью флага -t передается имя образа, включая имя аккаунта и тег. Как обычно, если не указывать тег, то подставляется latest.
$ docker build -t my_account_name/eslint .
После выполнения данной команды вы можете увидеть текущий образ в списке docker images . Вы даже можете начать его использовать без необходимости публикации в Registry. Напомню, что команда docker run не пытается искать обновленную версию образа, если локально есть образ с таким именем и тегом.
4. Публикация
$ docker push my_account_name/eslint
Для успешного выполнения публикации нужно соблюсти два условия:
- Зарегистрироваться на Docker Cloud и создать там репозиторий для образа.
- Залогиниться в cli интерфейсе используя команду docker login .
Docker Compose
Docker Compose — продукт, позволяющий разрабатывать проект локально, используя Докер. По решаемым задачам его можно сравнивать с Vagrant.
Docker Compose позволяет управлять набором контейнеров, каждый из которых представляет из себя один сервис проекта. Управление включает в себя сборку, запуск с учетом зависимостей и конфигурацию. Конфигурация Docker Compose описывается в файле docker-compose.yml , лежащем в корне проекта, и выглядит примерно так:
# https://github.com/hexlet-basics/hexlet_basics version: '3.3' services: db: image: postgres app: build: context: services/app dockerfile: Dockerfile command: mix phx.server ports: - "$:$" env_file: '.env' volumes: - "./services/app:/app:cached" - "~/.bash_history:/root/.bash_history:cached" - ".bashrc:/root/.bashrc:cached" - "/var/tmp:/var/tmp:cached" - "/tmp:/tmp:cached" depends_on: - db
В бою
При использовании Докера настройка машин проекта, как правило, сводится к установке Докера. Дальше нужно только деплоить. Простейший процесс выкладки выглядит так:
- Скачать новый образ.
- Остановить старый контейнер.
- Поднять новый контейнер.
Причем, данный порядок действий не зависит от стека технологий. Выполнять деплой можно (как и настройку машин) с помощью Ansible.
Другой вариант, подходящий для нетривиальных проектов, основан на использовании специальных систем оркестрации типа Kubernetes. Данный вариант требует от вас довольно серьезной подготовки, включающий понимание принципов работы распределенных систем.
Докер под капотом
Изоляция, которую предоставляет Докер, достигается благодаря возможностям ядра Cgroups и Namespaces. Они позволяют запускать процесс операционной системы не только в изолированном окружении, но и с ограничением по использованию физических ресурсов, таких как память или процессор.
Дополнительные ссылки
- Вебинар: Введение в докер
- Docker: Основы
Установка и использование Docker в Ubuntu 20.04

Docker — это приложение, упрощающее процесс управления процессами приложения в контейнерах. Контейнеры позволяют запускать приложения в процессах с изолированными ресурсами. Они похожи на виртуальные машины, но более портативные, более эффективно расходуют ресурсы и в большей степени зависят от операционной системы хоста.
Подробное описание различных компонентов контейнера Docker см. в статье Экосистема Docker: знакомство с базовыми компонентами.
В этом обучающем модуле мы установим и начнем использовать Docker Community Edition (CE) на сервере Ubuntu 20.04. Вы самостоятельно установите Docker, поработаете с контейнерами и образами и разместите образ в репозитории Docker.
Предварительные требования
Для выполнения этого руководства вам потребуется следующее:
- Один сервер Ubuntu 20.04, настроенный в соответствии с руководством по начальной настройке сервера Ubuntu 20.04, включая пользователя non-root user с привилегиями sudo и брандмауэр.
- Учетная запись на Docker Hub, если вы хотите создавать собственные образы и загружать их на Docker Hub, как показано в шагах 7 и 8.
Шаг 1 — Установка Docker
Пакет установки Docker, доступный в официальном репозитории Ubuntu, может содержать не самую последнюю версию. Чтобы точно использовать самую актуальную версию, мы будем устанавливать Docker из официального репозитория Docker. Для этого мы добавим новый источник пакета, ключ GPG от Docker, чтобы гарантировать загрузку рабочих файлов, а затем установим пакет.
Первым делом обновите существующий список пакетов:
Затем установите несколько необходимых пакетов, которые позволяют apt использовать пакеты через HTTPS:
Добавьте ключ GPG для официального репозитория Docker в вашу систему:
Добавьте репозиторий Docker в источники APT:
-
sudo add-apt-repository «deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable»
Потом обновите базу данных пакетов и добавьте в нее пакеты Docker из недавно добавленного репозитория:
Убедитесь, что установка будет выполняться из репозитория Docker, а не из репозитория Ubuntu по умолчанию:
Вы должны получить следующий вывод, хотя номер версии Docker может отличаться:
Output of apt-cache policy docker-ce
docker-ce: Installed: (none) Candidate: 5:19.03.9~3-0~ubuntu-focal Version table: 5:19.03.9~3-0~ubuntu-focal 500 500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
Обратите внимание, что docker-ce не установлен, но является кандидатом на установку из репозитория Docker для Ubuntu 20.04 (версия focal ).
Docker должен быть установлен, демон-процесс запущен, а для процесса активирован запуск при загрузке. Проверьте, что он запущен:
Вывод должен выглядеть примерно следующим образом, указывая, что служба активна и запущена:
Output● docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2020-05-19 17:00:41 UTC; 17s ago TriggeredBy: ● docker.socket Docs: https://docs.docker.com Main PID: 24321 (dockerd) Tasks: 8 Memory: 46.4M CGroup: /system.slice/docker.service └─24321 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
После установки Docker у вас будет доступ не только к службе Docker (демон-процесс), но и к утилите командной строки docker или клиенту Docker. Мы узнаем, как использовать команду docker позже в этом обучающем руководстве.
Шаг 2 — Настройка команды Docker без sudo (необязательно)
По умолчанию команда docker может быть запущена только пользователем root или пользователем из группы docker, которая автоматически создается при установке Docker. Если вы попытаетесь запустить команду docker без префикса sudo или с помощью пользователя, который не находится в группе docker, то получите следующий вывод:
Outputdocker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?. See 'docker run --help'.
Если вы не хотите каждый раз вводить sudo при запуске команды docker , добавьте свое имя пользователя в группу docker :
Чтобы применить добавление нового члена группы, выйдите и войдите на сервер или введите следующее:
Вы должны будете ввести пароль вашего пользователя, чтобы продолжить.
Проверьте, что ваш пользователь добавлен в группу docker, введя следующее:
Outputsammy sudo docker
Если вам нужно добавить пользователя в группу docker , для которой вы не выполнили вход, объявите имя пользователя явно, используя следующую команду:
В дальнейшем в статье подразумевается, что вы запускаете команду docker от имени пользователя в группе docker. В обратном случае вам необходимо добавлять к командам префикс sudo .
Давайте перейдем к знакомству с командой docker .
Шаг 3 — Использование команды Docker
Использование docker подразумевает передачу ему цепочки опций и команд, за которыми следуют аргументы. Синтаксис имеет следующую форму:
Чтобы просмотреть все доступные субкоманды, введите:
Для 19-й версии Docker полный список субкоманд выглядит следующим образом:
Output attach Attach local standard input, output, and error streams to a running container build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container's filesystem events Get real time events from the server exec Run a command in a running container export Export a container's filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers version Show the Docker version information wait Block until one or more containers stop, then print their exit codes
Чтобы просмотреть параметры, доступные для конкретной команды, введите:
Чтобы просмотреть общесистемную информацию о Docker, введите следующее:
Давайте изучим некоторые из этих команд. Сейчас мы начнем работать с образами.
Шаг 4 — Работа с образами Docker
Контейнеры Docker получают из образов Docker. По умолчанию Docker загружает эти образы из Docker Hub, реестр Docker, контролируемые Docker, т.е. компанией, реализующей проект Docker. Любой может размещать свои образы Docker на Docker Hub, поэтому большинство приложений и дистрибутивов Linux, которые вам потребуется, хранят там свои образы.
Чтобы проверить, можно ли получить доступ к образам из Docker Hub и загрузить их, введите следующую команду:
Данный вывод говорит о том, что Docker работает корректно:
OutputUnable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 0e03bdcc26d7: Pull complete Digest: sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. .
Docker первоначально не смог найти локальный образ hello-world , поэтому он загрузил образ из Docker Hub, который является репозиторием по умолчанию. После того как образ был загружен, Docker создал контейнер из образа, а приложение внутри контейнера было исполнено, отобразив сообщение.
Вы можете выполнять поиск доступных на Docker Hub с помощью команды docker с субкомандой search . Например, чтобы найти образ Ubuntu, введите:
Скрипт пробежится по Docker Hub и вернет список всех образов с именами, совпадающими со строкой запроса. В данном случае вывод будет выглядеть примерно следующим образом:
OutputNAME DESCRIPTION STARS OFFICIAL AUTOMATED ubuntu Ubuntu is a Debian-based Linux operating sys… 10908 [OK] dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface … 428 [OK] rastasheep/ubuntu-sshd Dockerized SSH service, built on top of offi… 244 [OK] consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC session… 218 [OK] ubuntu-upstart Upstart is an event-based replacement for th… 108 [OK] ansible/ubuntu14.04-ansible Ubuntu 14.04 LTS with .
В столбце OFFICIAL OK указывает на образ, созданный и поддерживаемый компанией, реализующей проект. После того как вы определили образ, который хотели бы использовать, вы можете загрузить его на свой компьютер с помощью субкоманды pull .
Запустите следующую команду, чтобы загрузить официальный образ ubuntu на свой компьютер:
Вывод должен выглядеть следующим образом:
OutputUsing default tag: latest latest: Pulling from library/ubuntu d51af753c3d3: Pull complete fc878cd0a91c: Pull complete 6154df8ff988: Pull complete fee5db0ff82f: Pull complete Digest: sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7 Status: Downloaded newer image for ubuntu:latest docker.io/library/ubuntu:latest
После того как образ будет загружен, вы сможете запустить контейнер с помощью загруженного образа с помощью субкоманды run . Как вы уже видели на примере hello-world , если образ не был загружен, когда docker выполняется с субкомандой run , клиент Docker сначала загружает образ, а затем запускает контейнер с этим образом.
Чтобы просмотреть образы, которые были загружены на ваш компьютер, введите:
Вывод команды должен выглядеть примерно следующим образом:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 1d622ef86b13 3 weeks ago 73.9MB hello-world latest bf756fb1ae65 4 months ago 13.3kB
Как вы увидите далее в этом обучающем руководстве, образы, которые вы используете для запуска контейнеров, можно изменить и использовать для создания новых образов, которые затем могут быть загружены (помещены) на Docker Hub или другие реестры Docker.
Давайте более подробно рассмотрим, как запускаются контейнеры.
Шаг 5 — Запуск контейнеров Docker
Контейнер hello-world , который вы запустили на предыдущем шаге, служит примером контейнера, который запускается и завершает работу после отправки тестового сообщения. Контейнеры могут быть гораздо более полезными, чем в примере выше, а также могут быть интерактивными. В конечном счете они очень похожи на виртуальные машины, но более бережно расходуют ресурсы.
В качестве примера мы запустим контейнер с самым последним образом образ Ubuntu. Сочетание переключателей -i и -t предоставляет вам доступ к интерактивной командной оболочке внутри контейнера:
Необходимо изменить приглашение к вводу команды, чтобы отразить тот факт, что вы работаете внутри контейнера, и должны иметь следующую форму:
Outputroot@d9b100f2f636:/#
Обратите внимание на идентификатор контейнер в запросе команды. В данном примере это d9b100f2f636 . Вам потребуется этот идентификатор для определения контейнера, когда вы захотите его удалить.
Теперь вы можете запустить любую команду внутри контейнера. Например, сейчас мы обновим базу данных пакетов внутри контейнера. Вам не потребуется начинать любую команду с sudo , потому что вы работаете внутри контейнера как root-пользователь:
После этого вы можете установите любое приложение внутри контейнера. Давайте установим Node.js:
Эта команда устанавливает Node.js внутри контейнера из официального репозитория Ubuntu. После завершения установки проверьте, что Node.js был установлен успешно:
Вы увидите номер версии, отображаемый в терминале:
Outputv10.19.0
Любые изменения, которые вы вносите внутри контейнера, применяются только к контейнеру.
Чтобы выйти из контейнера, введите exit .
Далее мы рассмотрим управление контейнерами в нашей системе.
Шаг 6 — Управление контейнерами Docker
После использования Docker в течение определенного времени, у вас будет много активных (запущенных) и неактивных контейнеров на компьютере. Чтобы просмотреть активные, используйте следующую команду:
Вывод будет выглядеть примерно следующим образом:
OutputCONTAINER ID IMAGE COMMAND CREATED
В этом обучающем руководстве вы запустили два контейнера: один из образа hello-world и другой из образа ubuntu . Оба контейнера больше не запущены, но все еще существуют в вашей системе.
Чтобы просмотреть все контейнеры — активные и неактивные, воспользуйтесь командой docker ps с переключателем -a :
Вывод будет выглядеть следующим образом:
1c08a7a0d0e4 ubuntu "/bin/bash" 2 minutes ago Exited (0) 8 seconds ago quizzical_mcnulty a707221a5f6c hello-world "/hello" 6 minutes ago Exited (0) 6 minutes ago youthful_curie
Чтобы просмотреть последний созданный вами контейнер, передайте переключатель -l :
Чтобы запустить остановленный контейнер, воспользуйтесь docker start с идентификатором контейнера или именем контейнера. Давайте запустим контейнер на базе Ubuntu с идентификатором 1c08a7a0d0e4 :
Контейнер будет запущен, а вы сможете использовать docker ps , чтобы просматривать его статус:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c08a7a0d0e4 ubuntu "/bin/bash" 3 minutes ago Up 5 seconds quizzical_mcnulty
Чтобы остановить запущенный контейнер, используйте docker stop с идентификатором или именем контейнера. На этот раз мы будем использовать имя, которое Docker присвоил контейнеру, т.е. quizzical_mcnulty :
После того как вы решили, что вам больше не потребуется контейнер, удалите его с помощью команды docker rm , снова добавив идентификатор контейнера или его имя. Используйте команду docker ps -a , чтобы найти идентификатор или имя контейнера, связанного с образом hello-world , и удалить его.
Вы можете запустить новый контейнер и присвоить ему имя с помощью переключателя —name . Вы также можете использовать переключатель —rm , чтобы создать контейнер, который удаляется после остановки. Изучите команду docker run help , чтобы получить больше информации об этих и прочих опциях.
Контейнеры можно превратить в образы, которые вы можете использовать для создания новых контейнеров. Давайте посмотрим, как это работает.
Шаг 7 — Внесение изменений в контейнер для образа Docker
После запуска образа Docker вы можете создавать, изменять и удалять файлы так же, как и с помощью виртуальной машины. Эти изменения будут применяться только к данному контейнеру. Вы можете запускать и останавливать его, но после того как вы уничтожите его с помощью команды docker rm , изменения будут утрачены навсегда.
Данный раздел показывает, как сохранить состояние контейнера в виде нового образа Docker.
После установки Node.js внутри контейнера Ubuntu у вас появился контейнер, запускающий образ, но этот контейнер отличается от образа, который вы использовали для его создания. Но позже вам может снова потребоваться этот контейнер Node.js в качестве основы для новых образов.
Затем внесите изменения в новый экземпляр образа Docker с помощью следующей команды.
Переключатель -m используется в качестве сообщения о внесении изменений, которое помогает вам и остальным узнать, какие изменения вы внесли, в то время как -a используется для указания автора. container_id — это тот самый идентификатор, который вы отмечали ранее в этом руководстве, когда запускали интерактивную сессию Docker. Если вы не создавали дополнительные репозитории на Docker Hub, repository , как правило, является вашим именем пользователя на Docker Hub.
Например, для пользователя sammy с идентификатором контейнера d9b100f2f2f6 команда будет выглядеть следующим образом:
Когда вы вносите образ, новый образ сохраняется локально на компьютере. Позже в этом обучающем руководстве вы узнаете, как добавить образ в реестр Docker, например, на Docker Hub, чтобы другие могли получить к нему доступ.
Список образов Docker теперь будет содержать новый образ, а также старый образ, из которого он будет получен:
Вывод будет выглядеть следующим образом:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE sammy/ubuntu-nodejs latest 7c1f35226ca6 7 seconds ago 179MB .
В данном примере ubuntu-nodejs является новым образом, который был получен из образа ubuntu на Docker Hub. Разница в размере отражает внесенные изменения. В данном примере изменение состояло в том, что NodeJS был установлен. В следующий раз, когда вам потребуется запустить контейнер, использующий Ubuntu с предустановленным NodeJS, вы сможете использовать новый образ.
Вы также можете создавать образы из Dockerfile , что позволяет автоматизировать установку программного обеспечения в новом образе. Однако это не относится к предмету данного обучающего руководства.
Теперь мы поделимся новым образом с другими, чтобы они могли создавать из него контейнеры.
Шаг 8 — Загрузка образов Docker в репозиторий Docker
Следующим логическим шагом после создания нового образа из существующего является предоставление доступа к этому образу нескольким вашим друзьям или всему миру на Docker Hub или в другом реестре Docker, к которому вы имели доступ. Чтобы добавить образ на Docker Hub или любой другой реестр Docker, у вас должна быть там учетная запись.
Данный раздел посвящен добавлению образа Docker на Docker Hub. Чтобы узнать, как создать свой собственный частный реестр Docker, ознакомьтесь со статьей Настройка частного реестра Docker на Ubuntu 14.04.
Чтобы загрузить свой образ, выполните вход в Docker Hub.
Вам будет предложено использовать для аутентификации пароль Docker Hub. Если вы указали правильный пароль, аутентификация должна быть выполнена успешно.
Примечание. Если ваше имя пользователя в реестре Docker отличается от локального имени пользователя, которое вы использовали при создании образа, вам потребуется пометить ваш образ именем пользователя в реестре. Для примера, приведенного на последнем шаге, вам необходимо ввести следующую команду:
Затем вы можете загрузить свой образ с помощью следующей команды:
Чтобы загрузить образ ubuntu-nodejs в репозиторий sammy, необходимо использовать следующую команду:
Данный процесс может занять некоторое время, необходимое на загрузку образов, но после завершения вывод будет выглядеть следующим образом:
OutputThe push refers to a repository [docker.io/sammy/ubuntu-nodejs] e3fbbfb44187: Pushed 5f70bf18a086: Pushed a3b5c80a4eba: Pushed 7f18b442972b: Pushed 3ce512daaf78: Pushed 7aae4540b42d: Pushed .
После добавления образа в реестр он должен отображаться в панели вашей учетной записи, как на изображении ниже.

Если при попытке добавления возникает подобная ошибка, вы, скорее всего, не выполнили вход:
OutputThe push refers to a repository [docker.io/sammy/ubuntu-nodejs] e3fbbfb44187: Preparing 5f70bf18a086: Preparing a3b5c80a4eba: Preparing 7f18b442972b: Preparing 3ce512daaf78: Preparing 7aae4540b42d: Waiting unauthorized: authentication required
Выполните вход с помощью команды docker login и повторите попытку загрузки. Проверьте, появился ли образ на вашей странице репозитория Docker Hub.
Теперь вы можете использовать docker pull sammy / ubuntu-nodejs , чтобы загрузить образ на новый компьютер и использовать его для запуска нового контейнера.
Заключение
В этом обучающем руководстве вы установили Docker, поработали с образами и контейнерами, а также добавили измененный образ на Docker Hub. После знакомства с основами, вы можете переходить к другим обучающим руководствам Docker в сообществе.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.