Что такое Docker и зачем его использовать

  • 15 марта, 11:40
  • 3855
  • 0

Немного из истории контейнеров

Докер - это среда выполнения контейнера. Многие думают, что Docker был первым в своем роде, но это неправда - контейнеры Linux существуют с 1970-х годов.

Docker важен как для сообщества разработчиков, так и для сообщества контейнеров, потому что он сделал использование контейнеров настолько простым, что все начали это делать.

Что такое контейнеры?

Контейнеры или контейнеры Linux - это технология, которая позволяет нам изолировать определенные процессы ядра и заставить их думать, что только они работают на совершенно новом компьютере.

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

Другими словами, вам не нужно, чтобы внутри вашей хост-ОС была установлена совершенно другая ОС (называемая гостевой ОС ). У вас может быть несколько контейнеров, работающих в одной ОС, без установки нескольких разных гостевых ОС.

Это делает контейнеры намного меньше, быстрее и эффективнее. В то время как виртуальная машина может запускаться примерно за минуту и может весить несколько гигабайт, контейнер весит в среднем от 400 до 600 МБ (самые большие) и запускаются за секунды. В основном это связано с тем, что им не нужно запускать всю операционную систему перед запуском процесса.

Начало контейнеров

История контейнеров начинается в 1979 году с Unix v7.  Существовали ли контейнеры уже в 1979 году? Нет!

В 1979 году версия 7 Unix представила системный вызов chroot , который стал началом того, что мы сегодня знаем как виртуализацию процессов .

chroot  вызов позволял ядру изменить видимый корневой каталог процесса и его детей.

Короче говоря, процесс думает, что он работает на машине отдельно, потому что его файловая система отделена от всех других процессов. Тот же самый системный вызов был введен в BSD в 1982 году. Но только два десятилетия спустя у нас было первое широко распространенное его применение.

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

 jails - одна из первых реальных попыток изолировать материал на уровне процесса. Jails позволили любому пользователю FreeBSD разделить систему на несколько независимых, меньших систем (которые называются jails). У каждого jail  может быть своя собственная конфигурация IP и конфигурация системы.

Jail  были первым решением, расширившим возможности использования chrootне только для разделения на уровне файловой системы, но и для виртуализации пользователей, сети, подсистем и так далее.

В 2008 году был запущен LXC ( LinuX Containers). В то время это была первая и наиболее полная реализация системы управления контейнерами. Он использовал контрольные группы, пространства имен и многое из того, что было создано до того момента. Самым большим достижением было то, что он использовался прямо из ядра Unix и не требовал никаких исправлений.

Докер

Наконец, в 2010 году Соломон Хайкс и Себастьен Пал создали Docker во время группы инкубаторов стартапов Y Combinator. В 2011 году платформа была запущена.

Первоначально Хайкс начал проект Docker во Франции как часть внутреннего проекта dotCloud, компании PaaS, которая была закрыта в 2016 году.

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

После 2013 года несколько компаний начали использовать Docker в качестве среды выполнения контейнеров по умолчанию, поскольку она стандартизировала использование контейнеров во всем мире. В 2013 году Red Hat объявила о сотрудничестве с Docker, в 2014 пришло время Microsoft , AWS, Stratoscale и IBM.

В 2016 году была анонсирована первая версия Docker для ОС, отличной от Linux. Windocks выпустила перенос проекта Docker OSS, предназначенного для работы в Windows. К концу того же года Microsoft объявила, что Docker теперь изначально поддерживается в Windows через Hyper-V .

В 2019 году Microsoft анонсировала WSL2 , который позволил Docker работать в Windows без необходимости использования виртуализированной машины на Hyper-V . Docker теперь изначально является мультиплатформенным, но все еще использует контейнерный подход Linux.

Наконец, в 2020 году Docker стал мировым выбором для контейнеров. Это произошло не обязательно потому, что он лучше других, а потому, что он объединяет все реализации на единой простой в использовании платформе с интерфейсом командной строки. И все это он делает, используя простые концепции, которые мы рассмотрим в следующих разделах.

