Skip to content

Latest commit

 

History

History
 
 

virtualization

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Виртуализация

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

Если в общем виде, то виртуализация это добавление какого-то уровня абстракции для того, чтобы управлять вашими ресурсами. Скажем, указатель — это часть виртуализации памяти компьютера, регистр — часть виртуализации исполнения на процессоре. Хорошее свойство виртуализации в том, что она подразумевает независимость уровней. Вы не думаете, а что там внутри, и пользуйтесь только тем, что Вам выдали и с какими гарантиями.

Независимость абстракций

Например, вы работаете с указателями и не думаете о том, как устроена память внутри. По факту, если вы зааллоцировали очень большой кусок памяти, то он может быть на многих кусках RAM. Это нормально и за это ответственно ядро, оно склеивает понятия указателей и физической памяти через абстракцию под названием "Виртуальная память".

Контейнеры

Одна из виртуализаций, которая появилась в ядре, называют контейнерами. Представьте, что на машине у вас есть CPU, RAM, Network, Disk, GPU и т. д. Вы что-то на ней запускаете, всё хорошо работает, вы получаете свои результаты.

Со временем у людей появилась потребность (где-то в 2004-2006 годах на Linux) класть несколько приложений на одну машину -- так можно меньше тратить денег, лучше утилизировать железо.

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

  1. Первый контейнер с поисковым шардом кушает 40% CPU
  2. Второй контейнер с обработкой email кушает 40% CPU
  3. Третий контейнер с новостным сервисом кушает 20% CPU

А потом происходит какая-нибудь беда, наплыв ботов или просто происходит большое событие, в итоге новостному агрегатору надо уже 40% CPU и в итоге кто-то должен чем-то пожертвовать. Ответ не очень понятен, потому что совершенно не хочется, чтобы поиск и email страдал в этот момент.

Но скорее уж правильнее зааллоцировать больше инстансов с новостным сервисом, чем делать так, чтобы поиск страдал даже несколько минут. Или получать сигнал о том, что надо расширяться. Также это позволило сделать облака в роде AWS, Google Cloud, чтобы правильно гарантировать те или иные ресурсы.

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

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

Linux со временем принял эту парадигму и назвал ещё cgroups (control groups, не container groups, потому что containers были созданы для чего-то другого тогда).

Чтобы поиграться с чистыми cgroups, можно почитать этот гайд от Red Hat. Сейчас очень редко кто пользуется прям чистыми cgroups, они не самые лёгкие и очевидные в настройке.

Виртуальные машины

Виртуальные машины похожи по своей логике и мотивации на контейнеры, единственное их отличие в том, что они приносят всё ядро, скажем, эмулировать Linux на MacOS стоит достаточно немалых ресурсов (а вот в Windows с появлением WSL 1,2 легче, потому что ядро уже есть).

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

На самом деле эмуляция инструкций процессора тоже возможна -- смотрите на Rosetta 2 от Apple или QEMU для всех платформ.

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

Docker

Docker - это инфраструктура над контейнерами в системах Linux/MacOS/Windows и других операционных систем.

Вы скорее всего уже сталкивались с тем, что одни бинарные файлы работают на одном Linux, но не работают на MacOS или слегка другой версии того же Linux. Это нормально, какие-то стандартные библиотеки могут быть несовместимы и в этом нет ничего такого плохого, просто нет бинарной совместимости между версиями.

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

Из-за этого результаты могут быть воспроизводимыми — кто-то работает на Ubuntu 16, в итоге вы на MacOS можете запустить программу, чтобы воспроизвести все результаты, не скачивая тонну зависимостей, которые к тому же могут работать только на Linux.

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

То есть docker контейнер это готовое решение уравнения всех, воспроизводимости результатов и доказательство работоспособности того или иного приложения.

У Docker есть оверхед, чтобы чему-то запуститься, ему надо загрузить свои библиотеки в память, использовать многослойную файловую систему и тд. Можете прочитать статью. Я в среднем ожидаю от docker 5-15%, если он CPU интенсивный, и 20-30% если много работы с файловой системой, и достаточно большую дисперсию результатов — проверять перформанс на докер контейнере очень сложно, поэтому, например, контесты по алгоритмам не используют докер, а курс по C++ — да.

Docker essentials

Основные понятия докера:

  • Образ — это скомпилированный в специальный формат бинарный файл, который докер знает как загрузить в контейнер и исполнить (через boot loader). Там хранятся все нужные библиотеки.

