powerman
0
С IPv6 хуже не будет. Наоборот, этот способ с легкостью позволит сократить время загрузки страницы примерно на 10%.

Хуже — вполне может быть. Включение IPv6 открывает новые интересные способы проникновения в вашу сеть (не актуально для одинокого сервера, но если у вас кластер с внутренними сервисами бэкенда или публичный сайт на сервере подключённом к домашней/корпоративной локалке, доступ к которым закрыт файрволом, то могут быть нюансы) — это не фатальный недостаток IPv6, а, скорее, недостаток квалификации по его настройке у многих админов. Так же включение IPv6 активирует кучу дополнительного кода, как в ядре ОС, так и в приложениях, где тоже регулярно находят новые уязвимости. В общем, если вас волнует безопасность, то включать IPv6 надо очень-очень осторожно, а лучше подождать с этим ещё пару лет, пока уязвимости исправят и появится больше хороших мануалов по корректной настройке IPv6.


Что касается ускорения благодаря IPv6 — это звучит довольно странно, интересно, с чем это может быть связано?

powerman
0

Конечно, но мы же здесь не микросервисы обсуждаем, а MVC. Если в микросервисе 10К строк — без какой-то архитектуры (может и MVC) внутри этого микросервиса, в большинстве случаев, будет очень неуютно. А если в нём 50-100 строк, то часто можно архитектурой не заморачиваться.

powerman
0

MVC это архитектурный подход. Его можно применять внутри какого-то модуля/библиотеки, строить по нему отдельное приложение (процесс ОС), и ровно так же строить по нему распределённое приложение состоящее из десятков микросервисов.


Мой изначальный коммент был про то, что когда у нас MVC в рамках одного процесса ОС, то соблюдать границы (не лазить в модель мимо фасада, не пропускать через фасад наружу исходные объекты доменной модели через которые опять же можно узнать лишние детали реализации модели и даже изменять модель мимо фасада, etc.) становится очень сложным т.к. язык/ОС не помогают соблюдать границы и это становится вопросом внутренней дисциплины разработчиков.

powerman
+1
Это не требование, а часто используемая практика. В конце-концов, СУБД тоже своего рода микросервис, которому никто не запрещает иметь несколько клиентов в рамках системы.

Это именно что требование. Как только у микросервисов появляется общая БД и начинаются философские рассуждения о том, что формально СУБД это тоже сервис (на микро он, вообще-то, не тянет) — то "Хьюстон, у нас проблема".


Общая СУБД — это, по сути, аналог громадной и сложной глобальной переменной, с которой одновременно работает куча разных кусков кода. Обложившись блокировками, транзакциями и версионированием схемы БД чтобы всё это хоть как-то работало.


Суть микросервисного подхода в том, что пока стабильно работают API сторонних микросервисов и стабильно работает API этого микросервиса — мы можем делать что угодно и как угодно в самом микросервисе, и это гарантированно ничего не сломает в других местах. Поэтому несовместимых изменений API стараются избегать из всех сил, потому что это единственное, что может поломать что угодно и где угодно. Хотя СУБД это безусловно сервис, но у этого сервиса нет стабильно работающего API — я имею в виду достаточно высокоуровневого API, которое бы гарантировало что сделав вот такой запрос в базу я получу нужные мне данные в корректном формате — потому что изменение схемы БД или ошибка в коде изменяющем данные всё это ломают.


На практике, безусловно, общие БД у сервисов встречаются. Но чтобы это более-менее нормально работало приходится относится к схеме БД как к публичному API — документировать его, стараться не изменять несовместимым образом, добавлять в саму БД функции контролирующие корректность записываемых значений и целостность данных… и работает это довольно паршиво. Потому что БД — это, всё-таки, не фасад а модель, возвращаясь к теме топика. И, по хорошему, перед такой общей БД надо вешать отдельный микросервис, который даст API к этой БД в стиле фасада и терминах бизнес-логики приложения, и скроет саму БД от всех остальных микросервисов.

powerman
0
В контексте этого топика, говоря об MVC и фасадах к доменной модели в качестве модели приложения, мы говорим об изоляции в рамках одного микросервиса, построенного по MVC паттерну.

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


В самих микросервисах внутри тоже может быть MVC, явно или неявно (как Вы описали), но зачастую в микросервисах полезного кода строк 50-100, шансов что он будет активно усложняться и развиваться практически нет (а если и будет — проще сделать новый микросервис), и заморачиваться там какой-либо архитектурой вообще нет смысла.

