Шаг 2. Проведите интервью с предметным экспертом

Предметный эксперт является гуру в своем деле, он основной источник информации и генератор идей для разработчика электронных курсов. Вот почему важно выстроить с ним тесное взаимодействие. Без эксперта сложно проделать всю работу, описанную в предыдущем пункте: определить цели курса, его аудиторию и подобрать необходимые обучающие материалы.
Эксперт поможет подготовить необходимый для создания курса материал, тексты, примеры из практики и кейсы.
При разработке обучающего курса вместе с экспертом важно дать ему свободу действий при выборе контента, однако стоит следить за тем, чтобы курс в дальнейшем не был перегружен теорией, которую сложно сразу применить на практике.
Предметный эксперт также окажется бесценным консультантом на этапе оценки готового курса перед его запуском, источником конструктивной критики и материалов для доработки курса.
Более подробно тому, как выстроить эффективное взаимодействие с предметным экспертом и его роли в создании курса, посвящен отдельный урок, подготовленный совместно с экспертами в электронном обучении.
Итоги шага 2: После прохождения второго этапа разработки курса у вас есть представление о том, какой предметный эксперт нужен вам для успешного создания онлайн-курса и как выстроить взаимодействие с ним.
Шаг 3. Напишите сценарий электронного курса

Сценарий — техническое задание, детальное описание и основа будущего обучающего курса, поэтому собрать курс без детально проработанного сценария невозможно.
Для последующей работы над ним в сценарии нужно прописать все нюансы: тип курса, его разделы, ситуации для каждого слайда, содержание тестов, анимации и тренажеров. Сценарий курса зависит от его типа: информационный, тренинговый или мотивационный, а также от уровня сложности.
В рамках разработки сценарий онлайн-курса разрабатывается его концепт, а большие массивы информации и практические задания делятся на отдельные элементы — модули — для большего удобства. Разбивать курс на модули целесообразно, если он длиннее пяти слайдов.
Чтобы не запутаться в процессе создания онлайн-курса, важно определиться со всеми диалоговыми тренажерами и тестами, их типами — обучающие или проверяющие — и целями. В дальнейшем предстоит написать небольшой сценарий для каждого практического задания.
После создания структуры наступает следующий этап — работа с тем материалом и текстами, который удалось собрать и получить от эксперта.
Подробную инструкцию по созданию сценария курса мы подготовили вместе с экспертом в области eLearning и основателем студии по разработке электронных курсов New York Александром Виноградовым.
Итоги шага 3: Если следуете всем инструкциям, у вас готов сценарий будущего онлайн-курса. Он имеет четкую структуру, поделен на блоки и модули, соответствует заявленным целям и задачам курса, а вы точно знаете, в какой последовательности выстроены все элементы.
Шаг 4. Оформите онлайн-курс

Успешно составленный онлайн-курс с нуля — это красивый и аккуратный дизайн. При этом быть профессиональным дизайнером для этого сегодня не требуется. Подробно о подходах к дизайну курсов рассказывается в нашем уроке.
Кроме того, если вам нужно быстро сделать качественный дизайн курса, можно использовать готовые шаблоны из библиотеки контента iSpring Suite.
Шесть главных составляющих, которые необходимо изучить и использовать при создании дизайна курса: композиция, шрифт, выравнивание, контраст, цвет и стиль. От них будет зависеть удобство обучения, юзабилити курса, психологическое воздействие на обучаемого и общий приятный и опрятный внешний вид онлайн-курса.
Как быстро создать курс с нуля при помощи библиотеки контента, смотрите в этом видеоуроке:
Итоги шага 4: Изучив основы дизайна вы узнаете, как упаковать полезную обучающую информацию в красивую обертку, чтобы она была приятная глазу, а также была понятна и проста для восприятия, что немаловажно.
Итоги шага 4: Изучив основы дизайна вы узнаете, как упаковать полезную обучающую информацию в красивую обертку, чтобы она была приятная глазу, а также была понятна и проста для восприятия, что немаловажно.
Шаг 5. Создайте диалоговый тренажер

Диалоговый тренажер в eLearning представляет собой интерактивное упражнение, которое имитирует разговор с человеком: покупателем, подчиненным или коллегой. Тренажер позволяет в формате диалога отработать навыки общения без рисков. Основой любого диалога выступает какой-либо пример из практики — бизнес-кейс, вокруг которого складывается сюжет ситуации.
При создании онлайн-курса с нуля стоит решить, нужен ли вообще в нем диалоговый тренажер и для чего. Этот инструмент должен решать конкретные цели обучения — навыки общения продавца с покупателем или продажи нового продукта клиенту. Диалог позволяет в безопасном пространстве обучить сотрудника говорить четко и по делу, чтобы на практике действовать без ошибок.
Как сверстать диалоговый тренажер читайте в отдельном уроке. В программе можно продумать ветвление, подобрать фон и персонажа к каждой сцене, озвучивать реплики, назначить баллы за правильные ответы и штрафовать за неправильные. Как им пользоваться, подробно описано в видео:
м электронного обучения — диалоговым тренажером.
Итоги шага 5: После прохождения пятого этапа разработки онлайн-курса вы сможете пользоваться важным инструментом электронного обучения — диалоговым тренажером.
Шаг 6. Создайте онлайн-тест

Онлайн-тест является неотъемлемой частью любого обучающего курса, так как позволяет проверить полученные знания.
Ошибки в составлении теста приводят к тому, что оценить результаты обучения адекватно становится невозможным. К таким ошибкам относятся неочевидные ответы, слишком высокая или, наоборот, низкая сложность, подсказки в самих вопросах.
Ниже приводится интерактивный тест для подготовки к сдаче экзамена в ГИБДД, в котором реализуются различные возможности онлайн-тестирования.
О том, как избежать неточностей при создании онлайн-теста, выбрать тип тестовых заданий, правильно рассчитать время тестирования, составить вопросы и решить ряд других задач, рассказывает основатель студии по разработке электронных курсов New York Александр Виноградов в этом уроке.
Говоря о популярности тестирования как метода оценки знаний, стоит отметить, что свыше 80% зарубежных компаний пользуются именно тестами для оценки уровня знаний соискателей и сотрудников. В России тесты используются 69% эйчаров.
Итоги шага 6: На этом этапе вы узнаете, как составить обучающий и аттестационный тесты для онлайн-курса, как выбрать типы вопросов и как их сочетать.
Шаг 7. Создайте обучающее видео

