Docker - DmitryGontarenko/usefultricks GitHub Wiki
Docker — это программа, которая даёт возможность упаковывать приложения со всеми их зависимостями в стандартизированный модуль (контейнер) и запускать их. Как результат, системы, основанные на контейнерах, легко масштабируются, переносятся и воспроизводятся.
Image (образ) — это некоторый набор слоёв. Каждый слой — результат работы команды в Dockerfile. Все что запускается на основе этого образа является контейнером, или инстансом. т.е. с одного образа можно запустить несколько
одинаковых копий этого образа — контейнеров.
Контейнер - это компонент докера, объединяющий код и зависимости. Несколько контейнеров могут работать на одном компьютере и совместно использовать ядро ОС с другими контейнерами, каждый из которых работает как изолированный процесс.
Dockerfile - файл, который содержит скрипт (инструкции) по созданию docker-образа.
Виртуализация - метод разделения вычислительных процессов выполняемых на одном физическом ресурсе. Виртаулизация означает создания виртуальной версии чего-либо. Чаще всего это относится к процессу запуска виртуального экземпляра компьютерной системы.
Виртуальная машина - виртуализация (эмуляция) реального компьютера. Виртуальная машина работает поверх физической машины, используя гипервизор (hypervisor).
Гипервизор (или Virtual Machine Monitors, VMM) - это часть программного или аппаратного обеспечения, позволяющая одновременное, параллельное выполнение нескольких операционных систем на одном и том же хост-компьютере. Именно гипервизор обеспечивает создание и запуск виртуальных машин, а также изоляцию ОС друг от друга и разделение ресурсов между ними.
Компьютер, на котором гипервизор запускает одну или несколько виртуальных машин, называется хост-машиной, а каждая виртуальная машина - гостевой.
Существует два типа гипервизора:
ТИП 1 - "автономные гипервизоры", запускаются непосредственно на аппаратном обеспечении ("голом железе"), то есть при установке не требуют наличия на машине установленной ОС. Из-за того, что гипервизоры типа 1 имеют прямой доступ к физическому оборудованию, этот тип считается наиболее эффективным.
Такой тип гипервизора требует поддержки технологий аппаратной виртуализации. Такую поддержку для своего оборудования оказывают технологии производителей Intel и AMD.
К гипервизорам 1 типа можно отнести: Xen, Oracle VM Server, Microsoft Hyper-V и VMware ESX / ESXi.
ТИП 2 - "хостовые гипервизоры", запускаются на обычной хостовой ОС, как и другие приложения в системе.
Это так называемая программная виртуализация. В этом случае не требуется никакого специализированного аппаратного обеспечения, как в случае с аппаратной виртуализацией. Достаточно установить одну из программ виртуализации.
К гипервизорам 2 типа можно отнести: VMWare Workstation, VirtualBox.
Типы виртуализации:
Эмуляция - полная виртуализация, включая ядро ОС. Недостатком такого типа виртуализации является дополнительная нагрузка на системные ресурсы. Эмуляцию можно отнести ко 2-му типу гипервизоров.
Паравиртуализация - также известная как гипервизор 1-ого типа, выполняется непосредственно на аппаратном уровне и предоставляет услуги виртуализации для виртуальных машин, работающих на нем.
Контейнерная виртуализация - виртуализация на основе контейнеров, она позволяет выполнять несколько процессов, которые совместно используют базовое ядро ОС. Примеры инструментов управления: Docker, LXC.
Отличия контейнеров от VM
- Контейнеры совместно используют (разделяют) ядро ОС для выполнения операций.
- Виртуализация на основе контейнеров на так сильно влияет на производительность хост-машины.
- Докер-образы имеют небольшой размер по сравнению с образами виртуальных машин.
Кратко: Docker - это инструмент управления контейнерами. Образ — это шаблон для запуска контейнера. Контейнер - это компонент докера, объединяющий код и зависимости.
Установка Docker и работа с ним проводилась в ОС - Ubuntu Mate 18.04.4 x64
ОС была установлена с помощью средств виртуализации - VMware Workstation 12 Pro (12.5.9 build-7535481)
Установка docker:
sudo apt-get update
sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install docker.ce --install-recommends
- Проверяем -
docker -v
Установка docker-compose:
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
- Проверяем -
docker-compose -v
Пробуем запустить контейнер - sudo docker run hello-world
Добавим нашего пользователя в группу docker (что бы каждый раз не писать sudo
):
sudo usermod -aG docker <username>
sudo service docker restart
- Перезагружаем ОС
- Проверяем -
docker images
, команда должна выполниться без ошибок
Список основных команд:
Описание | Команда |
---|---|
Добавить пользователя в группу docker | sudo usermod -aG docker |
Перезапустить docker | sudo service docker restart |
Указать свою учетную запись в docker-hub | docker login |
Проверить версию docker | docker -v, docker-compose -v |
Зафиксировать изменения контейнера в новый образ | docker commit [exist_container] [image_name] |
Получить методанные контейнера или образа | docker inspect [container_id] / [image_id] |
Вывести сведения о занимаемом месте докер сервисов | docker system df -v |
Удалиь неиспользуемые образы, контейнеры, тома | docker system prune |
Образы:
Описание | Команда |
---|---|
Посмотреть список существующих образов | docker images |
Собрать образ (на основе Dockerfile) | docker build -t [image_name] [path/to/dockerfile] |
Собрать образ (на основе Dockerfile) | docker build -t [image_name] [path/to/dockerfile] |
Удалить образ с локальной машины | docker rmi [IMAGE ID] |
Контейнеры:
Описание | Команда |
---|---|
Запустить контейнер | docker run [image] |
Запустить контейнер и удалить после завершения | docker run --rm [image] |
Запустить контейнер в фоновом режиме | docker run -d [image] |
Запустить контейнер с интерактивным терминалом | docker run -it [image] |
Выполнить команду в запущеном контейнере | docker exec [container] [command] |
Просмотреть ВСЕ контейнеры | docker ps -a |
Просмотреть все запущенные контейнеры | docker ps |
Переименовать контейнер | docker rename <old_name> <new_name> |
Просмотр детальной информации о контейнере | docker inspect [NAME] |
Просмотр логов контейнера | docker logs [container_id] |
Просмотр изменений в контейнере | docker diff <name> |
Перезапустить контейнер | docker start [NAME/CONTAINER ID] |
Остановить запущенный контейнер | docker stop [NAME/CONTAINER ID] |
Удалить контейнер | docker rm [NAME] |
Удалить ВСЕ контейнеры | docker rm $(docker ps -aq) |
Удалить все остановленные контейнеры | docker rm -v $(docker ps -aq -f status=exited) |
Команды Docker 1.13+:
Описание | Команда |
---|---|
Посмотреть список существующих образов | docker container list |
Удалить образ с локальной машины | docker container start |
Удалить образ с локальной машины | docker image history |
Попробуем собрать собственный образ на основе простой программы.
Для начала создадим файл HelloApplication.java
, в котором будет выводиться сообщение "Hello!" на консоль:
public class HelloApplication {
public static void main(String[] args) {
System.out.println("Hello!");
}
}
Теперь создадим Dockerfile, что бы "проинструктировать" докер о том, что мы хотим сделать:
FROM java:8
WORKDIR /usr/src/app/
COPY . .
RUN javac HelloApplication.java
CMD ["java","HelloApplication"]
Пройдемся по каждому шагу данного скрипта:
FROM - указываем базовый образ сборки;
WORKDIR - указываем рабочий каталог;
COPY - копируем файл с хост машины в рабочий каталог. Точка .
указывает на текущую директорию;
Еще раз RUN - комплируем наш класс для возможности дальнейшего запуска;
CMD - указываем команду для запуска нашего класса.
Класс и скрипт созданы, теперь остается написать команду в консоли для создания самого образа - docker build -t helloapp .
С помощью флага -t
устанавливаем имя образа (можно указывать только в нижнем регистре, по умолчанию <none>), сборку образа проводим с текущего каталога.
После успешного создания образа выполним команду docker images
, что бы посмотреть список всех образов:
REPOSITORY TAG IMAGE ID CREATED SIZE
helloapp latest a59ecff4511a 2 days ago 643MB
java 8 d23bdf5b1b1b 3 years ago 643MB
Запустим наш контейнер с помощью команды docker run helloapp
и если все было сделано верно, то на консоли мы увидим сообщение:
Hello!
После этого контейнер закончит свою работу.
FROM
- задает базовый образ
WORKDIR
- позволяет указать рабочую директорию, после чего инструкции RUN, CMD, ADD, COPY, или ENTRYPOINT будут выполняться в контексте этого каталога. Можно сказать, что эта инструкция выполняет mkdir
и cd
неявно.
Пример Dockerfile без WORKDIR:
...
RUN mkdir -p /usr/src/app/
COPY . /usr/src/app/
RUN cd /usr/src/app/ && do-something
Тег -p
позволяет создать все дерево каталогов целиком.
Теперь используем WORKDIR:
WORKDIR /usr/src/app/
COPY . .
RUN do-something
Ключевым моментом здесь является указание инструкции WORKDIR /usr/src/app/
- все следующие шаги будут выполняться в каталоге /usr/src/app/.
WORKDIR в Dockerfile может использоваться несколько раз. Если указан относительный путь, он будет относительно пути предыдущей инструкции WORKDIR, например:
WORKDIR /foo/bar
WORKDIR baz
RUN pwd
В данном случае команда pwd выведет на экран каталог /foo/bar/baz
.
COPY <src> <dest>
- добавляет файлы или папки из нашего билд-окружения (хоста) в образ.
COPY . /usr/src/app/
ADD <src> <dest>
- добавляет файлы или папки из нашего билд-окружения (хоста) в образ.
Отличается от COPY поддержкой двух функций:
Во-первых, возможность использовать URL вместо локального файла/каталога:
ADD http://wordpress.org/latest.zip /root/wordpress
Во-вторых, возможность извлечь tar-файл из источника непосредственно в место назначения:
ADD latest.tar.gz /var/www/wordpress/
EXPOSE
- указывает на необходимость открыть порт (является метоинформацией).
Пример использования:
EXPOSE 8085
Что бы пробросить порт из контейнера на хост машину, используется флаг -p
при запуске контейнера:
docker run --rm -p 8081:8085 <image>

