Однажды топ-менеджер компании по производству собачьего корма во время презентации открыл банку собственного продукта и... съел ее. Так он хотел донести до клиентов простую мысль: если ты действительно уверен в своем продукте, ты готов пользоваться им сам. Сегодня эту практику применяют многие: Google пользуется собственными сервисами, Slack общается через Slack, Uber заказывает поездки через Uber.

Так появился термин Dogfooding — использование собственного продукта внутри компании.

Привет, Хабр! Я — Александр Чернев, руковожу инженерной командой платформенных сервисов в K2 Cloud. Раньше занимался системами виртуализации и различными self-hosted-решениями, а сейчас наконец-то витаю в облаках как cloud-инженер.

Но вернемся к нашей теме. Мы в К2 также используем подход Dogfooding: сами строим внутренние сервисы в собственном облаке, используем его API, разворачиваем инфраструктуру, подключаем платформенные сервисы — словом, живем внутри того же продукта, который получают наши заказчики. Сегодня я расскажу вам, как это устроено у нас и почему такой подход оказался одним из драйверов развития облака.

Главное правило Dogfooding’a и что оно нам дает

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

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

  • стоит использовать те же лимиты и ограничения, что действуют в production. Если у заказчика есть определенные политики, значит, и для наших внутренних проектов они должны быть такими же;

  • нужно стараться максимально распределять ресурсы на своих тестовых окружениях так же, как они распределяются в production;

  • использовать собственный продукт не только для тестирования, но и для внутренних сервисов;

  • работать через те же API, которыми пользуются ваши заказчики.

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

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

Резюмируя вышесказанное, Dogfooding — это не только тестирование на проде, он не отменяет процессов тестирования. Вы не просто должны использовать данную концепцию, вы должны ее интегрировать в свои процессы.

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

Dogfooding встроен во все эти этапы. Мы не заменяем им тестирование — мы интегрируем его в существующий процесс. За счет этого повышаем и качество тестирования, и его эффективность.

Как это работает у нас

Поскольку я занимаюсь платформенными сервисами, проще всего показать это именно на их примере.

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

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

Когда виртуальная машина стартует, начинает работать Cloud Init. Он выполняет первоначальную конфигурацию сервиса. После этого запускается Puppet-агент, который уже донастраивает сервис. В этот момент он взаимодействует с metadata-сервисом облака и получает все необходимые данные, например, для развертывания PostgreSQL.

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

Представим, что на вершине потребления ресурсов нашего облака находятся платформенные сервисы и Kubernetes.

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

Например, нам понадобилось добавить в Kubernetes новые worker-ноды. Что мы делаем? Обращаемся к API автоскейлинга, запрашиваем новые ресурсы, получаем виртуальную машину и подключаем ее к Kubernetes. По сути, это тот же самый сценарий, который может использовать любой пользователь облака.

Или другой пример — балансировщики нагрузки. Если вам нужен балансировщик, вы создаете его через платформенные сервисы. При этом внутри все происходит точно так же: используются те же публичные endpoint'ы и те же обращения к ELB API.

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

Как платформенные сервисы и Kubernetes используются уже для наших внутренних сервисов

В облаке постоянно собирается код. Значит, нам нужны сборочные системы, надо где-то хранить артефакты. Все это работает в нашем EKS-сервисе, куда приходит основная рабочая нагрузка, а backend этих сервисов использует платформенный PostgreSQL.

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

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

Для нас это было важно, потому что API AWS —  это единый стандарт, к которому стремятся все облака, и совместимость с ним позволяет запускать подобные приложения без необходимости переписывать провайдера. Именно этого мы и хотели добиться. Мы нашли эти несоответствия, устранили их, после чего сервис спокойно вышел в эксплуатацию.

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

Промежуточный итог

Выходит, что сама концепция платформенных сервисов буквально заставляет нас использовать собственное облако.

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

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

Как Dogfooding используют все разработчики облака

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

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

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

Что происходит во время развертывания такого стенда? Если говорить в целом, то здесь несколько этапов:

  • настроить сетевые доступы и ограничения;

  • собрать код;

  • развернуть инфраструктуру;

  • развернуть само приложение облака в облаке.

Начнем с самого первого этапа — сетевых доступов и ограничений. Почему вообще мы уделяем этому столько внимания? Потому, что одна из основных идей Dogfooding заключается в том, чтобы максимально приблизиться к своему пользователю. Именно поэтому в рабочем проекте каждого разработчика мы специально вводим ограничения: сокращаем количество внешних IP-адресов, используем проектные квоты на потребление ресурсов, применяем те же политики доступа, что действуют и для клиентов облака. То есть разработчик работает практически в тех же условиях, что и заказчик. Благодаря этому мы гораздо быстрее получаем обратную связь и лучше понимаем, как ведет себя продукт.

Теперь давайте перейдем непосредственно к сетевым доступам.

Сетевые доступы

Раньше, чтобы предоставить разработчику доступ к своему стенду, нужно было назначить ему внешний IP-адрес, а затем через Security Groups открыть необходимые входящие правила. Работало это нормально, но был один минус: всегда существовал риск, что где-то случайно останется открытый порт или доступ окажется шире, чем требовалось. А это уже потенциальная проблема с точки зрения безопасности.

