Создание среды AWS Boto3 на Python с Docker Compose



Книга Создание среды AWS Boto3 на Python с Docker Compose



Вступление


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



Skillfactory.ru


Что будем создавать?


Boto3, cреду Python с изолированными контейнерами разработки и продакшена.


Понадобится:



  1. 3 файла Dockerfile для сборки 3 образов Docker.

  2. 3 контейнера Docker: 1 для разработки и 2 для продакшена.

  3. 2 виртуальные сети для разработки и продакшена: доступ контейнера разработки к продакшену/взаимодействие с ним исключается.

  4. Файл Docker Compose, где все это оркестрируется одной командой.


Необходимые условия



  1. Учетная запись Docker Hub.

  2. Знание файловых систем и команд Linux.

  3. Базовые знания о контейнерах, образах Docker, командах CLI.

  4. Доступ к инструменту командной строки.

  5. IDE, например VS Code или Cloud9.




Создание учетной записи Docker Hub и установка Docker


Создаем учетную запись


Docker Hub  —  это платформа с открытым исходным кодом для управления всеми приложениями и ресурсами Docker, в том числе образами. Когда создаются контейнеры и определяется рабочий образ/операционная система, в Docker образы извлекаются из Docker Hub. Берутся надежные официальные образы Centos, Ubuntu, NGINX, Alpine и т. д. или на основе любого из них собирается собственный образ и загружается на Hub для легкого доступа и совместного использования.



Устанавливаем Docker


Простейший способ установить Docker на локальный компьютер с Mac, Windows или Linux  —  приложение Docker Desktop. Пошагово устанавливаем его и авторизуемся со своим именем пользователя/паролем в Docker Hub.



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



Чтобы установить Docker на сервер Linux, установите через командную строку Docker engine. Инструкции по установке  —  в официальной документации Docker.



Расширения VS Code


Чтобы упростить распознавание файлов Dockerfile/Docker Compose и подсветку синтаксиса, установите эти расширения:



Установив Docker на хост-машине, находим зеленый логотип внизу приложения и запускаем команду docker --version:




Docker готов к работе.


Настройка файла


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



Я создал папку boto3_env, которая будет корневым каталогом хоста и клонированным репозиторием из Github. Внутри нее три подкаталога: development, productionA и productionB.


В development добавил Python-скрипты, связанные с AWS Boto3.


Файлы Dockerfile и docker-compose создадим потом.


Файл требований (необязательно)


Упакуем все необходимые зависимости Python в файл requirements.txt. Затем, чтобы установить их в образе Docker, укажем его в Dockerfile.



Skillfactory.ru

Чтобы создать этот файл, устанавливаем на компьютере python и pip, с помощью cd переходим в корневой каталог boto_env и запускаем:


pip freeze > requirements.text


Boto3 включен в этот файл.


Создание образов


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


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


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


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



  • FROM: базовый образ, например Ubuntu, Alpine, Centos, NGINX и т. д.

  • RUN: серия команд оболочки, например установка/обновление пакетов, создание каталогов и т. д., запускаемых во время сборки.

  • COPY/ADD: копирование файлов из каталога хоста в образ/контейнер.

  • WORKDIR: создание/изменение рабочего каталога образа/контейнера.

  • CMD: команда(-ы) времени выполнения, исполняемая(-ые) при запуске контейнера, т. е. запуске веб-сервера/приложения.


Образ среды разработки


Создадим в каталоге хоста development новый файл Dockerfile. Расширения не требуются. Docker «умеет» находить это имя файла, и в Docker выполнится сборка образа.


Начнем с определения базового образа как основы всего. Создавая среду Python, имеет смысл использовать удобный официальный образ Python на Docker Hub.



FROM python:3.9-alpine3.17

Выбираю образ Alpine, сверхлегкого  —  всего 5 Мб  —  дистрибутива Linux. Выбирайте версию. Все версии  —  в разделе tags на странице образа.



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



Для сохранения легковесности образы Docker обычно урезаются, поэтому в них могут отсутствовать ожидаемые базовые пакеты. Командой RUN запустим update и установим нужные нам пакеты curl, bash, git, unzip и iputils:


RUN apk update \
&& apk add bash \
&& apk add curl zip git unzip iputils

