LINUX.ORG.RU
решено ФорумAdmin

Концепция Docker контейнеров и их практическое использование

 


2

6

Возник вопрос по контейнерам в linux. Контейнер - это некая служба запущенная в изолированной среде. Сам контейнер получается методом развертывания его из образа (image). При завершении работы контейнера, данные внутри него теряются и запустив его снова мы получим первоначальный контейнер из образа. Если нам нужно, чтобы данные, которые контейнер создаст в процессе работы, не терялись, нам нужно подключить к нему раздел (volume) и тогда контейнер работая с файлами может сохранить их на этом разделе и они не исчезнут при завершении работы контейнера. В контейнер можно передать некоторые параметры для приложения в нем, путем указания параметров окружения при развертывании. При этом мы ограничены параметрами в образе, которые можно передать. Вопрос, мне надо создать контейнер, в котором изначально будет приложение с нужным мне конфигом и дополнительными файлами. Я так понимаю, что правильным в этом случае будет собрать новый образ из некого дефолтного, зашив в него все необходимое (конфиг, доп файлы). Таким образом при развертывании контейнера из этого нового образа, у контейнера будет все необходимое для работы и мне не надо будет передавать в него что-то, что нельзя передать при развертывании.

Простой пример: мне нужен сервис nginx определенным образом сконфигурированный и имеющий файлы с сертификатами. Я беру штатный image nginx, на основе него собираю новый кастомный image и уже с него развертываю контейнеры?

Я правильно понял концепцию? На практике оно как-то так должно быть?

Да, правильно. Молодец (серьезно, тут толпа регистрантов до сих пор не понимает что такое контейнеры, как их готовить и зачем они нужны).

mandala ★★★★★
()
Последнее исправление: mandala (всего исправлений: 1)

В принципе да. Но необязательно пересобирать контейнеры под себя. Обычно контейнеры легко настраиваются через переменные окружения.

spoilt ★★★
()
Ответ на: комментарий от spoilt

Обычно контейнеры легко настраиваются через переменные окружения.

Мне понравилась технология, когда я создаю контейнер из стандартного образа (image) Затем вношу в него изменения (меняю/добавляю/удаляю файлы) и потом на основании этого контейнера делаю новый image. Это все работает и отлично.

Теперь мне захотелось передать в контейнер несколько новых параметров и потом использовать эти параметры в конфигурационном файле приложения внутри контейнера. Вопрос - это возможно?

Вот такой командой я создаю новый image nginx-m:1.0 из доработанного контейнера nginx-m

docker commit nginx-m nginx-m:1.0

Но мне еще надо добавить к стандартным переменным окружения два параметра REMOTEHOST и REMOTEPORT. А потом, мне нужно эти два параметра вставить в nginx.conf, чтобы приложение их воспринимало. Подскажите, как это сделать?

samson_b
() автор топика
Последнее исправление: samson_b (всего исправлений: 2)

Это уровень не мальчика, но Senior DevOps engineer

anonymous
()
Ответ на: комментарий от mandala

Толпа просто умеет писать на баше, а не на ямле и искренне не понимает, почему так пляшут с запакованными чрут-окружениями, которые почему-то обязательно надо заворачивать в unshare по всем фронтам.

У меня, как у представителя толпы анонимусов и свидетеля свидетелей секты докера, появилось подозрение: вот это вот всё (микросервисная архитектура, докер, контейнеры, выбери нужное в зависимости от контекста) нужно в первую очередь тем, кто не хочет и не умеет обеспечивать совместимость, пилить не-хардкод, конфигурировать софт, продумывать архитектуру, обеспечивать безопасность и так далее. Можно же выкачать увешанный слоями образ с докерхаба, накидать контейнеров и притвориться, что всё хорошо. Такая кнопка «сделать всё замечательно».

Ещё я искренне не понимаю, зачем выкидывать свою инфраструктуру и гнать её в облако, да. Это тоже процветает в среде девопс-приближённых. Уже стартапы по сбору логов организовывают, не то, что db помесячно.

anonymous
()
Ответ на: комментарий от anonymous

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