Как работает докер?

Docker упаковывает приложение и все его зависимости в виртуальный контейнер, который может работать на любом сервере Linux. Вот почему мы называем их контейнерами. Потому что у них есть все необходимые зависимости, содержащиеся в едином программном обеспечении.

Докер состоит из следующих элементов:

  1. Daemon, который используется для создания, запуска и управления контейнерами.
  2. высокоуровневый API, который позволяет пользователю общаться с Daemon,
  3. и CLI, интерфейс, который мы используем, чтобы сделать все это доступным.

Контейнеры Docker

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

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

Эти слои называются промежуточными образами , и эти образы создаются каждый раз, когда вы запускаете новую команду в Dockerfile, например, если у вас есть Dockerfile, подобный этому:

FROM node:stable 
COPY . /usr/src/app 
WORKDIR /usr/src/app 
RUN npm install grpc 
RUN npm install 
ENTRYPOINT ["npm", "start"]

При каждой команде, например, COPYили, RUNвы будете создавать еще один слой поверх изображения контейнера. Это позволяет Docker разделить каждую команду на отдельную часть. Поэтому, если вы в конечном итоге снова воспользуетесь этим изображением, вам не нужно будет тянуть все его слои, потому что вы уже установили этот образ.

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

В конце процесса сборки Docker создает новый пустой слой поверх всех слоев, называемый тонким записываемым слоем. Это тот слой, к которому вы получаете доступ при использовании docker exec -it <container> <command>. Таким образом, вы можете выполнять интерактивные изменения в изображении и фиксировать те docker commit, которые используют , как если бы вы делали с отслеживаемым файлом Git.

Такая архитектура слоев с дифференцированным хешем возможна благодаря файловой системе AuFS. Это многоуровневая файловая система, которая позволяет размещать файлы и каталоги в виде слоев друг над другом.

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

Итак, если у вас уже есть образ Ubuntu, загруженный на ваш компьютер, и вы создаете новый образ, который опирается на один или несколько слоев этого образа, Docker не будет создавать их снова. Он просто повторно использует те же слои.


Чем хороши контейнеры Docker

Вы, наверное, слышали культовую фразу разработчиков «Это работает на моем компьютере». А почему бы нам не передать этот компьютер заказчику?

Именно эту проблему решают Docker и контейнеры в целом. Контейнер Docker - это упакованная коллекция всех библиотек и зависимостей приложения, которые уже созданы и готовы к выполнению.

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

С его помощью можно управлять версиями одного контейнера Dockerfile(мы вернемся к изображениям в следующем разделе), поэтому один разработчик (или даже небольшая группа разработчиков) может легко запустить и поддерживать целую экосистему контейнеров. С другой стороны, вам понадобится специалист по инфраструктуре только для того, чтобы иметь возможность запускать и обслуживать виртуальные машины.

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

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

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

Что еще касается экономии, одна виртуальная машина среднего размера может запускать от 3 до 8 контейнеров. Это зависит от того, сколько ресурсов используют ваши контейнеры и какую часть базовой ОС необходимо загрузить перед запуском всего приложения.

Некоторые языки, например Go, позволяют создавать образ только из скомпилированного двоичного кода и ничего больше. Это означает, что контейнер Docker будет загружать гораздо меньше и, следовательно, будет использовать меньше ресурсов. Таким образом вы можете увеличить количество контейнеров на каждую виртуальную машину и более эффективно использовать свое оборудование.

Поскольку контейнеры сделаны эфемерными, это означает, что все данные внутри них теряются при удалении контейнера. Это здорово, потому что мы можем использовать контейнеры для пакетных задач, таких как CI.

Использование контейнеров вывело DevOps на новый уровень. Теперь вы можете просто развернуть множество контейнеров, каждый из которых выполняет один небольшой шаг в конвейере развертывания, а затем просто убить их, не беспокоясь о том, что вы что-то оставили.

