Главная / Блог / Docker PART 2

Docker.
Тома,
контроль версий,
Docker Hub,
Docker Compose.

Docker. Тома, контроль версий, Docker Hub, Docker Compose.

Smartiqa Article docker
  • Дата: 21 июня 2022
  • Автор: Михаил Макарик

1. Доступ к файлам и ресурсам с помощью томов

Работа с изолированными контейнерами при помощи Docker является удобной и простой, но может иметь недостаток: все сгенерированные ими данные автоматически исчезают в момент удаления. Предположим, мы делали некоторые расчеты, которые хотелось бы сохранить. Однако, это по умолчанию невозможно. Естественно, имеются решения, помогающие решить указанную проблему (и не только):
  1. Копирование (команда cp)
  2. Тома (volumes)
  3. Совместные каталоги (bind mounts)

Охарактеризуем каждое:

1.1. Использование цикла For

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

Далее активируем контейнер Python в интерактивном и обособленном режиме (чтобы не видеть консоль интерпретатора). Скопируем данный документ в контейнер в корневую директорию. Загрузим файл обратно на наш ПК с новым именем.
Пример – Терминал

# Запускаем контейнер с Питоном
> docker run -it --rm -d python

# Получаем его имя
> docker ps -a
inspiring_sammet 

#Перемещаем файл в запущенный контейнер 
> docker cp ./temp.txt inspiring_sammet:/temp.txt

Скачиваем его обратно под новым именованием
>docker cp inspiring_sammet:/temp.txt ./downloaded.txt

Если теперь проверить папку на нашей машине, то этот документ в ней появится.

1.2. Тома

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

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

Анонимные тома, обычно, создаются в Dockerfile (его содержимое представлено ниже).
Dockerfile

FROM python:alpine3.9
WORKDIR /datas
COPY ./main.py /data_folder
VOLUME ["/datas"]
CMD ["python", "main.py"]
Напишем простой скрипт main.py с нижеследующим кодом:
Пример – IDE

data = input('Напишите что-нибудь: ')

with open('data.txt', 'a', encoding='utf-8') as file:
    print(data, file=file)

with open('data.txt', 'r', encoding='utf-8') as file:
    print(file.read())
Создадим образ, запустим контейнер, а затем повторим его работу еще раз, чтобы убедиться, что данные в документе data.txt сохраняются.
Пример – Терминал

# Формируем образ с именем «data»
> docker build . -t data
# Запускаем его в интерактивном режиме
> docker run -it data
Напишите что-нибудь: 555
# Узнаем его имя
> docker ps -a
silly_feistel
# Повторно стартуем контейнер
> docker start -i silly_feistel
Напишите что-нибудь: 111
555
111
После удаления контейнера вся информация уничтожается.

Именованные тома задаются после команды run или volume. Сначала создадим его с именем my_data, а потом свяжем с контейнером из примера выше. Нужно лишь подправить Dockerfile (удалить строчку VOLUME) и пересоздать образ.
Пример – Терминал

# Создаем именованный том
> docker volume create my_data

# Проверяем его наличие
> docker volume ls
DRIVER    VOLUME NAME
local     my_data

# Формируем образ «data»
> docker build . -t data

# Запускаем контейнер с автоматическим удалением после работы
> docker run -it --rm -v my_data:/data_folder data
Напишите что-нибудь: поле
поле

# Еще раз активируем контейнер (он будет носить другое имя) из того же образа
> docker run -it --rm -v my_data:/data_folder data
Напишите что-нибудь: золотое
поле
золотое
Место хранения обоих типов томов мы практически не контролируем и не имеем к ним прямого доступа. Docker сам «решает» эту задачу

Читайте также

1.3. Совместные каталоги и файлы

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

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

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

Сделаем совместный файл data.txt (он должен находиться в директории запуска терминала). Предварительно в Docker Desktop в настройках -> Resources -> File Sharing обозначаем каталог, в котором расположен данный документ (иначе может возникнуть ошибка).
Пример – Терминал

Осуществляем монтирование
> docker run -it --rm -v "C:/Users/Mik/Desktop/pyProject/data.txt:/datas/data.txt" data
> Напишите что-нибудь: 123
123
Если открыть файл на ПК, то в нем появится строка 123. Добавим еще одну строку вручную 505 и повторим запуск контейнера.
Пример Терминал

> docker run -it --rm -v "C:/Users/Mik/Desktop/pyProject/data.txt:/datas/data.txt" data
> Напишите что-нибудь: 321
123
505
321
Подытожим
Как видно, Docker представляет широкий набор возможностей для совместного пользования файлами, переносов их, а также хранения данных даже после ликвидации контейнеров.

2. Docker Hub. Контроль версий.
Совместная разработка.

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

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

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