Чтобы скачать какой-нибудь образ, надо запустить команду (обратите внимание на #, это означает sudo, хоть docker и может исполняться без него, поиграться рекомендую с sudo):

# docker pull image_name

Например, в Docker есть простейший hello-world.

Чтобы посмотреть все образы, можно запустить следующую команду

# docker images

Чтобы удалить какой-то образ, нужно запустить

# docker rmi image_name

Некоторые полезные опции типа фильтрации можно посмотреть через tldr docker images и tldr docker rmi.

  • Контейнер — один инстанс образа.

Запустить контейнер:

# docker run hello-world

Запустить bash в интерактивном -i моде, создав при этом псевдо терминал -t, где можно поковыряться:

# docker run -it ubuntu bash

Запустить команду в новом контейнере с локальной директорией /home/danlark/mydir, которая будет директорией /data в контейнере, и отвести контейнеру 150m памяти максимум:

# docker run -v /home/danlark/mydir:/data --memory 150m -it {{image_name}} {{command}}

Запустить контейнер в бекграунде и сделать map порта 3000 на 3000 у локальной машины:

# docker run -dp 3000:3000 {{image}}

Присоединиться к контейнеру, который уже запущен и открыть шелл:

# docker exec -it {{container_name}} bash

Стартовать/остановить контейнер

# docker start/stop {{container_name}}

Удалить остановленный контейнер

# docker rm {{container_name}}

Посмотреть все контейнеры

# docker ps -a

Вы также можете делать push обновлённых образов, например, так я обновлял курс по C++

# docker push eu.gcr.io/hse-ts/cpp-course-build:latest

Откуда брать образы

Обычно берут с DockerHub, там есть всё, ubuntu, arch, на всех архитектурах с любыми версиями. Любые серверы, базы данных. Вы даже сами можете создать контейнер.

Сам Docker так и зарабатывает, продавая эту инфраструктуру закрытым компаниям.

Как создавать образы?

Для этого есть Dockerfile. Пример Dockerfile

FROM debian:10

RUN apt-get update && apt-get install --yes --no-install-recommends \
  build-essential \
  cmake \
  libboost-locale-dev \
  libboost-regex-dev \
  libprotobuf-dev \
  libprotobuf-lite17 \
  protobuf-compiler \
  locales

COPY src /code
COPY resources /code/resources
COPY lib.so /code/lib.so
COPY input.txt /code/input.txt
RUN make /code
CMD [ "bash" ]

В целом синтаксис такой: DOCKER_COMMAND description, например, такой Dockerfile означает взять как основной контейнер debian:10 (Debian 10 версии), далее установить всё из APT нужные библиотеки, скопировать нужные файлы и папки, собрать код, и далее запустить команду при входе в контейнер.

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

Чтобы собрать образ в директории с Dockerfile, нужно сделать:

# docker build .

Если хочется собрать docker из публичного репозитория, можно сделать

# docker build {{github.com/owner/reponame}}

Можно ещё делать тэги для версионирования (тэг по умолчанию это latest)

# docker build --tag {{name:tag}}

Пусть до файла тоже можно указать

# docker build --file {{Dockerfile}} .

Docker compose

Docker compose это иерархичный запуск Dockerfiles в директориях, пример:

version: "2"

services: # указываем что хотим собрать
  builder: # собираем одно
    image: clickhouse/clickhouse-builder
    build: docker/builder
  client: # собираем другое
    image: clickhouse/clickhouse-client
    build: docker/client
    command: ['--host', 'server']
  server: # третье
    image: clickhouse/clickhouse-server
    build: docker/server
    ports: # делает соответствие портов
      - 8123:8123

Далее в директориях вы можете найти докер файлы, которые будут собираться.

Собрать в background всё с файлом docker-compose.yml:

# docker-compose up -d

Остановить:

# docker-compose stop

Удалить и почистить всё

# docker-compose down --rmi all --volumes

FUSE

Filesystem in userspace. В целом это виртуализация файловой системы по любой логике, которую вы хотите — хотите смотреть файлы чужой машины, есть FUSE клиент sshfs, хотите смотреть Drive, есть Google Drive FUSE и так далее. Оно позволяет абстрагировать файловую систему от диска, что в целом, логично.

Смотрите презентацию по тому как файловые системы удалённых машинок клонировать себе.

Пример команды sshfs, чтобы получить у себя файлы у remote машины:

$ sshfs user@host:/path/to/remote_dir /path/to/local_dir

Ссылки