воскресенье, 20 августа 2017 г.

Заметки о Dockerfile

Перевод: Dockerfile Notes
Автор: Соня Гамильтон (Sonia Hamilton)

Примечания переводчика:
Искал однажды что-то в интернете и вышел на блог этой авторши. Сейчас уже не помню почему, добавил этот материал в список того, что было бы неплохо перевести. Сейчас смотрю и недоумеваю - зачем мне это понадобилось? Ничего лучше фразы "чтоб было" в голову не пришло. Ну пусть будет.
Несколько заметок о Dockerfile'ах Docker.

Команды

  • MAINTAINER - автор, адрес электронной почты и т.п.
  • FROM - базовый образ, например Ubuntu.
  • CMD и ENTRYPOINT. Любая из них по отдельности может быть использована для указания исполняемого файла по умолчанию. Если используются обе, то CMD добавляется к ENTRYPOINT для получения командной строки контейнера. Любая из них может быть заменена при запуске docker. Однако CMD легче - она просто берёт остаток команды запуска docker (как "$*" в сценариях оболочки) - разрешая образу docker почувствовать себя в роли выполняемого файла, запущенного через "обёртку".
  • RUN - установочные команды. В режиме разработки разделите команды RUN, так что слои кэшировались и собирались быстрее. В рабочем режиме лучше воспользоваться цепочкой команд RUN, разделённых знаками && или точкой с запятой, поскольку несколько отдельных команд RUN создают несколько слоёв.
  • COPY и ADD. COPY копирует файлы в образ. ADD делает то же самое, но также может разархивировать файл или скачать его по ссылке. Избегайте использования команды ADD, поскольку она обладает излишне сложным поведением.
  • VOLUME - постоянный каталог на родительской файловой системе внутри /var/lib/docker/volumes. Для получения ожидаемого поведения (общий каталог для родительской системы и контейнера) воспользуйтесь командой docker run -v /var/tmp/foo:/var/tmp/foo.
  • ENV, WORKDIR и USER - переменные окружения, текущий каталог и идентификатор пользователя для команд CMD/ENTRYPOINT.
  • EXPOSE - открыть сетевой порт. Воспользуйтесь форматом nn, а не nn:mm, который позволяет пользователю указать публичный порт при помощи опции -p. Порт, открытый при помощи команды EXPOSE может быть автоматически отображён при помощи опции -P.

Сборка, запуск, выполнение

# Собрать образ и пометить его, использовать текущий каталог в качестве контекста
docker build -t="soniah/foo:1.0" .
# Запустить, автоматически отобразить порты. В режиме разработки опустите -D - стандартный поток
# вывода будет выводиться на экран, а контейнер автоматически остановится при нажатии Ctrl-C.
docker run -P sonia/foo
# Получить интерактивную оболочку
docker exec -it random_name bash
# Удалить все старые образы, за исключением базовых образов Ubuntu
docker rmi -f `docker images | tail -n +2 | grep -v 'ubuntu' | awk {'print $3'}`
# Удалить все контейнеры, включая остановленные контейнеры
docker rm -f `docker ps --no-trunc -aq`

Смотрите также

воскресенье, 13 августа 2017 г.

Карго-культ микросервисов

Перевод: The microservices cargo cult
Автор: Ставрос Корокитакис (Stavros Korokithakis)

"Всё сделано правильно. Форма совершенна. Он выглядит точно так же, как и раньше. Но он не работает."

Микросервисы - это чудо. Мы знаем это, потому что об этом говорят все последние истории успеха. Новости наполнены историями о том, как люди берут огромную монолитную систему, разбивают её, добавляют веб-API и наслаждаются всеми выгодами.

Как и со всеми модными практиками, всё начинается довольно невинно. Кто-то пробует её, она хорошо себя показывает. Затем он в красках расписывает все преимущества новой практики. Все воодушевлены и хотят её попробовать. Вскоре появляется бурный поток статей, рассказывающий о том, как хорошо работает новая практика, как много людей попробовали её и убедились в её достоинствах. Однако, никто не рассказывает о тех случаях, когда она не сработала, просто потому что люди не любят рассказывать о собственных неудачах.

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

Карго-культы

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

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

Достоинства

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

