Зарегистрируйтесь, чтобы продолжить обучение

Запуск Docker: Основы

Знакомство с Docker лучше всего начать с примеров запуска, которые постепенно будут детализироваться и раскрываться. Начнем с самого простого варианта, запустим с его помощью bash.

# -it означает, что мы запускаемся в интерактивном режиме
# это нужно для программ, которые ожидают пользовательский ввод
# к таким относится bash
docker run -it nginx bash
Unable to find image 'nginx:latest' locally
08bc36ad5247: Download complete
1bb5c4b86cb7: Download complete
021283c8eb95: Download complete
91bb7937700d: Download complete
76579e9ed380: Download complete
f46d7b05649a: Download complete
103501419a0a: Download complete
cf707e233955: Download complete
faef57eae888: Download complete
4b962717ba55: Download complete
root@a59191412f5c:/#

Этой командой мы говорим запусти bash внутри контейнера используя образ nginx. Что это значит?

  • Образ (Image) - это слепок файловой системы, в который "упаковано" что-то, ради чего мы используем Docker — например, PostgreSQL, Nginx или, даже, разрабатываемое нами приложение. В примере выше, мы используем готовый образ с названием nginx, поэтому Docker "знает" про его существование. Сам образ взят просто для примера, в течении курса мы будем использовать разные образы, как готовые, так и созданные нами.
  • Контейнер (Container), упрощенно, это процесс операционной системы, подключенный к образу, то есть его файловой системе. Кроме того, контейнер изолирован от внешней среды и живет в своем окружении. В этом смысле, он похож на обычную виртуальную машину, но в отличии от неё гораздо более легковесный и зависимый от основной операционной системы.

При первом вызове данная команда начнет скачивать образ nginx, поэтому придется немного подождать. Когда образ скачается, запустится bash, и вы окажетесь внутри контейнера под суперпользователем (root).

С этого момента вы можете взаимодействовать с содержимым контейнера, так как будто вы работаете в обычном терминале. Технически это обеспечивается комбинацией флагов -it, которые нужны в случае работы с интерактивными приложениями, такими как bash.

root@a59191412f5c:/# pwd
/
root@a59191412f5c:/# cd /root/
root@a59191412f5c:~# ls -la
total 16
drwx------ 2 root root 4096 Jul  3 00:00 .
drwxr-xr-x 1 root root 4096 Jul  7 20:35 ..
-rw-r--r-- 1 root root  571 Apr 10  2021 .bashrc
-rw-r--r-- 1 root root  161 Jul  9  2019 .profile
root@a59191412f5c:/# ls -la /home/
total 8
drwxr-xr-x 2 root root 4096 Mar  2 13:55 .
drwxr-xr-x 1 root root 4096 Jul  7 20:39 ..

Побродите по файловой системе, посмотрите содержимое директории /home. Как видите, её содержимое не совпадает с тем, что находится у вас на компьютере.

Эта файловая система появилась из образа nginx. Всё, что вы сделаете здесь, никак не затронет вашу основную файловую систему, то есть можно смело удалять любые файлы внутри. После экспериментов не забудьте выйти командой exit, либо сочетанием клавиш Ctrl + D, либо просто закройте вкладку терминала.

root@a59191412f5c:/# exit
exit

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

# Общая структура команды
# docker run <имя образа> <команда> <параметры если есть>
docker run nginx cat /etc/nginx/nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;
...

Команда выполняется практически мгновенно, так как образ уже загружен. В отличие от предыдущего старта, где запускается баш и начинается интерактивная сессия внутри контейнера, запуск команды cat /etc/nginx/nginx.conf для образа nginx выведет на экран содержимое указанного файла (взяв его из файловой системы запущенного контейнера) и вернет управление в то место, где вы были. Вы не окажетесь внутри контейнера, после завершения команды.

Последний вариант запуска будет таким: docker run -p 8080:80 nginx. Этот запуск отличается тем, что после имени образа не указана никакая команда. Такой подход работает в случае, если команда на запуск прописана в самом образе и Docker подставляет ее во время старта если не указана конкретная команда. В каких случаях так делают? Почти всегда, когда образ строится вокруг конкретной программы, у которой есть стандартный способ запуска, как у веб-серверов, баз данных и так далее. А вот для образа ubuntu, в который упакована только операционная система, такой команды нет, так как тут она не имеет смысла.

# -p — проброс портов, расскажем о нем в следующих уроках
docker run -p 8080:80 nginx

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/07/07 20:43:10 [notice] 1#1: using the "epoll" event method
2023/07/07 20:43:10 [notice] 1#1: nginx/1.25.1
2023/07/07 20:43:10 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2023/07/07 20:43:10 [notice] 1#1: OS: Linux 5.15.49-linuxkit-pr
2023/07/07 20:43:10 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/07/07 20:43:10 [notice] 1#1: start worker processes
2023/07/07 20:43:10 [notice] 1#1: start worker process 29
2023/07/07 20:43:10 [notice] 1#1: start worker process 30
2023/07/07 20:43:10 [notice] 1#1: start worker process 31
2023/07/07 20:43:10 [notice] 1#1: start worker process 32

Данная команда не возвращает управление терминалу, потому что стартует nginx. Ввод оказывается заблокированным, а на экране выводится процесс запуска Nginx. Откройте браузер и наберите localhost:8080. Вы увидите как загрузилась страница Welcome to nginx!. Если в этот момент снова посмотреть в консоль, где был запущен контейнер, то можно увидеть, что туда выводится лог запросов к localhost:8080. Остановить nginx можно комбинацией Ctrl + C.

^C2023/07/07 20:43:58 [notice] 1#1: signal 2 (SIGINT) received, exiting
2023/07/07 20:43:58 [notice] 30#30: exiting
2023/07/07 20:43:58 [notice] 29#29: exiting
2023/07/07 20:43:58 [notice] 31#31: exiting
2023/07/07 20:43:58 [notice] 30#30: exit
2023/07/07 20:43:58 [notice] 29#29: exit
2023/07/07 20:43:58 [notice] 31#31: exit
2023/07/07 20:43:58 [notice] 32#32: exiting
2023/07/07 20:43:58 [notice] 32#32: exit
2023/07/07 20:43:58 [notice] 1#1: signal 17 (SIGCHLD) received from 31
2023/07/07 20:43:58 [notice] 1#1: worker process 29 exited with code 0
2023/07/07 20:43:58 [notice] 1#1: worker process 30 exited with code 0
2023/07/07 20:43:58 [notice] 1#1: worker process 31 exited with code 0
2023/07/07 20:43:58 [notice] 1#1: signal 29 (SIGIO) received
2023/07/07 20:43:58 [notice] 1#1: signal 17 (SIGCHLD) received from 32
2023/07/07 20:43:58 [notice] 1#1: worker process 32 exited with code 0
2023/07/07 20:43:58 [notice] 1#1: exit

Несмотря на то, что все запуски выполнялись по-разному и приводили к разным результатам, общая схема их работы одна. Docker при необходимости автоматически скачивает образ (первый аргумент после docker run) и на основе него стартует контейнер с указанной командой.

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. Из этого можно сделать несколько выводов:

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

Самостоятельная работа

По традиции первая программа, которую создают программисты, называется Hello, World!. В нашем случае запустим аналогичную программу, которая выведет приветствие.

Изучите ридми образа hello-world и запустите его.


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

  1. Docker Documentation: docker run

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
новый
Git, JavaScript, Playwright, бэкенд-тесты, юнит-тесты, API-тесты, UI-тесты, Github Actions, HTTP/HTTPS, API, Docker, SQL
8 месяцев
c опытом
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»