Уймин - про разработку
190 subscribers
3 photos
1 file
40 links
Авторский канал про backend-разработку. Подробнее - в закрепллённом сообщении.

Личиный аккаунт: @maksimuimin
Download Telegram
Docker - контейнеризация, доступная всем

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

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

📥 Перед началом работы необходимо установить docker. В стандартную поставку docker входят cli-утилита и docker-демон. После установки надо удостовериться, что демон запущен:
docker stats --no-stream
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

# Ошибка говорит о том, что демон не запущен
# В зависимости от способа установки, надо:
# - либо запустить либо GUI-приложение Docker Desktop
# - либо запустить docker-демон через systemctl

systemctl start docker

docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS


⚙️ Теперь, когда окружение готово, попробуем запустить чего-нибудь в контейнере. Создадим файлик helloworld.py, это наше тестовое приложение. Содержимое файла:
print('Hello world')


📃 Далее нам нужен имейдж - неизменяемый архив, в который мы запакуем окружение для нашего приложения. Для сборки имейджа докеру нужна инструкция. Создадим файлик Dockerfile, в нём мы опишем, какие шаги надо выполнить для сборки имейджа. Содержимое файла:
# Указываем базовый имейдж.
# Нам не обязательно создавать свой имейдж с нуля, можно взять за основу что-то готовое.
# Обычно, за основу берут базовый имейдж с желаемым дистрибутивом Linux и основным ПО.
# В данном случае, дистрибутив нам не важен. Нас устроит любой, где есть python версии 3.
# Имейджи по-умолчанию скачиваются с https://hub.docker.com/
FROM python:3

# Добавляем наше приложение в имейдж
ADD helloworld.py /root/helloworld.py

# По-умолчанию при запуске контейнера из нашего имейджа будет выполнена вот эта команда.
CMD ["python3", "/root/helloworld.py"]

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

🔨 Собираем имейдж из Dockerfile:
docker build --tag helloworld .
# docker build - собрать имедйж
# --tag helloworld - назвать имейдж "helloworld"
# . - Dockerfile искать в текущей директории


👟 Запускаем контейнер (т.е. стартуем процесс нашего приложения):
docker run --name helloworld_container helloworld
# docker run - запустить контейнер
# --name helloworld_container - назвать контейнер "helloworld_container"
# helloworld - взять окружение для запуска из имейджа "helloworld"

Если вы всё сделали правильно, на этом этапе увидите Hello world в терминале 😉

♻️ Приберём за собой и почистим созданные ранее ресурсы:
# Вывести список контейнеров. Флаг -a означает "в т.ч. завершившихся"
docker ps -a

# Удаляем наш контейнер
docker rm helloworld_container

# Вывести список имейджей
docker images

# Удаляем наш образ
docker rmi helloworld

# Удаляем базовый образ
docker rmi python:3


👍 На сегодня знакомство с docker закончим. Напоминаю, что контейнеры - это очень полезная технология, на её изучение имеет смысл потратить время 😉 Ставь огонёк, если хочешь более продвинутые туториалы по docker 🔥

#hardskills #containers #tools #Linux #docker
Отладка docker-контейнеров

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

🐳 Создадим Dockerfile:
# Alpine - это минималистичный дистрибутив Linux
# Его любят использовать для контейнеров, потому что он очень мало весит
FROM "alpine"

# Бесконечно выводим "Hello world" с интервалом 0.5 секунды
CMD ["while", "[[ 1 ]];", "do", "echo", "'Hello world';", "sleep 0.5;", "done"]


🔨 Собираем имейдж:
docker build --tag dockerdebug .


👟 Запускаем контейнер
docker run --name dockerdebug_container -d dockerdebug
# Флаг -d нам раньше не встречался
# Это значит "запустить в бэкграунде", т.е. в режиме демона


🪲 Oh-oh…
41f8f5d28c04f9ba705b4482e26333152071fdd7c06af736933ebc9f0eb83cba
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "while": executable file not found in $PATH: unknown

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

1️⃣ Смотрим на статус контейнера:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41f8f5d28c04 dockerdebug "while '[[ 1 ]];' do…" 9 minutes ago Created dockerdebug_container

Официальная документация говорит, что Created значит “контейнер никогда не стартовал”. Окей, статус узнали, это хорошо. Уточнить текущее состояние важно для отладки, но никакой информации к размышлению это нам не дало. Идём дальше.

2️⃣ Смотрим логи:
docker logs dockerdebug_container

А в логах пусто 😢 В целом, это было ожидаемо, раз контейнер не стартанул. Если бы он “стартанул и сразу упал”, то в логах можно было бы что-то найти. Однако этим шагом никогда не стоит пренебрегать! Логи - это самый простой способ узнать, что происходит с вашим софтом. В случае любых проблем всегда смотрите логи. Ну а мы переходим к тяжёлой артиллерии:

3️⃣ Переопределим команду и запустим контейнер. Подключимся к нему и выполним исходную команду сами. Таким образом, мы получим боевое окружение, в котором сможем запустить свою команду с дополнительным дебагом без пересборки имейджа.
# Удаляем багованный инстанс контейнера
docker rm dockerdebug_container
# Запускаем новый инстанс
# Обратите внимание на `sleep infinity` после тега имейджа
# Эта команда будет запущена при старте _вместо_ команды из Dockerfile
docker run --name dockerdebug_container -d dockerdebug sleep infinity
# Мы получили запущенное боевое окружение, в нём ничего не происходит
# Подключимся к этому окружению, чтобы увидеть мир "изнутри" контейнера
docker exec -it dockerdebug_container /bin/sh
# Мы получили шелл внутри контейнера. Выполним исходную команду.
while [[ 1 ]]; do echo 'Hello world'; sleep 0.5; done
Hello world
^C
# ^ работает, лол 0_o

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

 Но у нас всё заработало как есть, почему так? Это потому что в контейнере мы запускали код в оболочке интерпретатора sh, а докер при старте контейнера делает простой exec. Т.е. мы пытались запустить интерпретируемый код без интерпретатора, такая вот учебная бага 😊

❤️‍🩹 Давайте починим:
FROM "alpine"
CMD ["/bin/sh", "-c", "while [[ 1 ]]; do echo 'Hello world'; sleep 0.5; done"]


docker stop dockerdebug_container
docker rm dockerdebug_container
docker rmi dockerdebug
docker build --tag dockerdebug .
docker run --name dockerdebug_container -d dockerdebug
docker logs dockerdebug_container
Hello world


🤔 Итого, алгоритм дебага docker-контейнеров: уточняем статус docker ps ⇒ смотрим логи docker logs ⇒ если не помогло, переопределяем команду на sleep infinity, подключаемся к контейнеру через docker exec и применяем стандартные #debug инструменты 😉 Этот же алгоритм применим к кейсам, когда контейнер запустился, но не работает. Ставь огонёк, если было полезно 🔥

#hardskills #containers #tools #Linux #docker #debug #logging