Попробуйте собрать свой образ для вашего демона используя официальный образ от microsoft
Докер / Основы Docker
Теперь потыкаем докер. Докер — это инструмент для контейнеризации. То есть это такая штука, которая позволяет упаковать ваш сервис в специальный файл сразу вместе с зависимостями. И его можно будет запустить одной командой.
Устанавливаем Docker
И так, сначала установил docker. Идем сюда https://docs.docker.com/engine/install/ubuntu/#prerequisites
там инструкция что делать, сначала подключаем репозиторий
а потом можно уже установить docker engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
чтобы проверить что он работает запустите
sudo docker run hello-world
увидим такое
Общая идея
Идея работы с докером заключается в следующем:
- Вы описываете в текстовом файлике который обычно называют
Dockerfile
команды необходимые для запуска вашего сервиса. - Потом на базе этого файлика создается так называемый образ. Образ это своего рода виртуальный диск с операционной системой, библиотеками которые вы установили на шаге 1 и иногда командой для запуска сервиса. Кстати образ не всегда содержит сервис и может быть просто базовой операционной системой
- Но для нас образ по сути является упакованным сервисом вместе со всеми необходимыми зависимостями, который можно передать другому программисту. Либо выложить на специальный репозиторий для докер образов https://hub.docker.com
- Далее образ используется для создания копии сервиса. И запуска его уже в виде контейнера. Контейнер — это копия образа подтюненная под ваш проект.
В жизни, как правило, берут какой-то базовый докер-образ и расширяют под свои нужды.
Собственно, и попробуем создать свой образ и запихать в него наш сервис.
Создаем Dockerfile и собираем образ
И так создадим файлик Dockerfile, я прям в файле с проектом сделаю:
Первая строчка в этом файле должна быть строкой которая описывает базовый образ для нашего сервиса. Мы разрабатывали наш сервис на ubuntu так что нам потребуется такая строка:
FROM ubuntu:20.04
Кстати даже если у вас archlinux, то все равно можно смело писать ubuntu. Докер использует только ядро от основной системы (кстати, именно поэтому он без костылей работает только на linux), а так как ядро у убунты и арча плюс-минус одинаковые, то все должно успешно работать
У команды FROM сначала идет название образа. А затем используемая версия. Полный спиок доступных версий можно глняуть тут для ubuntu https://hub.docker.com/_/ubuntu?tab=tags
теперь можно попробовать собрать образ. Пишем
docker build -t my_daemon_image .
где my_daemon_image
это имя, которые мы даем нашему образу, чтобы потом на основании его запускать контейнеры, а точка на конце означает, что использовать Dockerfile из текущей папки
увидим что-то такое
дело в том, что docker работает на достаточно низком уровне и требует дополнительных привилегий для выполнения своих команд. Можно конечно запустить команду под sudo. Но более каноничным решением является добавление нашего пользователя к группе docker. Запускаем команды
sudo groupadd docker # создаем группу docker
sudo usermod -aG docker $USER # добавляем нашего юзера в эту группу
newgrp docker # перезагружаем разрешения групп
sudo chown "$USER":"$USER" /home/"$USER"/.docker -R # настраиваем разрешения файлов .docker
sudo chmod g+rwx "$HOME/.docker" -R
он может сказать, что группа docker уже существует, просто проигнорируйте это сообщение.
И так пробуем по новой создать наш образ. Пишем:
docker build -t my_daemon_image .
Увидим такое сообщение:
тут написано, что docker стянул образ ubuntы и создал на базе его наш образ my_daemon_image
Запускаем контейнер
Теперь можем попробовать запустить на базе этого образа контейнер. Пишем
docker run my_daemon_image
пока, если запустить, то ничего не произойдет. То есть как будто бы наша команда сработала вхолостую. Дело в том, что наш образ по сути просто копия ubuntы. Он запускается. Так как команда для запуска не указана он собственно сразу прекращает работу.
Вообще конечно что-то произошло. Как минимум, был создан контейнер (микро-копия нашего образа), и докер его даже запустил. Мы можем посмотреть эту следующим образом
docker container list -a
я дважды запускал команду docker run
и у меня создалось два контейнера на базе образа my_daemon_image.
Вообще docker любит сжирать много место. И поэтому бывает полезным чистить не используемые контейнеры. Для этого есть команда
docker container rm <CONTAINER_ID>
Команда CMD
Добавим в наш Dockerfile команду
FROM ubuntu:20.04
CMD ["echo", "Привет всем"]
CMD – это одна из главных команд docker файла, в которую прописывается команда, которая должна запустится при запуске контейнера. Пересоберем образ
docker build -t my_daemon_image .
Теперь запустим образ по новой:
ну вроде вывел, но чет не сильно много действия для простого echo.
Давайте попробуем запихать туда нашего демона. Одно из преимуществ докер контейнеров заключается в том, что вам не надо создавать service файл. По сути ваш Dockerfile это уже своего рода описание вашего сервиса.
Посмотрим где наш файлик лежит, у меня он находится тут и называется daemon:
попробуем вместо команды echo запустить демона.
Кстати я устал билдить и запускать вручную. Поэтому сделаю Makefile
# Makefile
all:
docker build -t my_daemon_image .
docker run my_daemon_image
и теперь могу запускать все команды разом путем вызова команды make
Теперь правим Dockerfile
FROM ubuntu:20.04
CMD ["bin/Debug/net6.0/daemon"]
запускаю:
говорит файл не найден… может надо полный путь прописать
и полный путь не помогает…
Так в чем же дело?
Команда COPY
А дело в том, что docker запускается в изолированной среде, а это значит, что для того чтобы файл запустился, его надо сначала скопировать внутрь образа. А потом оттуда уже запустить.
FROM ubuntu:20.04
# скопировал файл bin/Debug/net6.0/daemon внутрь образа в папку /opt
COPY bin/Debug/net6.0/daemon /opt/daemon
CMD ["/opt/daemon"]
запускаем:
о, уже интереснее. Правда все равно не запустилось. Говорит надо файл daemon.dll.
Давайте скопируем папку целиком:
FROM ubuntu:20.04
COPY bin/Debug/net6.0/ /opt/
CMD ["/opt/daemon"]
запускаем:
о, попытался запустится, но написал, что .NET не найден. Так вроде ж ставили .net…
Так я ж говорил, что докер работает изолированно.
Он просто использует ядро основной системы, доступа к основным файлам у него все равно нет. А значит нам надо поставить внутрь образа .net
Но как это сделать, ведь CMD
используется под основную команду. А если копировать через COPY
этож надо знать какие файлы.
Команда RUN
К счастью в dockerfile есть еще одна команда RUN
с помощью которой можно вызывать команды внутри образа. А результаты работы этих команд будут зафиксированы в образе навечно.
В общем с помощью RUN и запускают команды для установки пакетов, их в отличии от CMD
может быть сколь угодно много. Я скопирую команды отсюда https://docs.microsoft.com/ru-ru/dotnet/core/install/linux-ubuntu#2004- и добавлю к ним префикс RUN. Ну и уберу sudo, так как команды внутри образа запускаются под суперюзером
FROM ubuntu:20.04
RUN wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
RUN dpkg -i packages-microsoft-prod.deb
RUN rm packages-microsoft-prod.deb
RUN apt-get update; \
apt-get install -y apt-transport-https && \
apt-get update && \
apt-get install -y aspnetcore-runtime-6.0
COPY bin/Debug/net6.0/ /opt/
CMD ["/opt/daemon"]
пробуем запустить:
у меня не нашел wget, давайте добавим команду по его установке
FROM ubuntu:20.04
RUN apt update && apt install -y wget # ДОБАВИЛ
RUN wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
# …
Если вы испольузете filget или tree или cowsay не забудьте их добавить.
и так после достаточно длительного ожидания, я таки дождался вот такого результат
так как демон используется в докере, то юзать сокет файл не перспективно, так как мы не сможем получить к нему доступ. Поэтому будем использовать порт.
Особенности обновления внутренних файлов
Если подправить нашего демона и пересобрать через dotnet build
, затем запустить наш make
то образ на самом деле не пересоберется.
Видите после каждого шага Step */*
он пишет Using cache
.
Это потому что на каждую команду докер создает промежуточный образ. С одной стороны, это удобно, при пересборе не будут выполняться все команды с нуля, а с другой стороны это тратит лишнее место на диске, что при использовании больших образов может быстро забивать место.
В общем чтобы наш образ пересобрался, надо как-то удалить промежуточный образ, и тогда он его пересоберет.
Можно конечно скопируовать эти цифры
глянуть какие образы у нас уже есть в системе:
docker image list -a
как видим наш образ my_daemon_image весит 248МБ, а еще там есть промежуточные образы которые весят столько же. Можно попробовать удалить образ соответствующий команде COPY
правда он не даст нам удалить образ, так как от него есть зависимые. В моем случае мне надо еще удалить образ fd8552a13f13
которые соответствует my_daemon_image.
В общем это достаточно неудобно. Короче, если хотите сбросить кеш команды просто поменяйте ее немного.
И тогда, если пересобрать и запустить, увидим такое. Все работает =)
Подключаемся к контейнеру
попробуем подключится
красота! =)
Теперь, не закрывайте запущенный образ. Откройте отдельную консоль и давайте глянем инфу о запущенных контейнерах
можно глянуть инфу обо всех контейнерах которые мы запускали
docker container list -a
так как вы их скорее всего не планируете использовать, имеет смысл их удалить. Пишем
docker container prune
ну вот, 35МБ освободили))
А теперь давайте остановим запущенный контейнер. Узнаем его имя:
и остановим
во время остановки, главному процессу контейнера (который в CMD
) посылается сигнал SIGTERM.
А теперь давайте обратно запустим его
docker start interesting_tharp
контейнер автоматически запустится в режиме демона. То есть он будет работать вне текущей консоли. Но можно будет к нему так же успешно подключатся через
socat TCP:172.17.0.2:8080 -
кстати как и с journalctl в докере можно посмотреть лог контейнера
docker logs interesting_tharp -f
Попробуйте теперь сделать задание