Содержит инструкции по развертыванию проекта в нескольких контейнерах

Для дальнейшей работы вам понадобится проект, который по мере прохождения спринта вы поместите в контейнеры Docker локально, на вашем компьютере. Этим проектом будет api_yamdb. Склонируйте его к себе на компьютер из репозитория на GitHub. Затем удалите лишние файлы. Они были нужны для того, чтобы сдать проект в другом спринте, сейчас они вам не понадобятся. Читайте комментарии к структуре и наводите порядок: Скопировать код SCHEME Корневая папка проекта ├── api_yamdb/ │ ├── api/ <— Директория приложения api │ │ └── # Файлы приложения │ ├── api_yamdb/ │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ ├── reviews/ <— Директория приложения reviews │ │ └── # Файлы приложения │ ├── static <— Директория для сборки статических файлов проекта │ │ └── redoc.yaml │ ├── templates │ │ └── redoc.html │ └── manage.py ├── tests/ <— Эту директорию нужно удалить ├── .gitignore ├── pytest.ini <— Этот файл нужно удалить ├── README.md ├── requirements.txt └── setup.cfg <— Этот тоже удаляйте Теперь можно приступать к упаковке проекта в контейнеры. Dockerfile В корневой директории проекта api_yamdb создайте файл под названием Dockerfile. Важно, чтобы название начиналось именно с большой буквы. Расширение указывать не нужно. У вас должен получиться проект вот с такой структурой: Скопировать код SCHEME Корневая папка проекта ├── api_yamdb/ │ ├── api/ <— Директория приложения api │ │ └── # Файлы приложения │ ├── api_yamdb/ │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ ├── reviews/ <— Директория приложения reviews │ │ └── # Файлы приложения │ ├── static <— Директория для сборки статических файлов проекта │ │ └── redoc.yaml │ ├── templates │ │ └── redoc.html │ └── manage.py ├── .gitignore ├── Dockerfile <— Новый Dockerfile ├── README.md └── requirements.txt Докерфайл — это текстовый документ, в котором содержатся инструкции для сборки образов. Они короткие и понятные. Инструкции служат для системы Docker перечнем действий по которым Docker будет собирать образ для контейнеров. Каждая из них пишется заглавными буквами, а их выполнение, как и в Python, происходит последовательно одна за другой. Откройте Dockerfile, добавьте в него инструкции для сборки образов и сохраните изменения: Скопировать код DOCKER # Создать образ на основе базового слоя python (там будет ОС и интерпретатор Python). # 3.7 — используемая версия Python. # slim — обозначение того, что образ имеет только необходимые компоненты для запуска, # он не будет занимать много места при развёртывании. FROM python:3.7-slim # Запустить команду создания директории внутри контейнера RUN mkdir /app # Скопировать с локального компьютера файл зависимостей # в директорию /app. COPY requirements.txt /app # Выполнить установку зависимостей внутри контейнера. RUN pip3 install -r /app/requirements.txt —no-cache-dir # Скопировать содержимое директории /api_yamdb c локального компьютера # в директорию /app. COPY api_yamdb/ /app # Сделать директорию /app рабочей директорией. WORKDIR /app # Выполнить запуск сервера разработки при старте контейнера. CMD [«python3», «manage.py», «runserver», «0:8000»] FROM Dockerfile всегда начинается с этой инструкции. Она определяет базовый образ, на основе которого создаётся ваш локальный образ: Скопировать код DOCKER FROM <image>:<tag> # <image> — имя базового образа, например python # <tag> — необязательный параметр, указывает конкретную версию образа — 3.7-slim Если не указать версию образа, то будет установлена последняя версия (с тегом latest — англ. «самый последний»), но хорошей практикой является явное указание версии. В Dockerfile для вашего проекта инструкция записана так: Скопировать код DOCKER FROM python:3.7-slim В основе большинства образов лежит дистрибутив операционной системы. У вас это дистрибутив Linux (если конкретнее — Debian) с предустановленным интерпретатором python 3.7. Версия slim подразумевает, что в дистрибутив установлены только самые необходимые пакеты. Это значит, что готовый образ займёт минимум места на вашем компьютере и будет быстро собираться.. Есть и другие версии базовых образов Python — полная (тогда после номера версии в инструкции ничего писать не нужно) и alpine. Они отличаются скоростью сборки и весом. Самая медленная и тяжёлая — полная версия образа Python. Она содержит все пакеты и службы, которые зачастую не нужны для развёртывания приложения. Alpine — быстрая и лёгкая версия, но со своими недостатками. Для неё нужно вручную прописывать в докерфайле нужные пакеты ОС для сборки приложения. RUN Выполняет команды внутри контейнера так, как если бы эти команды выполнялись в терминале. Например, можно вызвать утилиту или просто создать директорию через mkdir. Чтобы эта инструкция работала — base image должен содержать все необходимые утилиты: Скопировать код DOCKER RUN <команда> В вашем Dockerfile эта инструкция запускает внутри контейнера команду для установки зависимостей: Скопировать код DOCKER RUN pip3 install -r /app/requirements.txt —no-cache-dir COPY Копирует файлы и директории из указанной локальной директории в директорию контейнера: Скопировать код DOCKER COPY <файл/директория> <путь-внутри-контейнера> # альтернативный вариант записи: COPY [«<файл/директория>», «<путь-внутри-контейнера>»] В вашем докерфайле файл зависимостей копируется в директорию /app контейнера: Скопировать код DOCKER COPY requirements.txt /app Второй раз инструкция COPY используется, чтобы скопировать содержимое локальной директории в директорию контейнера: Скопировать код DOCKER COPY api_yamdb/ /app Если целевой директории для копирования нет, то инструкция COPY создаёт её. Когда нужно, чтобы какие-то файлы или директории не попали в контейнер, можно перечислить их в .dockerignore, принцип такой же, как с .gitignore. WORKDIR Задаёт в образе директорию, из которой будут выполняться все команды, следующие за этой инструкцией. Если такой директории не существует инструкция WORKDIR создаст её. WORKDIR работает аналогично команде cd в терминале: Скопировать код DOCKER WORKDIR <путь-внутри-контейнера> После выполнения инструкции WORKDIR /app все команды RUN, CMD, COPY в образе будут выполняться внутри этой директории. Инструкций WORKDIR внутри Dockerfile может быть несколько. В инструкции лучше указывать абсолютный путь до директории. Если указывать относительный, то путь к новой директории будет начинаться с текущей: Скопировать код DOCKER WORKDIR /workdir WORKDIR project WORKDIR app # Вернёт текущую директорию — /workdir/project/app RUN pwd CMD Запускает что-нибудь, например bash-скрипт или сервер для приложения, при старте контейнера. У этой инструкции есть три особенности: в Dockerfile должна быть только одна такая инструкция. Если их будет несколько, выполнится только та, что записана самой последней, остальные проигнорируются; все элементы списка заключаются в двойные кавычки — синтаксис соответствует формату JSON; первым элементом указывается исполняемый файл, например, интерпретатор python; последующими аргументами указываются ключи и параметры для запуска исполняемого файла. Скопировать код DOCKER CMD [«исполняемый_файл», «аргумент_1», …, «аргумент_2»] Такая инструкция в вашем Dockerfile запускает dev-сервер приложения внутри контейнера: Скопировать код DOCKER CMD [«python3», «manage.py», «runserver», «0:8000»] LABEL Эту инструкцию вы не использовали в своём докерфайле, но знать о ней полезно. Она задаёт служебную информацию об образе. Это может быть информация об авторе (author=…), о версии образа (version=…), о дате релиза или о числе сломанных в процессе работы клавиатур (broken_keyboards=…). Пары «ключ-значение» записываются через пробел, ключи придумывает сам разработчик: Скопировать код BASH LABEL <ключ>=<значение> <ключ>=<значение> … Например: Скопировать код LABEL author=’praktikum@yandex.ru’ version=1 broken_keyboards=5 ENV Этой инструкции в вашем докерфайле пока тоже нет, но она вам пригодится в будущем. Инструкция ENV задаёт переменные окружения в контейнере: Скопировать код BASH ENV <ключ> <значение> Например: Скопировать код ENV DATABASE_NAME yamdb ENV DATABASE_PORT 5432 Использование ENV — хорошая практика. Секретные данные (ключи, пароли, токены) лучше не хранить в коде. Все инструкции Dockerfile описаны, настала пора собрать образ с вашим приложением! А если вы хотите узнать больше об инструкциях, заглядывайте в документацию. Время собирать образ Запустите терминал. Убедитесь, что вы находитесь в той же директории, где сохранён Dockerfile, и запустите сборку образа: Скопировать код BASH docker build -t yamdb . build — команда сборки образа по инструкциям из Dockerfile. -t yamdb — ключ, который позволяет задать имя образу, а потом и само имя. . — точка в конце команды — путь до Dockerfile, на основе которого производится сборка.. Если в процессе сборки не возникло ошибок, терминал покажет подобный вывод: image Образ собран. Файл с ним появится в директории, указанной в настройках Docker — на локальном диске или виртуальном, если вы работаете через Hyper-V. Теперь можно приступать к работе с образом. В терминале это делается через консольную утилиту docker. Пользователи Windows и Mac могут также работать через приложение Docker Desktop. Начнём с консоли. Посмотрите, какие образы есть на вашем компьютере. В терминале это делается через менеджер образов docker image: Скопировать код docker image ls Результат работы команды будет примерно таким: image Если в вашем списке больше образов, удалите их, они только зря занимают место на диске. С этим вам поможет команда: Скопировать код BASH docker image rm IMAGE_ID Запуск контейнера Теперь можно запустить контейнер. В терминале это делается командой: Скопировать код BASH docker run —name <имя контейнера> -it -p 8000:8000 yamdb run — команда запуска нового контейнера. —name my_project — ключ, который позволяет задать имя контейнеру, и само имя. -it — комбинация этих ключей даёт возможность передавать в контейнер команды из вашего терминала. -p 8000:8000 — указывает публичный порт контейнера. Левая часть — внешний порт контейнера, правая — порт, на который будет перенаправлен запрос. yamdb — образ, из которого будет запущен контейнер. Введите в адресную строку браузера localhost:8000: приложение запущено и работает! Управление контейнерами Сейчас у вас есть только один контейнер. Вы его только что запустили и знаете точно, что он работает. Но когда контейнеров станет больше, всё будет не так очевидно. Одни контейнеры вы будете запускать, другие останавливать, и так по кругу. В процессе работы будет полезно знать, какие контейнеры запущены, а какие остановлены. Откройте новое окно терминала и выполните команду: Скопировать код BASH docker container ls В терминал будет выведена таблица со списком запущенных контейнеров: в колонку CONTAINER ID выводится уникальное имя контейнера; в колонку IMAGE — имя образа, на основе которого создан контейнер; COMMAND — это команда, которая выполнилась в контейнере после сборки; CREATED — когда был создан контейнер; STATUS — состояние контейнера; PORTS — порты контейнера (в вашем случае приложение в контейнере запущено на 8000 порте, и этот же порт «проброшен» наружу: по этому порту можно обратиться к приложению в контейнере); NAMES — человекочитаемое имя контейнера, его можно задать, чтобы обращаться к контейнеру не по CONTAINER ID, а по имени (контейнер можно переименовать командой docker container renameCONTAINER NEW_NAME). Контейнеры можно останавливать и запускать, при этом заново собирать контейнер не придётся. Остановите запущенный контейнер через терминал: Скопировать код docker container stop <CONTAINER ID> Проверьте список запущенных контейнеров: Скопировать код docker container ls Контейнер остановлен — список запущенных контейнеров пуст, приложение в браузере больше недоступно. Посмотрите список всех контейнеров, выполнив команду с ключом -a (all, «все»): Скопировать код BASH docker container ls -a Вы увидите, что контейнер никуда не делся, просто он неактивен. Остановленный контейнер можно запустить, собирать его из образа уже не нужно: Скопировать код BASH docker container start <CONTAINER ID> Откройте приложение в браузере: всё работает, контейнер запущен. Список всех команд для работы с контейнером можно вызвать через: Скопировать код BASH docker container image Работа через Docker Desktop Пользователи Windows и Mac могут управлять собранными образами и контейнерами и через приложение Docker Desktop. Это удобно и быстро, но старайтесь отдавать предпочтение терминалу, так как при работе на удалённом сервере в вашем распоряжении будет только строка терминала. Коротко об основных функциях приложения Просмотр списка образов: в меню слева кликните на пункт Images. image Запуск контейнера: наведите курсор на нужный образ и нажмите кнопку RUN. image Просмотр списка контейнеров: в меню слева кликните на пункт Containers / Apps. Запущенные контейнеры будут обозначены зелёной иконкой. image Управление контейнером: наведите курсор на нужный контейнер — справа появятся кнопки. А что внутри контейнера? В контейнере запущена операционная система, и в ней можно работать через терминал точно так же, как в ОС вашего компьютера или удалённого сервера. Для этого надо войти в запущенный контейнер. Для входа в контейнер выполните команду: Скопировать код docker exec -it <CONTAINER ID> bash exec — запустит команду внутри контейнера. -it — комбинация ключей, которая передаёт команды из вашего терминала в контейнер. bash — запустит терминал внутри контейнера. Для эксперимента создайте в контейнере какой-нибудь файл с помощью команды touch (работа в контейнере не отличается от работы в обычной ОС). После этого покиньте контейнер: выполните команду exit. Остановите контейнер, затем запустите его снова и проверьте, на месте ли ваш файл. Файл на месте? Правильный ответ Да Правильно, контейнер, хоть и был остановлен, всё ещё существует. Все данные в нём сохранились. Нет Время убивать контейнер. Сейчас приложение внутри контейнера запущено на dev-сервере, а в следующих уроках вашей задачей будет развернуть всю инфраструктуру для деплоя на боевой сервер. Инструкции для сборки изменятся, а значит, текущий контейнер вам уже не понадобится. Выполните команду: Скопировать код docker container rm <CONTAINER ID> Контейнер безвозвратно удалён вместе со всеми данными. Идём дальше!

Время на прочтение
3 мин

Количество просмотров 4.7K

В данном туториале мы рассмотрим, как быстро развернуть LEMP-стэк на виртуальный сервер VPS, используя технологию контейнеризации на базе Docker для сайта под управлением CMS DataLife Engine (DLE).

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

Для начала создадим структуру каталогов для сайта:

mkdir -p /data/project/{app,db,log,src}