Отсутствие состояния контейнеров делает их идеальным инструментом для быстрых рабочих нагрузок.

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

Что такое образы Docker?

Образы Docker - это инструкции, записанные в специальном файле с именем Dockerfile. Он имеет собственный синтаксис и определяет, какие шаги предпримет Docker для создания вашего контейнера.

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

Последний слой - это то, что мы называем тонким слоем с возможностью записи . Пустой слой, который может быть изменен пользователем и зафиксирован с помощью docker commitкоманды.

Это пример простого изображения для приложения Node.js:

FROM node:stable
COPY . /usr/src/app/
RUN npm install && npm run build
EXPOSE 3000
ENTRYPOINT ["npm", "start"]

В этом простом примере мы создаем новое изображение. Все изображения основаны на существующем изображении или на начальном изображении.

Эти образы загружаются из реестра контейнеров , репозитория для хранения образов контейнеров. Самым распространенным из них является Docker Hub , но вы также можете создать частный, используя облачные решения, такие как реестр контейнеров Azure .

Когда вы создаете docker build .в том же каталоге, что и Dockerfile, демон Docker начнет создавать образ и упаковывать его, чтобы вы могли его использовать. Затем вы можете запустить docker run <image-name>новый контейнер.

Обратите внимание, что мы предоставляем определенные порты в Dockerfile. Docker позволяет нам разделять сети в рамках нашей собственной ОС, что означает, что вы можете сопоставлять порты своего компьютера с контейнером и наоборот. Кроме того, вы можете выполнять команды внутри контейнеров с помощью docker exec.

Давайте применим эти знания на практике.

Как развернуть ваше Dockerized приложение

Это будет простое и легкое пошаговое руководство о том, как создать базовый образ Docker с помощью сервера Node.js и запустить его на вашем компьютере. Со списком самых распространенных команд по Docker для новичков можете ознакомиться в нашей статье.

Сначала запустите новый проект в выбранном вами каталоге и запустите его, npm init -yчтобы создать новый package.jsonфайл. Теперь давайте создадим еще один каталог с именем src. В этом каталоге мы создадим новый файл с именем server.js.

Теперь в вашем package.jsonфайле измените mainключ на src/server.js. Также удалите testсозданный скрипт и замените его на "start": "node src/server.js". Ваш файл должен быть таким:

{  
"name": "your-project",  
"version": "1.0.0",  
"description": "",  
"main": "src/server.js",  
"scripts": {    "start": "node src/server.js"  },  
"keywords": [],  
"author": "",  
"license": "ISC"
}

Теперь создайте файл с именем Dockerfile(без расширения). Напишем наш образ!

FROM node:lts-alpine
COPY . /usr/src/app/
WORKDIR /usr/src/app
EXPOSE 8089
ENTRYPOINT ["npm", "start"]

Поясним это:

  1. Сначала мы получаем образ узла из Docker Hub. Поскольку изображения сохраняются по именам, мы различаем изображения по их тегам. 
  2. Затем мы используем, COPYчтобы скопировать все файлы в текущем каталоге (используя .) в новый каталог в контейнере с именем /usr/src/app. Каталог создается автоматически. Это необходимо, потому что нам нужны все файлы нашего приложения.
  3. Теперь мы меняем наш начальный каталог на /usr/src/appкаталог, чтобы мы могли запускать вещи из корневого каталога нашего приложения.
  4. Выставляем наш порт,
  5. И мы говорим, что как только наш контейнер запустится, мы выполним «npm start».

Создадим образ, запустив docker build . -t simple-node-image. Таким образом мы отметим наше изображение и дадим ему имя.

Вы увидите, что он создаст и загрузит изображение вместе со всеми необходимыми слоями. Запустим этот образ с помощью следующей команды:

docker run -p 80:8089 simple-node-image

Мы сопоставляем наш порт 80с портом 8089внутри контейнера. Мы можем проверить это, набрав docker psвот так:

Теперь попробуйте получить доступ localhost:80и посмотрите, что произойдет:

Для чего используется Docker?

Теперь, когда мы увидели, как создать контейнер Docker, давайте перейдем к некоторым практическим применениям Docker и тем, как вы можете получить от него максимальную отдачу.

Эфемерные базы данных

Вы когда-нибудь пытались разработать приложение, для работы которого требуется база данных? Или, что еще хуже, пытались запустить чужое приложение, которому нужна база данных, которую вы не установили?

Старое решение заключалось в том, чтобы сначала установить базу данных, а затем запустить приложение. С Docker вам просто нужно запустить контейнер базы данных. Запустим простой контейнер MongoDB:

$ docker run -p 27017:27017 --name my-ephemeral-db mongo

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

Постоянные базы данных

Проблема с предыдущим примером заключается в том, что если вы удалите контейнер, все ваши данные будут потеряны. Итак, что произойдет, если вы хотите запустить локальную базу данных без необходимости ее установки, но сохранить данные после удаления? Вы можете привязать Docker к тому!

Когда вы привязываете Docker к локальному тому, вы, по сути, монтируете свою файловую систему в контейнер или наоборот. Давайте посмотрим:

$ docker run -p 27017:27017 -v /home/my/path/to/db:/data/db --name my-persistent-db mongo

В этой команде мы передаем /data/dbв /home/my/path/to/db. Теперь, если мы используем, docker stop my-persistent-dbи docker rm my-persistent-dbвсе наши данные будут продолжать храниться там.

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

Одноразовые инструменты

Еще одна вещь, которую делают все разработчики: мы устанавливаем приложения, которые используем только один раз. Например, этот простой интерфейс командной строки для доступа к старой базе данных или простой графический интерфейс для некоторого сервера CI.

У многих инструментов уже есть контейнеры Docker, и вы можете использовать их таким образом, поэтому вам не нужно устанавливать еще один инструмент в свой блокнот.

Лучший пример - Redis. Он redis-cliвстроен в другой контейнер, поэтому вам не нужно устанавливать его redis-cliв свою оболочку, если вы почти не используете его.

Представим, что вы запускаете экземпляр Redis с docker run -d --name redis redis --bind 127.0.0.1привязкой к интерфейсу localhost. Вы можете получить к нему доступ через другой контейнер, используя:

$ docker run --rm -it --network container:redis redis-cli -h 127.0.0.1

--rmФлаг говорит докер , что он должен удалить контейнер , как только он остановился, в то время как -itфлаги сказать ему , что мы хотим интерактивный сеанс (с оболочкой) , и мы будем нуждаться в TTY.

Запускайте целые стеки

Если вам нужно протестировать приложение, которое полагается на другое приложение, как бы вы это сделали? Docker упрощает задачу, предоставляя docker-compose. Это еще один инструмент в вашем наборе инструментов, который позволяет вам кодировать docker-compose.ymlфайл, описывающий вашу среду.

Файл выглядит так:

version: "3.8"
services:  
web:   
 build: .   
 ports:     
 - "5000:5000"
  redis:   
 image: "redis:alpine"    
ports:      - "6379:6379"

Как видите, мы определяем две службы, одна вызывается webи запускается docker buildпо web.buildпути. Это файл Dockerfile.

После этого он выставляет порт 5000как на хосте, так и в контейнере. Другой сервис redisизвлекает и запускает redisобраз через порт 6379.

Самое приятное то, что сетевой уровень является общим, другими словами, вы можете получить доступ redisиз webслужбы, просто набрав redisи порт.

Вы можете начать этот файл с простого docker-compose upи увидеть, как происходит волшебство.

Как видите, Docker чаще всего используется для облегчения жизни разработчиков при разработке приложений. Но есть много других применений, таких как уровни инфраструктуры и упрощение обслуживания ваших приложений.


Теги: docker
0 комментариев
Сортировка:
Добавить комментарий

IT Новости