powerman
0
Должен или не должен определяется требованиями и выделенными ресурсами. Введение дополнительных уровней изоляции увеличивает как трудоемкость разработки приложения, так и ресурсы, потребляемые ею в рантайме.

Один из ключевых моментов, которые делают микросервисную архитектуру реально полезной и работающей — как раз эта изоляция. Именно ради этой изоляции выдвинуто требование, что у каждого микросервиса должна быть собственная БД, куда нет доступа другим микросервисам. А для передачи данных между двумя частями приложения приходится их сериализовывать и передавать по сети. Что, безусловно, заметно жрёт ресурсы и увеличивает трудоёмкость. Но, тем не менее, это окупается тем, что нарушить слой изоляции между микросервисами невозможно при всём желании.


Теоретически, безусловно, можно обеспечить ровно такую же изоляцию между двумя модулями/пакетами/объектами в рамках одного физического приложения, не разделяя его на несколько независимых микросервисов. Но ключевое слово здесь — теоретически. А на практике абсолютное большинство разработчиков не в состоянии удерживаться от нарушения этих "виртуальных" границ, более того, зачастую они даже не дают себе труд понять где эти границы проходят и почему их категорически нельзя нарушать. Ведь всегда кажется, что если нарушить их совсем чуть-чуть — то это как-бы и не нарушение вовсе… зато можно намного быстрее и не включая голову сделать нужную фичу.


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


Но реально и на практике я такое видел только в одном месте — в языке Limbo, который работает только под OS Inferno. Там сама OS обеспечивает необходимый уровень изоляции — по сути, там можно отдельные библиотеки или части приложения (функции, по сути) запускать в отдельном лёгком потоке работающем в собственном уникальном окружении (а-ля продвинутый chroot), при этом доступ в память есть только к тем объектам, которые этому потоку передали параметрами при запуске или позднее прислали по типизированному каналу. В результате получается, что у каждого такого модуля (или даже функции) программист описывает интерфейс, к чему него есть доступ, и после запуска ни этот модуль не может получить доступ к чему-либо выходящему за рамки этого интерфейса, ни кто-то другой не может получить доступ к внутренностям этого модуля если он заранее не предоставил к этим внутренностям соответствующий интерфейс.

powerman
+13

К сожалению, их более новые и продуманные системы, где решены многие из упомянутых проблем — OS Plan9, OS Inferno — не взлетели. Не нужны народу элегантные системы, в которых нет этих костылей — наверное, скучно без них. Я много лет работал с OS Inferno, и это буквально "открыло глаза" на многие проблемы *NIX. Пока радует только рост популярности Go, может хоть одна из их попыток хоть немного исправить сверх-популярные UNIX и C спустя 40 лет окажется относительно успешной.

powerman
+5

Каждый сам выбирает мир, в котором ему жить.


Безусловно, существует много проектов, в которых автотесты никто не пишет. И коммерческий успех или провал проекта вряд ли зависит от наличия или отсутствия автотестов — по крайней мере я такой зависимости пока не замечал. Так что я не пытаюсь сказать, что автотесты это серебрянная пуля и мастхэв, и без них никуда — если вдруг Вы поняли мой комментарий в этом ключе.


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

powerman
+4

Если подходить формально, то в статье, по большей части, всё верно. Но есть нюансы, которые очень значительно влияют на общее впечатление и финальные выводы.


Автоматические тесты надо уметь писать. Если тестировать немного не то и не так, то они, действительно, будут "хрупкими" (часто ломаться), на их разработку/поддержку будет уходить намного больше времени, польза от них будет сомнительна, и (с точки зрения менеджмента) затраты на их разработку действительно не будут окупаться. Но ровно то же самое касается и разработки кода: если нанять слабых разработчиков, которые пишут не тот код и не так, как надо — вместо фич будут только баги, разработка может занимать в разы больше времени, и затраты на неё не будут окупаться.


Без юнит-тестов мы запускаем в продакшн очень много кода, который никто никогда не запускал. Программист его "скомпилировал в голове" когда писал, но при ручном тестировании большая часть веток if-ов (и даже целых функций) ни разу не выполнялась. Особенно это касается кода обработки разных ошибок (сеть, БД, данные в некорректном формате, etc.). А, как известно из опыта, если код ни разу не запускали — как правило он корректно работать не будет.


Преимущества автоматических тестов

Не упомянута ещё несколько очень важных преимуществ.


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


Автоматизированные тесты очень сильно упрощают тестирование в разных окружениях — с разными версиями OS, библиотек, кросс-платформенное тестирование.


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

