Передача переменных окружения в Docker

Мы на работе немного угорели по микросервисам и всё заворачиваем в docker-контейнеры. Зачем — это тема для отдельного поста, сейчас об этом не будем. Просто поверьте, что оно нам действительно надо.

Что особенно удобно — легко поддерживается идентичность среды у разработчика на маке и винде и на серверах с линуксом. Но есть некоторые вещи, например подключения к БД и другим сервисам, ключи от всяких API и т.п. должны быть разными на разных окружениях.

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

Потом к нам пришли переменные окружения, их можно передавать при запуске контейнера поодиночке или все сразу, используя специальный файл (или несколько файлов).

$ docker run --rm --env DB_HOST=postgres_1.local --env-file=dev-env ubuntu env

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

Всё очень хорошо и красиво, но когда я начал переводить старый проект на эти новые рельсы, то наткнулся на несколько странное поведение. Проект написан на питоне, поэтому для чтения переменных окружения мы используем библиотеку environs. Она позволяет валидировать значения переменных во время чтения, и для одной такой переменной (пусть это будет тот же DB_HOST) был ограничен набор возможных значений.

Но для удобства разработки переменные брались из .env-файла, монтируемого прямо в контейнер и считывались прямо из него всё-той же библиотекой environs. Всё было прекрасно, пока не пошли деплоить на стейджинг. Тут приложение внезапно стало валлиться с ошибкой, что для DB_HOST передано недопустимое значение.

Проверяю env-файл на сервере — всё в нём правильно, ну ладно иду читать, что на самом деле пришло в контейнер и вижу, что значение переменной передано вместе с кавычками (то есть "postgres_1.local" вместо postgres_1.local). Мы давно привыкли всегда заключать значения переменных окружения в кавычки, потому что bash их игнорирует, но зато это позволяет нормально передать значения из нескольких слов, да и вообще, файлы лучше читаются. Но делать нечего, пришлось вычищать все кавычки из значений переменных, чтобы приложение смогло запуститься.

Но что ещё печальнее, такая внимательность к кавычкам у Докера проявляется только для переменных из env-файла, если переменная передаётся явно, через --env, то значение переменной преспокойно можно заключать в кавычки и в контейнер придут правильные данные.

По случаю этой ошибки была Issue на гитхабе, но что-то её закрыли ничего не починив.

Про сравнение объектов Immutable.js

Примерно год назад я начал переводить проект, над которым работаю в Charge.auto с жутко запущенного легаси на реакт-редакс-вот это всё. Для представления данных в сторе решил взять Immutable.js. Граблей было исхожено не одно поле, но на днях до меня наконец-то дошло, как разрешить одну из самых раздражающих меня проблем.

В приложении с сервера прилетает множество разных массивов данных, эти массивы раскладываются туда-сюда в сторе в List и дальше забираются в редакс-контейнерах и передаются как пропсы в компоненты. И вот тут начался праздник. Как правило, нужно выводить не весь список, а какую-то выборку по нему. Сначала я делал что-то типа

function mapStateToProps(store) {
  const items = store.get('beans').get('items');
  const activeItems = items.filter((item) => item.get('isActive'));

  return { activeItems };
}

Но почти сразу же я заметил, что компоненты постоянно обновляются, даже если данные не менялись. Причина проста — List.filter() создаёт новый инстанс отфильтрованного списка при каждом вызове, а в shouldComponentUpdate() использовалась просто строгое неравенство. На тот момент я ещё не до конца понимал всей кухни реакта и как писать реакт-компоненты правильно, поэтому просто стал передавать из контейнера в компонент полные списки, а фильтрацию и всё остально делать уже в компонентах. Но меня постоянно бесил тот факт, что приходится гонять туда-сюда жирные объекты, а компоненты получаются с излишней логикой.

Но вот на днях я нашёл целых два решения проблемы.

Во-первых, все объекты Immutable.js имеют метод .equals(), так что его и нужно использовать в shouldComponentUpdate()

shouldComponentUpdate(nextProps) {
  return !nextProps.activeItems.equals(this.props.activeItems);
}

Ну а во-вторых, можно пойти упарываться функциональщиной дальше и использовать мемоизацию (например, из библиотеки rambda)

function mapStateToProps(store) {
  const items = store.get('beans').get('items');
  const filterActive = R.memoize((list) => list.filter((item) => item.get('isActive')));
  const activeItems = filterActive(items);

  return { activeItems };
}

Такое вот простое решение. Теперь осталось отрефакторить всё.

Шаблоны платежей в Альфа-клике

Альфа-банк — неплохой банк, а Альфа-клик признают лучшим из интернет-банков в России. Лучшим, но не идеальным. Есть множество мелочей, которых не позволяют дать такую оценку.

Например, создание шаблонов. Для того, чтобы создать шаблон перевода другому клиенту Альфа-банка я обязан совершить перевод. Хотя бы на один рубль. При этом в шаблоне зачем-то сохраняется назначение перевода и его приходится каждый раз менять. Не вижу причин, по которым невозможно создать шаблон «на будущее» и указать только необходимые действительно обязательные поля — номер счёта и ФИО.

Если я хочу привязать шаблон к Альфа-мобайл (создать его из мобильного приложения нельзя в принципе), то я должен ввести код, который придёт по смс. Кто объяснит, чем вызвана такая повышенная доза безопасности?

В общем, есть куда расти, есть над чем подумать.

Пиксельная графика в Illustrator

Я уже немного писал про создание макетов сайтов в Adobe® Illustrator. А сегодня случайно набрёл на простой способ создания пиксельной графики.

Что нам собственно нужно?

  • Привязка линий строго по пиксельной сетке;
  • Отсутствие сглаживания

Решение как всегда пришло конца. У меня на маке не оказалось достойного кириллического пиксельного шрифта. А те, что на скорую руку нашлись в интернете отображались в Illustrator просто отвратительно. Кроме того, в Illustrator, в отличие от Photoshop, никак нельзя управлять сглаживанием шрифта. В результате набрёл на такую настройку: Preferences > General; снимаем галку «Anti-aliased Artwork», далее работаем в режиме Pixel Preview (View > Pixel Preview).

Снимок экрана 3.png

В итоге получаем шрифты без антиалиасинга, что почти то, что мне хотелось.

Снимок экрана 6.png

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

shots-200.png

shots-3200.png

Есть и ложка дёгтя. Пока что не удалось получить такой же результат при выполнении команды File > Save for web — картинка растеризуется так, как будто никто и не отключал антиалиасинг у Artboard. При этом при выполнении команды File > Export всё пучком.

Этот неприятный минус, а так «квадратные» края у кривых, не позволяют использовать этот метод как основной в разработке макетов. Однако для создания схем и графиков, а так же черновых набросков — самый сок.

И помни, путь джедая — всегда «прибивать» опорные точки кривых к узлам пиксельной сетки.

P.S.: В статье использована картинка в к учебному пособию по курсу «Профессиональная вёрстка сайтов».