Чтобы полностью избавиться от этой истории, мы перешли на другую схему. Теперь используем Transit Gateway, Direct Connect и VPN. По сути, это позволило нам полностью отказаться от внешнего неавторизованного доступа к рабочей сети. 

Как это работает? Представим, что есть наша общая рабочая сеть и отдельные сети разработчиков. Чтобы разработчик мог попасть в инфраструктурную сеть — туда, где находятся сборочные системы, хранилища кода и другие внутренние сервисы, — мы используем Transit Gateway. Он маршрутизирует трафик между закрытыми подсетями и сетями разработчиков. За счет этого разработчик получает доступ ко всем необходимым ресурсам без дополнительной настройки внешних подключений.

И здесь есть еще один плюс, который мы почувствовали практически сразу. Приходит к вам коллега и говорит: «Слушай, помоги, пожалуйста. У меня на стенде возникла проблема, не могу разобраться». 

Он присылает IP-адрес своего стенда, я подключаюсь и сразу смотрю на проблему. Не нужно ничего дополнительно настраивать, открывать порты или менять правила доступа — все уже работает изначально. На практике такие вещи очень экономят время.

Но это еще не все. Чтобы попасть в свою закрытую сеть с рабочего компьютера, мы используем связку Direct Connect и Transit Gateway. У нас есть отдельная инфраструктурная сеть, где работают VPN-серверы, различные инфраструктурные сервисы и тестовые стенды.

Direct Connect соединяет эту инфраструктуру с Transit Gateway, и за счет этого мы получаем единое сетевое пространство. Со своих devel-стендов мы можем работать не только с облачными сервисами, но и при необходимости подключаться к железной инфраструктуре. Для нас это тоже оказалось важным сценарием, так как помогает использовать железную инфраструктуру в повседневной работе.

Если сравнить то, как было раньше и как стало сейчас, разница существенная. Раньше мы использовали Elastic IP. Чтобы контролировать безопасность, приходилось регулярно проводить аудиты: сканировать сети разработчиков, искать открытые порты, приходить к коллегам и просить закрыть лишние доступы. После перехода на Transit Gateway необходимость в этих проверках просто исчезла. В результате мы сэкономили и время инженеров, и ресурсы, которые раньше тратились на постоянные аудиты.

Если подвести итог именно этой части, то новая схема дала сразу несколько плюсов:

  • разработчики получили простой и понятный доступ ко всей инфраструктуре;

  • закрытая сеть стала безопаснее;

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

  • мы снова получаем эффект Dogfooding.

Мы каждый день пользуемся Direct Connect и Transit Gateway в своей работе — настолько они вошли в нашу жизнь, что часто даже перестаем это замечать. Но именно благодаря этому очень быстро видим любые неудобства или недоработки, если они появляются.

Но на этом Dogfooding не заканчивается — если мы говорили раньше про инфраструктуру, то картина, на самом деле, гораздо шире.

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

Что происходит на этапе сборки кода

При сборке кода мы используем свои же сервисы. Сам код хранится в Git, артефакты складываются в S3, доменные имена обслуживаются нашим DNS as a Service. Сама сборочница, как я уже говорил раньше, работает в Kubernetes, база данных для нее находится в платформенном PostgreSQL, а все собранные артефакты снова отправляются в S3.

Что нам это дает? Мы все глубже и глубже погружаемся на уровни потребления собственного облака. Прямо как в фильме с Ди Каприо «Начало»: там герои погружались на все более глубокие уровни сна, а мы — на все более глубокие уровни использования собственного облака.

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

Переходим к следующему этапу — деплою инфраструктуры

Инфраструктуру мы разворачиваем с помощью нашего Terraform-провайдера.

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

Что именно мы разворачиваем с помощью Terraform? В первую очередь это вычислительные ресурсы, дисковая подсистема и сетевая подсистема. Сначала посмотрим на вычислительные ресурсы и диски.

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

Например, в платформенных сервисах мы используем выделенные узлы, потому что  нам важно максимально использовать ресурсы узла. Там же используем GPU — например, когда нужно подключить их к Kubernetes для AI-вычислений.

Для ресурсоемких задач юзаем диски IO2 — они позволяют полностью раскрыть потенциал этого типа SSD-дисков. Большинство команд при этом работает с General Purpose-инстансами и дисками GP2, которые закрывают большую часть повседневных задач разработки.

Для веб-проектов — Shared Core. В рамках веб-разработки не всегда требуется постоянная загрузка процессора на 100%, поэтому такие ресурсы подходят очень хорошо. Вместе с магнитными дисками это позволяет эффективно использовать те ресурсы, которые уже есть в облаке, для наших devel-стендов.

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

Когда инфраструктура полностью готова, переходим, наверное, к самому интересному — к непосредственному развертыванию нашего облака в облаке.

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

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

Как еще можно использовать Dogfooding

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

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

Что мы в итоге получили

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

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

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

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

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

Вместо заключения

Давайте подведем итоги. 

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

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

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

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

Комментарии (0)