Очевидно, если это изменение руками тестируется уже в 3-5-й раз, то к этому моменту написать автоматизированный тест было бы быстрее.


В каждый отдельный момент, решая что выгоднее, писать тесты или не писать, второе всегда предпочтительнее.

Это не так, из-за упущенного Вами и упомянутого мной выше преимущества автотестов — их наличие сильно ускоряет внесение (качественных и работающих, наверное стоит добавить) изменений в код.


Ситуация в корне меняется в длительной перспективе.

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


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


И замедляем не на 10%, а вдвое, втрое или даже больше.

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


Но не все так просто.

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

powerman
0

Так что в результате, реальные альтернативы скайпу есть? Хотя бы то, что нужно для митингов по работе:


  • клиенты под все платформы с хоть какой-то синхронизацией
  • поддержка групповых (до 20 человек) аудио/видео звонков
  • относительная стабильность (чтобы глюки не мешали пользоваться) работы самих клиентов
  • приемлемое (на уровне скайпа хотя бы) качество аудио/видео
powerman
0

Всё ещё смешнее: sleep(n) действительно может отработать чуть-чуть меньше, чем за n. С чем связано — не разбирался, но видел своими глазами неоднократно.

powerman
0

По-моему просто указать url в git-репо вместо имени модуля. Погуглите… вот, например: https://github.com/perl-carton/carton/issues/132

powerman
0

И в этом примере некорректные строки:


strings.Count("I  ", "")  // 6
len("I  ")                // 9
powerman
0

Я и хотел бы всё это добавить, но как реалист обычно счастлив уже когда есть хотя бы нормальные юнит-тесты.

powerman
0

Если тестировать только то, что действительно нужно тестировать, и делать это правильно (читай — не писать хрупкие юнит-тесты, которые постоянно ломаются и нуждаются в непрерывной поддержке) — то не в несколько раз. По моему опыту на разработку нормальных юнит-тестов (с покрытием 80-90%) нужно примерно столько же времени, сколько и на разработку кода, который они тестируют. Таким образом время (стоимость) непосредственного написания кода удваивается, но в общей стоимости проекта написание кода это далеко не 100%, так что в финале стоимость разработки увеличивается примерно в 1.5 раза.


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


А вот если тесты писать не уметь, и в результате писать их слишком много и/или слишком хрупких — тогда да, ничего кроме раздувания стоимости разработки в разы не получится.

powerman
+1

А Вы, что же, ждали, что PandaLabs публично объявит "мы нарушили закон и хакнули чужой сервак"? Конечно же, они ничего не ломали, сервер стоял совершенно открытый для всех желающих, а они просто случайно мимо проходили.

powerman
0

Не знаю, чем он там ограничен… Я им пользуюсь с девяностых, сейчас вот заглянул в .muttrc, в .mailcap, в /etc/portage/patches/mail-client/mutt/ — вот всё, что накопилось за столько лет:


  • в .muttrc одна строка (в смысле, запускающая внешние команды — а сам .muttrc у меня по-больше одной строки :)) динамически определяющая список mailboxes из существующих файлов в ~/Mail/: find … | sort … | sed …
  • в .mailcap целых 3 строки: просмотр html-писем внутри mutt через lynx -dump, и запуск просмотрщиков для картинок и pdf
  • дополнительных патчей у меня для mutt целых два: один добавляет мелкую фишку для юзабилити (автоматическое добавление настраиваемого приветствия/подписи в зависимости от, например, получателя), а второй добавляет поддержку s/mime

Ну и разбором входящих писем по отдельным папкам занимается не mutt — ну так оно вроде так и задумано в *NIX. Никаких "расширений" тянущих perl/python нет. Что касается необходимости в текстовом редакторе — да, это серьёзно. Действительно, кому был бы нужен текстовый редактор, если бы не этот чёртов устаревший mutt. :-)

powerman
+3
И давно у нас все UDP-сервисы обязательно отвечают отправителю?
powerman
0
У веб-скайпа ещё недавно не было поддержки голоса, скорее всего и до сих пор нет. Хэнгаутс работает, но глючно и не очень удобно. Как, впрочем, и десктопный скайп (особенно под линухом). В результате приходится пользоваться одним и держать под рукой второй, на случай если первый заглючит совсем сильно.