#!/bin/bash
docker stop nginx-m
docker rm nginx-m
docker rmi nginx-m:2.0
docker run -d -p 443:80 --name nginx-m --link websrv nginx:alpine
docker exec -it nginx-m rm /etc/nginx/conf.d/default.conf
docker exec -it nginx-m rm /etc/nginx/nginx.conf
docker exec -it nginx-m mkdir /etc/nginx/webcert
docker exec -it nginx-m apk add nginx-mod-stream
docker exec -it nginx-m rm -r /var/cache/apk
docker exec -it nginx-m mkdir /var/cache/apk
docker cp nginx.conf nginx-m:/etc/nginx/
docker cp cfg-upd nginx-m:/sbin/
docker cp pubkey.pem nginx-m:/etc/nginx/webcert/
docker cp privkey.pem nginx-m:/etc/nginx/webcert/
docker commit --change "ENV REMOTEHOST=websrv" --change "ENV REMOTEPORT=80" --change 'CMD ["/sbin/cfg-upd"]' nginx-m nginx-m:2.0
docker stop nginx-m
docker rm nginx-m

Теперь создаем новый контейнер и можем указывать любые хост и порт

docker run -d -p 443:80 -e REMOTEHOST=server2 -e REMOTEPORT=777 --name nginx-m --link websrv nginx-m:2.0

samson_b
() автор топика
Ответ на: комментарий от anonymous

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

Думаю это тупо дешевле (быстрее/качественнее) на сложных проектах.

samson_b
() автор топика
Последнее исправление: samson_b (всего исправлений: 1)

Почитай еще про ConfigMap в kubernetes.

Можно делать контейнерные образы без хардкода конфигов, а добавлять их в момент запуска.

alpha ★★★★★
()
Ответ на: комментарий от alpha

Почитай еще про ConfigMap в kubernetes.

Обязательно. Это уже следующая задача, перетащить это все в kubernetes.

samson_b
() автор топика
Ответ на: комментарий от samson_b

Думаю это тупо дешевле (быстрее/качественнее) на сложных проектах.

а что значит качественнее? как это объективно оценить?

nerve ★★
()
Ответ на: комментарий от samson_b

Обычно для создания или доработки какого-то образа пишут не bash-скрипт с кучей docker exec, docker cp, docker commit, а Dockerfile, который содержит все эти действия, а потом собирают образ обычным docker build.

FROM nginx:alpine
RUN rm ... && mkdir ... && ...
COPY nginx.conf /etc/nginx/
...
ENV REMOTEHOST=websrv REMOTEPORT=80
В вашем примере, используя docker run --name nginx-m, вы не сможете запустить несколько параллельных сборок, т.к. с конкретным именем можно запустить только один контейнер. А через Dockerfile и docker build - сможете, ибо там при сборке имена контейнеров не важны и генерируются случайным образом.

Также при повторных пересборках в вашем случае не будет задействовано кеширование. Каждый запуск сборки будет заново выполнять все шаги. А при сборке через Dockerfile шаги (слои), которые не изменялись, будут взяты из кеша (старого готового образа).

spirit ★★★★★
()
Ответ на: комментарий от nerve

а что значит качественнее? как это объективно оценить?

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

https://youtu.be/CZ3wIuvmHeM

samson_b
() автор топика
Ответ на: комментарий от spirit

Обычно для создания или доработки какого-то образа пишут не bash-скрипт с кучей docker exec, docker cp, docker commit, а Dockerfile, который содержит все эти действия, а потом собирают образ обычным docker build.

Спасибо за дополнение. Я сделал, то о чем вы говорите и оно тоже заработало. На мой субъективный взгляд, отлаживать удобнее, когда работаешь с живым контейнером через bash скрипт и сразу смотришь, что получается.

Меня смутило пару вещей при сборки образа из dockerfile, первое - образ получается больше. В моем случае на пару мегабайт. (~22mb vs ~24mb) Я не понял как это так получилось. Еще момент - это необходимость все параметры прописывать заново (например cmd и все env). В случае с docker commit я могу просто добавить новые параметры или поменять некоторые, остальное останется неизменным.

Еще вопрос возник, каждая строчка в Dockerfile добавляет слой в контейнере. Мы не получим никаких негативных последствий, если слоёв будет много?

samson_b
() автор топика
Ответ на: комментарий от samson_b

С живым контейнером можно играться в ходе экспериментов. В прод нужно отправлять Dockerfile, это стандарт. Например, когда ты будешь собирать образ в CI, едва ли портянка шелл-скрипта добавит удобства.