В век мобильных технологий и YouTube создание обучающего видео при разработке онлайн-курса воспринимается как нечто само собой разумеющееся. Видео — удобный и понятный формат для передачи практически любой полезной информации.
Обычно выделяют три типа обучающего видео:
- Скринкаст — запись с экрана компьютера, сопровождаемая закадровым голосом комментатора. Подробнее о скринкастах мы рассказали в статье «Как записать скринкаст: пошаговая инструкция».
- Формат видеосопровождения, с так называемой “говорящей головой”, когда лектор сопровождает презентацию в PowerPoint.
- Обучающий видеоурок, который по формату похож на телепередачу с богатым видеорядом, продуманным сценарием.
Как и при создании других форматов, для начала нужно определиться с задачами обучения, целевой аудиторией, затем разработать сценарий и воплотить его в жизнь.
На сегодняшнем уровне развития и доступности техники делать видео самостоятельно не так сложно, как кажется. Об этом детально рассказывается в очередном уроке по созданию онлайн-курса с нуля, который подготовили наши эксперты — Владимир Раджапов, Дмитрий Якушев и Мария Плоткина.
Кстати, создать видеоурок можно, не выходя из PowerPoint. Подробнее о том как это сделать, смотрите в видеоуроке:
Итоги шага 7: Изучив наши материалы, вы сможете определить, какое именно видео нужно вашему обучающему курсу и как его создать, начиная с написания сценария и заканчивая постановкой света и закадровым текстом.
Шаг 8. Запустите пилотный проект

Пилотный запуск проекта — это тест-драйв обучающего курса, который позволит найти слабые места и неточности до массового запуска обучения.
В процессе проверки курса он по-прежнему должен отвечать целям и задачам обучения, быть комфортным для учеников. Пробный запуск помогает найти фактические неточности, опечатки, устаревшую информацию, собрать мнения на основе обратной связи.
На этапе пилотного запуска проекта курс, как правило, проходит фокус-группа из числа как опытных сотрудников, так и новичков для объективной оценки. После пробного запуска, курс следует доработать на основе полученных данных от “тестировщиков”.
Подробнее узнать о том, что представляет собой пилотный запуск проекта и зачем это нужно, можно из нашего урока от эксперта eLearning, сооснователя Corporate e-Learning Club Марины Литвиновой.
Итоги шага 8: К этому этапу у вас уже есть готовый курс со всем необходимым контентом, осталось протестировать его, собрать отзывы, доработать и вот он — готовый обучающий онлайн-курс!
Резюме
Итак, в данном материале мы прошлись по основным шагам создания онлайн-курса с нуля. Разобрали, что необходимо для его максимальной эффективности.
- Научились ставить цели и задачи
- Определять аудиторию курса
- Создавать сценарий курса
- Работать с экспертами
- Создавать дизайн курса
- Создавать видео-уроки
- Создавать тесты и диалоги
- Проводить пилотный запуск
Успехов!
Чему уделить больше времени — продукту или маркетингу?
Чтобы запуск курса прошел удачно, надо провести серьезную подготовительную работу. Нужно хорошенько доработать информационный продукт, а также грамотно «упаковать» его, т.е. проработать маркетинговую составляющую. Можно встретить диаметрально противоположные мнения: кто-то считает, что хороший курс будет продавать себя сам, а другие специалисты настаивают на том, чтобы сделать упор на рекламу.
Как показывает практика, в успешных запусках онлайн-курса внимание уделялось обеим составляющим. Сделав упор на продукт, вы столкнетесь с тем, что об обучении узнает мало потенциальных слушателей — и значит, долгое время придется работать в минус, поскольку эффект сарафанного радио наращивается месяцами, если не годами. С другой стороны — массовая реклама поможет привлечь большую аудиторию потенциальных клиентов, но при недоработанном курсе они не вернутся к вам и не порекомендуют курс своим знакомым.
Таким образом, составляя план запуска онлайн-курса, стоит поровну распределить усилия и направить внимание как на доработку продукта, так и на его упаковку. И если инфопродукт получит от слушателей хорошие отклики, то в следующий раз можно будет сделать больший упор на рекламу и продвижение.

