Раніше я вже писав собі шпаргалку по докеру, яка нікому крім мене майже не потрібна, тут буде додаток до неї.
Контейнери докера – це аналог процесів в ОС – тобто щось що запущено виконується. Запускаються імеджі (аналог виконуваної програми). Можна взяти готовий імедж, можна зробити свій за допомогою докерфайла (аналог коду програми), який описує як білдиться (аналог компіляції) імедж.
Загалом команда запуску контейнера виглядає так:
docker run $image_name [$command]
Наприклад якщо цікаво виконати якийсь код на останньому Python, але лінь його ставити, докер скачає і виконає:
docker run python:latest python -c "import sys; print(sys.version)" # Unable to find image 'python:latest' locally # latest: Pulling from library/python # 22dbe790f715: Pull complete # ... # 61b3f1392c29: Pull complete # Digest: sha256:c32b1a9fb8a0dc212c33ef1d492231c513fa326b4dae6dae7534491c857af88a # Status: Downloaded newer image for python:latest # 3.7.2 (default, Mar 5 2019, 06:22:51) # [GCC 6.3.0 20170516]
Якщо не передавати ніяку команду, контейнер виконуватиме ту що для нього задана за замовчуванням. Наприклад
docker run --name test_python_run python:latest # задаємо контейнеру ім'я щоб не сплутати з іншими: docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d95e1e13e3f2 python:latest "python3" 5 seconds ago Exited (0) 4 seconds ago test_python_run
Бачимо що контейнер запускав команду “python3” але вийшов з неї (бо термінал не приєднався). Щоб увійти в інтерактивну сесію, треба запускати так (-i вроді означає інтерактивно, тобто очікувати на stdin, -t – приєднати до поточного терміналу):
docker run -it python:latest
Тільки через командний рядок багато Python коду не передаш. Тому є два варіанти передати файли в контейнер. Перший – прямо в image, за допомогою dockerfile.
Візьмемо для експерименту такий скрипт що поступово пробує використати все більше й більше пам’яті:
import random import time data = [] for i in range(10 ** 6): data.append(random.random()) if i % 1000 == 0: print(len(data)) time.sleep(0.25)
Managing memory in Python is easy—if you just don’t care. Документація Theano.
Щоб створити з ним імедж достатньо такого докерфайлу:
FROM python:3.7 COPY script.py ./script.py CMD python script.py
Тепер, щоб створити з нього імедж який називається наприклад memeater
(зжирач пам’яті), треба виконати:
docker build -t memeater -f Dockerfile .
А щоб потім запустити цей контейнер:
docker run -t memeater
-t щоб бачити що він пише в stdout.
Далі ми можемо за допомогою команди docker stat
спостерігати за тим скільки ресурсів цей контейнер їсть:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 8a58c19cc93c exp 0.28% 6.02MiB / 10MiB 60.20% 3.17kB / 0B 565kB / 1.01MB 2
Аби він не з’їв всю доступну пам’ять, можна йому обмежити ресурси:
docker run -t --name experiment --memory="10M" --cpus=0.1 memeater
Якщо вискакує повідомлення “WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.”, значить у вас трохи не такий Linux, і обмеження стосуватиметься лише RAM, а не області підкачки. Задати параметр --memory-swap
теж не допоможе.
Допоможе – взагалі відключити зберігання сторінок на диск.
docker run -t --name experiment --memory="20M" --memory-swappiness=0 --cpus=0.1 memeater
Якщо отримуєте помилку “docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused “process_linux.go:424: container init caused \”\””: unknown.”, то це тому що обмеження по пам’яті за сильне. В мене при 10M вискакує, при 20 – ні.
Що відбувається коли пам’ять закінчується? Лог закінчується так:
492001 Killed
З цього експерименту можна зробити висновок що Python, запущений в системі з доступною пам’яттю 20 мегабайт може втримати в пам’яті трохи менше ніж пів мільйона чисел з плаваючою крапкою.