Недостатки

  • Сложность: Сразу на порядок увеличивается количество работы, выполняемой серверами. Между ними появляются промежуточные прослойки, работающие через сеть, что на порядок увеличивает общее количество развёртываний и нагрузку на администраторов, а количество сервисов, требующих мониторинга, увеличивается во много десятков раз.
    Также появляется масса дополнительного кода, выполняющего сериализацию и десериализацию данных, передаваемых между сервисами. И хотя обычно его суммарный объём не велик, ничего хорошего в этом нет.
  • Накладные расходы: Все эти разнообразные хранилища данных, преобразования данных и сетевые вызовы не обходятся даром. Лично мне встречалось замедление порядка 1000% из-за перехода на микросервисы (да, в десять раз медленнее).
  • Сегрегация данных: Поскольку все данные теперь хранятся в разрозненных хранилищах данных, нужно следить за их согласованностью. Если в монолитной системе можно было обойтись простым каскадным удалением, то теперь нужна сложная симфония зависимостей, вызовов и перепроверок. Это очень похоже на использование не реляционного хранилища данных. Если у вас есть опыт работы не реляционными хранилищами и вы успешно с ними справлялись, то проблем возникнуть не должно.

Критическая оценка

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

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

Стоит ли вам использовать микросервисы?

Из описанного выше следует, что небольшие проекты не смогут извлечь пользы из микросервисной архитектуры. Однако, они всё же могут извлечь пользу из более чёткой архитектуры и меньшей кодовой базы, верно?

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

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

Простой способ принятия решения

Чтобы помочь вам сориентироваться в лабиринте вопросов и доводов при принятии решения - нужны ли вам микросервисы, я создал соответствующую диаграмму. Вот она:

Диаграмма для принятия решений, нужны ли вам микросервисы

Эта диаграмма ответит на все ваши вопросы о микросервисах.

Это немного щекотно.

Заключение

Не начинайте с микросервисов, это сложный способ, который вначале не требуется.

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

Истинно глаголю вам: не начинайте с микросервисов лишь потому что так делают крутые парни. Это сложный подход, который поначалу не нужен. Наслаждайтесь простотой разработки и гибкостью развёртывания, которые даёт одно приложение. Когда ваш бизнес окрепнет и вырастет, и вы не сможете найти достаточно мощный сервер для приложения, только тогда выделяйте части из общей инфраструктуры в отдельные сервисы, соединяя их через HTTP или через очередь сообщений.

Принять участие в последующей священной войне можно найдя меня в Twitter. Чтобы избежать невинных жертв, можете просто оставить комментарий на этой странице.

Примечания переводчика
Сам довольно скептически отношусь к идее микросервисов, по многим причинам.

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

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

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

воскресенье, 6 августа 2017 г.

Bottle - полный веб-стек без Django

Перевод: Bottle, full stack without Django
Автор: Тьяго Авелино (Thiago Avelino)

Эта заметка в блоге основана на лекции, которую я прочитал здесь, в Бразилии. Посмотрите слайды!

Веб-микрофреймворк Bottle

Bottle - это веб-микрофреймворк, совместимый с WSGI, который зависит только от стандартной библиотеки Python и совместим с Python версий 2.6, 2.7, 3.2, 3.3 и 3.4. Весь исходный текст фреймворка умещается в одном файле. Он был создан Марселем Хеллкэмпом (Marcel Hellkamp - @defnull) и поддерживается сообществом, образовавшимся вокруг этого фреймворка.

Django - это прагматичный фреймворк для быстрой веб-разработки, который написан на Python, использует стандарт MTV (model-template-view - модель-шаблон-представление). Изначально он был создан как система для управления сайтом журнала в городе Лоуренс, в Канзасе. Стал проектом с открытым исходным кодом, был опубликован под лицензией BSD в 2005 году. Название Django фреймворк получил в честь джазового музыканта Джанго Рейнхардта. Django стал очень известен благодаря поставке с "батарейкам", то есть благодаря нескольким библиотекам, добавленным к основному коду фреймворка для упрощения разработки. Вместе с фреймворком эти библиотеки сформировали так называемый "полный стек".

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

Хорошо ли, если вместе с веб-фреймворком поставляются "батарейки"? Если вы согласны использовать всё, что даёт вам фреймворк, то ответ - да. Однако, не все веб-проекты одинаковы.

В большинстве проектов используется не более 80% возможностей Django. В тех случаях, когда используется не более 50% возможностей, мы вынуждены платить за все, что было предусмотрено архитектурой Django. То есть теряем в производительности, потому что в Django имеется множество модулей, которые не используются, но по-прежнему продолжают работать. Когда же мы используем микрофреймворк, мы берём на себя роль архитектора приложения. Поскольку у нас нет предопределённой архитектуры, нам нужно время, чтобы определить архитектуру приложения.

Все пакеты Python, которые имеются в библиотеке Django, в микрофреймворке могут быть заменены!

SQLAlchemy

SQLAlchemy существовал до Django (да, до Django) и начиная с 2005 года появилась команда, которая стала заниматься разработкой ORM. Команда же разработчиков Django занимается одновременно и разработкой фреймворка и разработкой ORM. Я думаю, что не стоит говорить о том, что результат работы специалистов обычно бывает лучше, чем результат работы универсалов.