Так что реально в данный момент удобного и бесплатного (на платное вряд ли кто-то перейдёт имея скайп и хэнгаутс) решения для голосовых звонков, которое бы работало в любом современном браузере, надёжнее и удобнее хэнгаутс, не требуя спец-плагинов от гугла, и поддерживало конференции на уровне, позволяющем использовать его для ежедневных митингов по проектам — просто нет. Есть надежда, что WebRTC позволит такое решение создать, когда-нибудь.
powerman
0
Так я-ж не вручную файрвол переключаю — на то есть Tasker, он меняет профиль файрвола автоматом когда я ручками запускаю Play Market.
powerman
0
Да, даже если он успеет что-то удалить за эту минуту — TitaniumBackup всё восстановит.
powerman
0
Ну, это на так смертельно, как кажется — на рутованном телефоне вполне можно заблокировать файрволом доступ в инет для "сервисов гугл" и "play market", открывать доступ последнему только в тот момент, когда его запустили ручками чтобы обновить приложения, а первому только в тот момент, когда этого потребует последний для периодической авторизации и буквально на минуту.
powerman
+5
Сразу честно признаюсь, что вопрос безопасности я поднял не для того, чтобы продемонстрировать недостатки докера, а наоборот, чтобы мне рассказали как его правильно готовить. По результатам обсуждения пока складывается следующая картина:

  • Работа очень большого и сложного процесса `docker daemon` под root. shuron и Crandel сказали, что с 1.10 это не так, но они ошиблись: в 1.10 появилась поддержка User Namespaces чтобы root внутри контейнеров не был UID=0 в хост-системе — что не имеет отношения к работе `docker daemon` под root. Фича хорошая, но, как упомянул frol в данный момент она создаёт новые угрозы безопасности.
  • aml разумно заметил, что при использовании компилируемых языков и статической линковки в контейнере кроме одного бинарника других приложений и библиотек просто не будет. В этом случае, действительно, нет необходимости ежедневно обновлять образ дистрибутива. Но возникает другая проблема: когда обнаруживается проблема безопасности в библиотеке (что, мягко говоря, не редкость), то обычно это решается штатным обновлением дистрибутива и перезапуском процессов куда подгружена старая версия библиотеки (которые легко найти, например, через `lsof`). Кто и как будет отслеживать необходимость перекомпиляции статических бинарников в этой ситуации — не понятно. Т.е. опять проблема прикапывается чтобы не пахла, а не решается, как метко описал amarao. (Кроме того, если у нас один статический бинарник — а так ли нам на самом деле нужен докер?)
  • Visphord описал процесс автоматической регулярной пересборки всех контейнеров на базе так же регулярно обновляемого базового образа. Плюс, разумеется, админы должны контролировать содержимое Dockerfile-ов образов с приложениями — чтобы там тоже все необходимые пакеты доустанавливались штатными средствами дистрибутива и были последних версий — а исключения брались на заметку и мониторились админами на предмет проблем с безопасностью вручную. Это приводит к более редким обновлениям, раз в неделю-две вместо каждые день-два, но, на мой взгляд, это вполне допустимо — учитывая что при необходимости срочно закрыть дыру всегда можно инициировать пересборку вручную. Так же увеличенный период обновлений по большей части снимает мой вопрос о возможно высокой стоимости беспричинных частых перезапусков большинства сервисов. Но у этого подхода есть своя цена: стабильных образов зафиксировавших необходимое для приложения окружение (а это одна из основных фишек докера описанных на главной странице сайта) больше не существует — образ собранный сегодня может работать, а собранный из того же Dockerfile завтра — уже нет. На мой взгляд, в общем и целом этот подход эквивалентен традиционному: админ регулярно обновляет пакеты дистрибутива на сервере (образе runtime:latest) и перезапускает задетые обновлением (все) сервисы; сначала это делается на тестовой площадке (CI), а после прохождения тестов и на продакшне.

Последний вариант выглядит вполне рабочим.

Для него нужен автоматизированный процесс деплоя образов докера через CI, что может оказаться слишком дорого/сложно для мелких проектов (вроде "интернет-шаурмятни" упомянутой JPEG в дополнении к статье). В то же время админа периодически обновляющего сервер такие проекты себе обычно могут позволить, так что для них переход на докер ухудшит общую безопасность проекта.

Так же это скажется на цене поддержки системы: вместо обычного обновления серверов админом каждое обновление потребует сборки кучи образов и перекомпиляции всех приложений. На это потребуется больше времени, больше CPU, если что-то не соберётся может потребоваться привлекать разработчиков для решения проблемы, etc.

