Env файл что это
Практичный гайд по переменным окружения в Go
Привет, Хабр! Представляю вашему вниманию перевод статьи A no-nonsense guide to environment variables in Go автора Enda Phelan.
Переменные окружения — лучший способ хранения конфигурации приложения, поскольку они могут быть заданы на системном уровне. Это один из принципов методологии Twelve-Factor App, он позволяет отделять приложения от системы, в которой они запущены (конфигурация может существенно различаться между деплоями, код не должен различаться).
Использование переменных окружения
Всё, что необходимо для взаимодействия с переменными окружения есть в стандартной библиотеке os. Вот так можно получить значение переменной окружения PATH:
А так — установить значение переменной:
Чтобы установить пакет запустим:
Теперь можно использовать эти значения в приложении:
Важно помнить, что если значение переменной окружения установлено на системном уровне, Go будет использовать именно это значение вместо указанного в env-файле.
Оборачиваем переменные окружения в конфигурационный модуль
Неплохо, конечно, иметь доступ к переменным окружения напрямую, как было показано выше, но вот поддерживать такое решение представляется довольно проблематичным. Имя переменной — это строка и, если оно изменится, то представьте себе головную боль, в которую выльется процесс обновления ссылок на переменную по всему приложению.
Чтобы решить эту проблему создадим конфигурационный модуль для работы с переменными окружения более централизованным и поддерживаемым способом.
Вот простой модуль config, который возвращает параметры конфигурации в структуре Config (также установим дефолтные значения параметров на случай, если переменной окружения в системе не окажется):
Далее добавим типы в структуру Config, поскольку имеющееся решение поддерживает только строковые типы, а это не очень-то разумно для больших приложений.
Создадим хэндлеры для типов bool, slice и integer:
Добавим в наш env-файл новые переменные окружения:
Теперь можно использовать их в любом месте приложения:
Готово!
Да, существуют пакеты, предлагающие готовое решение для конфигурации вашего приложения, но насколько они необходимы, если это так легко сделать самостоятельно?
А как вы управляете конфигурацией в вашем приложении?
Переменные окружения и PHP
Поговорим про конфигурацию и переменные окружения.
Полезные ссылки по теме:
Допустим, у нас есть PHP приложение. Приложению нужна какая-то конфигурация, как минимум настройки подключения к базе данных, возможно настройки подключения к Redis, к почтовому серверу.
Фреймворки общего назначения дают нам достаточно большую гибкость по настройке работы самого фреймворка. Если заглянуть в папку config в Laravel, то увидим там множество различных php файлов описывающих параметры подключения к базе, кеширование, логирование, аутентификацию и многое другое. При этом не все параметры на самом деле являются секретами или зависят от окружения. Есть такие параметры, которые мы задаём на старте разработки проекта и они справедливы для всех окружений и не представляют секрета, например, пути к папкам для шаблонов ( config/view.php в Laravel) или имена файлов для логов.
Получается, часть конфигурации является секретной или зависит от окружения и её мы не хотим добавлять в git репозиторий (максимум, мы можем добавить некий example файл в git репозиторий). А часть конфигурации – это по сути зафиксированные для данного проекта значения и их, конечно, нужно сохранять в git.
Чтобы отделить одни от других, можно развести их по разным конфигурационным файлам.
Для секретной или платформозависимой части конфигурации можно использовать так называемые переменные окружения, которые уже давно были изобретены в unix системах. А в наше время к ним подталкивает и методология 12-факторных приложений, и такие инструменты как Docker, Kubernetes и различные сорта Serverless.
Однако в PHP с переменными окружения есть некоторая путаница давайте разберёмся.
Итак, у нас есть переменные окружения, которые предоставляет нам операционная система (и Linux, и Windows, и macOS). Есть средства чтобы их прочитать из PHP приложения. Казалось бы найдено идеальное место для хранения секретов и настроек зависящих от окружения! Но как эти переменные окружения задать? Тут целая наука.
Впрочем, не будем пока сдаваться и отказываться от переменных окружения, продолжим рассуждать так будто мы их используем.
Ещё один нюанс: php-fpm по умолчанию не передаёт переменные окружения, заданные операционной системой, в свои процессы-воркеры. За это отвечает настройка clear_env в файле конфигурации пула php-fpm (обычно у нас один пул, который называется www и его конфигурация соответственно в файле www.conf ). С этим сталкиваешься, когда пытаешься пробросить переменные окружения в php-fpm внутри Docker контейнера.
Слишком много мороки с настройкой этих переменных окружения!
.env файлы по задумке не рекомендуется использовать в production. Это удобное текстовое описание для конфигурации в процессе разработки, но в production лучше всё-таки пользоваться переменными окружения, предоставляемыми операционной системой.
Подводя итог, сформулируем несколько тезисов:
Конфигурирование и переменные окружения — казалось бы, тема простая, но есть своя глубина и разные подходы. Копайте глубже, это интересно!
Использование переменных окружения в Node.js
Материал, посвящённый переменным окружения в Node.js, перевод которого мы сегодня публикуем, написал Берк Холланд, веб-разработчик, в сферу интересов которого входят JavaScript, Node.js и VS Code. Кроме того, стоит отметить, что у него сложились непростые отношения с Java. Вот его история.
Переменные окружения — одна из фундаментальных конструкций среды Node.js, но почему-то я никогда не стремился научиться правильно ими пользоваться. Возможно, случилось так из-за их названия — «Environment Variables». Это название вызывало у меня нечто вроде посттравматического синдрома, неприятные воспоминания о том, как я пытался добавить путь к домашней директории Java в Windows. Я тогда толком не мог понять, надо ли добавлять этот путь в переменную PATH, в переменную JAVA_HOME, или и туда и туда. Было неясно и то, нужно ли, чтобы в конце этого пути стояла точка с запятой. Собственно говоря, тогда у меня возникал и вопрос о том, почему я использую Java. Как бы там ни было, я наконец нашёл в себе силы и приступил к знакомству с переменными окружения Node.
Если вы пишете для платформы Node.js, и, так же, как и я, неважно — по каким причинам, до сих пор не особенно хорошо знакомы с переменными окружения — предлагаю это исправить.
Переменные окружения в Node.js
В Node переменные окружения могут быть глобальными (как в Windows), но часто они используются в применении к конкретному процессу, в выполнении которого заинтересован разработчик. Например, если у вас имеется веб-приложение, это значит, что в нём могут применяться следующие переменные окружения:
Кстати, на тему «hard code» — задания в коде неких значений вместо получений их из внешних источников, хочу поделиться моим собственным твитом.
Цитирую сам себя на пике помешательства
Как же использовать переменные окружения в Node.js-приложениях? Мне пришлось изрядно потрудиться для того, чтобы найти хороший материал по переменным окружения в Node, с непременным условием наличия в этом материале достаточного количества шуток о Java. Такого материала я не нашёл, поэтому решил написать его сам.
Вот несколько способов использования переменных окружения в приложениях для Node.js.
Указание переменных окружения в терминале
Вы можете указывать переменные окружения в терминале, в котором планируется запускать Node. Например, если у вас имеется приложение, использующее Express, и вы хотите передать ему сведения о порте, сделать это можно так:
Кстати, интересная вещь. Оказывается, самое большое значение, которое может принимать номер порта, это 65535. Как я это узнал? Конечно, нашёл на StackOverflow. Как вообще кто-либо что-либо узнаёт? Но в Node самый большой номер порта — это 65534. Почему? Понятия не имею. Я не могу знать абсолютно всё.
Однако использование описанного здесь подхода может плохо кончиться. Если у вас есть, например, строка подключения к базе данных, вы, вероятно, не будете особенно рады перспективам её ввода в терминал. На самом деле, ввод длинных значений в терминале похож на болезненную зависимость, а нам это совершенно ни к чему. Посмотрите сами:
Такой подход не масштабируется, а все хотят масштабирования. По мнению каждого архитектора, рядом с которым мне доводилось сидеть на разных мероприятиях, «масштабирование» — это даже важнее, чем сам факт работоспособности приложения.
Читать эти значения можно разными способами. Пожалуй, проще всего — с помощью пакета dotenv из npm :
Итак, пока всё хорошо, но то, о чём мы тут говорили, не очень-то удобно. Подключать dotenv придётся в каждом файле, где надо использовать переменные окружения, и dotenv придётся использовать в продакшне, когда, в сущности, вам это не нужно. Я не отношусь к фанатам развёртывания бесполезного кода в продакшне, хотя, мне кажется, до сих пор я только этим и занимался.
Что же делать? К счастью, вы пользуетесь VS Code (я абсолютно в этом уверен), а это значит, что у вас есть ещё несколько вариантов.
Конфигурация запуска VS Code
Создание базовой конфигурации запуска для Node
После того, как вы создадите базовую конфигурацию запуска для Node (щёлкните по значку с шестерёнкой и выберите Node), можно выполнить одно из следующих действий, или сделать и то и другое.
Первый вариант заключается во включении переменных в конфигурационный файл.
Переменные в конфигурационном файле
Это — вполне приемлемый вариант, но меня немного беспокоит то, что каждое значение должно быть строкой. Всё-таки некоторые значения — это числа, а не строки, а в JavaScript есть лишь, скажем так, три основных типа данных, и мне не хотелось бы лишаться одного из них.
До тех пор, пока мы запускаем процесс Node.js из VS Code, файл с переменными окружения будет передаваться этому процессу. При этом нам не придётся втискивать числа в кавычки, делая из них строки, и не придётся разворачивать ненужный код в продакшне. Ну, по крайней мере, вам этого делать не придётся.
Запуск node-скриптов через NPM
Задача Launch Via NPM
Настройка запуска проекта с помощью npm
Переменные окружения в продакшне
В продакшне определение переменных окружения будет зависеть от особенностей используемой платформы. Например, в случае с Azure есть три способа объявления таких переменных и управления ими.
Первый способ заключается в использовании Azure CLI.
Это работает, но выглядит не очень. Ещё один способ — использование веб-портала Azure. Я не часто пользуюсь веб-порталом, но когда это случается, я обращаюсь к нему именно для установки переменных окружения.
Здесь то, что мы называем «переменными окружения», называется «Application Settings».
Настройка переменных окружения в Azure
Ещё один вариант, учитывая то, что вы пользуетесь VS Code, заключается в установке расширения App Service и в настройке вышеописанных Application Settings прямо из редактора.
Настройка переменных окружения из VS Code
Мне нравится делать в VS Code абсолютно всё, и если бы там можно было бы писать электронные письма, я бы так и поступал. Кстати, похоже, моя мечта сбылась.
Итоги
Теперь вы знаете то же, что знаю я (не так много, позволю заметить), и я чувствую, что выполнил свою цель по шуткам на тему Java. Если вдруг их тут недостаточно — вот ещё одна, автор которой неизвестен: «Java — это очень мощный инструмент по превращению XML в стек-трейсы».
Уважаемые читатели! Как вы решаете проблемы использования переменных окружения Node в ходе разработки и в продакшне?
Переменные окружения позволяют переключаться между локальной разработкой, подготовительной средой, пользовательским приемочным тестированием (UAT), производственной средой и любыми другими средами, которые являются частью рабочего процесса вашего проекта.
Вместо того чтобы по отдельности передавать переменные в скрипты, с помощью env-cmd вы можете группировать их в файлах окружения (.env) и передавать эти группы в скрипт.
В этом мануале вы узнаете, как установить env-cmd и использовать его (на примере простого тестового проекта).
Требования
Примечание: Это руководство использует команды для env-cmd версии 9.0.0+.
Руководство проверено на версиях Node v15.14.0, npm v7.10.0 и env-cmd v10.0.1.
1: Настройка проекта
В этом руководстве предполагается, что у вас уже есть простой тестовый проект. Давайте подготовим его к работе с переменными.
Сначала создайте новый каталог:
Передавать файлы среды в систему управления версиями, как правило, не рекомендуется. Если доступ к репозиторию могут получить посторонние, они найдут там ваши учетные данные (поскольку они будут навсегда записаны в историю проекта системой контроля версий).
Примечание: Мы не требуем добавлять файлы в gitignore в рамках этого мануала, но в образовательных целях коротко расскажем, как это делается.
Инициализируйте новый проект git:
Откройте его в редакторе кода и добавьте следующую строку:
Это определяет три переменные: creature со значением shark, green со значением #008f68 и yellow со значением #fae042.
Затем создайте новый файл log.js и поместите в него такие строки:
Этот файл будет записывать ранее определенные переменные в консоль. Также он выведет значение NODE_ENV.
Теперь наше тестовое приложение подготовлено к использованию файлов окружения и env-cmd.
2: Использование env-cmd
Современные утилиты npm и yarn могут запускать env-cmd, не внося его в зависимости.
Используйте либо npx:
npx env-cmd node log.js
yarn run env-cmd node log.js
Также вы можете установить пакет как зависимость или devDependency:
npm install env-cmd@10.0.1
Пакет env-cmd устанавливает исполняемый сценарий env-cmd, который можно вызывать перед другими сценариями, чтобы легко загрузить переменные среды из внешнего файла.
В зависимости от ваших настроек вы можете ссылаться на env-cmd несколькими способами.
Возможно, наиболее совместимым с пакетными менеджерами вариантом является добавление пользовательского скрипта в файл package.json:
Например, вы сможете запустить этот сценарий с помощью npm:
Если вы предпочитаете использовать env-cmd непосредственно через командную строку, вы можете вызвать его из node_modules:
./node_modules/.bin/env-cmd node log.js
В дальнейшем в этом руководстве будет использоваться npx, но все описанные выше подходы одинаково хороши.
Теперь запустите сценарий в своем терминале.
Передать NODE_ENV можно перед вызовом env-cmd. К примеру, вот команда для npx, которая сделает это:
NODE_ENV=development npx env-cmd node log.js
Снова запустите команду с определенной NODE_ENV, и вы получите такой результат:
3: Форматы файлов
Есть множество форматов файлов, доступных для хранения переменных окружения.
Файл JSON
А вот пример использования этого формата для файла env-cmd:
Файлы окружения в формате JavaScript
А вот пример файла env-cmd в этом формате:
RC-файлы
Формат файла rc (или runcom) особенный: он позволяет определять несколько сред в одном файле JSON и ссылаться на среду по имени, а не по файлу.
Затем вы можете сослаться на одну из сред в файле с помощью команды:
Вы даже можете ссылаться на несколько сред, что объединит все переменные среды (причем последняя среда будет иметь приоритет, если одни и те же переменные встречаются в нескольких средах, но имеют разные значения):
Указав все три среды, мы установим три разные переменные otherVar, а остальные переменные будут извлечены из последней указанной среды, production.
4: Флаг –fallback
В ситуациях, когда пользовательский файл окружения отсутствует:
env-cmd выдаст ошибку:
5: Флаг –no-override
В некоторых ситуациях возникает необходимость сохранить все или некоторые из переменных, уже установленных в среде.
Эта команда вернет такой результат:
Заключение
В этой статье вы изучили основы использования env-cmd на примере простого проекта.
Файлы окружения помогут вам легко переключаться между средами разработки и производства.
Эффективное использование process.env
Что такое process.env?
О важности окружения, в котором работает приложение
До тех пор пока приложение не развёрнуто, будь то код, реализующий простейший сайт, или сложное API, используемое в тяжёлых вычислениях, оно совершенно бесполезно. Это — лишь строки текста, хранящиеся в файлах.
Если предположить, что переменными окружения мы не пользуемся, есть два варианта действий.
Подобные конструкции увеличивают число путей выполнения программы, что усложняет тестирование, да и о красоте кода тут говорить не приходится.
Если же для указания строки подключения к базе используются переменные окружения, нашу задачу можно решить так:
При таком подходе можно как подключаться к локальному экземпляру СУБД при разработке, так и организовать соединение с чем-то вроде защищённого удалённого кластера баз данных, поддерживающего балансировку нагрузки и умеющего масштабироваться независимо от приложения. Это даёт возможность, например, иметь множество экземпляров приложения, которые независимы от конкретного экземпляра СУБД.
В целом, рекомендовано всегда рассматривать зависимости приложения от неких внешних служб как присоединённые ресурсы и настраивать подключение к ним с помощью переменных окружения.
Как использовать переменные окружения
Действия, которые выполняются для того, чтобы подготовить переменные окружения для приложения называют предоставлением ресурсов (provisioning) или подготовкой к работе. При подготовке сервера можно выделить два уровня, на которых можно работать с переменными окружения: уровень инфраструктуры и уровень приложения. Подготовить окружение можно, либо используя специализированные инструменты, либо — некую логику, реализованную на уровне приложения.
Загрузка переменных окружения выполняется с помощью следующей простой команды:
Docker Compose, аналогичным образом, позволяет задавать свойство environment в манифест-файле сервиса:
У Kubernetes есть похожее свойство env в шаблоне манифеста, которое также позволяет задавать переменные окружения:
Сценарии использования переменных окружения
▍Настройки приложения
Настройки приложения не влияют на то, какие именно действия выполняет это приложение, не влияют на его логику. Например, приложению известно, что ему необходимо прослушивать порт для того, чтобы к нему можно было обратиться извне, но ему необязательно знать — какой именно это будет порт. Такие данные вполне подходят для вынесения их в переменные окружения. Поэтому их установку и подготовку сетевой инфраструктуры можно доверить средствам развёртывания приложений.
▍Взаимодействие с внешними службами
Переменные окружения часто используют для указания того, как приложение должно подключаться к службам, от которых оно зависит. Это позволяет сделать код чище и улучшить тестируемость приложения. В частности, такой подход позволяет окружению тестирования передавать приложению некие условные данные, которые, например, имитируют внештатные ситуации, что позволяет проверить приложение на предмет сбоев в подобных ситуациях. Тут мы имеем дело с похожей ситуацией: приложение нуждается в некоей службе, но где именно она расположена, заранее неизвестно. Настройку переменных окружения для подобных случаев можно доверить менеджерам развёртывания.
▍Вспомогательные средства разработки
Анти-паттерны
Вот несколько распространённых вариантов неправильного использования переменных окружения.