Привет!
У меня есть веб апи проект c# .net. Есть воркфлоу в открытом репозитории гитхаб, где я собираю проект, упаковываю в докер образ и публикую опять-таки в публичный докер хаб.
Так же есть два сервера, просто виртуалки, тестовая и прод.
Не очень понятно, как работать с секретами, например, строки подключений к базам.
Ранее, когда не было воркфлоу ci/cd я настраивал трансформации для appsettings.json, например, при билде с конфигурацией Release, применялись трансформации appsettings.Release.json (для прода аналогично) и я со своего компа из исходного кода публиковал прост сразу в нужной конфигурации на нужный сервер (в студии можно сохранять несколько видов публикаций). Эти файлы типа appsettings.Release.json я добавлял в gitignore и не паблишил их в публичный репозиторий, был спокоен.
Трансформации делал через библиотеку slow cheetah как-то так, посмотрел еще, что есть пользовательские секреты, чуть по другому делается, но смысл тот же
Теперь, с этим ci/cd у меня автоматизированно делается сборка, в секреты гитхаба я засунул логин и пароль от докер хаба, но дальше, во-первых, я больше не могу использовать appsettings.Release.json, так как он не хранится в коде, нужно переходить на env переменные и не очень поняно, мне теперь нужно всё что есть в этом файле засунуть в секреты гитхаба? как-то не очень удобно, учитывая, что нужно держать несколько конфигов и как в этом вообще не запутаться
И во-вторых, готовый образ я размещаю в докер хабе, так же в публичном и в нем все равно не должно быть моих подключений, иначе любой, кто развернет мой образ сможет подключаться к моей базе.
То есть, насколько я понимаю, мне нужно применять какие-то свои файлы именно в момент разворачивания образа и я не очень понимаю, как с этим можно удобно работать (прокидывать все настройки через аргументы как-то выглядит совсем ущербно)
Василий Банников, вы соверщенно правы но докер не позволяет без сворма
а валт это наверное черезчур. кромк того рест сервис написать это должнв быть вовсе не сложное упражнение для кольника а Виктор П это по его собственной классификации уверенный пользователь
кубер мне пока сказали рано ковырять, ну и мелкие проекты без него как-то живут.
про докер сварм почитаю, такое надо в ответы закидывать, а не в комменты )
в целом склоняюсь к тому, чтобы сделать апи для деплоймента, выглядит просто и должно быть удобно, но кажется изобретением велосипеда, как другие-то со всем этим живут, хочется узнать
Прокидывай секреты через переменные среды. Благо по умолчанию IConfiguration умеет работать со слоёными конфигами, где по порядку применяются следующие слои:
1. appsettings.json
2. appsettings.Environment.json
3. переменные среды
4. аргументы командной строки
Соответственно никакие трансформации не нужны - можно спокойно пушить конфиг в репозиторий, заменяя секреты какими-нибудь заглушками (например мы туда кладём строки, которые похожи на тот секрет, который должен быть)
Локально (на машине разработчика) переменные среды можно хранить в .env файлах, либо можно продолжать иметь дополнительные appsettings - это тоже ок.
При разворачивании образа, повторюсь, прокидывай секреты в переменные среды.
Так делают почти все, и все оркестраторы умеют с этим работать и прокидывать в переменные среды контейнера значения из каких-нибудь файлов или даже из хранилища секретов типа vault.
Можешь скинуть пару ссылок на туториалы (или видосы от индусов), я не очень хорошо формулирую запрос, видимо, как с этим правильно работать, чтобы удобно было?
Первое, тема какая-то мега-обширная и глаза в принципе разбегаются
Давай разберем по косточкам, переменные окружения, это пары ключ-значение. Если говорить в контексте линукса, то мы можем задать и получить такими командами:
Второе, то, что ты привел, гуглится по словам appsettings.json vs environment variables или override appsettings.json with environment variables
Вкратце, в конфиг мы добавляем что-то вроде такого:
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json")
.AddEnvironmentVariables()
.Build();
И теперь, если у нас есть в файле appsettings.json есть, например
Тогда мы можем задать на сервере (или даже переопределить в райдере или студии через переменные окружения этого проекта). В общем, создать в терминале переменную ASPNETCORE__ConnectionStrings__AppConnection='другое подключение' и тогда при запуске проекта у меня будет использовано другое подключение. Вроде там просто через двойное подчеркивание идет, ну и можно свой префикс поставить.
Тут я всё правильно понял?
Ну это уже как минимум неудобно, например, я добавляю какое-то внешнее апи, мне нужно в appsettings.json добавить три строчки (url, user, password) и руками лезть на все мои окружения и создавать руками такие переменные. Плюс еще писать куда-то в чат своей команде, что мол добавьте себе вот такое, иначе ничего работать не будет. Создавая новую виртуалку для тестирования, мне нужно как-то залезть на работающую и повыдирать все необходимые переменные окружения и руками потом добавить на новую машину, кажется, что я не до конца понимаю, как с этим удобно работать
Конечно же третье, это докер, у него я не уверен, что будет доступ в принципе к переменным окружения на какой-то машине, так как он изолирован. Я увидел, что у него есть свои переменные окружения и мы должны задавать именно в докере, чтобы схема, описанная выше, заработала. Я вижу флаг --build-arg:
Это нам не подходит, так как сборки лежат в докерхабе в открытом репозитории. В принципе, прокатит, если будет приватный репозиторий (то есть можно хранить все секреты в гитхаб секретах, например, и делать сборку через gha под конкретное окружение). Хотя это все равно не правильно, потому что на прод мы должны ставить именно ту же самую сборку, которую ставили на тестовое окружение и тестировали, а не собирать новую.
Дальше я вижу, что можно переменные окружения все же прокидывать через docker run docker run -e MYVAR1 --env MYVAR2=foo ubuntu bash
Вроде как это именно то, что нужно, но... эти переменные будут задаваться так же, как я писал во втором пункте и просто прокидываться на запуск в докер контейнер? Тогда помимо того ада добавится еще один шаг на запуск контейнера с правильными переменными окружения, это многострочная нечитаемая команда, которую нужно будет править с добавлением новой переменной, стало только хуже.
Увидел еще команду на запуск --env-file ./env.list, выглядит перспективно, но я не вижу повсеместного использования
Вроде нормально расписал, надеюсь ход моих мыслей понятен и проблемные места подсвечены.
Как с этим всем нужно работать удобно и правильно?
В общем, создать в терминале переменную ASPNETCORE__ConnectionStrings__AppConnection='другое подключение'
Префикс ASPNETCORE__ тут не нужен.
Ну это уже как минимум неудобно, например, я добавляю какое-то внешнее апи, мне нужно в appsettings.json добавить три строчки (url, user, password) и руками лезть на все мои окружения и создавать руками такие переменные. Плюс еще писать куда-то в чат своей команде, что мол добавьте себе вот такое, иначе ничего работать не будет. Создавая новую виртуалку для тестирования, мне нужно как-то залезть на работающую и повыдирать все необходимые переменные окружения и руками потом добавить на новую машину, кажется, что я не до конца понимаю, как с этим удобно работать
На машине разработчика можно продолжать использовать appsettings.Development.json, который в репозиторий не коммитится.
Можно ещё использовать .env файлы.
Конечно же третье, это докер, у него я не уверен, что будет доступ в принципе к переменным окружения на какой-то машине, так как он изолирован.
Специально ради этого у команды docker run есть параметры, но ты и так их уже нашёл:
-e, --env stringArray Set environment variables in container
--env-file strings Read in a file of environment variables
Тогда помимо того ада добавится еще один шаг на запуск контейнера с правильными переменными окружения, это многострочная нечитаемая команда, которую нужно будет править с добавлением новой переменной, стало только хуже.
А эта проблема уже решается средствами оркестраторов.
У k8s для этого есть configMap, а у docker swarm - хз, но наверняка тоже есть что-то.
Честно скажу, что не уверен, есть ли какой-нибудь компактный способ записывать переменные окружения в маленьких проектах - я в общем-то надеюсь, что секреты добавляются не каждый день и поправить иногда скрипт для запуска - это не большая проблема.
В более крупных проектах у тебя, часто, уже есть vault, k8s и активно используется helm - с помощью них ты можешь автоматизировать прокидывание секретов из предопределённого каталога vault в запускаемый сервис.
Увидел еще команду на запуск --env-file ./env.list, выглядит перспективно, но я не вижу повсеместного использования
Не очень часто пользуются из-за того что dotnet не умеет с ними из коробки работать, и это файлы
Василий Банников >я в общем-то надеюсь, что секреты добавляются не каждый день и поправить иногда скрипт для запуска - это не большая проблема.
Это как раз и смущает, получается должен быть какой-то скрипт для запуска, где он должен лежать и как с ним работать? Например, мне понадобилось создать еще какой-то стенд, дев-стенд или для нагрузочного тестирования, не суть важно. Мне нужно руками залезть на какой-то похожий стенд, командами повыписывать переменные окружения куда-то в блокнот, затем залезть на новую виртуалку и там руками повбивать аналогичные переменные. Понадеяться, что ничего не забыл. Затем скопировать какой-то скрипт для запуска, который по сути маппит переменные окружения в докер run. Понадеяться, что скрипт актуальный.
По сути это текстовички, которые будут копироваться с сервера на сервер. Но где система контроля версий? Где правило infrastructure as code?
С --env-file для докера (не для .net проекта) звучит попроще в том плане, что если нужно развернуть аналогичный стенд, то можно просто скопировать один файл. Ну и в целом сравнивать два файла проще, чем отдельные переменные, а если мы их засунем в гит, пусть даже в отдельный приватный репозиторий, то придем к тому, с чего начали, что нельзя секреты хранить в коде, кто получит доступ к репозиторию, получит доступ вообще ко всем секретам, и разницы как бы нет с тем, чтобы хранить настройки окружения в appsettings.Release.json и appsettings.Prod.json в приватном репозитории
В общем, звучит всё как-то очень не прикольно и я не могу отделаться от мысли, что как-то все живут и ни у кого никаких проблем в этом нет. (и без куберов с хелмом).
Есть какие-то статьи нормальные или даже может коллективные стандарты, как с этим всем работать, чтобы удобно было?
переменную среды можно назначить персонально каждому процессу свои.
Персонально каждому окружению, а окружение - каждому процессу. Проблема в том, что это сложный многоуровневый процесс, а стандартные команды докера выделяют персональное окружение всем процессам контейнера сразу.
Василий Банников, ну это в теории + зависит от начального образа и предустановленного софта. Вполне возможен вариант случайно отправить свои секреты вместе с телеметрией.