Осталось понять, перевешивают ли (оставшиеся :)) плюсы докера эти дополнительные затраты.
powerman
0
Пересборка контейнера — это запуск docker build.
Формально — да. Но в контексте ответа на мой комментарий пересборка контейнера подразумевает обновление установленного в нём софта, правку конфигов, разрешение конфликтов — в общем, всё то, что обычно делается при обновлении сервера. Простым запуском docker build тут обычно не обойдёшься.
Вы не делаете перезапуск вручную
Я тоже этим восхищён, но описанная мной проблема перезапуска не в том, что его нужно делать вручную, а в том, что многие сервисы достаточно нетривиальны, и их перезапуск — штука достаточно дорогостоящая (в плане ресурсов, производительности, etc.) чтобы делать его без веской причины каждый день.
Рут, который в докере, …
… меня никогда особо и не волновал, так что не совсем понятно, к чему Вы это описали. Проблема попадания злоумышленника внутрь контейнера не в том, что он там будет root, а в том, что он получит доступ к тому (базы/сети), к чему есть доступ у работающего в контейнере сервиса.
powerman
+2
…и мы получаем, по сути, вместо 5-ти разных серверов за которыми следит профессиональный админ — 50 разных образов, которые по сложности поддержки почти ничем не отличаются от полноценных серверов, но следить за которыми должны разработчики, причём от них ожидается, что после "вменения обязанности" они будут делать это не хуже профессионального админа.

В общем, теоретически и формально то, что Вы предлагаете можно назвать решением проблемы, но практически оно им никак не является.
powerman
+3
Оттуда, что при использовании докера подготовкой образов начинают обычно заниматься разработчики микросервисов, а их волнует только работоспособность их сервиса, а не общая безопасность образа. Поэтому обновляют они эти образы только тогда, когда нужно обновить их сервис, а не когда вышло обновление пакетов для дистрибутива используемого в качестве базового образа — и обновляют только свой сервис, разумеется, если только ему для работы не понадобятся свежие версии каких-то пакетов дистрибутива.
powerman
+1
Это отличная новость, но никак не решение всех упомянутых проблем с безопасностью. На самом деле основная проблема с регулярными обновлениями — скорее концептуальная, а docker daemon работающий под root — техническая, причём из серии "выведи козу".
powerman
+2
Вот именно. Я не понимаю только одного: почему людям хайп вокруг новых технологий настолько сильно забивает голову, что они забывают то, что вообще-то отлично знают (ну, не забывают, но на некоторое время перестают об этом задумываться и применять)? Обычно здравый смысл и опыт могут временно отключаться из-за сильных эмоций, но докеру уже сколько лет — как эмоции могут держаться так долго?
powerman
+2
Это вовсе не так, ответил там же чуть ниже.
powerman
+1
Реально если ваше приложение распилино нормально на сервисы которые предоставляют наружу четко ограниченое АПИ (например порт 80) то какай вам разница бежит ваш сервис внутри контейнера на Hardened Gentoo или альпине? Какая потенциальная угроза?
А в чём, по-вашему, разница между обычным сервером где стоит один такой сервис и контейнером докера? В том, что на сервере есть ещё и SSH? Так конкретно SSH никогда не была большой проблемой в плане безопасности, и всё, что делается в Hardened Gentoo — делается вовсе не ради защиты sshd. Или Вы считаете что сервера, на которых только SSH и один сервис с сетевым API, не имеют проблем с безопасностью и не нуждаются в регулярных обновлениях?

Любой сервис, который смотрит в сеть и принимает пользовательский ввод — можно пытаться ломать подсовывая ему не тот ввод, который он ожидает. А сломав его и оказавшись «всего лишь» внутри контейнера — злоумышленник внезапно получает доступ ко всему, к чему есть доступ у взломанного сервиса: базам данных, виртуальной сети связывающей его с другими контейнерами, и возможно даже к управлению самим докером (если им управлять из обычного контейнера, как упоминалось в статье).

Да, в контейнерах может не быть openssl и bash — но, скажите честно, много Вы видели базовых контейнеров без bash? И любой микросервис на питоне может, внезапно, часть своих фич реализовывать запуская конвейеры внешних утилит, т.е. тот же bash и shellshock для него будут актуальны на все 100%. А что касается openssl, то в неё напихали слишком много всего помимо самого SSL, поэтому любой микросервис который пользуется, например, хеш-функциями или AES для реализации каких-нибудь JSON Web Token или миллиона других мелких вспомогательных задач не связанных с его основной функциональностью — внезапно обычно оказывается слинкован с libcrypto.so из openssl.
powerman
+4
вы начали за безопасность, но я вообще не понял как вы её там подразумевали
Безопасность подразумевает необходимость ежедневных обновлений пакетов ОС, из-за чего почти каждый день необходимо будет пересобирать как базовый образ, так и часть образов с приложениями (если они содержат какие-то дополнительные пакеты ОС помимо самого микросервиса).

