• Стоит ли хранить исходные коды приложения и конфигураций Docker в одном или разных git репозиториях?

    @HiDiv Автор вопроса
    Дмитрий, А Вас не смущает, что в одном репо смешаны две разные по назначению "фичи"? Исходники php вообще-то самодостаточны и если рассматривать вариант доработок через pull requests, то "куски от сборки" тут совсем не к чему... Для php в принципе "сборка", как, например, make-файл для C, вообще не нужна! С другой стороны сами скрипты сборки, возможно с небольшими изменениями, могут быть переиспользованы на другом подобном проекте... То, что у нас так сделано, это исключительно наше решение для CI/CD (условно!).

    У меня, почему-то, вообще есть "стойкое чувство", что все связанное со "сборкой" и деплоем должно быть только в конфигурационном файле сборщика gitlab и все... Правда тогда непонятно, как "все это" разворачивать на рабочем месте разработчика и на проде руками.
    Написано
  • Стоит ли хранить исходные коды приложения и конфигураций Docker в одном или разных git репозиториях?

    @HiDiv Автор вопроса
    Everything_is_bad, GitHub большой, как мне найти нужные репо и при этом быть уверенным, что это именно "правильный выбор"?
    Написано
  • Как реализовать внешний ingress-сервис для доступа к контейнерам под управлением Docker?

    @HiDiv Автор вопроса
    Alexey Dmitriev, Про "smtp relay сервер" идея понятна... А вот со вторым вариантом "балансировщиком\реверспрокси", можно поподробнее?

    Вот установлен этот "балансировщик" на "внешнем интерфейсе" и виден, как ip X.X.X.X. Пусть в DNS есть две записи о server1.docker.company.tld и server2.docker.company.tld, обе указывают на ip X.X.X.X (или как?).
    Далее, есть какой-то клиент, который хочет соединиться с smtp-сервером server1.docker.company.tld по порту 25/tcp. Этот клиент, вначале обращается к DNS-серверу для разрешения имени и получает ip-адрес X.X.X.X в ответ. После этого пытается установить tcp-соединение с ip-адресом X.X.X.X и портом 25/tcp. Как "балансировщик" в таком случае поймет, что эту попытку соединения нужно отфорвардить именно на server1.docker.company.tld? Или я вас неправильно понял?
    Написано
  • Как реализовать внешний ingress-сервис для доступа к контейнерам под управлением Docker?

    @HiDiv Автор вопроса
    Вы не правильно поняли - во-первых ingress это сущность кластера kubernetes и к docker отношения не имеет, даже как термин.

    Вы совершенно правы, я просто хотел как-то описать некий сервис, который находится на границе "внешней" и "внутренней" сетей и перенаправляет внешний трафик к конкретному контейнеру docker...
    Во-вторых - и traefik и nginx и большинство load balancers\reverse proxy умеют проксировать любой tcp трафик, а не только http. Их можно использовать и для smtp трафика в том числе.

    Я тоже на это надеялся, но могу представить, как с помощью того же traefik реализовать тот кейс, который описан в исходном вопросе (с двумя smtp-сервисами внутри docker окружения). Вы можете подробнее описать, как сделать такие настройки?
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    pindschik,
    думаю, что решение в таком виде, как вы описываете - писать и реализовывать придется самостоятельно, и это превратиться в "кровавую баню".

    Отчасти согласен с Вами, на самом деле, смысл текущего поста был еще и в том, чтобы понять, насколько актуальна проблема для "сообщества". Потому, что "придумывать такой велосипед" в одиночку, заранее обреченная на провал задача, хотя бы по той причине, что у меня нет необходимых компетенций по всем аспектам поставленной задачи. Другое дело, если бы тема была актуальна для сообщества... Тогда был бы шанс. ;(

    Однако, все не так утопично, как может показаться на первый взгляд. Я лично проводил (правда достаточно давно) следующий эксперимент:

    * Взял два облачных хранилища на бесплатных тарифах (точно сейчас не помню, но вроде тогда это был Google Диск и Яндекс Диск, а объем был то ли 20 Gb, то ли 50 Gb).
    * Установил на свой Linux, клиентов для этих хранилищ и получил два каталога, в которых можно было создавать/изменять/удалять файлы и они в фоновом режиме синхронизировались со своими хранилищами.
    * Создал в этих каталогах набор произвольных файлов заполненных случайными данными на весь доступный объем.
    * Каждый такой файл разметил и смонтировал, как LUKS том.
    * Потом, с помощью LVM, эти тома сделал PV в режиме зеркала (одно отражение на данные первого хранилища, а второе на данные второго).
    * В полученном дисковом пространстве нарезал себе разделов, отформатировал в ext4 и смонтировал, как обычный диск.

    Потом, на такой диск/раздел можно писать и читать данные обычным образом, все преобразования и синхронизация с облаками происходит в обычном режиме....

    Но это был просто эксперимент!

    У него есть несколько явных недостатков относительно выдвинутых изначально требований:

    * Во-первых, все данные из всех хранилищ должны в полном объемы быть размещены на локальных дисках всех моих устройств, которым нужно иметь доступ к "хранилищу".
    Если это достаточно большой объем, например, 500 Gb, то для двух разных облаков, что является минимальным требованием, нужно уже 1Tb на локальном диске, а если реплик больше, то и объем пространства значительно вырастает... Хотя сейчас локальное дисковое пространство стало доступнее.
    * Во-вторых, быстро взять и скачать/посмотреть один/два файла не получится, нужно развертывать целую конфигурацию и ожидать пока из хранилищ будет сделана полная копия на "локальный диск"... Частично эту проблему можно решить, например, с помощью "загрузочной флешки", но проблема с закачкой из хранилища все еще остается.
    * В-третьих, подобное решение работает на полноценном Linux, но не взлетит, например, на телефоне или на чем-то подобном.
    * В-четвертых, требование к реализации "отрицаемого шифрования" (ввод пароля под принуждением) остается нереализованным.

    Правда есть и плюсы:

    * Во-первых, используются только стандартные средства практически любого Linux-дистрибутива. Из нестандартного, только скрипты для создания/монтирования всего этого хозяйства.
    * Во-вторых, мы получаем на выходе "стандартную ФС", которую можно использовать любым удобным образом, например, файлы БД на нее положить. В варианте же удаленного хранилища, перечень доступных действий значительно ограничен.
    * В-третьих, возможно, если использовать для создания LUKS дисков, например, VeraCrypt, то удастся реализовать и "отрицаемое шифрование", либо просто создать многомерное хранилище...
    * В-четвертых, при создании LUKS можно не формировать на дисках "служебную информацию", когда это будет просто случайный набор данных и доказать, что это зашифрованный диск будет очень сложно. Правда при этом может пострадать надежность (защита от случайных сбоев), но это компенсируется наличием копии или копий в других облаках, с которых всегда можно восстановить данные...
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    О боже, как всё сложно...

    Возможно и так, я писал выше, что возможно фантазирую, но считаю, что требования описаны достаточно четко... Только давайте не как в том анекдоте "про вопрос на американском, еврейском и русском форуме". ;)

    1) Используйте Resilio File Sync для размазывания файлов по нескольким вашим устройствам.

    Никогда не слышал о таком решении. Спасибо. Обязательно посмотрю.

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

    Второе, это что само решение не соответствует поставленной задаче! Основная его функция, это полная или частичная синхронизация данны[ между своими устройствами. Про шифрование, не совсем понял... ;( У меня же задача, это скорее создание "децентрализованной удаленной файловой системы". Следовательно, ни на одном из моих устройств может и не быть полной копии, хотя бы исходя из того, что она слишком большая для "локального хранения", либо просто нет в этом желания. Отсюда же вытекает, что при "больших объемах" сервисы, которые предоставляют только функцию хранения, например, Облако Mail.ru могут и не иметь возможности запускать у себя какие-то сторонние приложения (просто хранилище с api-интерфейсом для доступа и все).

    2) Дополнительно сделайте сервер бэкапа, КОТОРЫЙ САМ будет залезать к вашим данным и выгребать их...

    С учетом того, что нужна удаленная ФС, которую можно при необходимости подключать к клиенту, то вполне возможна такая ситуация, что метод pull (сервер затягивает изменения с клиента) просто технически невозможен... Тогда остается только метод push, когда изменения по "хранилищам" раскладывает сам клиент и только он является единственным "активным приложением"...
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    CityCat4, я не питаю иллюзий на сей счет, но мы отклонились от изначальной темы...
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    mayton2019, Это когда "обычным образом" авторизовавшить "под принуждением" ты получаешь доступ к файловому хранилищу, то там вместо "реальных данных" доступна какая-то "реалистичная бутафория" типа фоток котиков или безобидного домашнего фотоархива, плюс несколько документов с рецептами приготовления пирогов... Ты как-бы попадаешь в "альтернативную реальность" похожую на действительность. ;)
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    CityCat4, Частично с Вами согласен, но...

    Если это будет "формальное требование", например, со стороны следствия, то факта добровольного предоставления пароля уже вполне достаточно. Даже если они будут "предполагать", что хранилище с "двойным дном", то доказательство этого, лежит уже в другой плоскости... Так можно "договориться" до того, что сам факт "надежного шифрования" чего-либо уже является, как минимум, "подозрительным".

    Если же это будут "пацаны с огоньком", то шансы уже "пониже", где-то 50 на 50. С одной стороны, они про "многомерное хранилище", скорее всего, ничего не слышали. С другой, будут "стимулировать вашу память" до тех пор, пока не найдут то, что им нужно... и не важно какой пароль вы им сказали. ;(
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    Василий, Ну, "пароль под давлением" это все же "частичная паранойя"... Недавно, кстати, смотрел фильм "про бредбери" (точное название не помню), где как раз "потенциального подозреваемого" не привлекли к ответственности, т.к. основные доказательства у него были в телефона, а он "забыл" от него пароль... Если это не художественный вымысел, то весьма занимательный кейс. К сожалению, в "наше время" уже несколько раз читал о других случаях, когда отказ от предоставления пароля к файлам или телефону трактовался, как "признание вины" со всеми вытекающими обстоятельствами... Поэтому, если это возможно, то лучше перебдеть.

    Вариант же с veracrypt тоже не подходит, т.к. шифрование он может и обеспечит, но как потом, например, с телефона "найти" нужный файл с фоткой или pdf-документом среди пару сотен файлов вида XXX-YYY-ZZZ? Возможность удобного и оперативного доступа тоже важно!
    Написано
  • Какие есть методы создания децентрализованных хранилищ файлов?

    @HiDiv Автор вопроса
    Спасибо за рекомендацию! Про NextCloud что-то слышал, но пристально не смотрел... Если он решит хотя бы две основные проблемы (несколько мест хранения от разных провайдеров и сквозное шифрование файлов), то вполне стоит изучить...

    Меня только немного смущает, что, кроме самого места для хранения, придется еще и арендовать сервер для обработки. Это конечно не show stoper, но обычно место на диске для просто сервера и место для хранения архива тарифицируются совсем по разному... Хотелось бы "быть в бюджете". ;)
    Написано
  • Как лучше сформулировать sql-запрос для поиска по историческим данным?

    @HiDiv Автор вопроса
    Ну вот, основная нагрузка получается из-за групировке по таблице accounts_audit - full table scan, кстати добавь индексы по одновременно двум полям, указываемых в group by, и само собой по полям, указываемым во where


    Это план уже при наличии всех возможных индексов. Там есть (parent_id, field_name, date_created), (field_name, parent_id, date_created), просто parent_id, просто date_created. Ни один из этих индексов не спасает от full table scan.

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

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

    В качестве решения, завел в БД таблицу, точно повторяющую структуру отчета, и сделал ежедневно запускаемое задание, которые заполняет ее данными за текущий день без всяких таблиц истории и т.п. Получил практически мгновенно работающий отчет, который выдает данные за любую дату, которая уже посчитана в этой таблице...
  • Как лучше сформулировать sql-запрос для поиска по историческим данным?

    @HiDiv Автор вопроса
    Так как тебе варианты с готовыми решениями подсказали

    Со всем уважением к тем, кто откликнулся, я не вижу тут никаких готовых решений!

    Первый комментарий относится к window function, но я четко написал, что у меня mysql 5.7, а там их нет... Менять версию СУБД нельзя!

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

    Идея с partions интересна, но не факт, что поможет. Плюс, без очень веских причин не хотелось бы использовать "СУБД-зависимые решения"...

    Только индексами похоже проблему не решить...

    Судя по всему, абстрактный пример оказался не достаточно информативный, т.ч. привожу "кусок" реального sql-запроса для примера
    spoiler
    SELECT
    	acc.*
    FROM
    	(
    		SELECT
    			accounts.id,
                CAST(
    				CASE
    					WHEN begin_date_before.parent_id IS NOT NULL THEN begin_date_before.after_value_string
    					WHEN begin_date_after.parent_id IS NOT NULL THEN begin_date_after.before_value_string
    					ELSE accounts.monitoring_begin_date
    				END
                AS DATE) AS monitoring_begin_date,
    			CASE
    				WHEN name_before.parent_id IS NOT NULL THEN name_before.after_value_string
    				WHEN name_after.parent_id IS NOT NULL THEN name_after.before_value_string
    				ELSE accounts.name
    			END AS name
    		FROM
    			accounts
    		LEFT JOIN
    			(
    				SELECT
    					accounts_audit.parent_id,
    					accounts_audit.after_value_string
    				FROM
    					accounts_audit
    				INNER JOIN
    					(
    						SELECT
    							parent_id,
    							field_name,
    							MAX(date_created) AS last_change
    						FROM
    							accounts_audit
    						WHERE
    							field_name = 'monitoring_begin_date' AND
    							date_created < '2022-05-20 00:00:00'
    						GROUP BY
    							parent_id,
    							field_name
    					) t1
    				ON
    					t1.parent_id = accounts_audit.parent_id AND
    					t1.field_name = accounts_audit.field_name AND
    					t1.last_change = accounts_audit.date_created
    			) begin_date_before
    		ON
    			begin_date_before.parent_id = accounts.id
    		LEFT JOIN
    			(
    				SELECT
    					accounts_audit.parent_id,
    					accounts_audit.before_value_string
    				FROM
    					accounts_audit
    				INNER JOIN
    					(
    						SELECT
    							parent_id,
    							field_name,
    							MIN(date_created) AS last_change
    						FROM
    							accounts_audit
    						WHERE
    							field_name = 'monitoring_begin_date' AND
    							date_created >= '2022-05-20 00:00:00'
    						GROUP BY
    							parent_id,
    							field_name
    					) t2
    				ON
    					t2.parent_id = accounts_audit.parent_id AND
    					t2.field_name = accounts_audit.field_name AND
    					t2.last_change = accounts_audit.date_created
    			) begin_date_after
    		ON
    			begin_date_after.parent_id = accounts.id
    		LEFT JOIN
    			(
    				SELECT
    					accounts_audit.parent_id,
    					accounts_audit.after_value_string
    				FROM
    					accounts_audit
    				INNER JOIN
    					(
    						SELECT
    							parent_id,
    							field_name,
    							MAX(date_created) AS last_change
    						FROM
    							accounts_audit
    						WHERE
    							field_name = 'name' AND
    							date_created < '2022-05-20 00:00:00'
    						GROUP BY
    							parent_id,
    							field_name
    					) t3
    				ON
    					t3.parent_id = accounts_audit.parent_id AND
    					t3.field_name = accounts_audit.field_name AND
    					t3.last_change = accounts_audit.date_created
    			) name_before
    		ON
    			name_before.parent_id = accounts.id
    		LEFT JOIN
    			(
    				SELECT
    					accounts_audit.parent_id,
    					accounts_audit.before_value_string
    				FROM
    					accounts_audit
    				INNER JOIN
    					(
    						SELECT
    							parent_id,
    							field_name,
    							MIN(date_created) AS last_change
    						FROM
    							accounts_audit
    						WHERE
    							field_name = 'name' AND
    							date_created >= '2022-05-20 00:00:00'
    						GROUP BY
    							parent_id,
    							field_name
    					) t4
    				ON
    					t4.parent_id = accounts_audit.parent_id AND
    					t4.field_name = accounts_audit.field_name AND
    					t4.last_change = accounts_audit.date_created
    			) name_after
    		ON
    			name_after.parent_id = accounts.id
    		WHERE
    			accounts.deleted = 0
    	) acc
    WHERE
    	acc.monitoring_begin_date < '2022-05-20' AND
        COALESCE(acc.name) != ''

    Это запрос только по двум полям, а мне нужно получить подобным образом 5, а потом еще join с другой таблицей с подобной же стуктуры.

    Вот это explain этого запрос на полупустой тестовой базе
    spoiler
    62b979cade851383377464.png
  • Как лучше сформулировать sql-запрос для поиска по историческим данным?

    @HiDiv Автор вопроса
    У меня в реальности значительно более сложный запрос... Я использую MAX и MIN для поиска наиболее близкого к отчетной дате значения в истории и все это оборачиваю в субзапрос. Плюс сделал дополнительный индекс с датой изменения. Точный explain привести сейчас не смогу...

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

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

    P.S.: Раньше на DBase мне довольно часто приходилось решать подобные задачи. Там обычно использовался индекс с последним элементом в виде даты отсортированной по убыванию и "неточный поиск" ближайшего значения меньше заданного, а потом шел обычный перебор по списку... Возможно в данном случае можно что-то подобное реализовать в виде хранимой процедуры, но не уверен.
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Антон Шаманов,
    так и надо было писать в вопросе, а не

    Что конкретно не так? Как переформулировать?
    Если вы поняли суть вопроса, то может быть подскажете вариант решения, а не просто будете писать "общие фразы"?

    это не вопрос из серии "стоит ли вообще писать автосты", это вопрос из серии "стоит ли писать тесты ради галочки?". 100% покрытие тестами не гарантирует, что сами тесты покрывают методы полностью.

    Если тесты написаны достаточно качественно и на разных уровнях (модульные, интеграционные и т.д.), то 100% покрытие дает достаточную уверенность в правильности работы приложения. Если тесты написаны формально, только чтобы соблюсти условие 100% покрытия, то они не только бесполезны, но и вредны...

    Если честно, то я не получаю особого удовольствия от траты времени на написание тестов, особенно если кусок кода кажется настолько тривиальным, что он просто не может работать не так, как нужно... И при этом уже не один раз ловил сам себя на том, что кусок из трех строчек не покрытый или некачественно покрытый тестами, может развалить всю систему! Причем это может быть банальная опечатка или ошибка при разрешении конфликта при сложном merge...
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Антон Шаманов, вы слишком радикальны в суждениях... ;)
    Если мне нужно протестировать функцию/метод, которая возвращает результат, то обычно я использую один из двух вариантов.

    Первый, если вызываемая функция "безопасна для теста" (не лезет в сеть или бд и т.п.), то просто вызываю ее и анализирую детально результат. Обычно, передаваемые на вход такой функции параметры, как-то учитываются в результате, например, записываются в структуры возвращаемого объекта, иначе какой смысл вообще в этих аргументах, если они не влияют никак на результат. Правда в этом случае модульный тест получается не вполне "модульным"...

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

    В большинстве случаев мне этого вполне хватает. Правда в описанной задаче, оба этих приема не подходят...
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Антон Шаманов, если метод-обертка делает только вызов другого метода, то согласен, но в данном случае это не так. Даже в вашем случае, если внутри одного метода только вызов другого, то возможно есть какие-то комбинации-преобразования в аргументах метода-обертки и "проксируемого метода", иначе я не вижу вообще никакого смысла в методе-обертки! Если же такие преобразования есть, например, захардкодены какие-то передаваемые аргументы, то важно убедиться в их правильности...

    А по поводу "бреда", что именно вы имеете ввиду? Необходимость 100% покрытия или что?
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Это вопрос из серии "стоит ли вообще писать автосты и если Да, то в каком объеме"...
    Лично я никогда не сомневался в необходимости писать автотесты, но, до недавнего времени, у меня просто не было на это время, т.к. конкретный заказчик не хотел оплачивать время на их разработку... В текущем проекте ситуация другая, очень много вариативной бизнес-логики, большинство из которой сложно проверить из вне (я имею ввиду внешний интерфейс), либо просто нет физической возможности проверять все варианты при каждом изменении... А нужно проверять ВСЕ и при КАЖДОМ, т.к. практика показала, что даже незначительное изменение в одном месте программы может "привести к проблеме" в совсем другом... Поэтому остаются только автотесты разных уровней.

    С другой стороны, если автотесты не покрывают 100%, как минимум, нового кода, то ценность их весьма сомнительна (IMHO)... Получается ты тратишь не мало времени на написание тестов, но их успешное прохождение не гарантирует в общем случае отсутствие ошибок... Тогда зачем их писать вообще?
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Антон Шаманов, я имел ввиду, что url передается аргументом в функцию getSoapClient и нужно убедиться, что именно он и без изменений был передан в соответствующий аргумент конструктора SoapClient, а остальные аргументы этого конструктора захардкодены и их тоже нужно провалидировать.
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Михаил, статью прочитал, спасибо. Правда я не уверен, что описанный в ней случай, это мой вариант... Я ведь не хочу тестировать работу или какие-то внутренности SoapClient, а хочу только проверить соответствие фактических аргументов моим ожиданиям...

    По поводу невозможности тестирования конструкторов (в общем случае) не соглашусь. У меня много тестов, где я тестирую прикладной код через AspectMock, в том числе и конструкторы... Я их успешно мокаю, но опять же для того, чтобы проверить соответствие параметров ожидаемым.
    Проблема в том, что сейчас это не прикладной код, а системная библиотека, которую я замокать не знаю как...
    Сейчас пришла мысль, добавить еще один метод, который бы возвращал наименование класса SoapClient, как строку. Тогда можно отдельно проверить такой метод (эту строку) и, подменив конструктор тестовым, потом проверить и его. Правда мне кажется, что это уже "тестовое извращение"... ;)