Чтобы получить доступ к репозиторию, необходимо создать там аккаунт (https://hub.docker.com). Теперь у нас имеется возможность не только скачивать чужие образы, но и загружать собственные.

Сформируем свой образ с именем days, который будет включать, помимо версии Python 3.9, файл main.py со следующим кодом.
main.py

from datetime import datetime

now_date = datetime.now()
your_birth = (int(num) for num in input('Введите свою дату рождения в формате "ГОД МЕСЯЦ ДЕНЬ": ').split())
birth_date = datetime(*your_birth)
days = now_date - birth_date
if days.days >= 0:
    print(f'С момента вашего рождения прошло дней: {days.days}')
else:
    print(f'Оказывается, вы еще не родились!')

В Dockerfile будут такие инструкции:
Dockerfile

FROM python:alpine3.9
WORKDIR /days
COPY ./main.py /days
CMD ["python", "main.py"]
Тут показано, что мы используем минимальную по размеру версию Python (alpine), создаем директорию days, в которую помещаем скрипт main.py. При запуске контейнера в интерактивном режиме этот скрипт активируется. Как видно, приложение высчитывает количество дней, прошедших с момента рождения любого человека.

Скомпонуем образ с именем my_days. Чтобы запустить контейнер на его основе, используем интерактивный режим.
Пример – Терминал

> docker build . -t my_days
> docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
my_days      latest    b0383074de33   18 minutes ago   98.5MB
> docker run -it --rm my_days
> Введите свою дату рождения в формате "ГОД МЕСЯЦ ДЕНЬ": 1933 12 19
С момента вашего рождения прошло дней: 31923
Так как программа исполнилась, она завершает свою работу, а контейнер уничтожается.

Следующая задача - поделиться нашим творением с другими программистами. Это можно сделать двумя способами:
  1. Передать Dockerfile и скрипт (при больших проектах это не очень рационально);
  2. Поделиться собственным образом.

О втором варианте и поговорим. В первую очередь, на сайте Docker Hub нужно создать репозиторий (https://hub.docker.com/repositories). Даем ему определенное имя (например, my_days).

Для добавления образа в хранилище потребуется залогиниться через терминал (это делается единожды).
Пример – Терминал

> docker login
> Username: 
> Password:
Login Succeeded

В следующие разы при входе в свой аккаунт нам не потребуется вводить имя и пароль, а достаточно прописать команду авторизации. Для выхода из учетной записи (чужой компьютер или требуется войти в другую учетку) применяется команда:
Пример – Терминал

> docker logout
Removing login credentials for https://index.docker.io/v1/
Важно, чтобы имя образа совпадало с тем, который мы создали на сайте с учетом имени пользователя (так, если ваш аккаунт называется doсker_tester, то наименование образа будет таким: doсker_tester/ my_days). В данный момент у нас его нет, поэтому просто переименуем старый (при помощи команды tag). Для загрузки образа используется инструкция push.
Пример – Терминал

> docker tag my_days:latest doсker_tester/my_days
> docker images
doсker_tester/my_days   latest    b0383074de33   54 minutes ago   98.5MB
> docker push doсker_tester/my_days
Docker: создание собственного образа
Docker: создание собственного образа
Если теперь зайти на страницу своих образов, то мы там увидим только что созданный образ с тегом latest (назначается по умолчанию). С этого момента он доступен не только вам, но и всем другим пользователям Docker. Можно создавать и приватные образы, закрытые от остальных (но за отдельную плату).

3. Docker Compose. Управление несколькими контейнерами.

Проект обычно состоит из множества инструментов (скрипты, исполняемые файлы, базы данных и т.п.). «Пихать» все в один образ - плохая практика. А когда их становится несколько - запускать каждый отдельно очень неудобно и затратно по времени.

Docker Compose – инструмент, заменяющий множественный вывод команд run и build. Необходимо сформировать только 1 конфигурационный файл и вся композиция приложения начнет действовать.

Все зависимости и команды прописываются в YAML-файле (расширение .yml). Тема довольно сложная, но для понимания ее возможностей создадим простой проект, состоящий из двух инструментов:
  1. Python (отвечает за работу программы) и
  2. Redis (хранилище данных).

Создайте файл проекта (с любым именем), куда поместите скрипт app.py следующего содержания:
app.py

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)


def count_visits():
    return cache.incr('visits')


@app.route('/')
def greet():
    return f'Привет! Это твой визит номер {count_visits()}'
Не забываем прописать зависимости в requirements.txt:
requirements.txt

click==8.0.0
colorama==0.4.4
Flask==2.0.0
itsdangerous==2.0.0
Jinja2==3.0.0
MarkupSafe==2.0.0
redis==3.5.3
Werkzeug==2.0.0
Вторым этапом обозначаем зависимости Python-приложения в Dockerfile:
Dockerfile

FROM python:alpine3.9
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
После этого прописываем все требуемые сервисы в docker-compose.yml.
docker-compose.yml

version: "3.8"
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  redis:
    image: "redis:alpine"
Redis будет взят из официального репозитория, а на основании Dockerfile создастся образ web с Python-приложением. Осталось только запустить compose:
Пример – Терминал

> docker-compose up
Creating network "pyproject_default" with the default driver
Building web
После активации сервера нужно заходить в браузере на адрес localhost:5000 и после каждого обновления страницы счетчик посещений будет увеличиваться.
С помощью Docker'a можно получать доступ к каталогам и файлам как внутри контейнеров, так и на рабочей машине. Для упрощения разработки приложений удобно пользоваться репозиторием, чтобы создавать собственные образы и делиться ими с другими программистами. Управление множественными контейнерами осуществляется средствами Docker Compose.

При дальнейшем изучении темы докеризации следует обратить внимание на оркестратор Kubernetes.
21 ИЮНЯ / 2022
Как вам материал?

Читайте также