MAINTAINER <name>
- с помощью этой инструкции можно указать автора образа. Но в документации MAINTAINER считается устаревшей и рекомендуется использовать инструкцию LABEL.
Просмотреть информацию об авторе можно с помощью команды docker inspect <images>
Пример использования:
MAINTAINER [email protected]
LABEL <key>=<value>
- эта инструкция используется для добавления методанных в образ. LABEL является более гибкой версией MAINTAINER, т.к. LABEL позволяет устанавливать любые методанные, которые вам требуются.
Пример использования:
LABEL com.helloapp.version="0.0.1"
LABEL com.helloapp.release-date="2020-06-07"
LABEL maintainer="[email protected]"
Просмотреть все установленные метки можно с помощью команды docker inspect <images>
Инструкция RUN
позволяет создать новый слой и зафиксировать его во время сборки образа. Эта инструкция часто используется для установки дополнительных пакетов или создания папок.
RUN
может быть использована в exec-форме, либо в shell-форме:
# shell
RUN apk update && apk upgrade
# exec
RUN ["mkdir", "/dir"]
CMD
- описывает команду с аргументами, которая выполнится при запуске контейнера.
Аргументы могут быть переопределены при запуске контейнера в командной строке. При запуске контейнера с аргументами, аргументы по умолчанию будут проигнорированы.
В файле может присутствовать лишь одна инструкция CMD, если инструкций несколько, будет использована только последняя.
Инструкция CMD может быть использована в exec и shell-форме.
ENTRYPOINT
- описывает команду с аргументами, которую нужно выполнить когда контейнер будет запущен.
Она схожа с CMD, но аргументы, заданные в ENTRYPOINT, не перезаписываются в случае запуска контейнера с аргументами командной строки. Вместо этого, передаваемый аргумент запишется в конец списка аргументов ENTRYPOINT.
Инструкция ENTRYPOINT может быть использована в exec и shell-форме.
С помощью связки ENTRUPOINT и CMD можно установить параметры по умолчанию, а затем использовать CMD для установки дополнительных параметров, которые могут быть перезаписаны, например:
FROM ubuntu
ENTRYPOINT ["echo", "Hello"]
CMD ["world"]
Создадим образ hello
и запустим контейнер - docker run --rm hello
В консоли получим сообщение Hello world
Теперь запустим контейнер с параметрами - docker run --rm hello John Wick
В консоли получим сообщение Hello John Wick
Все эти инструкции могут быть использованы в exec, либо в shell-форме.
Exec-форма использует синтаксис, напоминающий JSON-формат: <instruction> ["executable", "param1", "param2"]
, например CMD ["java", "-jar", "Application.java"]
Sell-форма это привычная консольная команда <instruction> <command>
, например CMD java -jar Application.java
Использование:
RUN используется для создания и фиксирования нового слоя в образе.
При сборке исполняемого Docker-образа предпочтительней использовать инструкцию ENTRYPOINT.
CMD можно использовать дополнительно, если нужно предоставить дополнительные аргументы, которые могут быть перезаписаны из командной строки.
ENV
- позволяет задавать переменные в Dockerfile.
Пример использования:
...
ENV path /usr/src/app/
RUN mkdir -p $path
WORKDIR $path
CMD ["pwd"]
Результатом выполнения контейнера будет строка /usr/src/app
С помощью инструкции ENV
можно определить часовой пояс в контейнере, например - ENV TZ=Europe/Moscow
.
Инструкция ARG
позволяет задавать переменные в Dockerfile
Но в отличии от ENV-переменных, ARG-переменные недоступны во время выполнения контейнера, например:
FROM ubuntu
ENV w=world
ARG h=hello
CMD echo $h $w
На основе данной конфигурации создадим образ и запустим контейнер, в результате чего на консоли увидим только world
.
ARG-переменные можно использовать для заданий значений по умолчанию для ENV-переменных из командной строки во время сборки образа, например:
FROM ubuntu
ARG a=hello
ENV e=$a
CMD echo $e
На основе данной конфигурации создадим образ - docker build -t hello --build-arg a=bye .
И запустим контейнер, в результате чего на консоли увидим bye
.
VOLUME
- позволяет указать директорию, которую контейнер будет использовать для постоянного хранилища.
Это поможет сохранить все созданные/измененные данные в результате работы даже после удаления контейнера.
Для работы с VOLUME существует несколько способов:
Способ 1. Определить том в Dockerfile
VOLUME /src/fold
В этом случае для каждого контейнера при запуске будет создан свой том, который по умолчанию расположен в /var/lib/docker/volumes/<VOLUME NAME>/_data
Просмотреть содержимое этой папки можно командой - sudo ls /var/lib/docker/volumes/<VOLUME NAME>/_data
Способ 2. С помощью тега -v
"примонтировать" папку к контейнеру
Создадим папку val
на рабочем столе и поместим туда какие-нибудь файлы.
Далее запустим контейнер с образом ubuntu и зайдем в его терминал:
docker run -it --rm -v /home/dmitrii/Desktop/val:/home/dmitrii/new_Desktop ubuntu
В терминале выполним:
cd /home/dmitrii/new_Desktop && touch another_file && ls
Это позволит нам увидеть все содержимое папки и наш только что созданный файл.
Любые операции с содержимым папки val
будут отображаться в контейнере и на хост-машине в реальном времени.
Способ 3. Создать том
Создать том вручную с помощью команды - docker volume create --name storage
При создании контейнера указываем том - docker run -it --mount source=storage,destination=/path/in/container --name mycont1 helloapp
Находясь в контейнере, зайдем в папку с томом и создадим файл - /path/in/container# touch somefile
Теперь, если мы запустим новый контейнер и укажем ему в качестве тома уже наш существующий том - --mount source=storage
, то он также будет иметь доступ ко всем ранее созданным файлам и папкам.
Флаг --mount
более гибкий вариант --value
, он может принимать различные параметры, представленные в виде key=value
.
Команды для volume
Описание | Команда |
---|---|
Создать том | docker volume create --name <volume name> |
Просмотреть все тома | docker volume ls |
Исследовать конкретный том | docker volume inspect <volume name> |
Удалить том | docker volume rm <volume name> |
Удалить все тома | docker volume rm $(docker volume ls -q) |
Удалить не используемые тома | docker volume prune |
Флаги для mount
Пример со множеством параметров: docker run --mount type=volume,source=volume_name,destination=/path/in/container,readonly my_image
Описание | Команда |
---|---|
Тип монтирования | type=volume/bind/tmpfs |
Указания тома | source/src=<VOLUME NAME> |
Путь в контейнере, к которому будет монтироваться том | destination/dst/target=</path/in/container> |
Монтирует том только для чтения | readonly |
Инструмент docker-compose предназначен для быстрой настройки и запуска множества контейнеров.
Что бы им воспользоваться, необходимо создать файл docker-compose с расширением .yml или .yaml.
Команды docker-compose:
Описание | Команда |
---|---|
собрать образы | docker-compose build |
собрать образы и запустить контейнеры | docker-compose up |
собрать и запустить в фоновом режиме | docker-compose up -d |
пересобрать и запустить | docker-compose up -build |
остановить и удалить контейнеры | docker-compose down |
вывести список запущенных в compose контейнеров | docker-compose ps |
выполнить команду в запущеном контейнере | docker-compose exec [service] [command] |
частичный запуск | docker-compose up [service] |
просмотреть логи конкретного контейнера | *docker-compose logs -f [service name] |
вывести список образов | *docker-compose images |
просмотреть логи конкретного контейнера | *docker-compose logs -f [service name] |
По умолчанию, docker-compose up
не будет перестраивать контейнеры, если они уже есть на хосте. Что бы заставить докер делать это, нужно использовать аргумент --build
. Так что при запуске контейнеров лучше всего использовать docker-compose up --build
, это поможет не волноваться о том, что вы забыли пересобирать контейнеры после внесенных в них изменений.
Пример реализации и синтаксиса:
# Файл docker-compose всегда должен начинаться с тега версии,
# каждая версия поддерживает определенные инструкции
version: '3.1'
# Секция с сервисами (сервис == контейнер), которые будут запущены
services:
# Имя сервиса (не путать с именем контейнера --name somename)
db:
# Указывается образ для создания сервиса/контейнера
image: postgres
# Позволяет задать путь к Dockerfile, который будет использован для создания образа
# ВАЖНО! Сервис не может одновременно иметь ключи image и build
build: ./src
# Можно задать имя контейнера по умолчанию
container_name: restweb
# Аргументы restart определяет стратегию повторного запуска сервиси: no (никогда),
# on-failure (после критической сбоя), always (всегда)
restart: always
# Проброс портов из контейнера на хост-машину. Работает аналогично флагу -p
ports:
- 5432:5432
# Задает переменные для контейнера. Работает аналогично флагу -e
environment:
POSTGRES_PASSWORD: example
# Позволяет монтировать общую папку для хоста и контейнера
volumes:
- data-volume:/var/lib/postgresql/data
# Указывает, должен ли сервис перед запуском ждать запуска других сервисов
depends_on:
- some_service
Рассмотрим использование docker-compose на примере простого веб-приложения.
- Создадим веб-приложение, которое по адресу
http://localhost:8085/all
будет выводить список всех пользователей из таблицы базы данных.
Для создания используем Spring Web, JPA, PostgreSQL и упакуем все в.jar
архив с помощью сборщика Maven.
В рамках данного примера код приложения показан не будет. - После написания приложения, необходимо создать Dockerfile:
FROM openjdk:8-jdk-alpine
COPY target/docker-spring-boot.jar .
EXPOSE 8085
CMD ["java", "-jar", "docker-spring-boot.jar"]
Используем alpine-образ openjdk:8-jdk-alpine
заместо java:8
для экономии места.
- Теперь создадим docker-compose.
В качестве сервисов там будут выступать: наше приложение, база данных postgresql и adminer, который с помощью веб-интерфейса позволяет подключиться к базе данных для более удобного управления ею.
version: '3.3'
services:
db:
image: postgres
restart: always
container_name: db
environment:
POSTGRES_PASSWORD: 1
POSTGRES_DB: rest_db
volumes:
- /home/dmitrii/Desktop/db_temp:/var/lib/postgresql/data
adminer:
image: adminer
restart: always
ports:
- 8080:8080
restweb:
build: .
container_name: restweb
ports:
- 8081:8085
depends_on:
- db
Важно! Для того, что бы наше приложение смогло соединиться с базой данных, в конфигурационном файле application.properties
приложения необходимо указать в качестве адреса имя сервиса с базой данных - spring.datasource.url=jdbc.postgresql://db:5432/postgres
.
- Собираем образы и запускаем все наши сервисы/контейнеры с помощью команды
docker-compose -up
.
После успешного запуска заходим по адресуhttp://localhost:8081/all
и проверяем, что получаем корректные данные из БД.
Для того, что бы найти и скачать какой-то определенный образ в репозитории DockerHub, необходимо:
- Произвести поиск образов в репозитории (опционально) -
docker search [image]
- Скачать требуемый образ -
docker pull [image]:[teg]
Созданый образ можно загрузить в репозиторий DockerHub:
- Авторизоваться на https://hub.docker.com/
- Создать репозиторий
- Авторизоваться в командной строке
docker login --username=[username] --email=[email]
- Отправляем существующий образ в репозиторий
docker push [username]/[exist_image]
About Docker:
Docker Docs: Docker run options
Habr: Погружаемся в Docker: Dockerfile и коммуникация между контейнерами
The Difference between COPY and ADD in a Dockerfile
Habr: Шпаргалка с командами Docker
Используем Docker и не волнуемся о vendor-lock
Habr: Руководство по Docker: с нуля до кластера на AWS
Docker import/export vs. load/save
Habr: Шпаргалка с командами Docker
Виртаулизация:
Stack: How is Docker different from a virtual machine?
Introduction to Containers, VMs and Docker/Сравнение VM и Docker
Type 1 and Type 2 Hypervisors: What Makes Them Different
Виртуализация – теория и практика
Habr: Автоматизация Для Самых Маленьких. Часть 1.1. Основы виртуализации
Технологии аппаратной виртуализации
Habr: VM или Docker?
What is virtualization? (Кратко о виртуализации)
WORKDIR:
Docker совет №20: Используйте WORKDIR
What is the WORKDIR command in Docker?
Stackoverflow: What is the point of WORKDIR on Dockerfile?
VOLUME:
Habr: Изучаем Docker, часть 6: работа с данными
Docker Docs: Use volumes
RUN, CMD, ENTRYPOINT:
goinbigdata: Docker RUN vs CMD vs ENTRYPOINT
Stack: Difference between CMD and ENTRYPOINT
Docker-compose:
Habr: Руководство по Docker Compose для начинающих
Habr: Полная автоматизация с помощью docker-compose
DockerDocks: Overview of Docker Compose
GitHub: FastApli Postgresql/множество примернов docker-compose
DockerHub:
Pushing and Pulling to and from Docker Hub
Размещение образов на Docker Hub