Структура модели:
class Entity(Base):
    __tablename__ = 'entity'
    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    name = Column(String(50))

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "<Entity('%d', '%s')>" % (self.id, self.name)

WTForms

Обходное решение для тех, кто не использует Django и кому нужно работать с формами - это WTForms, которые были созданы в 2008 году и поддержка которых продолжается до сих пор!

Структура формы:
class UserForm(Form):
    name = TextField(validators=[DataRequired(), Length(max=100)])
    email = TextField(validators=[DataRequired(), Length(max=255)])

Шаблонизатор

Jinja2 - это современный удобный для дизайнеров язык шаблонизации для Python, который был создан по образцу шаблонов Django. Он быстрый, широко используется и может быть дополнительно защищён изоляцией рабочего окружения.

Структура шаблона:
<title>{% block title %}{% endblock %}</title>
<ul>
{% for user in users %}
  <li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>

Миграция

Использование Alembic начинается с создания среды миграции. Это каталог сценариев, которые относятся к отдельному приложению. Среда миграции создаётся единожды, а затем поддерживается совместно с исходным кодом самого приложения.

Структура миграции:
revision = '1975ea83b712'
down_revision = None

from alembic import op
import sqlalchemy as sa

def upgrade():
    pass

def downgrade():
    pass
Как создать обновление и откат:
def upgrade():
    op.create_table(
        'account',
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('name', sa.String(50), nullable=False),
        sa.Column('description', sa.Unicode(200)),
    )

def downgrade():
    op.drop_table('account')
Структура модификации таблицы:
"""
$ alembic revision -m "Add a column"
"""

revision = 'ae1027a6acf'
down_revision = '1975ea83b712'

from alembic import op
import sqlalchemy as sa

def upgrade():
    op.add_column('account', sa.Column('last_transaction_date', sa.DateTime))

def downgrade():
    op.drop_column('account', 'last_transaction_date')

Заключение

Здесь было продемонстрировано всё, что можно найти в стеке Django. Я писал эту заметку для не для того, чтобы принизить Django. Я лишь показал, что существуют другие полностековые решения для разработки приложений. Многие люди используют Django, не понимая экосистемы Python. В наше время Django предоставляет множество готовых решений, что заставляет некоторых разработчиков лениться и не наращивать мастерство в проектировании архитектуры приложения.

Помогайте Bottle. Мы - растущее сообщество. Чтобы внести свой вклад в код Bottle, обратитесь к списку открытых задач. В случае сомнений можно обратиться в список рассылки или в IRC-канал.

ПРИСОЕДИНЯЙТЕСЬ

Примечания переводчика:
Считаю, что в статье тема не раскрыта. Не понятно, какая такая особенная архитектура приложения имелась в виду,
которая никак не сочетается с Django. Перечислено несколько средств, которые в чём-то заменяют средства, имеющиеся в Django. Без сомнений, SQLAlchemy заткнёт за пояс джанговский ORM. Безусловно, Jinja2 - очень быстрый шаблонизатор, быстрее джанговского. Но стоит иметь в виду, что в Django все эти средства глубоко интегрированы друг с другом.

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

Другой пример - в Django миграции можно сгенерировать автоматически. Автоматическая генерация даже умеет определять переименованные поля. А если же автоматика не сработала корректно, то автоматически сгенерированный код миграции можно подправить и руками.

Наконец, в комплекте с Django имеется административный интерфейс, для которого можно определять собственные классы для редактирования таблиц. В большинстве случаев этот административный интерфейс позволяет сэкономить время на создании шаблонов и написании представлений для просмотра и редактирования таблиц. Да, его возможности ограничены, но ведь в комплекте с Bottle ничего подобного нет, а если и есть в сторонних модулях, то наверняка такие модули тоже окажутся недостаточно интегрированными с ORM или модулем форм - придётся писать дополнительный код, который предоставит необходимую информацию этому модулю.

Я сам в своих проектах использую Django, но для некоторых задач он действительно избыточен. Например, в одной из прошлых своих заметок я писал Тайловый сервер на основе Python, Mapnik и Bottle. Денис Рыков, материалами которого я воспользовался, тоже писал тайловый сервер, воспользовавшись фреймворком Bottle. Для себя я решил, что если приложение не работает с собственной базой данных, а берёт информацию из сторонних источников и занимается лишь её преобразованием, или выполняет какие-то действия по требованию, то лучше использовать Bottle, т.к. в нём нет избыточных возможностей, а сам он обладает минимумом зависимостей и работает с любой версией Python.