Ну и ещё она подразумевает использование hardened gcc (с PIE, SSP, …) для сборки пакетов ОС, что прямого отношения к докеру не имеет, но необходимость при обновлениях компилировать пакеты из исходников может сильно замедлить пересборку всех образов по сравнению с такой же компиляцией для упоминавшихся мной обычных серверов (потому что, как я опять же упоминал выше, сервера вынужденно стараются держать одинаковыми, поэтому на них одинаковый набор USE-флагов — в Gentoo они определяют настройки опциональных фич/зависимостей пакетов, как правило это задаёт параметры передаваемые в `./configure` — т.е. можно скомпилировать пакет один раз на build-сервере и быстро установить на все сервера как бинарный пакет, а в докере продвигается идея специализированных окружений для каждого приложения, так что набор USE-флагов может и как-бы даже должен отличаться, что приведёт к необходимости компилировать один пакет несколько раз в разных конфигурациях. (Кстати, может кто-то знает, уже появились не source-based дистрибутивы в которых все пакеты собраны hardened gcc? Когда я последний раз этим интересовался в некоторых дистрибутивах так собирали 20-30% пакетов, не больше.)
Да, сама идея root-демона, который занимается неизвестно чем — не самая приятная для осознания.
Беда не столько в том, что он занимается неизвестно чем, сколько в том, что он делает слишком много всего. Обычно ту часть кода, которая работает с полными root-правами стараются вынести отдельно и держать там самый минимум кода. А докер это бинарник на 25+ MB в котором с root-правами работает всё, включая Go runtime.
Однако, стоит отметить, что вы лукавите здесь, говоря, что он доступен по сети и из контейнеров. По умолчанию, docker-daemon использует UNIX-сокеты, так что доступен он только локальным пользователям
Лукавите здесь Вы. Да, по умолчанию всё именно так. Но я в своём комментарии отвечал на конкретную статью, где автор рассказывал как докер радостно создаёт сети между датацентрами так, что контейнеры этого даже не замечают, и управляет всем этим хозяйством с одной машины — через какие конкретно UNIX-сокеты, по-вашему, всё это может работать?
powerman
+20
Предположим на секунду, что нас немного волнует безопасность… в том смысле, что злоумышленник не должен получить доступ ко всем этим микросервисам и их базам данных. Сейчас у нас пяток серверов с Hardened Gentoo, на каждом, скажем, пара десятков микросервисов. И примерно раз в сутки эти сервера обновляются (а когда случается какой-нить shellshock или heartbleed — то и несколько раз в сутки).

Теперь мы решили перенести все эти микросервисы в докер. Они все разные, написаны на разных языках, используют разные библиотеки, etc. — так что получаем мы по отдельному образу на каждый микросервис, т.е., скажем, десятков пять образов. Выкатываем их на сервера и радуемся жизни… примерно часов 10.

А потом наступает новый день и возникает необходимость обновить базовый образ Hardened Gentoo лежащий в основе всех образов микросервисов. Плюс обновить те дополнительные библиотеки и приложения, которые были доустановлены поверх базового образа в образах разных микросервисов — причём в разных образах они, естественно, будут немного отличаться, так что в /etc разных образов придётся обновлять разные конфиги, и делать это немного по-разному. И вместо обновления 5-ти примерно одинаковых (вынужденно одинаковых, разумеется) серверов внезапно нужно пересобрать 50 разных (ведь в этом суть докера — каждому приложению дать уникальную для него среду выполнения!) образов. Кому-то только что конкретно прибавилось работы.

И, в качестве вишенки на торте, после того как пересобрали все образы — перезапустить все контейнеры, ведь это единственный способ "доставить" сегодняшнее обновление системы. При этом надо отметить, что когда обновляется, например, openssl, то мы, конечно, перезапускаем все процессы куда она подгружена… но, как правило, после ежедневного обновления системы перезапускать вообще ничего не требуется, или достаточно перезапустить один сервис. И далеко не все микросервисы безболезненно можно перезапускать — кто-то долго стартует, кто-то теряет разогретые кеши, кто-то закрывает сокеты миллиона подключенных юзеров и все эти юзеры начинают судорожно переподключаться создавая этим всплеск нагрузки на пустом месте…

А приложение продолжает развиваться, и вот у нас уже не 7 серверов вместо 5-ти, а 100 образов вместо 50-ти… Хотя, вру. У нас уже давно обратно 7 серверов, а докер используется только для разработки и тестирования, где безопасность никого не волнует.

И это я ещё оставил за кадром вопрос небезопасности самого докера — а ведь это сервис, который работает под root, активно меняет настройки всей системы (так что бессмысленно даже пытаться SeLinux-ом или другой RBAC обрезать его права до необходимого минимума как принято делать для всех остальных рутовых сервисов), доступен по сети и из контейнеров, и при этом очень активно допиливается (в отличие от большинства других рутовых сервисов).
powerman
+1
1. Определиться с каталогами, которые имеет смысл бэкапить.

Бэкап домашней системы может не позволять вернуть «всё как было» одним нажатием кнопки — это обычно требует слишком много места и/или времени и/или денег — но он должен позволить восстановить все важные файлы и настройки ОС/приложений. Можно позволить себе потерять то, что без проблем можно заново выкачать с торрентов, но не результаты своей работы и не то, восстановление чего потребует слишком много личного времени.

Подбор каталогов для бэкапа потребует некоторого времени, возможно понадобится даже как-то реорганизовать что где лежит на винте. Но в результате можно получить достаточно скромный размер полного бэкапа системы — у меня это порядка 5-6GB (на 3TB винт). Ежедневные инкрементальные бэкапы занимают в 10-20 раз меньше места. Такой объём можно заливать в любое облако достаточно быстро, как и скачивать в случае необходимости.

2. Настроить любую утилиту, которая по расписанию будет раз в сутки делать полные и инкрементальные бэкапы этих каталогов. И крайне желательно — в любом стандартном формате, для распаковки которого не требуется использовать исключительно какую-то одну конкретную утилиту! Особенно платную и/или с закрытыми исходниками — добровольно делать вендор-лок своим бэкапам может только ССЗБ.

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

4. После чего обязательно необходимо убедиться, что из облака бэкапы удаётся скачать, и у них совпадает контрольная сумма с залитыми файлами (я использую 4shared.com через DAV, так вот, вы удивитесь, как часто после скачивания обнаруживается проблема, и не думаю, что это уникальная «фишка» 4shared).
powerman
+1
Относительно GMail складывается впечатление аналогичное ситуации, когда один вирус заражая комп удаляет с него другие вирусы: гугл хочет иметь эксклюзивную возможность читать чужие письма. А на мой взгляд, SSL для SMTP это, безусловно, неплохо, но если вас волнует безопасность переписки — нужно использовать PGP, а не SSL.
powerman
0
У меня только один вопрос: а чем это лучше try...catch?
А кто сказал, что эта дикая смесь ошибок и исключений лучше try/catch? Она не лучше, она намного, намного хуже.

У меня только один вопрос: нафига писать такую дичь, полностью оторванную от реальных задач?
powerman
+1
Ну смотри, ты не прав.
Великолепно! Кратко, и по сути!
Я считаю, что не стоит разделять на конечные пкг и приложения, не стоит этим заниматься.
Почему, собственно?
Различать разные сущности очень полезно — это позволяет каждую из них обрабатывать максимально специфичным для неё, т.е. более простым и эффективным, способом. Абстрактный и универсальный код — это в большинстве случаев либо тривиально и практически бесполезно, либо очень сложно и медленно.
конечному приложению нужны стектрейсы, если что-то в библиотеке сломалось.
Насколько сильно сломалось? Если очень сильно — и так будет паника. Если библиотека просто некорректно работает и вернула не то значение или ошибку — в её коде всё-равно придётся разбираться, отлаживать и фиксить, и поиск места где эту ошибку вернули (на которое бы указал стектрейс, и то только в случае возврата ошибки-исключения, а если библиотека просто возвращает некорректное значение то никакого стектрейса бы не было всё-равно) обычно занимает секунды/пару минут, которые полностью теряются на фоне времени необходимого на отладку и исправление кода (да и это время не является бесполезно потраченным — чтобы исправить ошибку всё-равно нужно разобраться почему она возникает, т.е. вычитать этот же самый код).
Скажем так, я не вижу причины не использовать сквозные паники.
Ну что тут скажешь… беда, просто беда. А я вот не вижу причины себя ими ограничивать, предпочитаю использовать тот подход, который лучше подходит в конкретной ситуации.
powerman
+4
те ошибки, которые Go не считает «исключительными», на самом деле, почти всегда cебе очень даже и исключительные
Исключительная ошибка или нет знает только конечное приложение. Библиотека этого знать не может в принципе. Поэтому использование panic в приложении вполне уместно, а в библиотеке крайне нежелательно. Кроме того, логика обработки ошибок — важнейшая часть логики приложения, поэтому крайне желательно побуждать программиста над ней задумываться, а не лепить механически panic везде просто потому, что ему лень думать.

Описываемый Вами стиль оформления ошибок в виде сложной структуры, как и любое абстрактно-универсальное решение, не является уместным везде и всегда. Там, где это имеет смысл — стандартная библиотека Go возвращает такие структуры (без контекста и стектрейса, там, где они нужны их несложно добавить: panic(err)). В абсолютном большинстве задач, с которыми работал я — текстового описания ошибки было абсолютно достаточно. и оно было намного удобнее сложной структуры. Желание всё усложнять без необходимости обычно проходит примерно через 10-15 лет работы программистом.

P.S. Кстати, поздравляю, Вы с этим шапито и немотивированными наездами на Пайка сформировали достаточно уникальный стиль речи, по которому автор текста определяется не хуже, чем по текстам Мицгола.
powerman
+2
Лично мне это читать тяжело.
Если это личная особенность, то это нормально. Все люди разные, и очень хорошо, что есть много разных языков программирования — каждый может подобрать себе такой, который ему понравится. Но личные предпочтения не могут являться аргументом при обсуждении языка — по определению кому-то что-то субъективно и немотивированно нравится, а что-то нет, и конструктивно здесь обсуждать просто нечего.
Я воспринимаю эти повторы как смысловой шум.
Это очень плохо — код, безусловно, выглядит намного проще и понятнее если из него выкинуть обработку ошибок, но дело в том, что обработка ошибок это важнейшая часть логики приложения, и даже бизнес-логики. Поэтому логика обработки ошибок должна быть максимально наглядной и легко доступной, т.е. находиться на виду, рядом с тем местом где ошибка возникла. Как и рекомендуется делать в Go.
Если я хочу понять бизнес, происходящий в коде, то я должен научиться отфильтровывать эти конструкции — но если я научусь это делать, вероятность того, что я пропущу в них что-то важное, резко увеличивается.
А вот здесь всё совсем наоборот. Фильтруются только типовые конструкции вроде if err != nil { return err } — за любое минимальное отличие в этой конструкции глаз сразу зацепляется, что сильно уменьшает вероятность пропустить что-то важное. Возможно, конечно, что здесь тоже имеют место отличия между нашими личными особенностями восприятия, но дело может быть и в том, что я на Go пишу, а Вы (как я понял из комментариев, прошу прощения если я ошибся) — нет, так что я опираюсь на практический опыт, а Вы на теоретическое впечатление сложившееся от чтения статей по Go. Раз уж Вас настолько интересует Go, что Вы постоянно критикуете его в комментариях, может быть Вам стоит потратить несколько недель и попробовать его в реальном проекте?
Впрочем, лично у меня к «стандартному способу обработки ошибок в Go» есть существенно более фундаментальная претензия, состоящая в том, что он… не стандартный. В стандартной библиотеке Go используются как минимум три разных способа сообщения об ошибочной ситуации
Стандартный способ обработки ошибок в Go — библиотеки не должны выкидывать наружу panic за исключением действительно редчайших особых ситуаций, а должны возвращать ошибку как значение. Покажите мне, пожалуйста, конкретные примеры кода стандартной библиотеки, о которых Вы говорите… хотя я подозреваю, что Вы просто подразумеваете что-то иное под «стандартным способом обработки ошибок в Go».
обсуждаемый выше пример с функцией-хелпером — это пример, приводимый в официальном блоге Go одним из авторов языка
Каждый может проявить слабость если сильно задолбать. Наверняка есть ситуации, когда такой хелпер вполне уместен — как и в случае с копипастом/goto у него есть и достоинства и недостатки, и существуют ситуации в которых достоинства перевешивают. Но я пока таких хелперов в реальном коде не встречал, так что эти ситуации скорее всего слишком редки, чтобы их имело смысл обсуждать в контексте глобальных особенностей языка.
Нет, несомненно, «ошибки — это значения», и поэтому к ним применимы все языковые средства во всем их разнообразии… вот только униформность в этом случае сильно страдает, а вместе с ней начинают рассыпаться и приведенные вами аргументы.
Извините, я, наверное, сильно устал, но я не уловил логики в этом утверждении. Можете развернуть мысль подробнее?