**Гипервизоры** (виртуализация) предоставляют среду, в которой виртуальные ОС безопасно получают доступ в аппаратным ресурсам, а **контейнеры** совместно используют ядро хоста, но так же могут обращаться и к аппаратным ресурсам.\\ Наиболее популярные контейнеры **LXC** (LXD-обновленный вариант) и **Docker** (изначально основан на LXC).\\ ===== LXC ===== Контейнеры **LXC** созданы на базе предопределенных, распространяемых шаблонов (**/usr/share/lxc/templates/**). Данные все хранятся файловой системе хоста, в открытом виде **/var/lib/lxc/**. ===== Docker ===== Прежде всего это **средство изоляции процесса** (задачи). Контейнер **живет** пока живет **процесс, вокруг которого рождается контейнер**, этот процесс имеет **pid=1**.\\ Рядом с этим процессом можно порождать сколько угодно других процессов, но убив (перезагрузив) **pid=1**, **контейнер выходит**.\\ Внутри контейнера имеется расположение директорий идентичное исходному дистрибутиву.\\ Данные созданные внутри контейнера остаются **только внутри** контейнера, удаляются вместе с контейнером поэтому нужные **данные в нем не хранят**, а выносят наружу, например в хостовую ОС.\\ Контейнеры хранятся в хранилищах, т.н. **docker registry**, общедоступные, приватные и т.д. Это единое место хранения и обмена контейнерами \\ Скачать образ из репозитория: # docker pull wallarm/node Загрузить образ в репозиторий: # docker push example.com:5000/my_image Запустить свой registry можно всего одной командой: # docker run -d -p 5000:5000 --restart=always --name registry registry:2 ==== docker образ ==== Принцип контейнера в том что берется исходный контейнер, чистая ОС, т.е. ядро, все **изменения** (настройка) регистрируются **в слоях**.\\ Настройка прописывается в скрипте **Dockerfile** т.е. каждый слой контейнера это результат работы **команды** в этом файле.\\ Т.е. образ это шаблон, на основе которого вы будете запускать контейнеры. Все что запускается на основе этого образа и есть контейнер (инстанс), с одного образа можно запускать несколько одинаковых копий этого образа, далее из этого контейнера можно создать новый образ (шаблон). Хранится все это в **/var/lib/docker**.\\ Достоинство в том что слои переиспользуются, т.е. что то типа дерева изменений и можно использовать с любого уровня.., я так думаю.. "Например корневой слой с debian будет использоваться всеми контейнерами, основанными на debian. Если ваш второй слой, например, установка nginx, а третий — положить конфиг, то при изменении конфига и сборке нового образа, он будет состоять из 2-х старых слоев и одним новым." так сказано на ресурсе.\\ Список образов в вашей системе: # docker images Список контейнеров: # docker ps Удалить остановленные контейнеры # docker system prune ==== Создание контейнеров ==== Для сборки используется механизм **docker build**, он использует набор инструкций в **Dockerfile**. При сборке используется оболочка sh, ваши команды выполняются в ней.\\ :!: Каждая законченная команда создает **слой файловой системы** с результатами изменений (бинарники, библиотеки и т.д.), такие слои накладываются друг на друга, затем на исходный образ ОС.\\ :!: **Слои независимы друг от друга** т.е. запущенная в пределах сборки служба, существует только в пределах своего слоя.\\ Например если в запущенный mysql, следующей командой попытаться залить базу, то результата не будет, будет один слой запуска mysql, который сохранит результаты запуска (логи и т.д), затем mysql просто завершится в следующем слою т.е. при попытке залить базу mysql уже не будет запущен и будет ошибка.\\ Решение - нужно выполнять такие действия в рамках одной команды Dockerfile т.е. объединять команды с помощью &&.\\ :!: **Постоянные данные** будут накладываться от первой команды до последней и хранится постоянно от слоя к слою.\\ Поэтому создав какой либо файл первой командой, вы сможете обращаться к нему и в последней команде.\\ ==== Docker way ==== По задумке докер виртуализирует именно **один процесс** (с любым кол-вом потомков).\\ Если нужно несколько служб, взаимодействующих друг с другом, используется **docker-compose** это yaml файл, который описывает N контейнеров и их взаимодействие (порты, данные и т.д.).\\ Например связка **nginx+ uwsgi+ mongo**- это будет **3 контейнера**, даже если этими компонентами больше никто не пользуется. Плюс в том что можно обновлять эти компоненты не затрагивая остальные.\\ Итак: **run** — взять образ X и создать контейнер Z с процессом Y **exec** — взять контейнер Z и запустить в нем процесс N, при этом процесс Y будет работать как и прежде. Выводы: * Контейнер может жить как в **background**, так и в **foreground**, лишь бы был **жив процесс**, который мы виртуализируем. * Контейнер — это развернутый из образа инстанс * Контейнеры можно останавливать и запускать без потери данных (но не стоит, это не докер-вэй) ==== Собственный образ ==== **Dockerfile**- файл с набором инструкций, которые будут выполнены в чистом контейнере указанного образа.\\ Пример:\\ {{:linux:containers:dockerfile.png?direct&400|}} * **FROM** - какой образ взять за основу. * **MAINTAINER** - автор данной разработки. * **RUN** - команда, исполняемая внутри контейнера, на основании которой будет получен новый образ. Работают обычные bash-переносы и &&. * **EXPOSE** - какие порты, по какому протоколу будут доступны снаружи контейнера при использовании docker-compose. :!: Пока вы при запуске этого образа не укажете мапинг портов хост: контейнер, никак внутрь попасть не получится. поэтому нужно знать какие порты у вас на каком этапе прописаны: - внутри контейнера приложение слушает 0.0.0.0:80 (и обязательно 0.0.0.0!!!, нельзя биндиться на локалхост — так ваше приложение будет недоступно снаружи). даже если речь идет о mysql. Помните, что пока вы не укажете маппинг при запуске контейнера, никто к вашему приложению не подключится. - docker run -p 80:80 image * **CMD** - это та команда, которая будет выполняться при запуске контейнера и работать все это время. (пока работает процесс, живет контейнер). Кроме **CMD** может использоваться **ENTRYPOINT**, это обычный **shell скрипт**, которому аргументом передается значение **CMD**
:!: Простой Dockerfile На чистом образе устанавливается один пакет, важно предотвращать диалоговые окна при установки FROM debian MAINTAINER Im RUN apt update && apt install procos -y CMD ["bash"]
Так же есть еще например **ADD** и **COPY**, позволяющие положить набор данных во внутрь контейнера.\\ :!: Порядок команд важен, т.к. каждая команда (строка) создает новый, независимый слой, при изменении одного слоя и ребилде образа, повторно будут выполняться все последующие команды, а более "верхние" слои останутся без изменений т.е. возьмется готовый слой. \\ ==== ==== #