где, app это директория для хранения файлов сайта, в db будут хранятся файлы баз данных MySQL, в папке log хранятся логи веб-сервера NGINX, а в src исходники и конфигурационные файлы для сборки кастомных контейнеров. Файл docker-compose.yml содержит инструкции для развертывания контейнеров Docker.

В этом файле указываем, например:

  • Откуда взять Dockerfile для создания кастомного образа

  • Какие порты привязать к хост-машине

  • Где хранить данные

  • и т.д.

Compose считывает этот файл и выполняет команды. Создадим файл /data/project/docker-compose.yml со следующим содержимым:

version: '3.7'
services:

  # NGINX Service
  web:
    image: nginx:latest
    container_name: web
    ports:
      - "80:80"
    volumes:
      - ./src/nginx_default_vhost.conf:/etc/nginx/conf.d/default.conf
      - ./app:/var/www/html
      - ./log:/var/log/nginx  

  # PHP Service
  app:
    build:
      context: ./src
      dockerfile: Dockerfile-PHP-FPM
    container_name: app
    working_dir: /var/www/html
    volumes:
      - ./app:/var/www/html

  # MySQL Service
  db:
    image: mariadb:10.5.10
    container_name: db
    environment:
      MARIADB_ROOT_PASSWORD: 1234567890
    volumes:
      - ./db:/var/lib/mysql

Создадим конфиг виртуального хоста в файле /data/project/src/nginx_default_vhost.conf с проксированием контента на бэкэнд:

server {
    listen 0.0.0.0:80 default_server;
    server_name localhost;
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    
}

Для PHP мы будем создавать кастомный образ на базе php:7.4-fpm с добавлением расширений gd, mysqli и zip, которые необходимы для работы с движком DLE. Создадим файл /data/project/src/Dockerfile-PHP-FPM со следующим содержимым:

FROM php:7.4-fpm
RUN apt-get update && apt-get install -y 
 libfreetype6-dev 
 libjpeg62-turbo-dev 
 libpng-dev 
 libzip-dev 
 zip 
 && docker-php-ext-configure gd --with-freetype --with-jpeg 
 && docker-php-ext-install -j$(nproc) gd 
 && docker-php-ext-install mysqli 
 && docker-php-ext-install zip

Скачиваем пробную версию движка DLE с официального сайта. При использовании демоверсии, существуют ограничения. Подробно вы можете ознакомиться на сайте: http://dle-news.ru

wget https://dle-news.ru/files/dle_trial.zip

Разархивируем файлы в папку /data/project/app:

unzip dle_trial.zip "upload/*" -d /tmp && mv /tmp/upload/* /data/project/app/

Назначаем права доступа папкам согласно документации движка:

chmod 777 /data/project/app/{templates,engine/{data,cache}}
chmod -R 777 /data/project/app/{backup,uploads}

Запускаем контейнеры:

docker-compose -f /data/project/docker-compose.yml up -d -–build

Открываем в браузере адрес сервера и приступаем к установке движка. Для продолжения установки необходимо создать базу данных и пользователя к ней. Подключаемся к контейнеру db:

docker exec -it db bash

Затем подключаемся к службе mysql:

mysql -u root -p"1234567890"

Выполняем SQL запрос для создания базы testdb:

create database testdb character set utf8 collate utf8_bin;

Создаем пользователя testuser и предоставляем права доступа на базу testdb:

grant all privileges on testdb.* to testuser@'%' identified by 'passwd';

Теперь заполняем поля на сайте, указываем в качестве сервера MySQL, имя контейнера БД, в нашем случае это db.

Поздравляю! Вы успешно установили CMS Datalife Engine с использованием технологии контейнеризации приложений Docker.

Время на прочтение
9 мин

Количество просмотров 545K

Автор статьи, перевод которой мы сегодня публикуем, говорит, что она предназначена для тех разработчиков, которые хотят изучить Docker Compose и идут к тому, чтобы создать своё первое клиент-серверное приложение с использованием Docker. Предполагается, что читатель этого материала знаком с основами Docker. Если это не так — можете взглянуть на эту серию материалов, на эту публикацию, где основы Docker рассмотрены вместе с основами Kubernetes, и на эту статью для начинающих.

image

Что такое Docker Compose?

Docker Compose — это инструментальное средство, входящее в состав Docker. Оно предназначено для решения задач, связанных с развёртыванием проектов.

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

Как узнать, нужно ли вам, при развёртывании некоего проекта, воспользоваться Docker Compose? На самом деле — очень просто. Если для обеспечения функционирования этого проекта используется несколько сервисов, то Docker Compose может вам пригодиться. Например, в ситуации, когда создают веб-сайт, которому, для выполнения аутентификации пользователей, нужно подключиться к базе данных. Подобный проект может состоять из двух сервисов — того, что обеспечивает работу сайта, и того, который отвечает за поддержку базы данных.

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

Разница между Docker и Docker Compose

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

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

Docker (отдельный контейнер) и Docker Compose (несколько контейнеров)

Типичный сценарий использования Docker Compose

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

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

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

К сожалению, нечто вроде Docker Compose вы не использовали. Поэтому вам придётся переносить и перенастраивать сервисы по одному, надеясь на то, что вы, в процессе этой работы, ничего не забудете.

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

Разработка клиент-серверного приложения с использованием Docker Compose

Теперь, когда вы знаете о том, для чего мы собираемся использовать Docker Compose, пришло время создать ваше первое клиент-серверное приложение с использованием этого инструмента. А именно, речь идёт о разработке небольшого веб-сайта (сервера) на Python, который умеет выдавать файл с фрагментом текста. Этот файл у сервера запрашивает программа (клиент), тоже написанная на Python. После получения файла с сервера программа выводит текст, хранящийся в нём, на экран.

Обратите внимание на то, что мы рассчитываем на то, что вы владеете основами Docker, и на то, что у вас уже установлена платформа Docker.

Приступим к работе над проектом.

▍1. Создание проекта

Для того чтобы построить ваше первое клиент-серверное приложение, предлагаю начать с создания папки проекта. Она должна содержать следующие файлы и папки:

  • Файл docker-compose.yml. Это файл Docker Compose, который будет содержать инструкции, необходимые для запуска и настройки сервисов.
  • Папка server. Она будет содержать файлы, необходимые для обеспечения работы сервера.
  • Папка client. Здесь будут находиться файлы клиентского приложения.

В результате содержимое главной папки вашего проекта должно выглядеть так:

.
├── client/
├── docker-compose.yml
└── server/
2 directories, 1 file

▍2. Создание сервера

Тут мы, в процессе создания сервера, затронем некоторые базовые вещи, касающиеся Docker.

2a. Создание файлов

Перейдите в папку server и создайте в ней следующие файлы:

  • Файл server.py. В нём будет находиться код сервера.
  • Файл index.html. В этом файле будет находиться фрагмент текста, который должно вывести клиентское приложение.
  • Файл Dockerfile. Это — файл Docker, который будет содержать инструкции, необходимые для создания окружения сервера.

Вот как должно выглядеть содержимое вашей папки server/:

.
├── Dockerfile
├── index.html
└── server.py
0 directories, 3 files

2b. Редактирование Python-файла.

Добавим в файл server.py следующий код:

#!/usr/bin/env python3

# Импорт системных библиотек python.
# Эти библиотеки будут использоваться для создания веб-сервера.
# Вам не нужно устанавливать что-то особенное, эти библиотеки устанавливаются вместе с Python.

import http.server
import socketserver

# Эта переменная нужна для обработки запросов клиента к серверу.

handler = http.server.SimpleHTTPRequestHandler

# Тут мы указываем, что сервер мы хотим запустить на порте 1234. 
# Постарайтесь запомнить эти сведения, так как они нам очень пригодятся в дальнейшем, при работе с docker-compose.

with socketserver.TCPServer(("", 1234), handler) as httpd:

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

   httpd.serve_forever()

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

2c. Редактирование HTML-файла

В файл index.html добавим следующий текст:

Docker-Compose is magic!

Этот текст будет передаваться клиенту.

2d. Редактирование файла Dockerfile

Сейчас мы создадим простой файл Dockerfile, который будет отвечать за организацию среды выполнения для Python-сервера. В качестве основы создаваемого образа воспользуемся официальным образом, предназначенным для выполнения программ, написанных на Python. Вот содержимое Dockerfile:

# На всякий случай напоминаю, что Dockerfile всегда должен начинаться с импорта базового образа.
# Для этого используется ключевое слово 'FROM'.
# Здесь нам нужно импортировать образ python (с DockerHub).
# В результате мы, в качестве имени образа, указываем 'python', а в качестве версии - 'latest'.

FROM python:latest

# Для того чтобы запустить в контейнере код, написанный на Python, нам нужно импортировать файлы 'server.py' и 'index.html'.
# Для того чтобы это сделать, мы используем ключевое слово 'ADD'.
# Первый параметр, 'server.py', представляет собой имя файла, хранящегося на компьютере.
# Второй параметр, '/server/', это путь, по которому нужно разместить указанный файл в образе.
# Здесь мы помещаем файл в папку образа '/server/'.

ADD server.py /server/
ADD index.html /server/

# Здесь мы воспользуемся командой 'WORKDIR', возможно, новой для вас.
# Она позволяет изменить рабочую директорию образа.
# В качестве такой директории, в которой будут выполняться все команды, мы устанавливаем '/server/'.

WORKDIR /server/

Теперь займёмся работой над клиентом.

▍3. Создание клиента

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

3a. Создание файлов

Перейдите в папку вашего проекта client и создайте в ней следующие файлы:

  • Файл client.py. Тут будет находиться код клиента.
  • Файл Dockerfile. Этот файл играет ту же роль, что и аналогичный файл в папке сервера. А именно, он содержит инструкцию, описывающую создание среды для выполнения клиентского кода.

В результате ваша папка client/ на данном этапе работы должна выглядеть так:

.
├── client.py
└── Dockerfile
0 directories, 2 files

3b. Редактирование Python-файла

Добавим в файл client.py следующий код:

#!/usr/bin/env python3

# Импортируем системную библиотеку Python.
# Она используется для загрузки файла 'index.html' с сервера.
# Ничего особенного устанавливать не нужно, эта библиотека устанавливается вместе с Python.

import urllib.request

# Эта переменная содержит запрос к 'http://localhost:1234/'.
# Возможно, сейчас вы задаётесь вопросом о том, что такое 'http://localhost:1234'.
# localhost указывает на то, что программа работает с локальным сервером.
# 1234 - это номер порта, который вам предлагалось запомнить при настройке серверного кода.

fp = urllib.request.urlopen("http://localhost:1234/")

# 'encodedContent' соответствует закодированному ответу сервера ('index.html').
# 'decodedContent' соответствует раскодированному ответу сервера (тут будет то, что мы хотим вывести на экран).

encodedContent = fp.read()
decodedContent = encodedContent.decode("utf8")

# Выводим содержимое файла, полученного с сервера ('index.html').

print(decodedContent)

# Закрываем соединение с сервером.

fp.close()

Благодаря этому коду клиентское приложение может загрузить данные с сервера и вывести их на экран.

3c. Редактирование файла Dockerfile

Как и в случае с сервером, мы создаём для клиента простой Dockerfile, ответственный за формирование среды, в которой будет работать клиентское Python-приложение. Вот код клиентского Dockerfile:

# То же самое, что и в серверном Dockerfile.

FROM python:latest

# Импортируем 'client.py' в папку '/client/'.

ADD client.py /client/

# Устанавливаем в качестве рабочей директории '/client/'.

WORKDIR /client/

▍4. Docker Compose

Как вы могли заметить, мы создали два разных проекта: сервер и клиент. У каждого из них имеется собственный файл Dockerfile. До сих пор всё происходящее не выходит за рамки основ работы с Docker. Теперь же мы приступаем к работе с Docker Compose. Для этого обратимся к файлу docker-compose.yml, расположенному в корневой папке проекта.

Обратите внимание на то, что тут мы не стремимся рассмотреть абсолютно все команды, которые можно использовать в docker-compose.yml. Наша главная цель — разобрать практический пример, дающий вам базовые знания по Docker Compose.

Вот код, который нужно поместить в файл docker-compose.yml:

# Файл docker-compose должен начинаться с тега версии.
# Мы используем "3" так как это - самая свежая версия на момент написания этого кода.

version: "3"

# Следует учитывать, что docker-composes работает с сервисами.
# 1 сервис = 1 контейнер.
# Сервисом может быть клиент, сервер, сервер баз данных...
# Раздел, в котором будут описаны сервисы, начинается с 'services'.

services:

  # Как уже было сказано, мы собираемся создать клиентское и серверное приложения.
  # Это означает, что нам нужно два сервиса.
  # Первый сервис (контейнер): сервер.
  # Назвать его можно так, как нужно разработчику.
  # Понятное название сервиса помогает определить его роль.
  # Здесь мы, для именования соответствующего сервиса, используем ключевое слово 'server'.

  server:
 
    # Ключевое слово "build" позволяет задать
    # путь к файлу Dockerfile, который нужно использовать для создания образа,
    # который позволит запустить сервис.
    # Здесь 'server/' соответствует пути к папке сервера,
    # которая содержит соответствующий Dockerfile.

    build: server/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./server.py".

    command: python ./server.py

    # Вспомните о том, что в качестве порта в 'server/server.py' указан порт 1234.
    # Если мы хотим обратиться к серверу с нашего компьютера (находясь за пределами контейнера),
    # мы должны организовать перенаправление этого порта на порт компьютера.
    # Сделать это нам поможет ключевое слово 'ports'.
    # При его использовании применяется следующая конструкция: [порт компьютера]:[порт контейнера]
    # В нашем случае нужно использовать порт компьютера 1234 и организовать его связь с портом
    # 1234 контейнера (так как именно на этот порт сервер 
    # ожидает поступления запросов).

    ports:
      - 1234:1234

  # Второй сервис (контейнер): клиент.
  # Этот сервис назван 'client'.

  client:
    # Здесь 'client/ соответствует пути к папке, которая содержит
    # файл Dockerfile для клиентской части системы.

    build: client/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./client.py".
 
    command: python ./client.py

    # Ключевое слово 'network_mode' используется для описания типа сети.
    # Тут мы указываем то, что контейнер может обращаться к 'localhost' компьютера.

    network_mode: host

    # Ключевое слово 'depends_on' позволяет указывать, должен ли сервис,
    # прежде чем запуститься, ждать, когда будут готовы к работе другие сервисы.
    # Нам нужно, чтобы сервис 'client' дождался бы готовности к работе сервиса 'server'.
 
    depends_on:
      - server

▍5. Сборка проекта

После того, как в docker-compose.yml внесены все необходимые инструкции, проект нужно собрать. Этот шаг нашей работы напоминает использование команды docker build, но соответствующая команда имеет отношение к нескольким сервисам:

$ docker-compose build

▍6. Запуск проекта

Теперь, когда проект собран, пришло время его запустить. Этот шаг нашей работы соответствует шагу, на котором, при работе с отдельными контейнерами, выполняется команда docker run:

$ docker-compose up

После выполнения этой команды в терминале должен появиться текст, загруженный клиентом с сервера: Docker-Compose is magic!.

Как уже было сказано, сервер использует порт компьютера 1234 для обслуживания запросов клиента. Поэтому, если перейти в браузере по адресу http://localhost:1234/, в нём будет отображена страница с текстом Docker-Compose is magic!.

Полезные команды

Рассмотрим некоторые команды, которые могут вам пригодиться при работе с Docker Compose.

Эта команда позволяет останавливать и удалять контейнеры и другие ресурсы, созданные командой docker-compose up:

$ docker-compose down

Эта команда выводит журналы сервисов:

$ docker-compose logs -f [service name]

Например, в нашем проекте её можно использовать в таком виде: $ docker-compose logs -f [service name].

С помощью такой команды можно вывести список контейнеров:

$ docker-compose ps

Данная команда позволяет выполнить команду в выполняющемся контейнере:

$ docker-compose exec [service name] [command]

Например, она может выглядеть так: docker-compose exec server ls.

Такая команда позволяет вывести список образов:

$ docker-compose images

Итоги

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

Уважаемые читатели! Пользуетесь ли вы Docker Compose в своих проектах?

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

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

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

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

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

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

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

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

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

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

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

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

Docker решает проблемы зависимостей и рабочего окружения

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

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

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

Изоляция и безопасность

Контейнер — это набор процессов, изолированных от основной операционной системы. Приложения работают только внутри контейнеров и не имеют доступа к основной операционной системе. Это повышает безопасность приложений:они не смогут случайно или умышленно навредить основной системе. Если приложение в контейнере завершится с ошибкой или зависнет, это никак не затронет основную ОС.

Ускорение и автоматизация развертывания приложений и масштабируемость

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

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

Контейнеры приближают к микросервисной архитектуре

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

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

Docker compose — одновременно развернуть несколько контейнеров

Docker-compose позволяет разворачивать и настраивать несколько контейнеров одновременно. Например, для веб-приложения нужно развернуть стек LAMP: Linux + Apache, MySQL, PHP. Каждое из приложений — это отдельный контейнер для ОС Linux. Но в этой ситуации нам нужны именно все контейнеры вместе, а не отдельно взятое приложение. Docker-compose позволяет развернуть и настроить все приложения одной командой, а без него пришлось бы разворачивать и настраивать каждый контейнер отдельно.

Создайте кластер любой конфигурации в несколько кликов

Упростите процесс развертывания, масштабирования и обслуживания контейнерной инфраструктуры с Managed Kubernetes.

Тестировать сервис

Хранение данных в Docker

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

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

Но далеко не все приложения такие, и есть много данных, которые нужно сохранить. В контейнерах для этого предусмотрены несколько способов.

Тома (Docker volumes)

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

Монтирование каталога (bind mount)

В этом случае директория сначала создается на хост-машине а уже потом монтируется в контейнеры.

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

Архитектура (компоненты) Docker

Теперь расскажем подробнее про компоненты, из которых состоит Docker.

Docker daemon

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

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

Docker client (клиент)

Это интерфейс командной строки для управления Docker daemon. Мы пользуемся этим клиентом, когда создаем и разворачиваем контейнеры, а клиент отправляет эти запросы в Docker daemon.

Docker image (образ)

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

Приведем аналогию на примере установки операционной системы. В дистрибутиве (образе) ОС есть все, что необходимо для ее установки. Но этот образ нельзя запустить, для начала его нужно «развернуть» в готовую ОС. Так вот, дистрибутив для установки ОС — это образ, а установленная и работающая ОС — это контейнер. Но контейнеры обычно разворачиваются одной командой — это намного проще и быстрее, чем установка ОС.

Docker container (контейнер)

Это уже развернутое из образа и работающее приложение.

Docker Registry

Это репозиторий с образами. Разработчики создают образы своих программ и выкладывают их в репозиторий, чтобы их можно было скачать и воспользоваться ими. Распространенный публичный репозиторий — Docker Hub. В нем собраны образы множества популярных программ или платформ: базы данных, веб-серверы, компиляторы, операционные системы и так далее. Также можно создать свой приватный репозиторий, например внутри компании. Разработчики будут размещать там образы, которые будут использоваться всей компанией.

Dockerfile

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

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

FROM python:3 
COPY main.py /
CMD [ "python", "./main.py" ]

Первая строчка означает, что за основу мы берем образ с названием python версии 3 это называется базовый образ. Docker найдет его в docker registry, скачает и будет использовать за основу. Вторая строчка означает, что нужно скопировать файл main.py в корень файловой системы контейнера. Третья строчка означает, что нужно запустить python и передать ему в качестве параметра название файла main.py.

Далее рассмотрим примеры нескольких команд докер и что происходит, когда мы их выполняем.

Все эти команды выполняются в Docker client, который отправляет их в Docker daemon:

  • Команда docker build (зеленая стрелка) читает dockerfile и собирает образ.
  • Команда docker pull (красная стрелка) скачивает образ из docker registry. По умолчанию docker скачивает образы из публичного репозитория Docker Hub. Но можно создать свой репозиторий и настроить докер, чтобы он работал с ним.
  • Команда docker run (черная стрелка) берет образ и запускает из него контейнер.

Создаем виртуальную машину для работы с Docker

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

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

На следующем экране выбираем параметры сервера: имя, регион, ОС, параметры производительности и так далее. Сейчас для нас важны параметры «Источник» — выбираем ОС Ubuntu 20.04 и «Конфигурация» — выбираем 2 vCPU и 8 ГБ оперативной памяти.

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

После этого внизу страницы нажимаем кнопку «Создать». Виртуальная машина создается за несколько минут, и после того, как она перейдет в статус ACTIVE, к ней можно подключаться по SSH.

Установка Docker

Мы рассмотрим установку докера на примере Ubuntu. Если у вас другой дистрибутив Linux или операционная система — ищите соответствующую инструкцию на официальном сайте.

Для начала синхронизируем пакетную базу apt и установим нужные зависимости:

sudo apt-get update
sudo apt-get install 
    apt-transport-https 
    ca-certificates 
    curl 
    gnupg 
    lsb-release

Далее импортируем GPG-ключ для репозитория docker:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Теперь добавим новый репозиторий в список apt:

echo 
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu 
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Теперь можно устанавливать докер:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

По умолчанию, доступ к docker daemon есть только у пользователя root. Чтобы с докером могли работать и другие пользователи, их нужно добавить в специальную группу — docker. Выполните эту команду из под обычного пользователя:

sudo usermod -aG docker $USER

После этого необходимо перелогиниться, чтобы изменение вступило в силу.

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

Теперь попробуем запустить какое-нибудь готовое приложение. Выполните команду:

docker run ubuntu echo 'hello from ubuntu'

Команда docker run создает и запускает контейнер из образа. В этом примере мы создаем контейнер из образа ubuntu, затем выполняем в нем команду echo ‘hello from ubuntu’. Но так как у нас чистая установка докера и мы не скачали ни одного образа, докер сначала найдет этот образ в публичном репозитории Docker Hub, скачает, а потом создаст из него контейнер. В следующий раз, когда нам понадобится образ ubuntu, докер уже не будет его скачивать.

После выполнения команды в терминале появится строка hello from ubuntu, и контейнер сразу остановится. Теперь выполним другую команду:

docker run -it ubuntu

Эта команда запустит контейнер в интерактивном режиме, то есть контейнер запустится и будет ждать дальнейших команд. При этом мы окажемся внутри операционной системы контейнера: запустится оболочка (bash), и мы сможем выполнять какие-то команды внутри контейнера. Чтобы выйти из контейнера, введите команду exit.

Создание собственного образа и запуск контейнера

Теперь создадим HelloWorld-приложение на Python, обернем его в образ и запустим.

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

mkdir first-docker-app
cd first-docker-app

Создадим файл main.py и запишем в него одну строчку кода:

echo 'print("Hello from python");' >> main.py

Проверим, что наша программа работает. Для этого выполним команду:

python main.py

В консоли должно выйти сообщение Hello from python. Это и есть наше простое приложение. Теперь нужно обернуть его в докер-образ. Для этого создадим файл Dockerfile и напишем в нем три строчки:

FROM python:3
COPY main.py /
CMD [ "python", "./main.py" ]

В первой строке мы указываем образ, который берем за основу. Так как мы пишем приложение на Python, нужно чтобы в нашем образе он уже был установлен. Самый простой способ это сделать — использовать готовый официальный образ с Docker Hub. Цифра 3 — это тег. Он означает, что нужно использовать третью версию Python. Вместо этого можно было бы использовать тег latest, который означает самую последнюю версию, или можно было указать номер конкретной версии, например 3.8.8.

Во второй строчке мы копируем наш файл main.py в корневую директорию образа.

Третья строчка — запускаем python и передаем ему в качестве параметра имя нашего файла.

Теперь из этого докер-файла можно собирать образ. Выполним команду:

docker build -t first-docker-app .

Параметр -t обозначает имя нашего образа, мы назвали его first-docker-app.

Так как у нас еще нет скачанного образа python, то докер сам скачает его из Docker Hub и затем будет использовать его в качестве основы для создания нашего образа.

Проверим список установленных у нас образов:

docker images

Мы увидим, что у нас установлено три образа:

REPOSITORY         TAG       IMAGE ID       CREATED         SIZE
first-docker-app   latest    649cceb4dfd2   4 seconds ago   885MB
python             3         b1aa63f57d3c   2 days ago      885MB
ubuntu             latest    8e428cff54c8   4 days ago      72.9MB

first-docker-app — это наш образ, который мы только что создали. python — это образ python, который докер автоматически скачал чтобы собрать наш образ. ubuntu — образ, который мы пробовали для запуска готового приложения.

Теперь создадим контейнер из нашего образа и запустим его:

docker run first-docker-app

В результате нам выведется результат: Hello from python.

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

Заботимся о работе и доступности вашего кластера даже в пиковые нагрузки

Managed Kubernetes — это готовый сервис Selectel. Мы отвечаем за автоматическое обновление кластера, несем ответственность по SLA за его доступность и бесперебойную работу Control Plane.

Создать кластер

Список полезных команд

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

Посмотреть список всех контейнеров

Эта команда выведет список всех докер контейнеров:

docker ps

Но по умолчанию выводятся только работающие контейнеры. Чтобы вывести все, в том числе и остановленные, используйте опцию -a:

docker ps -a

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

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

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

Запустить контейнер с последующим удалением

По умолчанию контейнеры после завершения работы останавливаются, но не удаляются. Они сохраняют свое состояние и при необходимости их можно запустить снова. Чтобы контейнер удалялся сразу после остановки, добавьте к команде docker run параметр —rm, например:

docker run --rm ubuntu echo 'hello from ubuntu'

Посмотреть список всех скачанных образов

docker images

Удалить докер образ

docker rmi <имя-образа>

Если у этого образа есть контейнеры, пусть даже остановленные, докер не позволит его удалить. Он выдаст сообщение:

unable to remove repository reference <имя-образа> (must force) - container <id-контейнера> is using its

Чтобы принудительно удалить образ, добавьте флаг -f:

docker rmi -f <имя-образа>

Получить список всех контейнеров, созданных из определенного образа

docker ps -a --filter ancestor=<название-образа>

Итог

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

Мы рассказали основы технологий, но не затронули более сложные темы, вроде Docker Swarm, настройку сети или настройки процессов CI/CD. Но этого вполне достаточно, чтобы погрузиться в основы технологий.

В этом гайде разбираемся, для чего нужен Docker и Docker Compose, что такое контейнеризация и Docker-образы, а также как развернуть простое веб-приложение с использованием PHP-FPM, Nginx и Postgres.

  • Что такое Docker
  • Как работает Docker
  • Как создать свой Docker-образ
  • Что такое Docker Compose и как он работает
  • Как создать простое веб-приложение с помощью Docker
  • Итог

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

Разработчик узнаёт, что сайт компании работает с помощью веб-сервера Nginx, менеджера процессов PHP-FPM и системы управления базами данных Postgres. Теперь программист ищет нужную страницу. Поиск выглядит так:

  1. Разработчик вводит в браузере адрес сайта
  2. Браузер запрашивает HTML-страницу с котиками по указанному адресу
  3. HTTP-сервер Nginx принимает запрос и делегирует создание страницы PHP-FPM
  4. PHP-FPM запрашивает данные о котиках из базы Postgres, строит HTML-страницу и отдает обратно его серверу Nginx, а тот — клиенту-браузеру
  5. Разработчик видит страницу с котиками.

Свое первое задание разработчик выполняет на компьютере тимлида, где уже установлен Nginx, PHP-FPM и Postgres. На следующий день ему выдают новый компьютер, на котором этих программ нет.

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

  • Устанавливает Nginx
  • Устанавливает PHP-FPM и все нужные расширения
  • Настраивает совместную работу Nginx и PHP-FPM
  • Устанавливает Postgres, создает пользователей, нужные базы и схемы.

Установка идет долго: приходится ждать, пока сначала установится одна программа, потом другая. Сложности добавляет и то, что вся его команда работает над проектом на разных операционных системах: одни на macOS, а другие на Ubuntu или Windows.

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

Что такое Docker

Docker — это популярная программа, в основе которой лежит технология контейнеризации. Docker позволяет запускать Docker-контейнеры с приложениями из заранее заготовленных шаблонов — Docker-образов (или по-другому Docker images).

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

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

На картинке видно, что приложение 1 и приложение 2 изолированы как друг от друга, так и от операционной системы.

Что еще может делать Docker:

  • Управлять изолированными приложениями
  • Ускорять и автоматизировать развертывание приложений
  • Доставлять приложения до серверов
  • Масштабировать приложения
  • Запускать на одном компьютере разные версии одной программы.

Читайте также:
Как читать чужой код: 6 правил, которые стоит помнить разработчику

Как работает Docker

Концепцию программы легче понять на практике. Сначала установим на компьютер Docker и запустим HTTP-сервер Nginx. Для этого введем следующую команду:

docker run -p 8080:80 nginx:latest

Далее откроем браузер и забьем в адресную строку: 127.0.0.1:8080. Откроется страница приветствия Nginx.

Теперь разберемся подробнее, что происходит, когда мы вводим команду docker run -p 8080:80 nginx:latest. Она выполняет следующее:

  1. Скачивает docker-образ — шаблон для создания Docker-контейнера — nginx:latest из публичного репозитория Docker Hub (если его не скачивали ранее). Docker-образ содержит все необходимое для запуска приложения: код, среду выполнения, библиотеки, переменные окружения и файлы конфигурации. На странице Nginx в Docker Hub можно найти Docker-образ nginx:latest, где latest — это тег (метка, снимок), который ссылается на самый свежий docker-образ и описывает его.
  2. Запускает Docker-контейнер с помощью Docker-образа
  3. Пробрасывает порт. Ранее мы объясняли, что процессы в Docker-контейнерах запускаются в изоляции от ОС, то есть все порты между ОС и Docker-контейнером закрыты. Для того, чтобы мы смогли обратиться к Nginx, нужно пробросить порт, что и делает опция -p 8080:80, где 80 — это порт Nginx внутри контейнера, а 8080 — порт в локальной сети ОС.

Как создать свой Docker-образ

Теперь попробуем создать свой Docker-образ, взяв за основу nginx:latest. Docker умеет создавать Docker-образ, читая текстовые команды, которые записаны в файл Dockerfile.

Вот пример простейшего Dockerfile:

FROM nginx:latest

RUN echo 'Hi, we are building a custom docker image from nginx:latest!'

COPY nginx-custom-welcome-page.html /usr/share/nginx/html/index.html

Команда FROM задает базовый (родительский) Docker-образ и всегда вызывается в первую очередь. Команда COPY копирует файлы в Docker-контейнер.

С помощью COPY можно заменить стандартную велком-страницу Nginx на такую страницу:

<!DOCTYPE html>
<html>
<body>
<h1>Welcome to custom Nginx page!</h1>
</body>
</html>

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

Теперь, когда мы разобрались, за что отвечают команды, создадим Docker-образ из Dockerfile:

$ docker build -t nginx_custom:latest -f  /opt/src/docker-for-kids/dockerFiles/Nginx-custom/Dockerfile /opt/src/docker-for-kids
Sending build context to Docker daemon  139.3kB
Step 1/3 : FROM nginx:latest
latest: Pulling from library/nginx
31b3f1ad4ce1: Pull complete
fd42b079d0f8: Pull complete
30585fbbebc6: Pull complete
18f4ffdd25f4: Pull complete
9dc932c8fba2: Pull complete
600c24b8ba39: Pull complete
Digest: sha256:0b970013351304af46f322da1263516b188318682b2ab1091862497591189ff1
Status: Downloaded newer image **for** nginx:latest
---**>** 2d389e545974
Step 2/3 : RUN echo 'Hi, we are building a custom docker image from nginx:latest!'
---**>** Running **in** 05ffd060061f
Hi, we are building a custom docker image from nginx:latest!
Removing intermediate container 05ffd060061f
---**>** 9ac62be4252a
Step 3/3 : COPY nginx-custom-welcome-page.html /usr/share/nginx/html/index.html
---**>** 704121601a45
Successfully built 704121601a45
Successfully tagged nginx_custom:latest

Поясним, какие команды мы использовали в этом коде:

  • -t nginx_custom:latest — это имя будущего Docker-образа, latest — это тег
  • -f /opt/src/docker-for-kids/dockerFiles/Nginx-custom/Dockerfile — путь до Dockerfile
  • /opt/src/docker-for-kids — директория, в контексте которой будет создан Docker-образ. Контекст — это все то, что доступно для команд из Dockerfile при сборке (билде) образа. Процесс создания Docker-образа может ссылаться на любой из файлов в контексте.

Теперь запускаем команду:

$ docker run -p 8080:80 Nginx_custom:latest

Docker-образ готов.

Читайте также:
Как настроить VS Code для разработки на PHP и JavaScript

Что такое Docker Compose и как он работает

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

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

Для описания приложений используется YAML-файл.

version: '3'

services:
  nginx:
    container_name: nginx-test # имя Docker-контейнера
    build: # создать Docker-образ из DockerFile
      context: . # путь, в контексте которого будет создан Docker-образ
      dockerfile: ./dockerFiles/nginx/Dockerfile # путь до Dockerfile, из которого будет собран Docker-образ
    ports: # проброс портов
      - "80:80"
    networks: # имя сети, к которой будет подключен Docker-контейнер
      - test-network
    depends_on: # эта программа будет запущена только после того, как запустится сервис под именем php-fpm 
      - php-fpm
    volumes: #  монтирование директорий, директория-на-хост-машине: директория-в-докере
      - ./:/var/www/hello.dev/
  php-fpm:
    container_name: php-fpm-test
    build:
      context: .
      dockerfile: ./dockerFiles/php-fpm/Dockerfile
    networks:
      - test-network
    volumes:
      - ./:/var/www/hello.dev/
  postgres:
    container_name: postgres-test
    image: postgres:14.1-alpine # тег Docker-образа из https://hub.docker.com/
    environment:
      postgres_PASSWORD: mysecretpass # переменные окружения, которые использует Docker-контейнер
    networks:
      - test-network
networks: # явно объявленные сети
  test-network:
    driver: bridge

Если изображать этот код схематично, то описание приложения выглядит так:

Каждый сервис находится внутри Docker-контейнера. Точкой входа в приложение, как и в случае с тем разработчиком и веб-сайтом компании, является Nginx. Пользователи веб-сайта делают запросы к Nginx, у которого проброшен порт 80.

Разберем еще несколько команд, которые реализует Docker:

  1. network. Как мы объяснили ранее, каждое приложение в Docker-контейнере находится в изоляции. networks объединяет все Docker-контейнеры в одну сеть с именем test-network, и это позволяет обращаться к нужному контейнеру по его имени.
  2. volumes — это механизм для хранения данных вне Docker-контейнера, то есть в файловой системе нашей ОС. volumes решает проблему совместного использования файлов.

Все примеры, а также исходники Dockerfile можно взять из репозитория на GitHub.

Как создать простое веб-приложение с помощью Docker

Создадим простое веб-приложение, которое покажет нам сообщение об успешном подключении к базе данных. Вместо адреса базы данных используем host=postgres, такое же имя cервиса, как и в YAML-файле. Напомню, что эта возможность появилась благодаря общей сети test-network.

index.php
<?php

try {
    $pdo = new PDO("pgsql:host=postgres;dbname=postgres", 'postgres', 'mysecretpass');
    echo "Подключение к базе данных установлено! <br>";

    return;
} catch (PDOException $exception) {
    echo "Ошибка при подключении к базе данных<br><b>{$exception->getMessage()}</b><br>";
}

PDO — это интерфейс для доступа к базам данных в PHP. Подробнее об этом можно узнать в официальной документации.

Теперь, чтобы создать все Docker-образы и запустить Docker-контейнеры нужно выполнить:

docker-compose up --build

Выполняем index.php и видим успешное соединение с базой данных.

Веб-приложение для самостоятельного запуска можно найти в репозитории на GitHub.

Итог

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

Изучите основы Docker:
На Хекслете есть курс по основам Docker. Пройдите его, чтобы подробнее узнать об этой программе, научиться работать с образами, управлять контейнерами и получить поддержку от менторов и единомышленников.

Изучить Docker

Docker: что это и как используется в разработке

На дворе закат 2022-го, и большая часть IT-индустрии только и делает, что работает с контейнерами. Откуда они появились, как добились глобального признания и при чём тут Docker? Расскажет разработчица в команде инфраструктуры Яндекса, действующий автор курса «DevOps для эксплуатации и разработки» Дарья Меленцова.

  1. Начнём с основ
  2. Благодаря каким механизмам работает Docker
  3. Терминология
  4. Запуск и начальная настройка Docker
  5. Развёртывание веб-приложения
  6. Создание Docker Image
  7. Выводы
  8. Дополнительные материалы по Docker

Дарья Меленцова

Дарья Меленцова


разработчица в команде инфраструктуры Яндекса, действующий автор курса «DevOps для эксплуатации и разработки»

Из этой статьи вы узнаете:

  • что такое Docker и его главные возможности;
  • почему Docker стал де-факто современной индустрией программного обеспечения;
  • как создавать и развёртывать Docker-контейнеры.

Начнём с основ

Что такое Docker

Разработчики Docker дают ему такое определение: «Docker helps developers bring their ideas to life by conquering the complexity of app development», что можно перевести как «Docker помогает разработчикам воплощать свои идеи в жизнь, преодолевая сложность разработки приложений». Звучит многообещающе, не правда ли?

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

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

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

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

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

  1. Все серверы настраивались вручную (или почти вручную). Подключение сервера, установка ОС, настройка правильного окружения, сети и других параметров занимали много времени.
  2. Были проблемы с гибким масштабированием. Представьте, что у вас на сервере развёрнут интернет-магазин. В обычное время приложение справляется с потоком пользователей, но в канун Нового года аудитория возрастает, ведь все хотят закупиться подарками. И тут оказывается, что интернет-магазин не справляется с нагрузкой и надо либо добавить ресурсы на сервер, либо поднять ещё несколько экземпляров сервиса. Да, мы можем заранее подумать о празднике и предвидеть наплыв покупателей, но что делать с теми ресурсами, которые будут простаивать после Нового года?
  3. Требовалось эффективнее использовать ресурсы. Если на большом и мощном физическом сервере разместить какое-нибудь скромное приложение, которому нужно от силы 20% всех мощностей, что делать с остальным запасом? Может быть, подселить к этому приложению ещё одно или несколько? Казалось бы, вариант, пока вы не узнаете, что для работы приложений нужны разные версии одного и того же пакета.

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

Виртуализация — технология, которая позволяет создавать виртуальное представление ресурсов отдельно от аппаратных. Например, под операционную систему (далее — ОС) можно отдать не весь диск, а только часть, создав его виртуальное представление.

Есть много разных видов виртуализации, и один из них — аппаратная виртуализация.

Схема аппаратной виртуализации

Аппаратная виртуализация

Идея в том, чтобы взять сервер и разделить его на кусочки. Допустим, у вас есть сервер, на котором установлена хостовая ОС, и внутри неё запускаются виртуальные машины (далее — ВМ) с гостевыми ОС. Между хостовой ОС и ВМ есть прослойка — гипервизор, который управляет разделением ресурсов, а также изоляцией гостевых ОС.

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

Казалось бы, проблемы с утилизацией ресурсов и изоляцией приложений решены, но как быть с установкой ОС и настройкой окружения: всё ещё делаем вручную и на каждой ВМ? Да и зачем платить за гипервизор, если не нужно держать на одном сервере Windows и Linux — достаточно ядра хостовой ОС?

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

Схема контейнерной виртуализации

Контейнерная виртуализация

Контейнер — это изолированный процесс, который использует основное ядро ОС. Работа с контейнерами помогает решить следующие проблемы:

  • утилизации ресурсов (на одном сервере можно запустить несколько контейнеров);
  • изоляции приложений;
  • установки ОС (по сути, мы используем хостовую ОС);
  • настройки окружения для приложения (можно один раз настроить окружение и быстро клонировать его между контейнерами).

Почему контейнеры и Docker

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

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

Особенности контейнеров:

  • Короткий жизненный цикл. Любой контейнер можно остановить, перезапустить или удалить. Данные, которые содержатся в контейнере, тоже пропадут. Поэтому при проектировании приложений, которые подходят для контейнеризации, используют правило: не хранить важные данные в контейнере. Такой подход проектирования называют Stateless.
  • Контейнеры маленькие и лёгкие, их объём измеряется в мегабайтах. Так получается, потому что в контейнер упаковывают лишь те процессы и зависимости ОС, которые необходимы для приложения. Легковесные контейнеры занимают мало места на диске и быстро запускаются.
  • Контейнеризация обеспечивает изоляцию процессов. Приложения, которые работают внутри контейнера, не имеют доступа к основной ОС.
  • Благодаря контейнерам можно перейти с монолита на микросервисную архитектуру.
  • Не нужно тратиться на гипервизор, и можно запустить больше контейнеров, чем ВМ на одних и тех же ресурсах.
  • Контейнеры хранятся в специальных репозиториях, и каждый контейнер содержит всё необходимое окружение для запуска приложения, благодаря чему можно автоматизировать развёртывание приложения на разных хостах.

Теперь обсудим, какие преимущества даёт Docker.

  • Сообщество. Существует огромное хранилище контейнеров с открытым исходным кодом, и вы можете скачать готовый образ для конкретной задачи.
  • Гибкость. Docker позволяет создавать базовые шаблоны контейнеров (image) и использовать их повторно на различных хостах. Docker-контейнеры можно легко запустить как на локальном устройстве, так и в любой облачной инфраструктуре.
  • Скорость развёртывания. Шаблон контейнера содержит всё необходимое окружение и настройки для работы приложения, нам не нужно настраивать всё это каждый раз с нуля.
  • Нет проблемы с зависимостями и версиями пакетов. Docker позволяет упаковывать различные языки программирования и стек технологий в контейнер, чем избавляет от проблемы несовместимости разных библиотек и технологий в рамках одного хоста.

Как вы уже знаете, в ядре Linux из коробки есть все необходимые механизмы для создания контейнеров:

  • capabilities — позволяет выдать процессу часть расширенных прав, которые доступны только root. Например, разрешить удалять чужие файлы, завершать другие процессы (команда kill) или изменять атрибуты у файлов (команда chown);
  • namespace — это абстракция в Linux, с помощью которой можно создавать своё изолированное окружение в ОС. То есть такую коробочку, в которой свои пользователи, своя сеть, свои процессы и всё остальное. При этом изменения в namespace видны только членам этого namespace. Есть шесть типов пространств имён (namespaces): IPC, Network, Mount, PID, User, UTS.

Например:

  • Network namespace отвечает за ресурсы, связанные с сетью. У каждого namespace будут свои сетевые интерфейсы, свои таблицы маршрутизации.
  • User namespace специализируется на пользователях и группах в рамках namespace.
  • PID namespace заведует набором ID процессов. Первый процесс, созданный в новом namespace, имеет PID = 1, а дочерним процессам назначаются следующие PID.
  • cgroup объединяет несколько процессов в группу и управляет ресурсами для этой группы.

Традиционно лимиты в Linux можно задавать для одного процесса, и это неудобно: вы могли задать какому-то процессу не больше n мегабайт памяти, но как указывать лимиты на приложение, если у него больше одного процесса? Поэтому появились cgroups, позволяющие объединить процессы в группу и навесить на неё лимиты.

Давайте разберёмся, как Docker создаёт контейнер из capabilities, namespace и cgroup.

Docker — это очень тонкая прослойка вокруг ядра. Он создаёт контейнер на основе docker image c заданными настройками. Когда вы попросите Docker создать контейнер, он автоматически создаст набор namespaces и cgroup для этого контейнера.

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

Network namespace — контейнер получит свой сетевой стек, а значит, он не сможет получить доступ к сокетам или сетевым интерфейсам другого контейнера.

Аналогичная история со всеми остальными пространствами имён — для каждого контейнера своё дерево каталогов, хостнеймы и прочее.

При создании Docker-контейнера мы можем указать, сколько памяти или cpu выдать конкретному контейнеру, и ОС будет следить за этим лимитом. Такой контроль нужен, чтобы один контейнер случайно не убил всю систему, съев всю память или перегрузив процессор.

По умолчанию Docker при создании контейнера урезает все capabilites внутри него, оставляя только часть возможностей — смену атрибутов UID и GID (chown), kill, chroot и несколько других. Это сделано в целях безопасности, чтобы злоумышленнику не достались все root-права, если бы он смог выбраться из контейнера.

Терминология

Прежде чем начать работу с Docker, нужно изучить несколько терминов.

Устройство архитектуры Docker

Архитектура Docker

Docker Image

Образ — это шаблон для ваших будущих контейнеров. В образе описывается, что должно быть установлено в контейнере и какие действия нужно выполнить при старте контейнера.

В практической части вы будете использовать команду docker pull, чтобы загрузить busybox image из специального хранилища Docker образов — docker hub.

Docker Container

Контейнер — это исполняемый экземпляр образа (image). Его можно создавать, запускать, останавливать и удалять. Также можно подключать к контейнеру хранилище, объединять контейнеры одной или несколькими сетями и общаться с контейнерами, используя Docker API или CLI.

Увидеть список запущенных контейнеров можно через команду docker ps.

Docker Daemon

Docker-демон (dockerd) — фоновый процесс в операционной системе, который обрабатывает запросы Docker API и управляет объектами Docker: образами, контейнерами, сетями и томами.

Docker Client

Docker-клиент — инструмент командной строки (Comand Line Interface — CLI), через который пользователь взаимодействует с демоном.

Когда вы используете команду docker run, то Docker-клиент отправляет команду dockerd. Аналогичная история с другими командами docker <команда>.

Docker Hub

Docker Hub — это общедоступный Docker registry, то есть хранилище всех доступных Docker-образов. При необходимости можно разворачивать свои приватные Docker registry, размещать собственные реестры Docker и использовать их для извлечения образов.

Запуск и начальная настройка Docker

Для работы потребуются:

  • базовые навыки работы с командной строкой;
  • Git;
  • Docker.

Docker — довольно популярный инструмент, и установить его на любую ОС не составит труда. В руководстве «Начало работы с Docker» есть подробные инструкции по настройке Docker на Mac, Linux и Windows.

После установки Docker стоит проверить, что он работает.

Для этого выполните:

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:62af9efd515a25f84961b70f973a798d2eca956b1b2b026d0a4a63a3b0b6a3f2
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly
**....**

Запускаем Busybox

Теперь, когда Docker установлен, запустим в нём первый контейнер. За основу контейнера возьмите Busybox image. Введите в терминале команду:

$ docker pull busybox

ПримечаниеВы можете увидеть ошибку permission denied после выполнения команды. Если вы работаете на Mac, убедитесь, что ядро Docker (engine) запущено. Если вы работаете в Linux, добавьте к командам docker префикс sudo. Кроме того, вы можете создать docker group, чтобы избавиться от этой проблемы.

Команда pull скачает (спулит) busybox image из Docker registry и сохранит его в вашей системе.

Чтобы увидеть список всех образов в вашей системе, используйте команду docker images:

$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
busybox       latest    ff4a8eb070e1   2 days ago      1.24MB=

Docker Run

Отлично! Давайте теперь запустим Docker-контейнер на основе этого образа. Используйте команду docker run:

$ docker run busybox
$

Пусть вас не смущает, что ничего не произошло. Ошибки здесь нет, и всё идёт по плану. Когда вы вызываете run, Docker-клиент находит образ (в нашем случае busybox), загружает контейнер и запускает в нём команду.

Когда вы запустили docker run busybox, то не передали команду, поэтому контейнер загрузился, выполнил ничего и затем вышел.

Давайте передадим команду и посмотрим, что будет:

$ docker run busybox echo "hello from busybox"
hello from busybox

Ура, хоть какой-то результат! Docker клиент выполнил команду echo в busybox-контейнере, а затем вышел из него. И всё это произошло довольно быстро.

Хорошо, контейнер вы запустили, а как посмотреть, какие контейнеры запущены на сервере прямо сейчас? Для этого есть команда docker ps:

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Сейчас нет запущенных контейнеров, и вы видите пустую строку. Попробуйте более полезный вариант — docker ps -a:

$ docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                      PORTS     NAMES
c3368945dc3a   busybox       "echo 'hello from bu…"   7 minutes ago    Exited (0) 7 minutes ago              zealous_hugle

Появился список всех контейнеров, которые вы запускали. Заметьте, столбец STATUS показывает, что эти контейнеры были закрыты несколько минут назад.

Итак, вы запустили контейнер, выполнили одну команду, и контейнер завершился. Какой в этом смысл? Может быть, есть способ запускать больше одной команды?

Конечно, есть! Давайте выполним docker run -it busybox sh:

$ docker run -it busybox sh
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # uptime
 22:34:42 up 35 min,  0 users,  load average: 0.02, 0.01, 0.00
/ #

run с флагами -it подключит вас к интерактивному терминалу в контейнере. Теперь можно запускать в контейнере столько команд, сколько захотите.

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

Чтобы увидеть список всех флагов, которые поддерживает run, выполните docker run --help.

Docker rm

Раз вы научились создавать контейнеры, нужно потренироваться их удалять. Вы сами видели, что даже после остановки контейнера информация о нём остаётся на хосте. Можно запускать docker run несколько раз и получать бесхозные контейнеры, которые будут занимать место на диске.

Место на диске нерезиновое, поэтому надо прибираться и удалять ненужные контейнеры. В этом поможет команда docker rm:

# какие есть контейнеры  
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                       PORTS     NAMES
f3776be78165   busybox       "sh"                     17 minutes ago   Exited (130) 3 seconds ago             optimistic_elion
c3368945dc3a   busybox       "echo 'hello from bu…"   33 minutes ago   Exited (0) 33 minutes ago              zealous_hugle

# удаление контейнеров по CONTAINER ID
$ docker rm f3776be78165 c3368945dc3a

# проверка, что контейнеры удалились
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                       PORTS     NAMES

Если на хосте много контейнеров, которые надо удалить, то придётся копировать много CONTAINER ID, а это может быть утомительно. Чтобы облегчить себе жизнь, можно использовать docker container prune:

$ docker container prune                                                     
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
f3776be78165721b1e7e00234a29eb962ee7d678821f7632b538540cfa537701

Команда удалит все остановленные контейнеры.

Чтобы удалить образы, которые больше не нужны, запустите docker image prune.

Развёртывание веб-приложения

Static-site

Итак, вы рассмотрели запуск docker и поиграли с контейнером. Настало время перейти к более реальным вещам и развернуть веб-приложение с помощью Docker.

Первым делом запустите очень простой статический сайт. Для этого заберите Docker-образ из Docker Hub, запустите его и проверьте, что у вас есть рабочий веб-сервер.

Образ, который вы будете использовать, — одностраничный веб-сайт, специально созданный для демонстрации и размещённый в registry — ifireice/static-site.

Вы можете загрузить и запустить образ сразу, используя docker run, флаг --rm автоматически удалит контейнер при выходе из него, а флаг -it запустит интерактивный терминал, из которого можно выйти с помощью Ctrl+C. Контейнер при этом будет уничтожен.

$ docker pull ifireice/static-sitedocker run --rm -it ifireice/static-site

Так как образа ещё нет на хосте, Docker-клиент сначала скачает образ с registry, а потом запустит его. Если всё пойдёт по сценарию, вы должны увидеть сообщение Nginx is running... в терминале.

Сервер запущен, но как увидеть сайт? На каком порту работает сайт? Как получить доступ к контейнеру?

Клиент не предоставляет никаких портов, поэтому вам нужно повторно запустить docker run и опубликовать порты. Нажмите Ctrl+C, чтобы остановить контейнер.

Также вам надо сделать так, чтобы работающий контейнер не был привязан к терминалу. Это нужно для того, чтобы после закрытия терминала контейнер продолжил работать, — принцип действия detached mode:

$ docker run -d -P --name static-site ifireice/static-site
9c9e7a8a552795c0312bcdf3cb8949ddeea7bdd60bbf683140b99abf3b43bff1
  • -d — отсоединить терминал,
  • -P — опубликовать все открытые порты на случайные порты,
  • --name — задать имя контейнеру.

Теперь вы можете увидеть порты, запустив команду docker port [CONTAINER]:

$ docker port static-site
80/tcp -> 0.0.0.0:55000

Откройте http://localhost:55000 в браузере. Также можно указать собственный порт, на который Docker-клиент будет перенаправлять подключения к контейнеру.

$ docker run -p 8888:80 ifireice/static-site
Nginx is running...

«Hello Docker!» в localhost

Если вы устали писать «Hello world!», самое время перейти на «Hello Docker!»

Чтобы остановить контейнер, запустите docker stop, указав идентификатор контейнера. В этом случае можно использовать имя static-site, которое вы задали контейнеру при запуске.

$ docker stop static-site
static-site

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

Создание Docker Image

Теперь, когда вы посмотрели, как запустить веб-сервер внутри образа Docker, наверное, хочется создать собственный Docker-образ?

Помните команду docker images, которая выводит список образов, располагающихся локально?

$ docker images
REPOSITORY             TAG       IMAGE ID       CREATED          SIZE
ifireice/django-app    latest    07f6ba4cc25b   23 seconds ago   945MB
ifireice/static-site   latest    b237e7cf6bd2   27 minutes ago   142MB
ubuntu                 18.04     71cb16d32be4   2 days ago       63.1MB
busybox                latest    ff4a8eb070e1   2 days ago       1.24MB

Перед вами список образов, скачанных из registry, а также образы, которые созданы нами:

  • TAG — относится к конкретному снимку изображения;
  • IMAGE ID — уникальный идентификатор этого image.

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

$ docker pull ubuntu:18.04

Новый образ можно или скачать из registry, или создать собственный.

Первый image

Допустим, вы хотите создать образ, который засунет в контейнер простое приложение на Django, отображающее случайную картинку с котиком. Для начала клонируйте это приложение к себе на локальный компьютер (не в Docker-контейнер):

$ git clone https://github.com/ifireice/docker-article.git
$ cd docker-article

Теперь это приложение нужно упаковать в image. Здесь пригодятся определения про образы.

  • Базовые образы — это образы, у которых нет родительского образа. Обычно это образы ОС — ubuntu, busybox или debian;
  • Дочерние образы — это образы, созданные на основе базовых образов с дополнительной функциональностью.

Также есть такие понятия, как официальный и пользовательский образы.

  • Официальные образы поддерживаются Docker-сообществом. Обычно их имя состоит из одного слова, например, python, ubuntu, busybox и hello-world.
  • Пользовательские образы созданы пользователями. Они строятся на основе базового и содержат дополнительную функциональность. Только поддерживаются уже не сообществом, а пользователем, который его создал. Имя у таких образов обычно имеет вид имя пользователя/изображения.

Вы будете создавать пользовательский образ, основанный на Python, потому что используете приложение на Django. Также вам понадобится Dockerfile.

Dockerfile

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

В директории приложения уже есть Dockerfile, но вы будете создавать его с нуля. Поэтому переименуйте его и создайте пустой файл с именем Dockerfile в директории Django-приложения.

Начните с определения базового image. Для этого используйте ключевое слово FROM:

FROM python:3.8

Потом задайте рабочую директорию и скопируйте все файлы приложения:

# установить каталог для приложения
WORKDIR /usr/src/app

# копировать все файлы в контейнер
COPY . .

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

# установка зависимостей
RUN pip install --no-cache-dir -r requirements.txt

Добавьте порт, который нужно открыть. Приложение работает на порту 5000, его и укажите:

EXPOSE 5000

Последний шаг — написать очень простую команду для запуска приложения: python ./manage.py runserver 0.0.0.0:5000. Для этого используйте команду CMD. Она говорит, какую команду должен запустить контейнер при старте.

CMD ["python", "./manage.py", "runserver", "0.0.0.0:5000"]

Теперь ваш Dockerfile готов и выглядит вот так:

FROM python:3.8

# установить каталог для приложения
WORKDIR /usr/src/app

# копировать все файлы в контейнер
COPY . .

# установка зависимостей
RUN pip install --no-cache-dir -r requirements.txt

# какой порт должен экспоузить контейнер
EXPOSE 5000

# запуск команды
CMD ["python", "./manage.py", "runserver", "0.0.0.0:5000"]

Раз у вас есть Dockerfile, нужно собрать образ. Для этого используйте docker build и передайте необязательный флаг -t — имя тега и расположение каталога, содержащего Dockerfile.

Чтобы сохранить (запушить) готовый image на Docker Hub, нужно создать там учётную запись. Сохранитесь, чтобы потом вы могли получить образ и развернуть контейнер на его основе на любом сервере.

В теге yourusername должно быть имя вашей учетной записи в Docker Hub, иначе ничего не сработает.

$ docker build -t yourusername/cats .
[+] Building 8.4s (10/10) FINISHED                                                                                                                                                                                                      
 => [internal] load build definition from Dockerfile                                                                                                                                                                               0.0s
 => => transferring dockerfile: 354B                                                                                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                  0.0s
 => => transferring context: 2B
....
 => => writing image sha256:398306665e853e7c8cbe1f6456951ca63e782bb286dff5dc9361b191260e0ce3                                                                                                                                       0.0s
 => => naming to docker.io/yourusername/cats

Если на локальной машине нет образа python:3.8, Docker-клиент сначала скачает образ, а затем создаст ваш. Тогда вывод команды может отличаться.

Если всё прошло хорошо, то image готов! Запустите его, не забыв изменить yourusername на правильный:

$ docker run -p 8888:5000 yourusername/cats

Команда взяла порт 5000 внутри контейнера и сопоставила его с портом 8888 на хосте. И теперь, если вы обратитесь на порт 8888 хостовой машины, запрос будет перенаправлен в контейнер на порт 5000. Узнать, что вернёт приложение на запрос, можно с помощью пути: http://0.0.0.0:8888.

Docker-образ кота

Котик дня

Поздравляем! Вы успешно создали свой первый Docker-образ.

Docker push

Осталось дело за малым — сохранить ваш образ в registry. Сначала авторизуйтесь в Docker Hub? Не забудьте про логин из yourusername.

$ docker login --username yourusername                                                                                                         1  1772  04:12:45 
Password: 
Login Succeeded

Logging in with your password grants your terminal complete access to your account. 
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/

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

Чтобы сохранить образ в registry, просто введите docker push yourusername/cats. Важно, чтобы тег имел формат yourusername/image_name. Тогда Docker-клиент будет знать, куда сохранять образ:

$ docker push yourusername/cats

Как только образ сохранится в registry, его можно увидеть в Docker Hub по адресу https://hub.docker.com/r/yourusername/cat.

Ну а забирать и запускать image с registry вы уже умеете!

Выводы

Главные мысли этой работы:

  • разобрались с виртуальными машинами, контейнерами и поняли, чем они отличаются;
  • узнали, что такое Docker, и обсудили основную терминологию: image, container, docker daemon, docker client, registry;
  • запустили Hello Docker;
  • запустили контейнер на базе образа из Docker Hub;
  • создали свой контейнер и сохранили на Docker Hub.

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

Если хочется изучить Docker глубже, отправляйтесь по ссылкам:

  • DevOps для эксплуатации и разработки
  • Начало работы с Docker
  • Dockerfile
  • Docker registry
  • Docker volumes
  • Docker Network
  • Docker compose
  • Image-building best practices
  • Видеоурок по Docker для начинающих
  • 12 факторов

Contents

  • 1 Docker и Docker-Compose — Tutorial и подборка видео по темам
    • 1.1 Что такое Docker и зачем он нужен?
      • 1.1.1 Видео — Что такое Docker за 200 секунд
      • 1.1.2 Сущности Docker: docker daemon, container, image, Dockerfile, Docker Registry
    • 1.2 Что такое docker image (образ)
    • 1.3 Что такое docker container (контейнер)
    • 1.4 Управление контейнерами. Схема Lifecycle of Docker Container
    • 1.5 Что такое Docker Hub?
    • 1.6 Как создать свой образ? Что такое Dockerfile?
      • 1.6.1 Пример dockerfile
      • 1.6.2 Команды Dockerfile
      • 1.6.3 Пример dockerfile для приложения flask app python
      • 1.6.4 Видео Tutorials — Dockerfile
    • 1.7 Что такое Docker Volume?
      • 1.7.1 Команды Docker Volume
      • 1.7.2 Подборка видео по Docker Volume
    • 1.8 Как взаимодействовать с контейнером?
    • 1.9 Docker Networking
    • 1.10 Что такое Docker Compose?
    • 1.11 docker-compose.xml
    • 1.12 Дополнительные подборки видео по Docker
  • 2 Примеры создания приложений с помощью Docker или Docker-Compose
      • 2.0.1 Docker + ReactJS tutorial: Development to Production workflow + multi-stage builds + docker compose
  • 3 Краткий экскурс в Linux
    • 3.1 Базовый список команд Linux
    • 3.2 Linux File System/Structure Explained
    • 3.3 Основы Ubuntu Linux: apt-get, bash, командная строка
    • 3.4 Linux command line for beginners
    • 3.5 Права Доступа и владения файлами и директориями
  • 4 Установка Докера на Linux. Install Docker on Ubuntu 20.04
  • 5 Portainer — что это такое?
    • 5.1 Установка Portainer внутри Docker
  • 6 GitHub Actions — CI/CD Pipeline with Docker
  • 7 Использованные источники для подготовки статьи и другие полезные статьи

Что такое Docker и зачем он нужен?

Официальный сайт docker.com.

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

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

И еще одно определение докера:

Docker — это инструмент с открытым исходным кодом, который позволяет вам включать и хранить ваш код и его зависимости в удобном пакете, который называется образом. Затем этот образ можно использовать для создания экземпляра вашего приложения (сервиса) — контейнера. Основное различие между контейнерами и виртуальными машинами заключается в том, что контейнеры охватывают только уровень приложения и полагаются на базовое ядро ​​операционной системы, в случае виртуальной машины создается новый экземпляр операционной системы.

Видео — Что такое Docker за 200 секунд

Сущности Docker: docker daemon, container, image, Dockerfile, Docker Registry

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

Рассмотрим компоненты рабочего процесса и инструменты для управления контейнерами и их развертывания, составляющие экосистему Docker:

  • Daemon Docker (Сервер): Выполняется в хост-системе и управляет всеми запущенными контейнерами. Docker Daemon — это сервер Docker, который прослушивает запросы Docker API. Docker Daemon управляет образами, контейнерами, сетями и томами.
  • Docker Container (Контейнер): Автономная виртуальная система, содержащая выполняющийся процесс, все файлы, зависимости, адресное пространство процесса и сетевые порты, необходимые приложению. Так как каждый контейнер имеет свое пространство портов, следует организовать их отображение в фактические порты на уровне Docker;
  • Docker Client (Клиент): Пользовательский интерфейс, или интерфейс командной строки, для взаимодействий с демоном Docker. Клиент Docker — это основной способ взаимодействия с Docker. Когда вы используете интерфейс командной строки (CLI) Docker, вы вводите в терминал команду, которая начинается сdocker. Затем клиент Docker использует API Docker для отправки команды демону Docker.
  • Docker Image (Образ): это шаблон только для чтения, который содержит набор инструкций по созданию контейнера, который может работать на платформе Docker. Он предоставляет удобный способ упаковать приложения и предварительно настроенные серверные среды, которые вы можете использовать для личного использования или публично публиковать с другими пользователями Docker. Также можно воспользоваться командой docker diff, чтобы увидеть различия между двумя образами. Каждый образ состоит из нескольких уровней, или слоев, которые могут совместно использоваться несколькими образами.
  • Реестр Docker: Репозиторий для хранения и распространения образов контейнеров Docker. Пример известного реестра — Docker Hub, куда можно помещать и откуда можно извлекать образы.
  • Dockerfile: Это очень простой текстовый файл, содержащий команды, которые выполняют сборку образов Docker. Посредством этих команд можно устанавливать дополнительные программные компоненты, настраивать переменные окружения, рабочие каталоги и точку входа ENTRYPOINT, а также добавлять новый код;
  • Docker Swarm: По сути своей, это готовый к использованию механизм кластеризации, позволяющий объединить несколько узлов Docker в один большой хост Docker.
  • Docker Compose: Приложения часто состоят из множества компонентов, и соответственно они будут выполняться в нескольких контейнерах. В состав Docker входит инструмент Compose, с помощью которого можно легко запустить приложение в нескольких контейнерах. Вы можете определить окружение для приложения в общем файле Dockerfile и определить перечень служб в файле docker-compose.yml, после чего Docker автоматически будет создавать и запускать необходимые контейнеры, как определено в этих файлах.

Что такое docker image (образ)

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

Образ Docker состоит из набора файлов, которые объединяют воедино все необходимое, например installations, application code, и dependencies, необходимые для настройки полностью работоспособной среды контейнера. Вы можете создать образ Docker одним из двух способов:

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

  • Dockerfile: путем создания текстового файла, известного как Dockerfile, который предоставляет спецификации для создания образа Docker.

Dockerfile — это файл с инструкциями о том, как Docker должны строить свой image.

С физической точки зрения docker image состоит из набора слоев, доступных только для чтения (read-only layers). Слои image работают следующим образом:

  • Каждый слой image является результатом одной команды в файле Dockerfile. Образ докера представляет собой сжатый (tar) файл, содержащий серию слоев.
  • Каждый дополнительный слой image включает только набор отличий от предыдущего слоя (попробуйте запустить для docker image команду docker history, которая выведет все его слои и те команды, которые их создало).

Пример Dockerfile:

FROM node:13.12.0alpine

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

Что такое docker container (контейнер)

Docker Container — это исполняемый экземпляр образа. Образ Docker плюс команда docker run image_name создает и запускает контейнер из образа.

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

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

Управление контейнерами. Схема Lifecycle of Docker Container

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

Пример схемы docker container lifecycle 1:

Пример схемы docker container lifecycle 2:

Create container

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

docker create name <containername> <imagename>

Run docker container

Запустите контейнер докера с требуемым образом и указанной командой / процессом. Флаг -d используется для запуска контейнера в фоновом режиме.

docker run it d name <containername> <imagename> bash 

Pause container

Используется для приостановки процессов, запущенных внутри контейнера.

docker pause <containerid/name> 

Unpause container

Используется для возобновления процессов внутри контейнера.

docker unpause <containerid/name> 

Start container

Запустите контейнер, если он находится в остановленном состоянии.

docker start <containerid/name> 

Stop container

Остановить контейнер и процессы, запущенные внутри контейнера:

docker stop <containerid/name> 

Чтобы остановить все запущенные контейнеры докеров

docker stop $(docker ps a q)

Restart container

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

docker restart <containerid/name> 

Kill container

Мы можем убить работающий контейнер.

docker kill <containerid/name> 

Destroy container

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

docker rm <containerid/name> 

Чтобы удалить все остановленные контейнеры докеров

docker rm $ (docker ps q f status = exited)

Что такое Docker Hub?

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

Как создать свой образ? Что такое Dockerfile?

Что такое Dockerfile?

  • Dockerfile — это текстовый файл конфигурации, написанный с использованием специального синтаксиса.
  • В нем описываются пошаговые инструкции по всем командам, которые необходимо выполнить для сборки образа Docker.
  • Команда docker build обрабатывает этот файл, создавая образ Docker в вашем локальном кэше образов, который затем можно запустить с помощью docker run команды или отправить в постоянный репозиторий образов (push).

Как создать Dockerfile?

Dockerfile создается в любом текстовом редакторе. Далее пишутся инструкции.

Пример dockerfile

Пример dockerfile для NGINX:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# Каждая инструкция в этом файле генерирует новый слой, который помещается в ваш локальный кеш docker image

# Строки, которым предшествует #, считаются комментариями и игнорируются

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

FROM ubuntu: latest

# Указываем, кто поддерживает docker image (автор)

LABEL Maintainer = «myname@somecompany.com»

# Обновляем образ до последних пакетов

RUN aptget update && aptget upgrade y

# Устанавливаем NGINX

RUN aptget install nginx y

# Выставить порт 80

EXPOSE 80

# Последний пункт — это команда для запуска NGINX в нашем контейнере

CMD [«nginx», «-g», «daemon off;»]

Команды Dockerfile

ADD — определяет файлы для копирования из файловой системы хоста в контейнер

ADD ./local/config.file /etc/service/config.file

CMD — это команда, которая будет запускаться при запуске контейнера

CMD [nginx, g, daemon off;]

ENTRYPOINT — устанавливает приложение по умолчанию, используемое каждый раз, когда контейнер создается из образа. Если используется вместе с CMD, вы можете удалить приложение и просто определить там аргументы

CMD Hello World!

ENTRYPOINT echo

ENV — установка / изменение переменных среды в контейнерах, созданных из образа

EXPOSE — Определите, какие порты контейнера открывать

FROM — Выберите базовый образ, чтобы построить новый образ поверх

LABEL Maintainer — необязательное поле, чтобы вы могли идентифицировать себя как maintainer этого образа. Это просто ярлык

LABEL maintainer=someone@xyz.xyz

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

RUN aptget update && aptget upgrade y && aptget install y nginx && rm rf/var/lib/apt/lists/*

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

VOLUME — создает точку монтирования в контейнере, связывая ее с файловыми системами, доступными хосту Docker. Новые тома заполняются уже существующим содержимым указанного места на image. Особенно уместно упомянуть, что определение томов в Dockerfile может привести к проблемам. Томами следует управлять с помощью команд docker-compose или docker run. Volumes не являются обязательными. Если у вашего приложения нет состояния (и большинство веб-приложений работают так), вам не нужно использовать тома. Volume требуются для баз данных, например, или для сохранения логов приложения.

WORKDIR — Определите рабочий каталог по умолчанию для команды, определенной в инструкциях «ENTRYPOINT» или «CMD».

Пример dockerfile для приложения flask app python

FROM python:3.6.4alpine3.6

ENV FLASK_APP=minitwit

COPY . /app

WORKDIR /app

RUN pip install editable .

RUN flask initdb

EXPOSE 5000

CMD [ «flask», «run», «—host=0.0.0.0» ]

Видео Tutorials — Dockerfile

Video: Dockerfile Tutorial — Docker in Practice

Видео: Docker создаем собственный образ

Видео: Dockerfile. Формат и создание образа контейнера

Что такое Docker Volume?

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

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

Таким образом, любое изменение файла внутри контейнера создает рабочую копию на уровне чтения-записи. Однако, когда контейнер останавливается или удаляется, этот уровень чтения-записи теряется.

При монтировании привязки (bind mount) используется файловая система хоста, но Docker Volumes встроены в Docker. Данные хранятся где-то в хранилище, подключенном к хосту — часто в локальной файловой системе:

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

В docker-compose.ymlvolumes может появляться в двух разных местах:

version: «3.7»

services:

  database:

    # …

    volumes: # Вложенный ключ. Настраивает тома для определенной службы.

volumes: # Ключ верхнего уровня. Объявляет тома, на которые можно ссылаться из нескольких сервисов.

  # …

Команды Docker Volume

Command Description
docker volume create Create a volume
docker volume inspect Display detailed information on one or more volumes
docker volume ls List volumes
docker volume prune Remove all unused local volumes
docker volume rm Remove one or more volumes

Подборка видео по Docker Volume

Docker Volumes explained in 6 minutes

Docker Volumes (Тома) урок 8

Attaching volumes to containers

Как взаимодействовать с контейнером?

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

Чтобы сопоставить порт на хосте с контейнером, нам нужно использовать флаг -p команды docker run:

docker run p <port_number_on_host>:<port_number_on_container> <image>

или

docker run v <порт_на_хосте>:<порт_в_контейнере> <образ>

Следующая команда запустит контейнер для mlflow и сопоставит порт 7000 этого контейнера с портом 7000 хоста докера:

docker run p 7000:7000 mlflow

Аналогичным образом будет работать контейнер для POSTGRESQL и порта 5432 этого контейнера в порт 5432 от DOCKER хоста:

docker run p 5432:5432 postgresql

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

docker run p 1234:5432 postgresql

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

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

docker container run p 8080:80 d nginx

Порт 80 контейнера Nginx доступен для внешнего мира через порт хоста 8080.

По умолчанию Docker предоставляет порты контейнера IP-адресу 0.0.0.0 (это соответствует любому IP-адресу в системе). Вы также можете указать Docker, какой IP-адрес нужно привязать. Это может быть 127.0.0.1 или другой IP-адрес.

Чтобы привязать порт 80 контейнера Docker к порту 8000 хост-системы и IP-адресу 127.0.0.1 (он же localhost), просто выполните следующую команду:

docker run d p 127.0.0.1:8000:80 nginx

Docker Networking

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

Docker Networking

Docker Networking Tutorial

Что такое Docker Compose?

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

Docker Compose позволяет записывать команды в docker-compose.yml файл для повторного использования. Интерфейс командной строки Docker Compose (cli) упрощает взаимодействие с вашим многоконтейнерным приложением. Docker Compose поставляется бесплатно с установленным вами Docker.

Схема работы Docker-Compose:

Docker-Compose in 12 Minutes

docker-compose.xml

docker-compose.yml — это файл Docker-Compose, который содежит инструкции, используемые для запуска и настройки сервисов (отдельных контейнеров нашего многоконтейнерного приложения).

Структура файла docker-compose.xml (источник — Руководство по Docker Compose для начинающих):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

# Файл docker-compose должен начинаться с тега версии.

# Мы используем «3» так как это — самая свежая версия на момент написания этого кода.

version: «3»

# Следует учитывать, что docker-composes работает с сервисами.

# 1 сервис = 1 контейнер.

# Сервисом может быть клиент, сервер, сервер баз данных…

# Раздел, в котором будут описаны сервисы, начинается с ‘services’.

services:

  # Как уже было сказано, мы собираемся создать клиентское и серверное приложения.

  # Это означает, что нам нужно два сервиса.

  # Первый сервис (контейнер): сервер.

  # Назвать его можно так, как нужно разработчику.

  # Понятное название сервиса помогает определить его роль.

  # Здесь мы, для именования соответствующего сервиса, используем ключевое слово ‘server’.

  server:

    # Ключевое слово «build» позволяет задать

    # путь к файлу Dockerfile, который нужно использовать для создания образа,

    # который позволит запустить сервис.

    # Здесь ‘server/’ соответствует пути к папке сервера,

    # которая содержит соответствующий Dockerfile.

    build: server/

    # Команда, которую нужно запустить после создания образа.

    # Следующая команда означает запуск «python ./server.py».

    command: python ./server.py

    # Вспомните о том, что в качестве порта в ‘server/server.py’ указан порт 1234.

    # Если мы хотим обратиться к серверу с нашего компьютера (находясь за пределами контейнера),

    # мы должны организовать перенаправление этого порта на порт компьютера.

    # Сделать это нам поможет ключевое слово ‘ports’.

    # При его использовании применяется следующая конструкция: [порт компьютера]:[порт контейнера]

    # В нашем случае нужно использовать порт компьютера 1234 и организовать его связь с портом

    # 1234 контейнера (так как именно на этот порт сервер

    # ожидает поступления запросов).

    ports:

       1234:1234

  # Второй сервис (контейнер): клиент.

  # Этот сервис назван ‘client’.

  client:

    # Здесь ‘client/ соответствует пути к папке, которая содержит

    # файл Dockerfile для клиентской части системы.

    build: client/

    # Команда, которую нужно запустить после создания образа.

    # Следующая команда означает запуск «python ./client.py».

    command: python ./client.py

    # Ключевое слово ‘network_mode’ используется для описания типа сети.

    # Тут мы указываем то, что контейнер может обращаться к ‘localhost’ компьютера.

    network_mode: host

    # Ключевое слово ‘depends_on’ позволяет указывать, должен ли сервис,

    # прежде чем запуститься, ждать, когда будут готовы к работе другие сервисы.

    # Нам нужно, чтобы сервис ‘client’ дождался бы готовности к работе сервиса ‘server’.

    depends_on:

       server

Пример сложного файла docker-compose.xml:

Если хотите реально разобраться в docker — очень рекомендую курс Docker и Docker Compose — Деплой проекта с нуля

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

version: ‘3’

services:

  frontend:

    build:

      dockerfile: Dockerfile.prod

      context: ./frontend

    container_name: dockerfrontend

    restart: unlessstopped

    command: serve s build l 3000

    networks:

       dockernetwork

  api:

    build: ./api

    container_name: dockerapi

    command: npm run start

    restart: unlessstopped

    environment:

       PORT=3001

       MONGO_URL=mongodb://api_db:27017/api

       AUTH_API_URL=http://auth:3002/api

    depends_on:

       api_db

    networks:

       dockernetwork

  auth:

    build: ./auth

    container_name: dockerauth

    command: npm run start

    restart: unlessstopped

    environment:

       PORT=3002

       MONGO_URL=mongodb://auth_db:27017/auth

       API_URL=http://api:3001/api

    depends_on:

       auth_db

    networks:

       dockernetwork

  api_db:

    image: mongo:latest

    container_name: dockerapidb

    volumes:

       mongodb_api:/data/db

    networks:

       dockernetwork

  auth_db:

    image: mongo:latest

    container_name: dockerauthdb

    volumes:

       mongodb_auth:/data/db

    networks:

       dockernetwork

  nginx:

    image: nginx:stablealpine

    container_name: dockernginx

    ports:

       «80:80»

    volumes:

       ./nginx/nginx.conf.prod:/etc/nginx/conf.d/nginx.conf

    depends_on:

       frontend

       api

       auth

    networks:

       dockernetwork

volumes:

  mongodb_api:

  mongodb_auth:

networks:

  dockernetwork:

    driver: bridge

Дополнительные подборки видео по Docker

Что такое Docker? Вечерняя школа Слёрма по Kubernetes.

Основы Docker. Большой практический выпуск

Docker Tutorial for Beginners [FULL COURSE in 3 Hours]

Docker-compose что это?

Примеры создания приложений с помощью Docker или Docker-Compose

Docker + ReactJS tutorial: Development to Production workflow + multi-stage builds + docker compose

Краткий экскурс в Linux

Базовый список команд Linux

1. Команда help
Запомнить все возможные параметры, которые можно использовать для команды, невозможно. Если вы не использовали команду ранее или в течение длительного времени, у вас есть возможность изучить возможные варианты, которые можно передать. Большинство команд поддерживают передачу справки в качестве опции и отображают небольшое сообщение о том, как использовать команду.

<command_name> help

Чтобы получить всю возможную помощь, есть команда man. Страница руководства (сокращенно man) — это документ, который иллюстрирует, что делает команда, возможные параметры, примеры использования и т. Д. Это вся помощь, которую вы можете получить для команды

man <command_name>

2. pwd: pwd печатает имя текущего рабочего каталога. Когда вы открываете терминал, вы попадаете в домашний каталог пользователя, под которым вы вошли в систему. pwdпечатает абсолютный путь. Он начинается с /корневого каталога файловой системы Linux.

3. ls: ls распечатывает все файлы, которые присутствуют в каталоге, в котором вы находитесь. Вы можете получить дополнительную информацию о файлах, а также увидеть скрытые файлы с помощью этой -al опции.

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

# takes you to your home directory (comment)

cd

# To navigate to the parent directory

cd ../

# To change to previous working directory

cd ~

5. mv: mv (расширяется при перемещении) используется для перемещения файлов / каталогов из location1 в location2. Его также можно использовать для переименования файла.

# Renaming file a.txt to b.txt

mv a.txt b.txt

# move file from directory test in your current directory to tmp

mv test/test.txt /tmp/test.txt

# move multiple files in your current directory to /tmp

mv a.txt b.txt c.txt /tmp

# move file from a dir A to dir B by specifying the absolute paths

mv /var/log/test.log /tmp/test.log

6. cp: скопируйте файлы из location1 в location2. Каталоги можно копировать с помощью -R опции.

# copy file from your home to directory to another location

cp test.txt /tmp/bckup

# copy contents of directories recursively

cp R test_dir /tmp/bckup

7. rm: rm (расширяется как remove) используется для удаления файла или каталога. При удалении файла нет отмены. Так что будьте осторожны, когда хотите что-то удалить

# rm a file in a location

rm /home/test_user/test.txt

# rm a directory that is empty

rm r <location_of_dir>

# rm a directory with contents in it

rm rf <location_of_dir>

8. mkdir: mkdir (расширенный как каталог make) используется для создания нового каталога в определенном месте.

# create a directory

mkdir test_dir

# create intermediate directory (test_directory) when creating a directory (test_directory_child)

mkdir p /home/test_user/test_directory/test_directory_child

9. rmdir: удалить каталог. Это альтернативная команда дляrm -rf

# delete a directory test_directory_child

rmdir /home/test_user/test_directory/test_directory_child

# Delete the intermediate directories in the path. It only works if # the intermediate directories don’t contain any other child

# directories other than the one specified

rmdir p test_dir/test_dir_child/test_dir_child2

10. cat: распечатывает содержимое файлов на терминале и возвращает обратно в командную строку. Существуют различные редакторы, которые вы можете использовать для просмотра содержимого файла (например, vim, nano и т. Д.), Но эта команда выводит содержимое в STDOUT (стандартный вывод).

# Print contents of a file.

cat test.sh

11. touch: Изменить file timestamps. Обновляет отметки времени в существующих файлах или создает файлы с текущей отметкой времени, если она не существует.

# Assuming file1.txt doesn’t exist, it creates a new file

touch file1.txt

12. sudo: Сокращение от SuperUser Do , эта команда помогает вам выполнять задачи, требующие административных разрешений. Однако не рекомендуется использовать эту команду случайным образом без причины, потому что любая ошибка, сделанная пользователем root, необратима.

# Read the contents of syslog

sudo cat /var/log/syslog

13. find: эта команда ищет в иерархии папок файл или каталог, соответствующий указанному имени или шаблону. Он выполняет рекурсивный поиск во всех каталогах вниз по дереву.

# find a file with name test.txt in a folder

find /home/test_user name test.txt

# find file of specific pattern recursively

find . type f name «*.sh» R

# find and remove multiple files following a same pattern

find . type f name «*.py» exec rm f {}

14.grep: эта команда печатает все строки в файле, соответствующие определенному шаблону.

# recursively grep for a pattern in a directory tree

grep r search_field /etc/

# search two different words

egrep w ‘x|y’ /home/test_user/*

15.df: Эта команда сообщает об использовании дискового пространства файловой системы.

# lists all the file system, use -a option in human readable format i.e., power of 1024

df ah

16. du: оценка использования файлового пространства. Он имеет различные параметры для отображения вывода в желаемом формате.

# Display disk usage of all files and directories in the current directory

du ah

# sum of sizes of files and directories in the directory specified

du sh /home/test_user

17. uname: Распечатать системную информацию. Есть несколько вариантов, которые можно передать, если вам нужна конкретная информация о системе, такая как версия ядра, тип процессора, аппаратная платформа и т. Д.

# Prints all the information about the system

uname a

18. lsblk: lsblk (Expanded as list block devices) используется для отображения всех блочных устройств в виде дерева. Он также предоставляет информацию о разделах, имеющихся на блочном устройстве.

NAME    MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT

sda       8:0    0  55.9G  0 disk

└─sda1    8:2    0  55.9G  0 part  /

sdb       8:16   0 111.8G  0 disk

└─sdb1    8:17   0 111.8G  0 part

19. hostname: распечатать / установить имя хоста машины. Только суперпользователь может обновить имя хоста

# print hostname of system

hostname

# set hostname

hostname set name <host_name>

20. tail: отображает последнюю часть файлов. По умолчанию, если файл передан, он печатает последние 10 строк

# output appended data as the file grows;

tail f /var/log/syslog

Linux File System/Structure Explained

Основы Ubuntu Linux: apt-get, bash, командная строка

Linux command line for beginners

Права Доступа и владения файлами и директориями

Установка Докера на Linux. Install Docker on Ubuntu 20.04

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

# Обновляем существующий список пакето

sudo apt update

# Далее устанавливаем пакеты, которые позволят apt использовать пакеты через HTTPS:

sudo apt install apttransporthttps cacertificates curl softwarepropertiescommon

# Далее добавим ключ GPG для официального репозитория Docker

curl fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add —

# Добавляем ремозиторий докер в источники apt

sudo addaptrepository «deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable»

# Обновляем базу данных пакетов и добавим в нее пакеты Docker из недавно добавленного репозитория

sudo apt update

# Далее проверим, что установка будет выполняться из репозитория Docker, а не из репозитория Ubuntu по умолчанию

aptcache policy dockerce

# Мы должны получить следующий ответ (номер версии Docker может отличаться):

# root@apache1superset:~# apt-cache policy docker-ce

# docker-ce:

#   Installed: (none)

#   Candidate: 5:20.10.6~3-0~ubuntu-focal

#   Version table:

#      5:20.10.6~3-0~ubuntu-focal 500

#         500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

#      5:20.10.5~3-0~ubuntu-focal 500

#         500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

#      5:20.10.4~3-0~ubuntu-focal 500

#         500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

#      5:20.10.3~3-0~ubuntu-focal 500

# …

# Далее устанавливаем докер командой (на доп.вопрос отвечаем «yes»)

sudo apt install dockerce

# Docker будет автоматически установлен, также запустится демон-процесс и будет активирован запуск при загрузке.

# Проверить статус докера можно командой (что он running/active):

sudo systemctl status docker

# Загружаем текущую стабильную версию Docker Compose

sudo curl L «https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m)» o /usr/local/bin/dockercompose

# Применяем разрешения для исполняемого файла к двоичному файлу

sudo chmod +x /usr/local/bin/dockercompose

# Чтобы протестировать docker-compose (установилась версия или нет), запустим команду

dockercompose version

Portainer — что это такое?

Portainer — это легкий пользовательский интерфейс управления, который позволяет легко управлять различными средами Docker и docker-containers. С помощью Portainer вы сможете в несколько кликов запустить на вашем сервере готовые контейнеры с популярным ПО и связать их между собой.

Описание с Github: Making Docker and Kubernetes management easy. На момент написания статьи 18.7k stars

Этот мощный набор инструментов с открытым исходным кодом, насчитывающий более полумиллиона постоянных пользователей, позволяет легко создавать и управлять контейнерами в Docker, Swarm, Kubernetes и Azure ACI.

По умолчанию мы управляем Docker через командную строку. Portainer предоставляет отличный и очень информативный пользовательский интерфейс для управления всеми аспектами Docker. Это диаграммы и информационные панели, которые предоставляют диаграммы использования ресурсов контейнера в реальном времени. Запуск и управление контейнерами и стеками можно выполнить несколькими щелчками мыши.

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

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

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

Здесь нам открывается вся суть инструмента:

  • Можно создать в несколько кликов из шаблонов приложения в докере

  • Можно управлять сетью, контейнерами.
  • Также можно создавать и настраивать Volumes:

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

Установка Portainer внутри Docker

#portainer install

sudo docker volume create portainer_data

docker run d p 8000:8000 p 9443:9443 name portainer

    restart=always

    v /var/run/docker.sock:/var/run/docker.sock

    v portainer_data:/data

    portainer/portainerce:2.9.3

Далее нужно перейти по ссылке https://68.133.234.42:9443/ (замените 68.133.234.42 на ваш адрес).

GitHub Actions — CI/CD Pipeline with Docker

Использованные источники для подготовки статьи и другие полезные статьи

  • https://medium.com/@BeNitinAgarwal/lifecycle-of-docker-container-d2da9f85959
  • Микросервисы и контейнеры Docker. Парминдер Сингх Кочер. Addison-Wesley. ДМК
  • Learn Enough Docker to be Useful
  • Building Docker Images with Dockerfiles
  • [Docker] Основы Docker: Dockerfile и docker-compose.yml
  • 20 Basic Linux Commands for Beginners!

Автор статьи, перевод которой мы сегодня публикуем, говорит, что она предназначена для тех разработчиков, которые хотят изучить Docker Compose и идут к тому, чтобы создать своё первое клиент-серверное приложение с использованием Docker. Предполагается, что читатель этого материала знаком с основами Docker. Если это не так — можете взглянуть на эту серию материалов, на эту публикацию, где основы Docker рассмотрены вместе с основами Kubernetes, и на эту статью для начинающих.

Руководство по Docker Compose для начинающих

Что такое Docker Compose?

Docker Compose — это инструментальное средство, входящее в состав Docker. Оно предназначено для решения задач, связанных с развёртыванием проектов.

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

Как узнать, нужно ли вам, при развёртывании некоего проекта, воспользоваться Docker Compose? На самом деле — очень просто. Если для обеспечения функционирования этого проекта используется несколько сервисов, то Docker Compose может вам пригодиться. Например, в ситуации, когда создают веб-сайт, которому, для выполнения аутентификации пользователей, нужно подключиться к базе данных. Подобный проект может состоять из двух сервисов — того, что обеспечивает работу сайта, и того, который отвечает за поддержку базы данных.

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

Разница между Docker и Docker Compose

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

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

Руководство по Docker Compose для начинающих
Docker (отдельный контейнер) и Docker Compose (несколько контейнеров)

Типичный сценарий использования Docker Compose

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

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

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

К сожалению, нечто вроде Docker Compose вы не использовали. Поэтому вам придётся переносить и перенастраивать сервисы по одному, надеясь на то, что вы, в процессе этой работы, ничего не забудете.

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

Разработка клиент-серверного приложения с использованием Docker Compose

Теперь, когда вы знаете о том, для чего мы собираемся использовать Docker Compose, пришло время создать ваше первое клиент-серверное приложение с использованием этого инструмента. А именно, речь идёт о разработке небольшого веб-сайта (сервера) на Python, который умеет выдавать файл с фрагментом текста. Этот файл у сервера запрашивает программа (клиент), тоже написанная на Python. После получения файла с сервера программа выводит текст, хранящийся в нём, на экран.

Обратите внимание на то, что мы рассчитываем на то, что вы владеете основами Docker, и на то, что у вас уже установлена платформа Docker.

Приступим к работе над проектом.

▍1. Создание проекта

Для того чтобы построить ваше первое клиент-серверное приложение, предлагаю начать с создания папки проекта. Она должна содержать следующие файлы и папки:

  • Файл docker-compose.yml. Это файл Docker Compose, который будет содержать инструкции, необходимые для запуска и настройки сервисов.
  • Папка server. Она будет содержать файлы, необходимые для обеспечения работы сервера.
  • Папка client. Здесь будут находиться файлы клиентского приложения.

В результате содержимое главной папки вашего проекта должно выглядеть так:

.
├── client/
├── docker-compose.yml
└── server/
2 directories, 1 file

▍2. Создание сервера

Тут мы, в процессе создания сервера, затронем некоторые базовые вещи, касающиеся Docker.

2a. Создание файлов

Перейдите в папку server и создайте в ней следующие файлы:

  • Файл server.py. В нём будет находиться код сервера.
  • Файл index.html. В этом файле будет находиться фрагмент текста, который должно вывести клиентское приложение.
  • Файл Dockerfile. Это — файл Docker, который будет содержать инструкции, необходимые для создания окружения сервера.

Вот как должно выглядеть содержимое вашей папки server/:

.
├── Dockerfile
├── index.html
└── server.py
0 directories, 3 files

2b. Редактирование Python-файла.

Добавим в файл server.py следующий код:

#!/usr/bin/env python3

# Импорт системных библиотек python.
# Эти библиотеки будут использоваться для создания веб-сервера.
# Вам не нужно устанавливать что-то особенное, эти библиотеки устанавливаются вместе с Python.

import http.server
import socketserver

# Эта переменная нужна для обработки запросов клиента к серверу.

handler = http.server.SimpleHTTPRequestHandler

# Тут мы указываем, что сервер мы хотим запустить на порте 1234. 
# Постарайтесь запомнить эти сведения, так как они нам очень пригодятся в дальнейшем, при работе с docker-compose.

with socketserver.TCPServer(("", 1234), handler) as httpd:

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

   httpd.serve_forever()

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

2c. Редактирование HTML-файла

В файл index.html добавим следующий текст:

Docker-Compose is magic!

Этот текст будет передаваться клиенту.

2d. Редактирование файла Dockerfile

Сейчас мы создадим простой файл Dockerfile, который будет отвечать за организацию среды выполнения для Python-сервера. В качестве основы создаваемого образа воспользуемся официальным образом, предназначенным для выполнения программ, написанных на Python. Вот содержимое Dockerfile:

# На всякий случай напоминаю, что Dockerfile всегда должен начинаться с импорта базового образа.
# Для этого используется ключевое слово 'FROM'.
# Здесь нам нужно импортировать образ python (с DockerHub).
# В результате мы, в качестве имени образа, указываем 'python', а в качестве версии - 'latest'.

FROM python:latest

# Для того чтобы запустить в контейнере код, написанный на Python, нам нужно импортировать файлы 'server.py' и 'index.html'.
# Для того чтобы это сделать, мы используем ключевое слово 'ADD'.
# Первый параметр, 'server.py', представляет собой имя файла, хранящегося на компьютере.
# Второй параметр, '/server/', это путь, по которому нужно разместить указанный файл в образе.
# Здесь мы помещаем файл в папку образа '/server/'.

ADD server.py /server/
ADD index.html /server/

# Здесь мы воспользуемся командой 'WORKDIR', возможно, новой для вас.
# Она позволяет изменить рабочую директорию образа.
# В качестве такой директории, в которой будут выполняться все команды, мы устанавливаем '/server/'.

WORKDIR /server/

Теперь займёмся работой над клиентом.

▍3. Создание клиента

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

3a. Создание файлов

Перейдите в папку вашего проекта client и создайте в ней следующие файлы:

  • Файл client.py. Тут будет находиться код клиента.
  • Файл Dockerfile. Этот файл играет ту же роль, что и аналогичный файл в папке сервера. А именно, он содержит инструкцию, описывающую создание среды для выполнения клиентского кода.

В результате ваша папка client/ на данном этапе работы должна выглядеть так:

.
├── client.py
└── Dockerfile
0 directories, 2 files

3b. Редактирование Python-файла

Добавим в файл client.py следующий код:

#!/usr/bin/env python3

# Импортируем системную библиотеку Python.
# Она используется для загрузки файла 'index.html' с сервера.
# Ничего особенного устанавливать не нужно, эта библиотека устанавливается вместе с Python.

import urllib.request

# Эта переменная содержит запрос к 'http://localhost:1234/'.
# Возможно, сейчас вы задаётесь вопросом о том, что такое 'http://localhost:1234'.
# localhost указывает на то, что программа работает с локальным сервером.
# 1234 - это номер порта, который вам предлагалось запомнить при настройке серверного кода.

fp = urllib.request.urlopen("http://localhost:1234/")

# 'encodedContent' соответствует закодированному ответу сервера ('index.html').
# 'decodedContent' соответствует раскодированному ответу сервера (тут будет то, что мы хотим вывести на экран).

encodedContent = fp.read()
decodedContent = encodedContent.decode("utf8")

# Выводим содержимое файла, полученного с сервера ('index.html').

print(decodedContent)

# Закрываем соединение с сервером.

fp.close()

Благодаря этому коду клиентское приложение может загрузить данные с сервера и вывести их на экран.

3c. Редактирование файла Dockerfile

Как и в случае с сервером, мы создаём для клиента простой Dockerfile, ответственный за формирование среды, в которой будет работать клиентское Python-приложение. Вот код клиентского Dockerfile:

# То же самое, что и в серверном Dockerfile.

FROM python:latest

# Импортируем 'client.py' в папку '/client/'.

ADD client.py /client/

# Устанавливаем в качестве рабочей директории '/client/'.

WORKDIR /client/

▍4. Docker Compose

Как вы могли заметить, мы создали два разных проекта: сервер и клиент. У каждого из них имеется собственный файл Dockerfile. До сих пор всё происходящее не выходит за рамки основ работы с Docker. Теперь же мы приступаем к работе с Docker Compose. Для этого обратимся к файлу docker-compose.yml, расположенному в корневой папке проекта.

Обратите внимание на то, что тут мы не стремимся рассмотреть абсолютно все команды, которые можно использовать в docker-compose.yml. Наша главная цель — разобрать практический пример, дающий вам базовые знания по Docker Compose.

Вот код, который нужно поместить в файл docker-compose.yml:

# Файл docker-compose должен начинаться с тега версии.
# Мы используем "3" так как это - самая свежая версия на момент написания этого кода.

version: "3"

# Следует учитывать, что docker-composes работает с сервисами.
# 1 сервис = 1 контейнер.
# Сервисом может быть клиент, сервер, сервер баз данных...
# Раздел, в котором будут описаны сервисы, начинается с 'services'.

services:

  # Как уже было сказано, мы собираемся создать клиентское и серверное приложения.
  # Это означает, что нам нужно два сервиса.
  # Первый сервис (контейнер): сервер.
  # Назвать его можно так, как нужно разработчику.
  # Понятное название сервиса помогает определить его роль.
  # Здесь мы, для именования соответствующего сервиса, используем ключевое слово 'server'.

  server:
 
    # Ключевое слово "build" позволяет задать
    # путь к файлу Dockerfile, который нужно использовать для создания образа,
    # который позволит запустить сервис.
    # Здесь 'server/' соответствует пути к папке сервера,
    # которая содержит соответствующий Dockerfile.

    build: server/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./server.py".

    command: python ./server.py

    # Вспомните о том, что в качестве порта в 'server/server.py' указан порт 1234.
    # Если мы хотим обратиться к серверу с нашего компьютера (находясь за пределами контейнера),
    # мы должны организовать перенаправление этого порта на порт компьютера.
    # Сделать это нам поможет ключевое слово 'ports'.
    # При его использовании применяется следующая конструкция: [порт компьютера]:[порт контейнера]
    # В нашем случае нужно использовать порт компьютера 1234 и организовать его связь с портом
    # 1234 контейнера (так как именно на этот порт сервер 
    # ожидает поступления запросов).

    ports:
      - 1234:1234

  # Второй сервис (контейнер): клиент.
  # Этот сервис назван 'client'.

  client:
    # Здесь 'client/ соответствует пути к папке, которая содержит
    # файл Dockerfile для клиентской части системы.

    build: client/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./client.py".
 
    command: python ./client.py

    # Ключевое слово 'network_mode' используется для описания типа сети.
    # Тут мы указываем то, что контейнер может обращаться к 'localhost' компьютера.

    network_mode: host

    # Ключевое слово 'depends_on' позволяет указывать, должен ли сервис,
    # прежде чем запуститься, ждать, когда будут готовы к работе другие сервисы.
    # Нам нужно, чтобы сервис 'client' дождался бы готовности к работе сервиса 'server'.
 
    depends_on:
      - server

▍5. Сборка проекта

После того, как в docker-compose.yml внесены все необходимые инструкции, проект нужно собрать. Этот шаг нашей работы напоминает использование команды docker build, но соответствующая команда имеет отношение к нескольким сервисам:

$ docker-compose build

▍6. Запуск проекта

Теперь, когда проект собран, пришло время его запустить. Этот шаг нашей работы соответствует шагу, на котором, при работе с отдельными контейнерами, выполняется команда docker run:

$ docker-compose up

После выполнения этой команды в терминале должен появиться текст, загруженный клиентом с сервера: Docker-Compose is magic!.

Как уже было сказано, сервер использует порт компьютера 1234 для обслуживания запросов клиента. Поэтому, если перейти в браузере по адресу http://localhost:1234/, в нём будет отображена страница с текстом Docker-Compose is magic!.

Полезные команды

Рассмотрим некоторые команды, которые могут вам пригодиться при работе с Docker Compose.

Эта команда позволяет останавливать и удалять контейнеры и другие ресурсы, созданные командой docker-compose up:

$ docker-compose down

Эта команда выводит журналы сервисов:

$ docker-compose logs -f [service name]

Например, в нашем проекте её можно использовать в таком виде: $ docker-compose logs -f [service name].

С помощью такой команды можно вывести список контейнеров:

$ docker-compose ps

Данная команда позволяет выполнить команду в выполняющемся контейнере:

$ docker-compose exec [service name] [command]

Например, она может выглядеть так: docker-compose exec server ls.

Такая команда позволяет вывести список образов:

$ docker-compose images

Итоги

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

Уважаемые читатели! Пользуетесь ли вы Docker Compose в своих проектах?

Понравилась статья? Поделить с друзьями:
  • Стиральная машина lg direct drive 5kg f1068ld инструкция
  • Гепасейф суспензия для собак инструкция по применению
  • Метформин канон 1000 инструкция по применению при диабете
  • Должностная инструкция начальника участка электромонтажных работ скачать
  • Ибалгин мазь инструкция по применению цена отзывы аналоги цена