что такое helm chart
Краткое руководство по разработке чартов в Helm
Helm — мощный инструмент для применения, обновления и управления приложениями в Kubernetes. Сообщество Helm создает множество чартов с открытым исходным кодом. Вы можете развернуть Redis, Nginx или Prometheus Operator с помощью одной команды. И они поставляются со всем, что нужно, например с Ingress.
Команда Mail.ru Cloud Solutions перевела статью, автор которой описывает быстрый способ создания базового чарта, показывает полезные команды и делится лучшими практиками. Он не останавливается на аспектах языка шаблонов Go, поскольку большинство из них описаны в документации по Helm. В этом руководстве — более абстрактные аспекты и идеи по улучшению рабочего процесса.
Создание базовой структуры чарта
Начните с простой команды, которая создаст пример структуры чарта:
Вот и всё, что нужно для создания готового к развертыванию чарта. Такой чарт позволяет развернуть приложение со всеми необходимыми компонентами. Если вы заглянете в values.yaml, то увидите, что это приложение развернет Nginx.
Развернуть чарт так же просто, как и создать:
Команда template — ваш лучший друг
Непосредственно перед установкой и после изменений в чарте следует проверять, всё ли обрабатывается в шаблонах должным образом.
Чтобы проверить, что именно будет развернуто в кластере, используйте команду:
Команда выведет каждый YAML, созданный всеми шаблонами. Если хотите увидеть результат только одного шаблона, используйте:
Результат будет примерно таким:
Для тестирования шаблона с настраиваемыми значениями используйте:
Сгенерированный шаблон можно протестировать на кластере при помощи команды:
Перед отправкой в репозиторий вы можете добавить еще один шаг для четкой проверки кода — linting (статистический анализ):
Helm работает с функциями
Если заглянуть в каталог шаблонов чарта, то можно увидеть _helpers.tpl. Сюда вы можете добавить свои функции, они будут доступны по всему чарту. Пример функции может выглядеть так:
Использование функции в шаблоне указывают при помощи функции include :
Мета-метки
Важная часть Kubernetes — правильное использование меток. Это очень важно, если вы используете Helm для развертывания множества манифестов. Чтобы легко добавлять метки для поиска ресурсов, управляемых Helm, можно использовать собственные функции:
И теперь несложно добавить несколько меток в чарт:
Если хотите отыскать сервисы, созданные с помощью этого чарта, то используйте команду:
Комментарии вас спасут
Возможны два типа комментариев:
Вывод шаблона будет таким:
Как вы видите, сгенерированный манифест содержит только комментарий простого типа. Какой тип использовать — решать вам. Но комментарии к шаблонам полезны, если вы описываете в YAML функции более сложных конвейеров или зависимостей.
Еще важно помнить, что комментарии, начинающиеся с #, тоже парсятся. Если вы поместите шаблон Go в комментарий, то он будет вычислен. Так что комментарии тоже могут быть шаблонами.
Обязательно ведите документацию
Документация для чартов незаменима, особенно если вы хотите опубликовать чарт. Самый простой способ создавать и поддерживать документы — использовать пакет Golang с именем helm-docs. С его помощью вы можете сгенерировать README.md, содержащий таблицы значений, версий и описания из values.yaml и chart.yaml или использовать другие пользовательские файлы.
Пример взят с https://github.com/norwoodj/helm-docs
Как видите, добавление в комментарии имени с — приводит к одной строке в таблице. Кроме того, в таблице содержится дополнительная информация, например, описание чарта, имя и версия. Helm-docs можно интегрировать в прекоммит вместе с линтингом. Сделать это просто:
Магия субчартов
Когда ваш чарт становится монстром, создающим всю архитектуру, лучше всего разделить некоторые компоненты чарта на более мелкие. Их называют субчартами или дочерними чартами.
Субчарты развертываются одновременно с основным чартом. Значения для субчартов можно предоставить в том же файле values.yaml, что и для основного чарта. Еще их можно подключать из GitHub, но для статьи я создам субчарт локально.
Чтобы начать работу с новым субчартом, от которого зависит основной чарт, создайте каталог charts внутри папки основного чарта. Затем создайте базовый чарт:
Чтобы подключить субчарт, измените определение основного чарта:
Теперь каждый раз при запуске команды helm install разворачивается не только основной чарт, но и субчарт. Чтобы переопределить референсное имя субчарта при развертывании в сервисе, добавьте в values.yaml основного чарта следующие команды:
Теперь запустите команду template и посмотрите измененный вывод сервиса субчарта. Тип сервиса изменится вместе с названием:
Важное примечание: субчарты не могут принимать значения из родительских чартов.
Моменты, о которых часто забывают
Еще несколько моментов:
Ну вот и всё!
Теперь вы можете написать свой первый чарт. Стоит упомянуть о прикреплении файлов — чарты не подходят для добавления файлов и сохранения их структуры в каталогах. Но на странице с рекомендациями вы не найдете информации о том, что следует держать в чарте, а что — нет.
Helm — довольно молодой инструмент, но с большим потенциалом. Не забывайте, что линтинг, генерация документации и даже dry-run шаблоны в кластере могут быть частью CI. Для GitHub уже доступны Helm Workflow.
Искусство Helm Chart: паттерны из официальных чартов Kubernetes
Установка и управление Helm Charts может вызвать у вас некоторые сложности, с которыми вы, возможно, не сталкивались раньше.
Картина о запуске helm install
Я хочу установить MySQL в свой кластер. Но мне не нужна версия MySQL, которую stable/MySQL устанавливает в файле values.yaml в официальном репозитории чартов. Итак, я создаю свой собственный файл values.yaml с именем mysql-values.yaml всего с одной строкой:
Helm генерирует для меня уникальное имя выпуска ( ignorant-camel ), и MySQL развернут в моем кластере. Вывод kubectl describe pod ignorant-camel-mysql-5dc6b947b-lf6p8 сообщает мне, что выбранный мной тег imageTag применен.
Процесс доступа к сгенерированным дескрипторам развертывания Kubernetes можно лучше понять, подумав о структуре Helm Chart:
Итак, наш чарт используется в других чартах, и они передаются пользователям в пищевой цепочке чартов. Увидеть, как удовлетворить наших потребителей в этой пищевой цепочке, — одна из ключевых задач при написании Helm Charts.
Проблемы написания чартов Helm
Мы можем многое узнать о том, как справляться с подобными проблемами из чартов в официальном репозитории Helm Charts. Давайте рассмотрим некоторые шаблоны, которые используются в этих чартах, чтобы понять, как использовать те же шаблоны в наших собственных чартах.
Прежде чем погрузиться в подробности, стоит иметь в виду, что публичные чарты довольно продвинуты. Если вы беспокоитесь о некоторых из вышеперечисленных вопросов при разработке ваших первых чартов Helm, постарайтесь для начала отложить более сложные заботы. Начните с ознакомления с документацией Helm и попробуйте сначала построить чарт, который работает только для самых простых случаев. Позже вы сможете добавить дополнительные параметры.
Итак, давайте попробуем получить снимок паттернов из официальных чартов. Это не будет исчерпывающим, и я ожидаю, что появятся новые опции и новые шаблоны, когда Helm 3 добавит скрипты с Lua. Но это даст нам возможность взглянуть на современное состояние искусства.
1. Шаблоны для раскрытия параметров конфигурации
Допустим, мы определили ресурс развертывания в нашем шаблоне и настроили раздел env, чтобы разрешить установку некоторых переменных среды из values.yaml :
Как сказано в руководстве разработчика Helm Charts, мы могли бы создать configmap с функцией диапазона. Хороший пример этого для стабильного/несвязанного чарта. Он содержит configmap, которая определяет его файл unbound.conf. Он монтирует этот файл в поды, созданные при его развертывании. Внутри configmap есть такие записи, как:
И его values.yaml позволяет устанавливать записи в localRecords в виде списка, например:
Sonarqube chart применяет аналогичный подход непосредственно к переменным среды, определяя некоторые и позволяя устанавливать дополнительные переменные с помощью коллекции extraEnv :
Таким образом, это означает, что вместо того, чтобы устанавливать записи extraEnv в values.yaml как простые пары, нам также нужно будет назвать каждый из ключей ( имя ) и значения ( значение ) в парах, например:
Чарт Keycloak снова делает это иначе:
2. Ссылки на взаимно развертываемые ресурсы
Обычно ресурсы, развертываемые через Helm, имеют префикс с именем выпуска, так что несколько выпусков могут быть установлены из одного чарта (и в одном пространстве имен) без конфликтов имен между установленными ресурсами. Это означает, что директивы шаблона должны использоваться для префикса имен ресурсов, когда один ресурс в чарте должен ссылаться на другой или на ресурсы в того же родительского чарта.
Распространенный случай, когда необходимо сослаться на совместно развернутый ресурс, — это секрет базы данных. Например, чарт Xray включает в себя возможность развертывания базы данных Postgres. Он настраивает развертывание своего компонента индексатора с учетными данными, указывая на секрет Postgres (который сам является частью чарта в виде подчарта и, следовательно, также имеет префикс с тем же именем выпуска):
Здесь чарт Xray знает, к какой базе данных ей необходимо подключиться, поскольку она сама включает чарт Postgres. Но что, если бы мы разрабатывали чарт для приложения, в котором пользователь может выбрать базу данных? Затем может потребоваться разрешить пользователю включать наш чарт в родительский чарт вместе с выбранной им базой данных. Как бы мы тогда разрешили пользователю устанавливать конфигурацию базы данных?
Или для загрузки в Secret нам нужно закодировать контент в base64:
3. Расширение возможностей наших коллег-разработчиков чартов
Затем пользователь может указать свой секрет (который содержит файл JSON) и смонтировать его через values.yaml:
Этот шаблон может быть особенно эффективным в сочетании с открытием Keycloak других параметров, таких как переменная preStartScript, которая используется в сценарии инициализации чарты:
4. Различное внешнее экспонирование
Это соответствует рекомендациям по обзору официального репозитория чартов, которые рекомендуют отключать вход по умолчанию.
Например, чарт RabbitMQ должна предоставить возможность раскрывать ли ее, задав правило входа на основе хоста (host-based):
(На самом деле, пользователь может захотеть, чтобы несколько хостов направлялись к службе, поэтому в рекомендациях по обзору предлагается использовать функцию диапазона для хостов. Чарт RabbitMQ предлагает только один хост.)
Чарт RabbitMQ также позволяет не устанавливать хост (условие else выше). В этом случае вполне вероятно, что пользователь вместо этого переопределит путь (так, чтобы RabbitMQ был доступен на уникальном маршруте, отличном от других открытых сервисов):
Также особенно важно, чтобы у пользователя была возможность настраивать аннотации для входящего ресурса, поскольку они используются для управления параметрами конфигурации маршрутизации.
В руководстве по обзору предлагается поддержать это с помощью toYaml:
Таким образом, пользователь может установить любые необходимые ему аннотации на входе через значения.yaml без чарты, требующей знать, что это могут быть за аннотации. Просто выставление этих аннотаций может быть равносильно тому, чтобы дать возможность применить конфигурацию, подобную сценарию, к входящей маршрутизации. Например, при входе NGINX пользователь может применять правила для установки заголовков пользовательскими способами с помощью фрагментов конфигурации:
Что мы узнали об Art of the Helm Chart
Хороший Helm Chart должен предвидеть, какой уровень гибкости необходим ее пользователям. Большая гибкость обычно означает либо большую сложность, либо большую абстрактность, либо и то и другое. Это может затруднить читаемость чартов и увеличить нагрузку на пользователей чартов. Задача состоит в том, чтобы выбрать инструменты, которые лучше всего соответствуют тому, что нужно пользователям для этой конкретной чарты.
Есть и другие проблемы, которые мы не затронули, такие как тестирование и безопасность. Это был просто взгляд на определенный фрагмент официальных чартов. Я попытался сосредоточиться на паттернах, которые кажутся мне особенно полезными для того, чтобы пользователи могли делать то, что им нужно, с вашими чартами. Официальные чарты Kubernetes были чрезвычайно полезны для меня в работе над чартми Helm для проекта Activity. Надеюсь, объяснение в этом посте поможет побудить других погрузиться в официальное репо и черпать вдохновение из его чартов.
Основы работы с Helm чартами и темплейтами — Часть 1
В этом руководстве мы кратко обсудим, как Helm может помочь упростить управление приложениями Kubernetes, и узнаем, как использовать Helm для создания базового чарта.
Управление приложениями — сложный аспект Kubernetes. Helm значительно упрощает его, предоставляя единый метод упаковки программного обеспечения, поддерживающий контроль версий. Helm устанавливает пакеты (называются Чартами в Helm) для Kubernetes и управляет ими, как это делают yum и apt.
В этом руководстве мы позволим Helm создать для нас базовый чарт. В этом руководстве предполагается, что у вас есть хотя бы базовое понимание того, что такое Helm. Если вы не знакомы с ним, я предлагаю вам ознакомиться с этим руководством, прежде чем приступить к статье: https://www.alibabacloud.com/help/doc-detail/86511.htm
Затем мы будем постепенно вносить изменения, чтобы узнать, как файл значений и части шаблона работают вместе.
С таким базовым рабочим чартом легче работать, чем начинать с нуля.
Чарт — это пакет Helm. Он содержит все определения ресурсов, необходимые для запуска приложения, инструмента или службы внутри кластера Kubernetes.
Думайте об этом как о Kubernetes-эквиваленте формулы Homebrew, Apt dpkg или Yum RPM-файле.
Создание полной структуры каталогов рабочего чарта
Это создает полный рабочий чарт со всеми необходимыми файлами в каталоге myhelm.
Вам будут представлены некоторые из этих файлов на протяжении всего этого руководства — только тогда, когда нам нужно узнать об этих конкретных файлах.
Цель — как можно скорее использовать чарт для создания работающего экземпляра. Затем мы исследуем, что создал чарт и как он это сделал.
Измените values.yaml вверху, чтобы использовать busybox, как показано ниже. Обратите внимание на изменения тегов.
Это развертывание (deployment), как и любое другое, которое вы используете в Kubernetes. Основное отличие состоит в том, что большинство значений полей он получает из только что отредактированного файла значений.
Отредактируйте файл deployment.yaml около строки 27 — добавьте команду. Мы используем образ busybox. Если мы создадим наши поды, они сразу же выйдут, так как ни одна команда или программа не запущены. Команда позволила нашему поду busybox спать 60 секунд.
Теперь мы готовы позволить Helm установить наш отредактированный чарт.
Helm автоматически генерирует название выпуска для вашего: NAME: loopy-otter
Ваш будет другим. Ненавижу эти глупые имена. Позже мы будем использовать наши собственные имена.
Мы видим сервис, развертывание и создание пода.
Эти примечания взяты из NOTES.txt, другого файла шаблона.
Через несколько секунд мы увидим, что наш Pod работает.
Релиз — это экземпляр чарта, работающей в кластере Kubernetes.
helmignore NOTES.txt
.helmignore содержит список имен файлов и шаблонов имен файлов, которые Helm должен игнорировать.
Если вы снова запустите установку, вы увидите, что эти примечания больше не отображаются.
(Позже мы будем использовать такие заметки, но здесь и сейчас этот файл нам не нужен.)
Удалите наш тестовый релиз test1.
Таким образом мы не засоряем наш узел Kubernetes несколькими ненужными объектами.
Как видите, релиз может существовать только один раз.
Проверим статус release
Мы просто удалили его.
Для тестирования отладки ( debug ) нам понадобится другое название релиза: мы используем test2:
Очень полезно, но слишком много информации, если мы хотим постоянно редактировать и устанавливать наш чарт.
Прямо сейчас я не буду пытаться все это разобрать, давайте сначала уменьшим вывод.
Под Хуками есть тестовое соединение. Это было полезно для тестирования исходного nginx. Нам это не нужно.
Нашему поду busybox не нужны порты или livenessProbes.
Удалите строки с 29 по 42 из deployment.yaml
Давайте запустим снова нашу установку.
Давайте разберемся данных командах:
Мы довольны результатами отладки, давайте запустим установку.
Как и ожидалось — происходит развертывание и его Pod. Через несколько секунд Pod запускается.
imagePullPolicy = Never
Значения в values.yaml заменяют свои заполнители (placeholders) в файлах шаблонов.
В этой части руководства демонстрируется передача imagePullPolicy в командной строке.
Редактирование не требуется, просто обратите внимание на последнюю строку извлечения файла значений ниже.
Файл значений по умолчанию должен называться values.yaml.
Теперь посмотрите, где он используется в шаблоне. (в диапазоне 22-25)
.Values.image.pullPolicy получает значение из
Предположим, что для этого тестового прогона мы НЕ хотим, чтобы образ было извлечен из репозитория. ( imagePullPolicy: Never )
Из документации Kubernetes:
imagePullPolicy: Never: предполагается, что образ существует локально. Попытки вытащить образ не предпринимаются.
USER-SUPPLIED VALUES кажутся правильными: imagePullPolicy: Never
COMPUTED VALUES: указывают на наличие проблемы:
Они имеют разные имена и находятся на разных уровнях yaml.
В развертывании мы видим: imagePullPolicy: IfNotPresent : переопределение не выполнено.
Давайте исправим это: смотрите на вторую попытку:
Почти готово, но все равно неверно. Теперь у нас есть две политики, написанные по-разному. (Первая буква в нижнем регистре — это правильная буква, которая появляется в файле значений).
Соглашение гласит, что мы должны называть наши значения, начиная со строчной буквы. Наши values.yaml верны. Наше переопределение командной строки неверно.
Третья попытка, смотрите команду ниже.
В приведенном выше развертывании показано, как imagePullPolicy: Never … прошло успешно.
COMPUTED VALUES показывают, что переопределение выполнено правильно.
Вывод отладки выглядит хорошо. Мы готовы установить этот выпуск вживую.
Я хочу скрыть все остальные значения, которые нам не нужны. Отредактируйте файл значений так, чтобы только первые 5 значений не закомментировались.
Установим наш чарт
Values.ingress.enabled используется в myhelm1/templates/ingress.yaml
Нам не нужен ingress — это часть чарта nginx, с которого мы начали.
Добавьте ingress.yaml в конец нашего файла игнорирования.
—set replicaCount правильно переопределяет значение в deployment.yaml
Сделаем живую установку.
Успешно. ЖЕЛАТЕЛЬНОЕ развертывание — 3, и мы видим, что создаются 3 модуля.
Демо завершено. Удалите наш релиз test3.
Определение нового value
Мы также передали значения переопределения в командной строке.
Теперь мы создаем собственное новое значение: terminationGracePeriodSeconds
terminationGracePeriodSeconds — Необязательная продолжительность в секундах, необходимая для корректного завершения работы модуля. grace period — это продолжительность в секундах после того, как процессы, запущенные в модуле, отправляют сигнал завершения, и время, когда процессы принудительно останавливаются с сигналом уничтожения. Установите это значение больше, чем ожидаемое время очистки для вашего процесса. По умолчанию 30 секунд.
Отредактируйте файл развертывания, чтобы он использовал это новое значение (строки с 22 по 29 должны быть такими, как показано ниже)
Сделайте пробный запуск.
Успешно. COMPUTED VALUES: показывает их правильно и развертывание внизу использует их правильно.
Еще один тест: давайте отладим тест, переопределив значение terminationGracePeriodSeconds на 10.
Успешно. COMPUTED VALUES: правильно показывает 10 и при развертывании внизу правильно используется 10.
Мы даже не посмотрели на _helpers.tpl или каталог чартов. (Это касается зависимостей. Это тема для другого руководства из этого набора.)
Мы внесли несколько изменений в наш файл значений, а также в файл развертывания и увидели его результаты с помощью отладки и команд живой установки.
На работе вы создадите свои собственные скелетные базовые чарты, из которых будете копировать.
Практическое знакомство с пакетным менеджером для Kubernetes — Helm
Статья является логическим продолжение нашей недавней публикации об истории пакетного менеджера для Kubernetes — Helm. В этот раз мы снова затронем вопросы устройства и функционирования нынешнего Helm (версия 2.x), а также управляемых им чартов и репозиториев, после чего перейдём к практике: установке Helm в кластер Kubernetes и использованию чартов.
Вступление
Helm — инструмент для управления чартами.
Чарт описывает необходимый набор данных для создания экземпляра приложения в кластере Kubernetes. Он может иметь вложенные чарты и использоваться как для описания полноценных сервисов, состоящих из множества зависимых ресурсов, так и для описания отдельных независимых составляющих. К примеру, чарт stable/gitlab-ce описывает комплексное решение с использованием независимых чартов redis и postgresql.
Чарт может быть установлен неограниченное количество раз в одном и том же кластере. Таким образом, описание логики выката приложения в разные окружения может и должно храниться в одном чарте.
Клиентская часть Helm отвечает за формирование чарта и передачу вместе с пользовательскими параметрами находящемуся в кластере Kubernetes компоненту Tiller. В свою очередь, Tiller отвечает за жизненный цикл экземпляра запущенного чарта, релиза. (На всякий случай напомню, что в следующем крупном обновлении Helm — версии 3 — уже не будет Tiller.)
А теперь — обо всём по порядку.
Установка и обновление
Для работы с Helm требуется Kubernetes. Можно использовать локально установленный Minikube (см. также «Начало работы в Kubernetes с помощью Minikube») или любой другой доступный кластер.
Начнём с установки клиента: выбираем релиз, скачиваем и распаковываем архив для своей системы, переносим исполняемый файл…
Теперь Tiller установлен в кластер и готов к управлению релизами, взаимодействию с Kubernetes API.
Репозитории чартов
По умолчанию Helm использует официальный репозиторий чартов Kubernetes. Он содержит тщательно проработанные актуальные чарты для решения множества прикладных задач. Этот репозиторий именуется stable:
При необходимости создание собственного репозитория не составит никаких проблем. Требования к серверу — минимальные, поэтому, как и большинство публичных репозиториев чартов, его можно разместить на GitHub Pages. Подробнее про инструменты и необходимые для этого шаги можно почитать в документации.
При использовании репозиториев чартов они могут быть добавлены и удалены. Для того, чтобы версии чартов были актуальными, необходимо периодически обновлять индекс. Приведу пример для публичного репозитория bitnami, большая часть чартов которого используется в официальном репозитории Helm:
Далее — поиск по репозиториям. Вызов helm search без аргументов показывает все доступные чарты:
В необязательном поле keywords в Chart.yaml разработчики указывают теги, которые используются для упрощения поиска в репозиториях чартов:
Примечание: При использовании команды helm search можно столкнуться с нестабильной работой нескольких фильтров: наличие результата зависит от порядка указания и количества фильтров.
В официальном репозитории чарты прекрасно документированы и содержат примеры использования, а некоторые чарты — даже готовые конфигурации для production. К примеру, хороший readme представлен у stable/wordpress (для его вывода в консоли см. helm inspect readme stable/wordpress ).
Поиск — это хороший способ найти доступные пакеты. После того, как пакет найден, можно использовать его для установки приложения в кластер.
Первое приложение
Для примера выбран уже упомянутый чарт stable/wordpress.
Установим чарт с конфигурацией для production, поменяем название блога, отключим сохранение данных WordPress в PersistentVolumeClaim (подробнее про постоянные хранилища см. в документации Kubernetes):
В случае работы с полноценным кластером далее можно следовать рекомендациям из блока NOTES выше. Если же у вас Minikube — откройте сайт в браузере следующим образом:
Поздравляю, приложение в кластере!
Развёрнутый чарт с WordPress появился в списке всех релизов Helm:
Следующим шагом обновим наш релиз и изменим образ с блогом. Для примера будет использован другой тег из того же Docker-репозитория ( 4.9.8-ol-7 ):
Обратите внимание, что при обновлении Tiller сравнивает полученный чарт с параметрами с последним сохранённым и выполняет соответствующие запросы в Kubernetes API, а актуальное состояние ресурсов релиза не берётся в расчёт. Важно понимать эту особенность и не совершать ошибок:
Состояние компонентов релиза приложения в кластере всегда можно проверить следующим образом:
Helm позволяет откатываться до определённой ревизии релиза. На текущий момент ревизий две:
Откатим приложения к первоначальному состоянию:
Теперь история ревизий пополнилась на одну запись:
Статья подходит к концу и релиз больше не требуется?
А удалён ли он в действительности.
Команда удаляет Kubernetes-ресурсы, связанные с релизом, но не сам релиз. Вся информация о релизе остаётся доступной, в том числе и его история:
Примечание: По задумке, удалённый релиз можно откатывать к предыдущим версиям, но в последних версиях эта возможность не работает — подробности см. в issue #3722.
Резюмируя
В этой статье рассказано про базовую архитектуру Helm 2, его компоненты и их функций, а также об основных примитивах, чартах, релизах и репозиториях чартов. Мы установили Helm в кластер Kubernetes и получили понимание жизненного цикла релиза и основных команд для работы с ним.
Следующий материал из этого цикла будет посвящён теме создания собственного чарта — в нём я расскажу про структуру чарта, шаблонизацию и инструменты отладки. ОБНОВЛЕНО: Новая статья доступна по этой ссылке.