Матрица осознанности применительно к запуску инфопродуктов
Рассуждая о том, как запустить онлайн-курс, много внимания обычно уделяется способам и инструментам привлечения слушателей. Каналов коммуникации сегодня существует огромное множество — это и сайты, и блоги, и социальные сети, и прямая реклама. Трудностью часто становится понимание того, как именно донести до потенциального клиента важность пройти онлайн-обучение и записаться на него именно к вам.
В этом случае при составлении алгоритма запуска онлайн-курса можно обратиться к матрице осознанности, которая часто используется в МЛМ и других техниках продаж. В этой матрице можно выделить четыре уровня, каждый из которых соответствует степени «прогрева» аудитории: от первого касания до последнего, на котором люди максимально замотивированы на совершение покупки онлайн-курса.
Человек не осознает наличие проблемы | Человек понимает, что у него есть проблема | Важность проблемы повышается | У человека возникает сильное желание бороться с проблемой | |
Вера в свои силы | Потенциальный слушатель не задумывается о решении проблемы | Человек сомневается, что сможет справиться | Есть понимание, что проблема теоретически решаема | Понимание того, что задачу можно решить конкретным способом |
Нет понимания способа решения проблемы | Человек слышал, что продукт может решить проблему | Ваш продукт рассматривается как вариант решения проблемы наряду с другими | Есть уверенность, что ваш продукт поможет решить проблему | |
Человек узнает, что вы потенциально можете ему помочь | Ваш продукт рассматривается в качестве способа решения проблемы наряду с другими | Человек хочет, чтобы именно вы ему помогли | ||
Мнение об инфопродукте | Потенциальный клиент ничего не знает о продукте | Человек узнает, что ваш продукт может ему помочь | Есть понимание того, что инфопродукт содержит способ решения проблемы | Клиент хочет обратиться именно к вам |
Перевод потенциальных клиентов с первого уровня на четвертый называется прогревом. Именно на последнем уровне находится «горячая» аудитория, которая хочет купить онлайн-курс, и именно на этом этапе совершается большинство продаж.
Какую стратегию прогрева выбрать, чтобы запустить курс с максимальной эффективностью? Ответить на этот вопрос сложно. Как правило, прорабатывая этапы запуска онлайн-курса, маркетологи и специалисты по рекламе используют разные подходы, проверяя их эффективность на различных сегментах ЦА. Это позволяет выявить наилучшую стратегию того, как запустить онлайн-курс, получив конечного слушателя по наименьшей цене. Подробнее о выборе стратегии продвижения онлайн-школ читайте у нас в блоге.
Пошаговая инструкция по подготовке контента для привлечения клиентов
Готовить контент перед запуском онлайн-курса стоит, опираясь на матрицу осознанности. Для каждого уровня нужны свои посты/видео, которые бы «дожимали» ЦА на этом уровне и помогали перейти на следующий. При этом на каждом из этапов запуска курса нужно прорабатывать три основных направления:
- понимание наличия проблемы;
- веру в информационный продукт/вас как эксперта;
- веру в собственные силы и способность справиться с проблемой при помощи инфопродукта.
Также на каждом уровне нужна проработка возражений. Перед тем, как запустить онлайн-курс, стоит трезво оценить продукт — а в идеале попросить посторонних людей дать объективную оценку. На основе обратной связи составляется список возражений — тех моментов, которые могут помешать человеку из целевой аудитории купить онлайн-курс. Это может быть высокая цена, отсутствие веры в собственные силы, занятость, наличие особых обстоятельств (семья, дети, отсутствие образования и т.д.), неудача в предыдущих аналогичных проектах. По всем этим вопросам нужно подготовить убедительные, аргументированные ответы, успешные кейсы, статистику, отзывы на курс и т.д.
Четкий план запуска онлайн-курса позволит вам не упустить из внимания ключевые моменты, а в случае ошибки отследить, на каком этапе она возникла, и исправить.
Если вы не знаете, как запустить онлайн-курс с максимальной выгодой, не теряйте время и деньги — обратитесь к нам. Специально для вас мы подготовили услуги по продвижению и продюсированию онлайн-школ. Мы привлечем заинтересованных слушателей и поможем вам стать уверенным и полноправным участником сегмента онлайн-образования.
Файлы Dockerfile
Используйте многоэтапные сборки
Воспользуйтесь многоэтапными сборками для того, чтобы создавать более компактные и лучше защищённые образы Docker.
Многоэтапные сборки Docker позволяют разделять выполнение действий, описываемых в файлах Dockerfile, на несколько этапов. Например, можно выделить этап компиляции и сборки приложения, а тем, что получится после прохождения этого этапа, можно воспользоваться на следующих этапах. Так как для создания образа используется лишь один, финальный этап, зависимости и инструменты, связанные с подготовкой приложения к работе, в итоговый образ не входят, что позволяет выйти на компактный, модульный образ, готовый к использованию в продакшне.
Вот пример файла Dockerfile из сферы веб-разработки:
# Этап, на котором выполняются подготовительные действия
FROM python:3.9-slim as builder
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN apt-get update && \ apt-get install -y --no-install-recommends gcc
COPY requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
# Финальный этап
FROM python:3.9-slim
WORKDIR /app
COPY --from=builder /app/wheels /wheels
COPY --from=builder /app/requirements.txt .
RUN pip install --no-cache /wheels/*В этом примере для установки определённых Python-пакетов требуется компилятор GCC. Поэтому мы описываем в файле этап, нужный лишь во время сборки проекта. Так как финальный образ, который будет использоваться для запуска проекта, не включает в себя GCC, этот образ получается компактнее и безопаснее, чем он был бы, если бы в его состав входил этот компилятор.
Сравним размеры образов:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-single latest 8d6b6a4d7fb6 16 seconds ago 259MB
docker-multi latest 813c2fa9b114 3 minutes ago 156MBВот пример Dockerfile из сферы Data Science:
# Этап, на котором выполняются подготовительные действия
FROM python:3.9 as builder
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /wheels jupyter pandas
# Финальный этап
FROM python:3.9-slim
WORKDIR /notebooks
COPY --from=builder /wheels /wheels
RUN pip install --no-cache /wheels/*Сравним размеры образов:
REPOSITORY TAG IMAGE ID CREATED SIZE
ds-multi latest b4195deac742 2 minutes ago 357MB
ds-single latest 7c23c43aeda6 6 minutes ago 969MBВ итоге можно отметить, что применение многоэтапных сборок позволяет выходить на более компактные продакшн-образы, что способствует экономии времени и денег. Это, кроме того, позволяет упростить продакшн-контейнеры. Благодаря тому, что образы имеют меньшие размеры, чем при использовании обычных сборок, и тому, что устроены они проще, поверхность атаки таких образов, в потенциале, меньше, чем у обычных образов.
Располагайте команды в файлах Dockerfile в надлежащем порядке
Обращайте особое внимание на порядок расположения команд в файлах Dockerfile для того чтобы пользоваться возможностями Docker по кешированию слоёв.
Docker выполняет кеширование каждого шага (или слоя) при обработке файлов Dockerfile для того чтобы ускорить выполнение следующих шагов. Когда содержимое слоя меняется, кеш подвергается инвалидации, причём речь идёт не только о кеше изменённого слоя, но и о кешах всех следующих за ним слоёв.
Вот пример:
FROM python:3.9-slim
WORKDIR /app
COPY sample.py .
COPY requirements.txt .
RUN pip install -r /requirements.txtВ этом Dockerfile мы скопировали код приложения до установки зависимостей с использованием файла requirements.txt. Теперь каждый раз, когда мы будем менять sample.py, будет осуществляться и переустановка пакетов-зависимостей. Это весьма неэффективный подход, особенно при использовании контейнера Docker для организации среды разработки. В результате важно, чтобы работа с файлами, которые часто меняются, была бы описана в слоях, которые описаны ближе к концу Dockerfile.
Выполнение нежелательных операций по инвалидации кеша можно предотвратить, воспользовавшись файлом .dockerignore. Это позволяет исключить попадание ненужных файлов в контекст сборки и в финальный образ Docker. Мы ещё затронем эту тему.
Итак, для улучшения ситуации с кешированием, в вышеприведённом Dockerfile стоит перенести команду COPY sample.py . в конец файла:
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r /requirements.txt
COPY sample.py .Обратите внимание на следующее:
Составляя файлы Dockerfile, всегда старайтесь размещать слои, которые, вероятнее всего, будут меняться как можно ближе к концу файла.
Комбинируйте команды RUN apt-get update и RUN apt-get install. (Это, кроме того, положительно сказывается на размерах файлов. Мы ещё об этом поговорим.)
Если вам нужно отключить кеширование для конкретной Docker-сборки — воспользуйтесь опцией –no-cache=True.
Стремитесь к использованию как можно более компактных базовых образов Docker
Маленькие образы Docker отличаются более высоким уровнем модульности и безопасности, чем более крупные образы.
Чем меньше образ — тем быстрее осуществляется его сборка, загрузка в репозиторий и скачивание из репозитория. Компактные образы, кроме того, обычно безопаснее больших образов, так как в их состав входят только библиотеки и системные зависимости, которые необходимы для запуска приложения.
Каким именно базовым образом Docker стоит пользоваться?
На этот вопрос, к сожалению, нет однозначного ответа. Всё зависит от конкретной ситуации.
Вот сравнение размеров различных базовых Docker-образов для Python:
REPOSITORY TAG IMAGE ID CREATED SIZE
python 3.9.6-alpine3.14 f773016f760e 3 days ago 45.1MB
python 3.9.6-slim 907fc13ca8e7 3 days ago 115MB
python 3.9.6-slim-buster 907fc13ca8e7 3 days ago 115MB
python 3.9.6 cba42c28d9b8 3 days ago 886MB
python 3.9.6-buster cba42c28d9b8 3 days ago 886MBХотя образ 3.9.6-alpine3.14, основанный на Alpine Linux, является самым компактным в этом списке, его применение часто приводит к увеличению времени сборки образа. Это происходит в том случае, если не удаётся найти нужные предварительно скомпилированные исполняемые файлы, которые будут в нём работать. В результате при выборе такого образа необходимые бинарники может понадобиться собирать самостоятельно, а это способно привести к увеличению размеров образа (что зависит от необходимых зависимостей системного уровня) и к увеличению времени сборки (из-за необходимости компиляции чего-либо из исходного кода).
Если вас интересуют подробности о том, почему в Python-проектах лучше не использовать базовые образы, основанные на Alpine Linux — взгляните на этот и этот материалы.
В результате, можно сказать, что подбор базового образа — это вопрос баланса. Если вы не можете решить, какой именно образ выбрать для разработки приложения, остановитесь на *-slim-разновидности интересующего вас образа. Особенно — если речь идёт об образе, используемом в процессе разработки. Процесс разработки упрощает отсутствие необходимости в постоянном обновлении Dockerfile для установки нужных зависимостей системного уровня при добавлении в проект новых Python-пакетов. А когда речь идёт о подготовке приложения и файлов Dockerfile к прощакшн-использованию, об оптимизации размеров и уменьшении поверхности атаки готового решения, вероятно, есть смысл рассмотреть возможность использования Alpine Linux-образа в роли базы для финального образа, полученного на выходе многоэтапной сборки.
Кроме того, не забывайте регулярно обновлять используемые вами базовые образы. Это способствует улучшению уровня безопасности и производительности готового решения. Когда выходит новая версия базового образа (например, в проекте используется 3.9.6-slim, а вышла 3.9.7-slim), стоит скачать новый образ и обновить работающие контейнеры, что позволит оснастить их самыми свежими патчами безопасности.
Минимизируйте количество слоёв образов
Комбинировать, всегда, когда это возможно, команды RUN, COPY и ADD — это отличная идея. Дело в том, что использование этих команд приводит к созданию слоёв. Каждый слой увеличивает размер образа, так как слои кешируются. В результате по мере того, как растёт количество слоёв, входящих в образ, растёт и размер образа.
Исследовать этот вопрос для конкретного образа можно с помощью команды docker history:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dockerfile latest 180f98132d02 51 seconds ago 259MB
$ docker history 180f98132d02
IMAGE CREATED CREATED BY SIZE COMMENT
180f98132d02 58 seconds ago COPY . . # buildkit 6.71kB buildkit.dockerfile.v0
<missing> 58 seconds ago RUN /bin/sh -c pip install -r requirements.t… 35.5MB buildkit.dockerfile.v0
<missing> About a minute ago COPY requirements.txt . # buildkit 58B buildkit.dockerfile.v0
<missing> About a minute ago WORKDIR /app
...Обратите внимание на размеры. Только использование команд RUN, COPY и ADD приводит к увеличению размеров образа. Уменьшить размер образа можно, комбинируя эти команды всегда, когда это возможно. Вот пара команд:
RUN apt-get update
RUN apt-get install -y netcatИх можно скомбинировать в одну:
RUN apt-get update && apt-get install -y netcatВ результате вместо двух слоёв будет создан один слой, что приведёт к уменьшению размеров финального образа.
Хотя сокращение числа слоёв, входящих в образ — это, в целом, хорошо, важно понимать, что не стоит видеть своей главной целью именно это, что главное тут — побочный эффект, выражающийся в уменьшении размеров образа и в сокращении времени сборки образа. Другими словами, рекомендуется уделять больше внимания трём предыдущим советам (многоэтапным сборкам, порядку команд в Dockerfile, подбору компактных базовых образов), а не пытаться оптимизировать абсолютно все команды.
Размышляя о слоях, из которых состоит образ, учитывайте следующее:
Использование команд RUN, COPY и ADD приводит к созданию слоёв.
Каждый слой содержит сведения о его отличиях от предыдущего слоя.
Слои увеличивают размеры финального образа.
Вот несколько дополнительных советов, касающихся работы со слоями:
Комбинируйте взаимосвязанные команды.
Удаляйте ненужные файлы, находясь в том же слое, созданном командой RUN, в котором они созданы.
Минимизируйте число вызовов apt-get upgrade, так как эта команда обновляет все пакеты, которые можно обновить, до их последних версий.
При использовании многоэтапных сборок не уделяйте слишком много времени тонкой оптимизации команд этапов, на которых выполняются подготовительные действия.
И, наконец, чтобы улучшить читабельность кода команд, списки аргументов, разбитые на несколько строк, имеет смысл располагать в алфавитно-цифровом порядке:
RUN apt-get update && apt-get install -y \ git \ gcc \ matplotlib \ pillow \ && rm -rf /var/lib/apt/lists/*Используйте непривилегированные контейнеры
По умолчанию Docker выполняет процессы в контейнере с root-правами. Но это порочная практика, так как процесс с root-правами, выполняющийся внутри контейнера, выполняется с root-правами и на Docker-хосте. Из этого следует, что, если злоумышленник получит доступ к контейнеру, то у него будет возможность воспользоваться всеми root-привилегиями. В результате он сможет атаковать и Docker-хост. Например, речь идёт о следующих атаках:
Копирование секретной информации из файловой системы хоста в контейнер.
Выполнение удалённых команд.
Для того чтобы не допустить подобного — обеспечьте выполнение контейнеризованных процессов с правами пользователей, не являющихся root-пользователями:
RUN addgroup --system app && adduser --system --group app
USER appМожно пойти и ещё дальше, отключив пользователю shell-доступ и отказавшись от создания его домашней директории:
RUN addgroup --gid 1001 --system app && \ adduser --no-create-home --shell /bin/false --disabled-password --uid 1001 --system --group app
USER appПроверим эту конфигурацию:
$ docker run -i sample id
uid=1001(app) gid=1001(app) groups=1001(app)Здесь контейнеризованное приложение запускается с правами пользователя, не являющегося root-пользователем. Но, принимая во внимание вышесказанное, учитывайте то, что демон Docker и сам контейнер при этом запускаются с root-привилегиями. Для того чтобы наладить запуск демона и контейнеров без root-привилегий — обратитесь к этому разделу документации Docker.
Если это возможно — используйте COPY вместо ADD
Если вы уверены в том, что вам не нужны дополнительные возможности, которые даёт команда ADD — используйте команду COPY.
В чём разница между COPY и ADD? Обе команды позволяют копировать в Docker-образы файлы из различных мест:
ADD <src> <dest>
COPY <src> <dest>Хотя, похоже, что эти команды предназначены для решения одной и той же задачи, команда ADD отличается некоторыми дополнительными возможностями:
Команда COPY используется для копирования с Docker-хоста в образ локальных файлов и директорий.
Команду ADD можно использовать и для решения той же задачи, и для загрузки в образ файлов из внешних источников. Кроме того, если речь идёт об исходных файлах ( в вышеприведённом описании команд), которые представляют собой архивы (хранящиеся в форматах tar, gzip, bzip2 и так далее), команда ADD автоматически распакует такие файлы в целевую директорию.
# Копирование локальных файлов с хоста в целевую директорию
COPY /source/path /destination/path
ADD /source/path /destination/path
# Загрузка внешнего файла и копирование его в целевую директорию
ADD http://external.file/url /destination/path
# Копирование и распаковка локального сжатого файла
ADD source.file.tar.gz /destination/pathКешируйте Python-пакеты на Docker-хосте
Когда изменяется файл requirements.txt — для установки новых пакетов нужно пересобрать образ. Данные предыдущих шагов будут кешированы, речь об этом шла в разделе «Минимизируйте количество слоёв». Загрузка всех пакетов при повторной сборке образа может привести к необходимости передачи больших объёмов данных по сети и может занять много времени. При каждой пересборке образа на загрузку обычных пакетов, используемых в разных образах, уходит примерно одно и то же время.
Избежать этого можно, указав локальную директорию, расположенную на хост-машине, в качестве директории, в которой хранится pip-кеш. После того как пакеты загружаются, они сохраняются в локальном кеше, что может ускорить операции повторной сборки образов, в которых используются эти пакеты.
Место для кеширования пакетов можно указать в виде опции при запуске Docker (-v $HOME/.cache/pip-docker/:/root/.cache/pip), назначение соответствующей директории директорией, где хранится кеш, можно описать и в файле настройки Docker Compose.
В коде, показанном выше, приведён лишь пример директории с кешем. Вы же можете выбрать ту директорию, которая вам нужна. Проверьте, чтобы в качестве директории, где хранится кеш, была бы назначена правильная директория, а не та, в которой хранятся пакеты, имеющие отношение к конкретному проекту (та, где находятся пакеты, используемые при сборке).
Перемещение кеша из Docker-образа на хост может помочь в деле уменьшения размеров финального образа.
Если вы применяете Docker BuildKit, можно для управления кешем воспользоваться ключом –mount=type=cache:
# syntax = docker/dockerfile:1.2
...
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \ pip install -r requirements.txt
...Запускайте в одном контейнере лишь один процесс
Почему рекомендуется запускать в одном контейнере лишь один процесс?
Представим, что стек вашего приложения состоит из двух веб-серверов и одного сервера базы данных. Хотя и можно, без особых сложностей, запустить все эти сервисы в одном контейнере, каждый из них следует запускать в отдельном контейнере, что облегчает повторное использование и масштабирование каждого отдельного сервиса. Можно отметить следующие сильные стороны такого решения:
Масштабируемость: если каждый сервис работает в собственном контейнере — можно горизонтально масштабировать веб-серверы в том случае, если возникнет необходимость в обработке большего, чем обычно, объёма трафика.
Возможность повторного использования кода: может быть, у вас есть другой сервис, нуждающийся в контейнеризованном сервере базы данных. Если у вас есть такой сервер, оформленный в виде отдельного контейнера, этот контейнер можно легко использовать повторно, не сталкиваясь при этом с дополнительной нагрузкой в виде двух ненужных веб-серверов, находящихся в том же контейнере.
Логирование: если в одном контейнере работают разные сервисы — это значительно усложняет задачу логирования. Подробнее об этом мы поговорим ниже.
Переносимость и предсказуемость: гораздо легче устанавливать патчи безопасности или заниматься отладкой в том случае, если речь идёт об одном процессе, а не о нескольких.
Всегда, когда это возможно, используйте exec-формы инструкций CMD и ENTRYPOINT
Инструкции CMD и ENTRYPOINT в файлах Dockerfile можно оформлять с использованием массивов (exec-форма) или с использованием строк (shell-форма):
# массив (exec)
CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "main:app"]
# строка (shell)
CMD "gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app"Оба способа оформления этих инструкций корректны и позволяют добиться практически одного и того же результата, но, всегда, когда это возможно, следует использовать их exec-форму. Вот что об этом сказано в документации Docker:
Постарайтесь использовать в файлах Dockerfile exec-форму инструкций CMD и ENTRYPOINT.
Итак, из-за того, что большинство оболочек не передают сигналы дочерним процессам, при использовании shell-формы команд сочетание клавиш CTRL+C (которое генерирует SIGTERM) может не остановить дочерний процесс.
Вот пример:
FROM ubuntu:18.04
# Плохо: shell-формат
ENTRYPOINT top -d
# Хорошо: exec-формат
ENTRYPOINT ["top", "-d"]Попробуйте оба варианта. Обратите внимание на то, что при использовании shell-формата сочетание клавиш CTRL+C не «убивает» процесс. Вместо этого можно увидеть ^C^C^C^C^C^C^C^C^C^C^C.
Ещё один недостаток shell-формата заключается в том, что при его использовании мы имеем дело с PID командной оболочки, а не самого процесса.
# exec-формат
root@18d8fd3fd4d2:/app# ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:00 python manage.py runserver 0.0.0.0:8000 7 ? Sl 0:02 /usr/local/bin/python manage.py runserver 0.0.0.0:8000 25 pts/0 Ss 0:00 bash 356 pts/0 R+ 0:00 ps ax
# shell-формат
root@ede24a5ef536:/app# ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:00 /bin/sh -c python manage.py runserver 0.0.0.0:8000 8 ? S 0:00 python manage.py runserver 0.0.0.0:8000 9 ? Sl 0:01 /usr/local/bin/python manage.py runserver 0.0.0.0:8000 13 pts/0 Ss 0:00 bash 342 pts/0 R+ 0:00 ps axРазберитесь с различиями инструкций ENTRYPOINT и CMD
Что использовать для запуска контейнеризованных процессов? ENTRYPOINT или CMD?
Существует два способа запуска команд в контейнере:
CMD ["gunicorn", "config.wsgi", "-b", "0.0.0.0:8000"]
# и
ENTRYPOINT ["gunicorn", "config.wsgi", "-b", "0.0.0.0:8000"]Обе, в общем-то, решают одну и ту же задачу: запускают приложение config.wsgi с помощью сервера Gunicorn и привязывают его к 0.0.0.0:8000.
Инструкцию CMD легко переопределить. Если для запуска контейнера воспользоваться командой вида docker run uvicorn config.asgi, то аргументы вышеприведённой инструкции CMD будут заменены новыми аргументами (например — uvicorn config.asgi). А вот для переопределения ENTRYPOINT придётся приложить некоторые усилия, которые заключаются в использовании опции –entrypoint:
docker run --entrypoint uvicorn config.asgi <image_name>В данном случае совершенно очевидно то, что мы переопределяем ENTRYPOINT. Поэтому рекомендуется пользоваться ENTRYPOINT, а не CMD для того, чтобы не допустить случайного переопределения некоей инструкции.
Эти инструкции, кроме того, можно использовать и совместно.
Например:
ENTRYPOINT ["gunicorn", "config.wsgi", "-w"]
CMD ["4"]Когда они, как здесь, используются совместно, команда, которая выполняется при запуске контейнера, выглядит так:
gunicorn config.wsgi -w 4Как уже было сказано, инструкцию CMD очень легко переопределить. В результате CMD можно использовать для передачи аргументов инструкции ENTRYPOINT. То есть — в данном случае предельно просто настроить число рабочих процессов:
docker run <image_name> 6Благодаря использованию такой команды контейнер будет запущен с шестью, а не с четырьмя рабочими процессами.
Пользуйтесь инструкцией HEALTHCHECK
Используйте инструкцию HEALTHCHECK для того, чтобы проверить то, что процесс, выполняемый в контейнере, не просто функционирует, а ещё и находится в «здоровом» состоянии.
Docker обладает API для проверки состояния процессов, выполняемых в контейнере. Этот API даёт о процессе больше сведений, чем лишь данные о том «работает» этот процесс или нет. Дело в том, что если процесс «работает» — это может означать и то, что он «находится в нормальном работоспособном состоянии», и то, что он «всё ещё запускается», и даже то, что он «ведёт себя неправильно и застрял в бесконечном цикле». Работать с этим API можно, используя инструкцию HEALTHCHECK.
Например, если вы поддерживаете веб-приложение, вы можете воспользоваться следующей командой для того, чтобы узнать о том, работоспособна ли конечная точка /, и о том, может ли она обрабатывать запросы, обеспечивающие функционирование приложения:
HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1Если выполнить команду docker ps — можно видеть результаты проверки HEALTHCHECK:
Вот — пример «здорового» контейнера:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09c2eb4970d4 healthcheck "python manage.py ru…" 10 seconds ago Up 8 seconds (health: starting) 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp xenodochial_clarkeВот — пример контейнера, с которым что-то не так:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09c2eb4970d4 healthcheck "python manage.py ru…" About a minute ago Up About a minute (unhealthy) 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp xenodochial_clarkeМожно пойти ещё дальше и подготовить специальную конечную точку, предназначенную исключительно для проверки «здоровья» сервисов, а после этого настроить HEALTHCHECK на проверку возвращаемых этой конечной точкой данных. Например, если конечная точка возвращает JSON-ответ {«ping»: «pong»}, можно предложить HEALTHCHECK проверить на правильность тело ответа.
Вот как просмотреть результаты HEALTHCHECK-проверки с использованием docker inspect:
❯ docker inspect --format "{{json .State.Health }}" ab94f2ac7889
{ "Status": "healthy", "FailingStreak": 0, "Log": [ { "Start": "2021-09-28T15:22:57.5764644Z", "End": "2021-09-28T15:22:57.7825527Z", "ExitCode": 0, "Output": "..."Здесь, для краткости, приведена лишь часть выходных данных, так как в их полном виде приведён большой объём HTML-кода.
Проверку можно включить и в файле настройки Docker Compose:
version: "3.8"
services: web: build: . ports: - '8000:8000' healthcheck: test: curl --fail http://localhost:8000 || exit 1 interval: 10s timeout: 10s start_period: 10s retries: 3Здесь доступны следующие опции:
test: команда для выполнения проверки.
interval: интервал тестирования (то есть, например, проводить тесты через каждые 10 секунд).
timeout: максимальное время ожидания ответа.
start_period: момент начала проверок. Эту опцию можно использовать в том случае, если перед тем, как контейнер будет готов к работе, нужно выполнить какие-то дополнительные операции, вроде миграции контейнера.
retries: максимальное число попыток выполнения теста, после которого тест может быть сочтён непройденным.
Если вы используете инструменты оркестрации контейнеров, отличные от Docker Swarm, то есть — Kubernetes или AWS ECS — весьма вероятно то, что эти инструменты имеют собственные внутренние системы для проведения проверок работоспособности процессов. Прежде чем пользоваться инструкциями HEALTHCHECK в своих проектах — обратитесь к документации используемых вами инструментов.
Образы
Ответственно подходите к версионированию Docker-образов
Всегда, когда это возможно, постарайтесь не пользоваться тегом latest.
Если вы полагаетесь на тег latest (это, на самом деле, не совсем «тег», так как он применяется по умолчанию в том случае, когда образ явным образом не тегирован), вы, опираясь на тег образа, не сможете понять, какая именно версия вашего кода работает в контейнере. Это усложняет процедуры проведения отката к предыдущим версиям ПО и открывает дорогу проблемам, связанным со случайной или злонамеренной перезаписью важных данных. Теги, как и инфраструктура, и развёртывания, должны быть иммутабельными.
Вне зависимости от того, как вы организуете работу со своими внутренними образами, категорически не рекомендуется использовать тег latest при описании базовых образов. Это ведёт к возможности непреднамеренного развёртывания в продакшне новой версии базового образа, содержащей изменения, несовместимые с программами, использующими этот образ.
При оформлении внутренних образов стоит использовать описательные теги, что упростит задачу выяснения того, какая именно версия кода работает в конкретном контейнере, облегчит выполнение откатов и позволит избежать коллизий имён тегов.
Например, в состав тега могут входить следующие дескрипторы:
Отметки времени.
Идентификаторы Docker-образов.
Хеши Git-коммитов.
Семантические версии.
О других подходах к составлению тегов вы можете узнать, обратившись к этому ответу на Stack Overflow, посвящённому грамотному версионированию Docker-образов.
Вот пример:
docker build -t web-prod-a072c4e5d94b5a769225f621f08af3d4bf820a07-0.1.4 .Здесь для формирования тега использованы следующие данные:
Имя проекта:
web.Имя окружения:
prod.Хеш Git-коммита:
a072c4e5d94b5a769225f621f08af3d4bf820a07.Семантическая версия:
0.1.4.
Очень важно выбрать схему тегирования образов и чётко её придерживаться. Так как хеши коммитов облегчают задачу перехода от образа к коду, на котором он основан, настоятельно рекомендуется разработать схему тегирования, включающую в себя, кроме прочего, и эти хеши.
Не храните в образах секретные данные
Секретные данные — это информация, которая ни в коем случае не должна попасть в чужие руки. Например это пароли, учётные данные для подключения к базам данных, SSH-ключи, токены, TLS-сертификаты. Подобные данные не должны включаться в состав образов в незашифрованном виде. Дело в том, что пользователи, не имеющие права работать с подобными данными, но получившие доступ к образам, могут извлечь из них эти данные, всего лишь исследовав слои образов.
Не добавляйте секретные данные в файлы Dockerfile в виде обычного текста, особенно — если вы отправляете образы в общедоступные репозитории вроде Docker Hub:
FROM python:3.9-slim
ENV DATABASE_PASSWORD "SuperSecretSauce"Вместо этого такие данные нужно внедрять в контейнеры следующим образом:
Посредством переменных окружения (во время выполнения контейнера).
Посредством аргументов, передаваемых Docker при сборке образов.
С использованием инструментов, доступных в рамках сред оркестрации контейнеров вроде Docker Swarm (с помощью Docker Secrets) или Kubernetes (с помощью Kubernetes Secrets).
Кроме того, можно предотвратить утечку секретных данных путём добавления описаний файлов и папок, в которых обычно хранятся такие данные, в файл .dockerignore:
**/.env
**/.aws
**/.sshИ наконец — чётко описывайте файлы, копируемые в образ, не прибегайте к рекурсивному копированию всех файлов:
# Плохо
COPY . .
# Хорошо
copy ./app.py .Чёткое описание файлов, включаемых в образ, кроме того, позволяет ограничить отключение кеширования.
Переменные окружения
Секретные данные можно передать в контейнер посредством переменных окружения, но эти данные будут видны всем дочерним процессам, связанным контейнерам, средствам логирования данных; посмотреть их можно будет и с помощью docker inspect. Такие данные, кроме того, сложно обновлять:
$ docker run --detach --env "DATABASE_PASSWORD=SuperSecretSauce" python:3.9-slim
d92cf5cf870eb0fdbf03c666e7fcf18f9664314b79ad58bc7618ea3445e39239
$ docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' d92cf5cf870eb0fdbf03c666e7fcf18f9664314b79ad58bc7618ea3445e39239
DATABASE_PASSWORD=SuperSecretSauce
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568
PYTHON_VERSION=3.9.7
PYTHON_PIP_VERSION=21.2.4
PYTHON_SETUPTOOLS_VERSION=57.5.0
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/c20b0cfd643cd4a19246ccf204e2997af70f6b21/public/get-pip.py
PYTHON_GET_PIP_SHA256=fa6f3fb93cce234cd4e8dd2beb54a51ab9c247653b52855a48dd44e6b21ff28bЭто — самый простой и прямолинейный подход к управлению секретными данными в Docker. Хотя этот подход и нельзя назвать самым безопасным, он, всё же, позволяет скрыть секретную информацию от любопытных глаз за тонким защитным слоем и, как говорится, помогает честным людям оставаться честными.
Передача секретных данных в контейнер с использованием общего тома безопаснее, но такие данные должны быть зашифрованы с помощью Vault или AWS Key Management Service (KMS), так как они сохраняются на диске.
Аргументы, передаваемые Docker при сборке образов
Передать в образ секретные данные можно во время его сборки, воспользовавшись соответствующими аргументами, но эти данные будут доступны, посредством команды docker history, тем, у кого есть доступ к образу.
Вот пример:
FROM python:3.9-slim
ARG DATABASE_PASSWORDСборка образа:
$ docker build --build-arg "DATABASE_PASSWORD=SuperSecretSauce" .Если секретные данные нужны лишь в течение некоторого времени, при сборке образа (например SSH-ключи для клонирования приватного репозитория или для загрузки приватного пакета), стоит использовать многоэтапную сборку, так как этапы, на которых выполняются подготовительные действия, не оставляют записей в истории сборки:
# Этап, на котором выполняются подготовительные действия
FROM python:3.9-slim as builder
# секретные данные
ARG SSH_PRIVATE_KEY
# установка git
RUN apt-get update && \ apt-get install -y --no-install-recommends git
# использование ssh-ключа для клонирования репозитория
RUN mkdir -p /root/.ssh/ && \ echo "${PRIVATE_SSH_KEY}" > /root/.ssh/id_rsa
RUN touch /root/.ssh/known_hosts && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts
RUN git clone git@github.com:testdrivenio/not-real.git
# Финальный этап
FROM python:3.9-slim
WORKDIR /app
# копирование репозитория из временного образа
COPY --from=builder /your-repo /app/your-repo
# используем репозиторий для решения неких задач!При многоэтапной сборке в истории сохраняются лишь сведения о финальном образе. Помните о том, что этот подход можно использовать и при работе с секретными данными, которые постоянно нужны приложению, вроде учётных сведений для доступа к базе данных.
Ещё, пользуясь командой docker build, можно прибегнуть к новой опции –secret, которая позволяет передавать в образы Docker секретные данные, которые не сохраняются в образах.
# "docker_is_awesome" > secrets.txt
FROM alpine
# показывает секретные данные из стандартного места для хранения таких данных:
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecretБлагодаря этому секретные данные будут взяты из файла secrets.txt.
Сборка образа:
docker build --no-cache --progress=plain --secret id=mysecret,src=secrets.txt .
# вывод
...
#4 [1/2] FROM docker.io/library/alpine
#4 sha256:665ba8b2cdc0cb0200e2a42a6b3c0f8f684089f4cd1b81494fbb9805879120f7
#4 CACHED
#5 [2/2] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
#5 sha256:75601a522ebe80ada66dedd9dd86772ca932d30d7e1b11bba94c04aa55c237de
#5 0.635 docker_is_awesome#5 DONE 0.7s
#6 exporting to imageИ, наконец, проверим историю для того, чтобы узнать о том, не произошла ли утечка секретных данных:
❯ docker history 49574a19241c
IMAGE CREATED CREATED BY SIZE COMMENT
49574a19241c 5 minutes ago CMD ["/bin/sh"] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago RUN /bin/sh -c cat /run/secrets/mysecret # b… 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:aad4290d27580cc1a… 5.6MBПодробнее о секретных данных, передаваемых в образ в процессе сборки, можно почитать здесь.
Использование инструмента docker secret
Если вы используете Docker Swarm, это значит, что управлять секретными данными вы можете с помощью инструмента docker secret.
Например, инициализируем Docker Swarm:
$ docker swarm initСоздадим, воспользовавшись командой docker secret, секретные данные, которые планируется использовать в Docker:
$ echo "supersecretpassword" | docker secret create postgres_password -
qdqmbpizeef0lfhyttxqfbty0
$ docker secret ls
ID NAME DRIVER CREATED UPDATED
qdqmbpizeef0lfhyttxqfbty0 postgres_password 4 seconds ago 4 seconds agoКогда контейнеру дают доступ к вышеописанным секретным данным — он смонтирует /run/secrets/postgres_password. В этом файле будет содержаться, в виде обычного текста, соответствующий пароль.
Примеряете другие инструменты для оркестрации контейнеров? Вот несколько полезных ссылок на материалы, имеющие отношение к управлению секретными данными с использованием этих инструментов:
Google Kubernetes Engine
Используйте файл. dockerignore
Мы уже несколько раз упоминали файл .dockerignore. Этот файл используется для указания файлов и папок, которые не нужно включать в исходный контекст сборки, отправляемый демону Docker, который потом будет заниматься сборкой образа. Другими словами — можно использовать этот файл для описания необходимого вам контекста сборки образов.
При сборке Docker-образа весь контекст Docker, то есть — корневая директория проекта, отправляется демону Docker до выполнения инструкций COPY или ADD. Это может оказаться крайне ресурсоёмкой операцией, особенно если в проекте имеется множество зависимостей, если в нём есть большие файлы с данными или артефакты сборки. В дополнение этому инструмент командной строки Docker и демон Docker могут размещаться на разных компьютерах. В результате если демон работает на удалённой машине, следует ещё внимательнее следить за размерами контекста сборки.
Что стоит описать в файле .dockerignore?
Временные файлы и папки.
Файлы журналов сборки.
Файлы с локальными секретными данными.
Локальные файлы, используемые в ходе разработки проекта, вроде docker-compose.yml.
Папки, используемые системами контроля версий, вроде .git, .hg и .svn.
Вот пример:
**/.git
**/.gitignore
**/.vscode
**/coverage
**/.env
**/.aws
**/.ssh
Dockerfile
README.md
docker-compose.yml
**/.DS_Store
**/venv
**/envВ результате оказывается, что правильно структурированный файл .dockerignore может помочь в решении следующих задач:
Уменьшение размеров Docker-образа.
Ускорение процесса сборки.
Предотвращение ненужных операций по инвалидации кеша.
Предотвращение утечки секретных данных.
Производите линтинг файлов Dockerfile и сканирование образов
Линтинг — это процесс проверки исходного кода на предмет программных и стилистических ошибок, на предмет использования в нём неудачных методик разработки, применение которых способно привести к каким-то проблемам. Статические файлы, как и файлы с кодом, могут подвергнуты линтингу. В частности, в случае с файлами Dockerfile, линтеры могут помочь проверить то, легко ли будет поддерживать эти файлы, то, что в них не используются устаревшие синтаксические конструкции, и то, что их авторы придерживаются лучших практических приёмов их разработки. Линтинг файлов Dockerfile должен быть стандартным шагом используемых вами CI-конвейеров.
Самым популярным линтером файлов Dockerfile можно назвать Hadolint:
$ hadolint Dockerfile
Dockerfile:1 DL3006 warning: Always tag the version of an image explicitly
Dockerfile:7 DL3042 warning: Avoid the use of cache directory with pip. Use `pip install --no-cache-dir <package>`
Dockerfile:9 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation.
Dockerfile:17 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT argumentsПосмотреть на него в деле можно здесь. Он существует и в виде расширения для VS Code.
Линтинг файлов Dockerfile можно совместить со сканированием контейнеров на предмет уязвимостей.
Вот некоторые инструменты для решения этой задачи:
Snyk — это инструмент, ориентированный на поиск уязвимостей локальных образов Docker, входящий в состав стандартных средств командной строки Docker. Для его использования нужно прибегнуть к команде docker scan.
Trivy можно использовать для сканирования образов контейнеров, файловых систем, Git-репозиториев и других конфигурационных файлов.
Clair — это опенсорсный проект, используемый для статического анализа контейнеров приложений на уязвимости.
Anchore — это ещё один опенсорсный проект, в рамках которого реализован централизованный сервис для исследования, анализа и сертификации образов контейнеров.
В результате можно порекомендовать выполнять линтинг файлов Dockerfile и сканирование образов на уязвимости для выявления потенциальных проблем, выражающихся в отклонениях от общепризнанных рекомендаций.
Подписывайте и верифицируйте образы
Как узнать, что образ, используемый для запуска продакшн-кода, не взломали?
Взлом образа может быть осуществлён дистанционно, с использованием атаки посредника (Man in the middle, MITM), подмена образа может быть осуществлена после компрометации репозитория.
Система Docker Content Trust (DCT) позволяет подписывать и верифицировать образы Docker, загружаемые из удалённых реестров.
Для того чтобы проверять целостность и подлинность образов, нужно установить следующую переменную окружения:
DOCKER_CONTENT_TRUST=1После этого, если попытаться скачать неподписанный образ, будет выдана следующая ошибка:
Error: remote trust data does not exist for docker.io/namespace/unsigned-image:
notary.docker.io does not have trust data for docker.io/namespace/unsigned-imageПодробности о подписывании образов можно найти в документации по Docker Content Trust. При загрузке образов с Docker Hub постарайтесь использовать либо официальные образы, либо верифицированные образы из надёжных источников. Большим командам стоит рассмотреть возможность использования собственного внутреннего приватного реестра контейнеров.
ТОП-30 агентств (компаний, студий) по разработке сайтов
| № п/п | Наименование | Обороты, млн. руб. | Среди клиентов | Год создания |
| 1 | DEFA | 112,7 | Нефтис, Интурист | 2000 |
| 2 | PROSCOM | 68,5 | Mars, IBS, iBinom | 2001 |
| 3 | Extyl-PRO | 42,9 | Эр телеком, Ральф Рингер | 2003 |
| 4 | BETA | 32,2 | Шереметьево, Цветной, СИБУР | 2012 |
| 5 | Синий муравей | 28,3 | ФСК «Лидер», концерн «РУСИЧ», ЛСР | 2010 |
| 6 | Улей | 27,3 | СПбГПУ, Piterra, Доктор Слон | 2006 |
| 7 | Cetera Labs | 27,1 | Vremex, Тихий Дон, Термы мира | 2002 |
| 8 | Hawking Brothers | 23,2 | Bike Center, POSITRON | 2014 |
| 9 | FREE Creative | 23,1 | Coral Black, Tyler, Nike | 2013 |
| 10 | Garin Studio | 20,8 | Audi, ВТБ, Фармстандарт | 2016 |
| 11 | SEO Intellect | 20 | Ашан, ГАЛС-Девелопмент, Karcher | 2010 |
| 12 | Red Collar | 19,9 | Inforza, Scania, Ростелеком | 2011 |
| 13 | Собака Павлова | 19,3 | Faberlic, Yota, Яндекс | 2012 |
| 14 | Webest | 18,7 | ЦЕЛДИ, АСМ СНМ, Вита Эко | 2014 |
| 15 | Alto Vision | 14,5 | Иннополис, КидСпейс, Appnow | 2011 |
| 16 | IronWaterStudio | 11,7 | «Оптима», «Слетать.ру», Хеликс | 2007 |
| 17 | No Logo Studio | 11,1 | РОСНАНО, Московская Фондовая Биржа, ОПИН | 2007 |
| 18 | MWI | 10,5 | 500 Люкс, Eclipse, АО Медицина | 2010 |
| 19 | ДругМедиа | 8,8 | Inglot, ФК “Рубин”, Мэрия Казани | 2012 |
| 20 | KIAN | 6,4 | Санта Бремор, Техносила | 2002 |
| 21 | SEOXL | 6,3 | Vaillant, Отличник, Технопласт | 2011 |
| 22 | Intensity Lab | 6,2 | НоваДент, Gepach International | 2009 |
| 23 | Wow | 5,8 | S7, Победа, Chery | 2004 |
| 24 | GreenMars | 3,9 | LG, Mazda | 2017 |
| 25 | Красная рамка | 3,5 | Пицца-РИО, ТУСУР, Сибирская аграрная группа | 2013 |
| 26 | Альтера | 2,3 | СМ-Клиника, ipGifts, Parure | 2004 |
| 27 | Motionpix | 1,6 | ЛСР, Сбербанк, ИППТ | 2014 |
| 28 | Socialair | 1,2 | Невская косметика, Вертекс, Улыбка радуги | 2012 |
| 29 | True.code | 1,1 | Сбербанк, Роснефть, Easy School | 2013 |
| 30 | Новая идея | 0,9 | Finnopolis, Bayer, Делфо | 2002 |
Подробнее ознакомиться с работой конкретной студии можно в нашем каталоге.
Как выбрать лучшую студию и не потратить деньги впустую?
Выбор целесообразно основывать на следующих параметрах:
- В соответствии с бизнес-задачами необходимо выбрать студию, специализирующуюся на конкретных услугах. Если вам нужен качественный сайт, то следует выбрать веб-студию. В этом случае можно рассчитывать на оптимальное сочетание сроков разработки, цены и качества. Ряд студий также может предложить услуги SEO.

- Изучить портфолио – примеры проектов, сопоставить с тем, что вы хотели бы увидеть для своих задач.
- Посмотреть уровень удовлетворенности клиентов по отзывам.
- Учесть, что небольшие региональные студии могут выполнить проект быстрее и дешевле с хорошим качеством.
- Опыт работы.
По нескольким подобранным студиям сравниваются цены и условия договора для окончательного выбора.
Моя школа в online