Прежде чем выполнять следующую команду, убеждаемся в успешном выполнении предыдущей, разделяя их символом \ и применяя оператор &&. При переходе от одного образа к другому в зависимости от базового дистрибутива Linux эти команды отличаются: yum, apt-get, apk, npm и т. д.


Запустим команду для установки AWS CLI:


RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&& ./aws/install -i /usr/local/aws-cli -b /usr/local/bin \
&& rm awscliv2.zip


Все эти команды можно поместить в один слой RUN, но у меня это не получилось. В Docker CLI отличная обратная связь с указанием ошибок и слоя, в котором они случились. Так что в разделении команд есть польза. Но будьте осторожны: от добавления слоев увеличиваются размер образа и время сборки.



Теперь создадим/поменяем рабочий каталог образа и скопируем requirements.txt из каталога хоста в образ:


COPY <host_directory_filepath> <image_directory_path>


WORKDIR /home/app

COPY requirements.txt .

Здесь символом . указывается текущий рабочий каталог /home/app.


Создадим другой слой RUN и с помощью pip установим зависимости из requirements.txt. Затем скопируем все файлы из папки development в рабочий каталог образа:


RUN pip install -r requirements.txt

COPY ./development .

Дальше создаем слой CMD для исполнения определенной команды/команд во время выполнения при создании или запуске контейнера. Используется это в основном для выполнения процессов при запуске приложения. Но в нашей среде нет процессов для «выполнения», поэтому нужно включить эту команду для продолжения работы контейнера при запуске. Если этого не сделать, контейнер остановится сразу после своего запуска.


CMD ["tail", "-f", "/dev/null"]

Подробнее о Dockerfile  —  в официальной документации.


Вот весь Dockerfile:


FROM python:3.9-alpine3.17

#обновляемся, устанавливаем curl, git, zip/unzip
RUN apk update \
&& apk add bash \
&& apk add curl zip git unzip iputils

#устанавливаем aws cli
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&& ./aws/install -i /usr/local/aws-cli -b /usr/local/bin \
&& rm awscliv2.zip

#создаем/меняем рабочий каталог
WORKDIR /home/app

#копируем файл требований
COPY requirements.txt .

#устанавливаем зависимости
RUN pip install -r requirements.txt

#копируем все файлы
COPY ./development .

CMD ["tail", "-f", "/dev/null"]

Протестируем: таков ли образ, как ожидалось. В командной строке переходим в корневой каталог boto3_env и собираем образ test-dev командой docker image build:


docker image build -t test-dev -f ./development/Dockerfile .

Dockerfile нет в корневой папке, поэтому путь к файлу указываем тегом -f:




В Docker CLI отличная обратная связь относительно хода выполнения: мы четко знаем, что и когда случается. Каждый слой становится «этапом» в процессе сборки.


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


docker container run -d --name dev test_dev

docker exec -it dev bash


Теперь все как надо: рабочий каталог корректно задан как /home/app, все файлы из папки хоста development перенесены.


В корневом каталоге контейнера видим, что AWS CLI установлен:



Образы среды продакшена


Создадим два образа среды продакшена. Этапы те же, но вместо копирования файлов  —  клонирование репозитория GitHub прямо в образ.


В каталоге хоста productionA создаем другой Dockerfile:


FROM python:3.9-alpine3.17
#обновляемся, устанавливаем curl, git, zip/unzip

RUN apk update \
&& apk add bash \
&& apk add curl zip git unzip iputils

#устанавливаем aws cli
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&& ./aws/install -i /usr/local/aws-cli -b /usr/local/bin \
&& rm awscliv2.zip

WORKDIR /home/app

COPY requirements.txt .

RUN pip install -r requirements.txt \
&& git clone https://github.com/aalokt89/LUIT_python

CMD ["tail", "-f", "/dev/null"]

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


Собираем образ, указав корректный путь к Dockerfile:


docker image build -t test_prod_a -f ./productionA/Dockerfile .


Снова создаем контейнер с этим образом и подключаемся для проверки его работоспособности:



Повторяем этот этап для финального образа среды productionB, но с другим репозиторием GitHub.


Оркестрируем и автоматизируем


С файлами Dockerfile создавать образы легко. Но что если у нас несколько и даже десятки контейнеров? Делать это вручную из командной строки  —  сущий кошмар.


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


Ею создается docker-compose.yml  —  практически конфигурационный файл, написанный на YAML. В нем для Docker указывается, какие контейнеры создавать: с какими образами, сетями, томами, переменными среды и т. д.  —  причем четко, организованно и очень быстро.