Многослойность образа может увеличить его размер, возможно скорость инициализации. Слои можно сквошнуть через экспорт-импорт.

filosofia
()
Ответ на: комментарий от filosofia

Слои можно сквошнуть через экспорт-импорт.

Этим вообще кто-нибудь занимается или это баловство? Подскажите, как этот экспорт-импорт сделать, хочу поэкспериментировать.

samson_b
() автор топика
Ответ на: комментарий от filosofia

В прод надо отправлять сам образ а не dockerfile. И способов получить этот образ много разных. Кто-то вообще make-ом собирает, кто-то gradle-ом.

Dockerfile как формат довольно убог, особенно в плане параметризации. Поэтому ничего страшного в том чтобы делать себе жизнь удобнее через разные автоматизации нет.

alpha ★★★★★
()
Ответ на: комментарий от alpha

Ок, под продом я подразумевал CI, который соберёт продовский образ. Make подталкивает писать нечитаемую кашу, с обобщенным кодом, подстановками и специализациями. Иногда даже банально порядок действий сложно восстановить. Dockerfile, напротив, — декларативный формат, достаточно тупой, и в этом его прелесть. Ты смотришь в него и сразу понимаешь, что он делает.

Возможно во мне говорит опыт переписывания make-mess в докерфайлы. Я верю, что на make можно сделать просто и декларативно. Но, чем он тогда будет лучше Dockerfile?

filosofia
()
Ответ на: комментарий от alpha

Я уже наигрался со всем этим, tl;dr ты не хочешь параметризировать, IRL тебе нужен один-два Dockerfile.

Сначала ты хочешь разные версии в FROM, потом разные базовые образы, затем тебе нужны разные версии софта внутри, через какое-то время уже и софт разный, и конфиги, и разный код инициализации всего это. Как итог, мы имеем какой-то дикий код, который фактически генерирует Dockerfile по заданным параметрам. Получаем тот же Makefile, вид сбоку. Как-то работает, но лучше не трогать.

А ради чего все это затевалось? Чтобы «настраивать» Dockerfile. Вопрос: чем редактирование файла руками — не настройка? Plain Dockerfile лучше еще и тем, что ты всегда видишь историю его изменения в гите.

Я не собираюсь кого-то переспорить, пусть ТС сам смотрит, какой подход ему ближе.

filosofia
()
Ответ на: комментарий от filosofia

Как итог, мы имеем какой-то дикий код, который фактически генерирует Dockerfile по заданным параметрам.

Если делать баш-скриптами правку докерфайла, то да.

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

Если у тебя таких задач нет - отлично, тебе повезло. Но они бывают.

alpha ★★★★★
()
Ответ на: комментарий от filosofia

Многослойность образа может увеличить его размер, возможно скорость инициализации.

Разобрался я почему у меня image получается больше, если его делать из Docerfile

У меня было так:

RUN apk add nginx-mod-stream      # Устанавливаем модуль
RUN rm -r /var/cache/apk          # Удаляем временные файлы
RUN mkdir /var/cache/apk          # Восстанавливаем директорию
Получается, что в слое, созданным первой командой, сохраняются временные файлы, даже если в следующей команде мы удаляем файлы.

Чтобы не раздувать image, нужно внутри одной команды сразу подчищать за собой временные файлы, чтобы они не сохранились в слое. Вот так:

RUN apk add nginx-mod-stream && rm -r /var/cache/apk && mkdir /var/cache/apk

В этом случае image получился практически идентичным по сравнению с image полученным через commit

samson_b
() автор топика

Класть в конфиг в контейнер — последнее дело. Если не хочешь делать красиво, то без проблем можешь его просто примонтировать.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Класть в конфиг в контейнер — последнее дело. Если не хочешь делать красиво

А красиво это как? И чем плох конфиг в контейнере?

samson_b
() автор топика
Ответ на: комментарий от samson_b

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

И чем плох конфиг в контейнере?

Есть у тебя два окружения — тест и прод. Ну, ты понял.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

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

Я так и сделал, создал пару переменных окружения, чтобы передавать два параметра, которые могут меняться. Также зашил скрипт внутрь контейнера, который патчит конфиг, добавляя в него указанные параметры и после запускает сам nginx. Остальное в конфиге статично и замены не потребует.

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

samson_b
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.