Создание файла Compose


В корневом каталоге хоста boto3-env создаем файл docker-compose.yml.


Вот базовая структура файла Docker Compose:


Version: "3"

services:
service_name1:
image: image_name
ports: 3000:80
volumes:

service_name2:
image: image_name

service_name2:
image: image_name

volumes:
volume1:
volume2:

networks:
network1:
network2:

Не все атрибуты обязательны, нужны как минимум service_name и image.


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


Service 1: dev


Начнем с контейнера, в котором размещается среда разработки dev:


Version: "3"

services:
dev:
build:
context: .
dockerfile: ./development/Dockerfile
image: boto3_dev
environment:
ENVIRONMENT: dev
volumes:
- type: bind
source: ./development
target: /home/app
networks:
- dev_net

networks:
dev_net:
prod_net:

Разберемся, что здесь происходит:



  • dev: название контейнера.

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

  • image: название нового образа или название и версия имеющегося образа.

  • environment: (необязательно) контейнерам присваиваются переменные среды́, присвоим этому переменную dev.

  • volumes: (необязательно) определяем bind-монтирование каталогов с хоста для контейнера dev. Хотя при создании образа мы скопировали все из каталога разработки хоста, для обновления содержимого приходилось бы каждый раз пересобирать этот образ. Монтирование каталогов с хоста  —  отличный способ получать на уровне контейнера постоянно хранимые данные. После выбора источника-хоста source и целевого назначения target каждый раз, когда обновляется файл или каталог на хосте, автоматически обновляются данные в контейнере. Это здорово  —  и работать в средах dev локально и знать, что изменения отражаются в контейнере.

  • networks: (необязательно) в Docker создаются виртуальные сети, к которым подключаются контейнеры. Если ни одна сеть не определена, все контейнеры находятся в стандартной мостовой сети. Не забываем, что доступ контейнера разработки к контейнерам продакшена и взаимодействие с ними исключаются. Поэтому для разработки и продакшена создадим отдельные сети, которые определяются в разделе верхнего уровня networks, а затем указываться на уровне service. При желании настраиваются IP, конкретные подсети и многое другое, но пока достаточно DNS-имени. Остальное в Docker создается за нас.



Service 2 и 3: Prod


То же, кроме монтирования каталогов с хоста, делаем для двух контейнеров продакшена:


prodA:
build:
context: .
dockerfile: ./productionA/Dockerfile
image: boto3_prod_a
environment:
ENVIRONMENT: prod
networks:
- prod_net

prodB:
build:
context: .
dockerfile: ./productionB/Dockerfile
image: boto3_prod_b
environment:
ENVIRONMENT: prod
networks:
- prod_net

Оркестрируем


Вот весь yaml-файл docker-compose:


version: '3'

services:
dev:
build:
context: .
dockerfile: ./development/Dockerfile
image: boto3_dev
environment:
ENVIRONMENT: dev
volumes:
- type: bind
source: ./development
target: /home/app
networks:
- dev_net

prodA:
build:
context: .
dockerfile: ./productionA/Dockerfile
image: boto3_prod_a
environment:
ENVIRONMENT: prod
networks:
- prod_net

prodB:
build:
context: .
dockerfile: ./productionB/Dockerfile
image: boto3_prod_b
environment:
ENVIRONMENT: prod
networks:
- prod_net

networks:
prod_net:
dev_net:

Подробнее о Docker Compose  —  в официальной документации.


Запускаем docker-compose.yml:


docker compose up -d

… и надеемся, что ошибок не будет.



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


Запуская docker container ls, видим все запущенные контейнеры, и проведем заключительный тест сети:



Сначала убедимся, что контейнер разработки Dev не взаимодействует с контейнерами продакшена Prod.


Запустим ping из контейнера Dev командой exec, записывая название целиком  —  для контейнера назначения  —  или только первые три цифры/буквы идентификатора:


docker exec -it 552 ping boto3_env-prodA-1


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


docker exec -it a24 ping boto3_env-prodB-1


Поздравляю с успешным развертыванием среды Boto3 в Docker на Python из одного файла Docker Compose. Представьте всю мощь этого метода в более сложной среде разработки и продакшена, и сколько времени, денег и ресурсов экономится.



67   0  
    Ничего не найдено.

Добавить ответ:
Отменить.