У traefik только 1 точка входа, это 80 порт. На порту 8080 будет доступна панель в которой визуально отображается какие сервисы доступны. Для поднимаемых нами сервисов указаны следующие доменные имена: nginx.test.ru и nginx2.test.ru,они используют созданную ранее docker сеть traefik и как мы видим, отвечают по одному 80 порту. Для того чтобы работал сервис работал ему прописывается пункт label где задаются параметры для traefik. Ниже показан ответ curl по нашим сервисам:
EXPOSE сообщает контейнеру, какие порты следует использовать для внутренней сети Docker. Другие контейнеры могут использовать эту информацию для подключения к нему. т.е. вы открываете порты, не публикуя их на хост-машине — они будут доступны только для связанных служб
================
если необходимо подключить ssl сертификат то необходимо создать дополнительный файл traefik.toml
Traefik – это обратный прокси с поддержкой Docker, который предоставляет встроенную панель мониторинга.
Проект Traefik предоставляет официальный образ Docker, который поможет быстро запустить Traefik в контейнере Docker.
Но прежде чем запустить контейнер Traefik, нужно создать конфигурационный файл и настроить зашифрованный пароль, чтобы получить доступ к панели мониторинга. данные действия мы выполнили в предыдущей статье. Панель инструментов представляет собой отдельное веб-приложение, которое будет работать в контейнере Traefik по порту 8080.
1: Настройка и запуск Traefik
Используйте утилиту htpasswd, чтобы создать зашифрованный пароль. Установите утилиту, которая входит в пакет httpd-tools.
yum install -y httpd-tools
Затем сгенерируйте пароль с помощью htpasswd. Замените secure_password паролем, который вы хотите использовать для пользователя администратора Traefik:
Этот вывод используется в конфигурационном файле Traefic для настройки базовой аутентификации HTTP в панели мониторинга Traefik. Скопируйте всю строку, чтобы затем вставить ее в файл.
Чтобы настроить сервер Traefik, создайте файл traefik.toml в формате TOML. TOML – это стандартизированный язык конфигурации (аналогичный INI-файлам). Этот файл позволяет настроить сервер Traefik и дополнительные провайдеры. В этом мануале используются три доступных провайдера Traefik: api, docker и acme, который нужен для поддержки TLS сертификатов Let’s Encrypt.
Откройте файл:
vi traefik.toml
Перейдите в режим вставки, нажав i, а затем добавьте две именованные точки входа, http и https, доступ к которым будет у всех бэкендов по умолчанию.
defaultEntryPoints = ["http", "https"]
Точки http и https будут настроены немного позже.
Настройте провайдер api, который дает доступ к интерфейсу панели мониторинга. Здесь нужно использовать строку, сгенерированную командой htpasswd:
Панель инструментов представляет собой отдельное веб-приложение, которое будет работать в контейнере Traefik по порту 8080.
Раздел entrypoints.dashboard настраивает подключение с провайдером api.
Раздел entrypoints.dashboard.auth.basic настраивает базовую аутентификацию HTTP для дашборда.
Вставьте вместо your_encrypted_password строку, сгенерированную утилитой htpasswd. Вы можете указать несколько пар учетных данных, разделив их запятыми.
Итак, мы определили первую точку входа, entryPoint, но для стандартного взаимодействия HTTP и HTTPS нужны другие точки.
Раздел entryPoints настраивает адрес, который будут слушать Traefik и контейнеры. Добавьте в файл строки:
Точка входа http обрабатывает порт 80, а точка входа https использует порт 443 для поддержки TLS/SSL. Весь трафик, поступающий по порту 80, будет автоматически перенаправлен в точку входа https, чтобы все запросы обслуживались только по защищенным соединениям.
Затем добавьте следующий раздел, чтобы настроить сертификат Let’s Encrypt для Traefik.
Этот раздел называется acme, потому что ACME – это протокол, с помощью которого сервер взаимодействует с Let’s Encrypt для управления сертификатами. Чтобы Traefik создавал сертификаты для хостов, укажите в строке email свой адрес электронной почты. Затем нужно указать, что хранить информацию Let’s Encrypt нужно в файле JSON, acme.json. В строке entryPoint должен быть порт обработки точки входа 443 (в данном случае это точка входа https).
Ключ onHostRule определяет, как Traefik будет генерировать сертификаты. Сертификаты должны появиться сразу, как только будут созданы контейнеры с указанными именами хостов; за это отвечает параметр onHostRule.
В разделе acme.httpChallenge нужно указать, как Let’s Encrypt будет определять, что сертификат должен быть сгенерирован. Мы настроим его для обслуживания файла в рамках задачи через точку входа http.
Провайдер Docker включает Traefik в качестве прокси-сервера для контейнеров Docker. Провайдер будет следить (строка watch) за новыми контейнерами в сети, которые мы скоро создадим, и выставлять их как субдомены your_domain.
На этом этапе файл traefik.toml должен выглядеть так:
Создайте сеть Docker для поддержки взаимодействия прокси-сервера и контейнеров. Сеть Docker необходима, так как ее можно использовать для работы с приложениями, запущенными в Docker Compose. Для примера можно назвать такую сеть web.
docker network create web
Когда контейнер Traefik будет запущен, нужно будет добавить его в эту сеть. Позже можно добавить в эту сеть дополнительные контейнеры, чтобы использовать Traefik в качестве прокси-сервера для этих контейнеров.
Затем создайте пустой файл, в котором будет храниться информация о шифровании Let’s Encrypt. Добавьте его в контейнер, чтобы Traefik мог его использовать.
touch acme.json
Затем заблокируйте доступ к файлу, чтобы только пользователь root мог читать и изменять его. Если вы этого не сделаете, Traefik не получится запустить.
chmod 600 acme.json
Когда файл будет передан Docker, права собственности автоматически перейдут пользователю root внутри контейнера.
Флаг –d запускает контейнер в фоновом режиме как демон. Затем команда добавляет в контейнер файл docker.sock, благодаря чему процесс Traefik может прослушивать изменения в контейнерах. Также в контейнер можно поместить конфигурационный файл traefik.toml и acme.json.
После этого порты 80 и 443 хоста Docker подключаются к одному и тому же порту в контейнере Traefik. Теперь Traefik получает все запросы HTTP и HTTPS.
Затем нужно установить две метки Docker, которые будут направлять трафик на хост monitor.your_domain по порту :8080 внутри контейнера Traefik, открывая дашборд.
В качестве сети контейнера нужно указать web. Контейнер называется traefik.
Затем для создания контейнера используется образ traefik:1.7.6-alpine.
ENTRYPOINT образа Docker – это команда, которая запускается всегда, когда контейнер создается из образа. В этом случае команда представляет собой бинарный файл traefik внутри контейнера. Вы можете передать дополнительные аргументы этой команде при запуске контейнера, но все необходимые данные мы уже указали в файле traefik.toml.
После запуска контейнера у вас будет дашборд, с помощью которого можно просмотреть состояние контейнеров. Вы также можете использовать эту панель для визуализации интерфейсов и бэкэндов, которые зарегистрировал Traefik. Откройте панель мониторинга в браузере:
https://monitor.your_domain
Будет предложено ввести имя пользователя и пароль администратора, и пароль (имя – admin, пароль – строка, которую вы сгенерировали в разделе 1).
После аутентификации на экране появится дашборд.
Пока что в панели еще не так много информации. Оставьте это окно открытым, и вы увидите, что содержимое дашборда изменится, когда вы добавите контейнеры для Traefik.
Теперь у вас есть прокси-сервер Traefik, настроенный для взаимодействия с Docker и готовый управлять другими контейнерами Docker.
3: Добавление контейнеров для Traefik
Контейнер Traefik запущен и готов обслуживать другие контейнеры приложений. Добавьте следующие контейнеры:
Версия 3 Docker Compose – это новейшая версия формата файла Compose.
Чтобы сервер Traefik мог опознать приложения, они должны входить в одну сеть. Поскольку используемая сеть создана вручную, нужно указать ее имя (web ) и установить в external значение true. Затем нужно определить другую сеть, чтобы связать контейнеры с контейнером базы данных, который не будет обслуживаться контейнером Traefik. Эта внутренняя сеть будет называться internal.
Затем нужно определить все сервисы по очереди. Начать можно с контейнера blog, который основан на официальном образе WordPress. Добавьте в файл эту конфигурацию:
Параметр environment позволяет указать переменные среды, которые будут установлены внутри контейнера. Если значение WORDPRESS_DB_PASSWORD не установлено, Docker Compose будет извлекать его из оболочки и передавать при создании контейнера. Определить эту переменную среды можно в оболочке перед запуском контейнеров. Таким образом пароли не попадут в конфигурационный файл.
В разделе labels указываются параметры Traefik. Метки Docker сами по себе ничего не делают, но Traefik читает их и понимает, как обращаться с контейнерами. Каждая метка выполняет такие действия:
traefik.backend определяет имя сервиса бэкенда (который указывает на контейнер blog).
traefik.frontend.rule=Host:blog.your_domain исследует запрашиваемый хост и, если он совпадает с шаблоном blog.your_domain, перенаправляет трафик в контейнер blog.
traefik.docker.network=web определяет сеть, в которой Traefik может найти внутренний IP-адрес контейнера. Поскольку Traefik имеет доступ ко всей информации Docker, он может случайно выбрать IP сети internal, если сеть не указана явно.
traefik.port указывает порт, который Traefik должен использовать для маршрутизации трафика в контейнеры.
При такой конфигурации весь трафик, отправленный на порт 80 хоста Docker, будет перенаправлен в контейнер blog.
Этот контейнер принадлежит двум различным сетям, чтобы Traefik мог найти его через сеть web и связываться с контейнером базы данных через сеть internal.
Параметр depends_on помогает Docker Compose понять, что этот контейнер нужно запускать после запуска его зависимостей. Поскольку для работы WordPress необходима запущенная БД, контейнер mysql запускается раньше, чем контейнер blog.
Для создания этого контейнера используется официальный образ MySQL 5.7. Обратите внимание: параметр environment снова не имеет значения. Для переменных MYSQL_ROOT_PASSWORD и WORDPRESS_DB_PASSWORD необходимо установить одинаковое значение, чтобы контейнер WordPress мог связываться с MySQL. Контейнер mysql не должен взаимодействовать с Traefik или с внешним миром, потому он принадлежит только сети internal. Поскольку Traefik имеет доступ к сокету Docker, процесс по-прежнему будет открывать фронтенд контейнера mysql по умолчанию. Поэтому нужно добавить метку traefik.enable = false, чтобы Traefik не смог сделать этот контейнер доступным.
Теперь нужно добавить параметры контейнера Adminer:
Этот контейнер основан на официальном образе Adminer. Параметры network и depends_on совпадают с этими же параметрами контейнера blog.
Однако поскольку весь трафик порта 80 хоста Docker направляется непосредственно в контейнер blog, нужно настроить контейнер adminer немного иначе, чтобы он получал свой трафик.
Благодаря строке traefik.frontend.rule=Host:db-admin.your_domain сервер Traefik будет проверять запрашиваемый хост. Если он соответствует шаблону db-admin.your_domain, Traefik направит трафик в контейнер adminer.
Вместо secure_database_password укажите надежный пароль БД. В WORDPRESS_DB_PASSWORD и MYSQL_ROOT_PASSWORD нужно использовать один и тот же пароль.
Теперь запустите контейнеры:
docker-compose up -d
Снова откройте панель Traefik. Вы увидите, что в ней появились новые контейнеры, а также backend и frontend.
Откройте в браузере blog.your_domain (где your_domain – ваш домен). Соединение будет перенаправлено на зашифрованный порт 443. Теперь можно закончить установку WordPress.
После этого откройте в браузере db-admin.your_domain. Контейнер mysql не доступен в интернете, но контейнер adminer имеет доступ к нему через внутреннюю сеть Docker (internal).
На экране появится форма входа Adminer. Используйте имя пользователя root, укажите mysql в поле server, в поле пароля введите значение переменной MYSQL_ROOT_PASSWORD. После этого вы получите доступ к интерфейсу Adminer.
Оба сайта теперь работают. Чтобы получить доступ к дашборду, введите monitor.your_domain.
Заключение
Теперь сервер Traefik проксирует запросы в контейнеры приложений Docker.
Traefik позволяет легко настраивать большое количество сервисов и устраняет необходимость перезапускать контейнер traefik при добавлении новых приложений в контейнер traefik. Traefik незамедлительно получает все сведения об изменениях через файл сокета Docker.
Harbor – это облачный реестр с открытым исходным кодом, который хранит, подписывает и сканирует образы контейнеров на наличие уязвимостей.
Это руководство покажет вам как установить Harbor Image Registry в Kubernetes / OpenShift с помощью чарта Helm.
Вот некоторые из интересных особенностей реестра образов Harbour:
Особенности Harbour
Поддержка Multi-tenant
Поддержка анализа безопасности и уязвимостей
Расширяемый API и веб-интерфейс
Подписание и проверка контента
Репликация образов в нескольких экземплярах Harbour
Интеграция и контроль доступа на основе ролей
Helm – это инструмент интерфейса командной строки (CLI), созданный для упрощения развертывания приложений и сервисов в кластерах Kubernetes / OpenShift
Helm использует формат упаковки, называемый чартами.
Чарт Helm – это набор файлов, описывающих ресурсы Kubernetes.
Шаг 1: Установка Helm 3 на Linux / macOS
Helm имеет бинарник, что означает, что для его установки на вашем компьютере Linux / macOS не требуется никаких зависимостей:
Шаг 2: Установите чарт Harbor в Kubernetes / OpenShift кластере
Чарт – это пакет Helm.
Он содержит все определения ресурсов, необходимые для запуска приложения, инструмента или службы внутри кластера Kubernetes.
Добавьте репозиторий Harbour Helm:
$ helm repo add harbor https://helm.goharbor.io
"harbor" has been added to your repositories
Обновите репозиторий:
$ helm repo update
Настройка чарта
Элементы конфигурации могут быть установлены с помощью флага –set во время установки или настроены путем непосредственного редактирования values.yaml.
Вы можете скачать файл values.yaml по умолчанию.
wget https://raw.githubusercontent.com/goharbor/harbor-helm/master/values.yaml
vim values.yaml
Установите чарт Harbor с пользовательскими настройками после внесения изменений.
$ helm install harbor harbor/harbor -f values.yaml -n harbor
NAME: harbor
LAST DEPLOYED: Wed Apr 1 19:20:07 2020
NAMESPACE: harbor
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://hbr.apps.hqocp.safaricom.net.
For more details, please visit https://github.com/goharbor/harbor.
Проверьте статус, чтобы подтвердить его развертывание:
$ helm status harbor
Исправление инициализации:CrashLoopBackOff в поде harbor-harbor-database на OpenShift
Некоторые образы контейнеров, такие как postgres и redis, требуют рутового доступа и имеют определенные ожидания относительно владения томами.
Нам нужно ослабить безопасность в кластере, чтобы образы не запускались как предварительно выделенный UID, не предоставляя всем доступ к привилегированному SCC:
Предоставьте всем аутентифицированным пользователям доступ к anyuid SCC:
Используйте внешний домен, настроенный во время установки, для доступа к панели мониторинга реестра контейнера Harbour.
Креды по умолчанию:
Username: admin Password: Harbor12345
использовать Harbor для сканирования образов Docker на наличие уязвимостей
Harbor – это локальный реестр Docker, который, будучи собранным с поддержкой Clair, позволяет сканировать спушенные образы на наличие известных уязвимостей.
Это должно считаться обязательным в компаниях, которые полагаются на контейнеры.
Но как использовать Harbour для сканирования этих образов?
Давайте посмотрим.
Что вам нужно
Самое главное, вам понадобится это Harbor (с поддержкой Clair).
Вам также понадобятся образа для отправки на сервер Harbor и учетную запись пользователя на сервере Harbour.
Сертификаты
Если вы планируете передавать образы с компьютеров в вашей сети (которые не являются вашим сервером Harbour), вам необходимо скопировать сертификаты с сервера Harbour на клиенты.
Если вы следовали инструкциям по установке Harbor, возможно, вы используете самозаверенные сертификаты.
Я собираюсь предположить, что это так.
И так … вот как скопировать эти сертификаты с сервера на клиент:
подключитесь по ssh (или войдите в консоль) к серверу Harbor.
Получите root-доступ с помощью команды sudo -s.
Перейдите в каталог сертификатов с помощью команды cd /etc/docker/certs.d/SERVER_IP (где SERVER_IP – это IP-адрес вашего сервера).
Скопируйте ключ ca.cert на клиент с помощью команды scp ca.cert USER @ CLIENT_IP: / home / USER (где USER – имя пользователя на клиентском компьютере, а CLIENT_IP – IP-адрес клиентского компьютера).
Скопируйте ключ ca.crt на клиент с помощью команды scp ca.crt USER @ CLIENT_IP: / home / USER (где USER – это имя пользователя на клиентском компьютере, а CLIENT_IP – это IP-адрес клиентского компьютера).
Скопируйте клиентский ключ ca.key с помощью команды scp ca.key USER @ CLIENT_IP: / home / USER (где USER – это имя пользователя на клиентском компьютере, а CLIENT_IP – это IP-адрес клиентского компьютера).
SSH к клиентскому компьютеру с помощью команды ssh USER @ CLIENT_IP (где USER – имя пользователя на клиентском компьютере, а CLIENT_IP – IP-адрес клиентского компьютера).
Создайте новый каталог сертификатов с помощью команды sudo mkdir -p /etc/docker/certs.d/SERVER_IP (где SERVER_IP – это IP-адрес сервера Harbour).
Скопируйте файлы с помощью команды sudo cp ca. * /etc/docker/certs.d/SERVER_IP (где SERVER_IP – IP-адрес сервера Harbor).
Теперь ваш клиент должен иметь возможность войти в репозиторий Harbor и отправлять образы.
Пометка образов ( теги )
Прежде чем отправить образ с клиента на сервер, сначала необходимо пометить его.
Допустим, у вас есть официальный образ Ubuntu, и вы хотите пометить его конкретным именем разработчика.
Чтобы пометить его так, чтобы его можно было перенести в реестр Harbor, команда tag будет выглядеть так:
docker tag ubuntu SERVER_IP/PROJECT_NAME/ubuntu:DEVNAME
Где:
SERVER_IP – это IP-адрес сервера Harbour.
PROJECT_NAME – это имя проекта на сервере Harbour.
DEVNAME: имя разработчика, которого вы хотите пометить.
Таким образом, команда может выглядеть так:
docker tag ubuntu 192.168.1.75/test/ubuntu:jack
Пушинг образа
Сначала вы должны войти в реестр на сервере Harbor.
Для этого выполните команду:
docker login SERVER_IP
Где SERVER_IP – это IP-адрес сервера Harbor.
Вам будет предложено ввести имя пользователя и пароль пользователя на сервере Harbour.
После входа в систему вы можете спушить образ с помощью команды:
docker push 192.168.1.75/test/ubuntu:jack
После завершения вы готовы отсканировать образ на наличие уязвимостей.
Сканирование образа
Войдите в свой реестр Harbor и перейдите к проекту, в котором размещен недавно подтянутый образ
Вы должны увидеть образ в списке:
Created with GIMP
Щелкните на новый образ и в появившемся окне установите флажок, связанный с тегом образа.
После выбора нажмите кнопку SCAN, чтобы начать сканирование.
Created with GIMP
Когда сканирование завершится, вы увидите полосу, представляющую результаты сканирования.
Наведите курсор на эту полосу, чтобы просмотреть отчет:
Created with GIMP
Если вы нажмете на имя тега, вы увидите полный отчет, в котором представлены полные результаты, включая CVE для каждой уязвимости:
Created with GIMP
Прокрутите весь отчет, чтобы просмотреть все уязвимости.
Если вы обнаружите, что образ содержит слишком много общих уязвимостей или достаточно средних или высоких уязвимостей, я предлагаю не использовать его.
Для загрузки исходников нам понадобиться загрузить некоторые файлы. Для этого в системе должны быть установлены соответствующие пакеты. В зависимости от типа системы процесс установки будет незначительно отличаться.
а) на системах Red Hat:
yum install git wget
б) для систем на основе Debian:
apt-get install git wget
Установка Go
Для компиляции исходника, нам необходимо установить Golang. Для этого переходим на страницу загрузки и копируем ссылку на архив с его последней версией:
* по умолчанию, страница предлагает загрузить Go для нашей операционной системы, поэтому, если мы открыли сайт на компьютере Windows, ниже под кнопкой загрузки выбираем Linux.
Воспользовавшись ссылкой, скачиваем архив на наш сервер:
* на момент написания инструкции, последняя версия была 1.15.6.
Распаковываем архив в каталог /usr/local:
tar -v -C /usr/local -xzf go*.tar.gz
Открываем файл:
vi /etc/profile
Добавляем в самый низ строку:
export PATH=$PATH:/usr/local/go/bin
Один раз выполняем данную команду:
export PATH=$PATH:/usr/local/go/bin
Проверяем, что go установлен и готов выполнять команды:
go version
Мы должны увидеть версию скачанного пакета.
Настройка безопасности
1. Брандмауэр
В зависимости от используемого брандмауэра, необходимо выполнить следующие настройки.
а) если используем iptables (по умолчанию, в системах на базе Debian):
iptables -I INPUT 1 -p tcp —dport 3100 -j ACCEPT
* данная команда добавит правило на разрешение порта 3100 (на котором, по умолчанию, запускается Grafana Loki).
Для сохранения правил устанавливаем пакет:
apt-get install iptables-persistent
Сохранение правил теперь можно выполнить командой:
netfilter-persistent save
б) если используем firewalld (по умолчанию, в системах на базе Red Hat):
firewall-cmd —permanent —add-port=3100/tcp
firewall-cmd —reload
* данная команда добавит правило на разрешение порта 3100 (на котором, по умолчанию, запускается Grafana Loki).
2. SELinux
Как правило, в системах на базе Red Hat активирована дополнительная система безопасности. В нашей инструкции мы ее отключаем командами:
setenforce 0
sed -i ‘s/^SELINUX=.*/SELINUX=disabled/g’ /etc/selinux/config
* первая команда вводится до разового отключения SELinux. Вторая не дает ему запуститься после перезагрузки.
Установка
Установка Grafana Loki сводится к загрузке готового бинарника или исходника с последующей компиляцией. Также мы настроим юнит в systemd для работы приложения в качестве сервиса.
Копирование бинарника и конфигурационного файла
Переходим в каталог:
cd /usr/src/
Загружаем исходные файлы проекта:
git clone https://github.com/grafana/loki
Переходим в каталог loki:
cd loki/
Запускаем компиляцию бинарника:
go build ./cmd/loki
В текущем каталоге появится файл loki — перенесем его в каталог /usr/local/bin:
mv loki /usr/local/bin/
Создадим каталог:
mkdir /etc/loki
… и перенесем в него конфигурационный файл:
mv cmd/loki/loki-local-config.yaml /etc/loki/
В конфиге, который идет в исходнике в качестве рабочего каталога для Grafana Loki используется /tmp — мы это исправим двумя командами:
sed -i ‘s//tmp/wal//opt/loki/wal/g’ /etc/loki/loki-local-config.yaml
* первой командой мы меняем настройку dir для wal (журнала предзаписи).
sed -i ‘s//tmp/loki//opt/loki/g’ /etc/loki/loki-local-config.yaml
* в данном примере мы заменили путь для storage_config, working_directory и ruler storage на /opt/loki.
Открываем браузер и переходим по адресу http://192.168.0.15:3100/metrics, где 192.168.0.15 — IP-адрес нашего сервера Grafana Loki. Мы должны увидеть страницу с метриками:
Значит наш сервис запустился и нормально работает. Можно прервать его работу на сервере комбинацией клавиш Ctrl + С и продолжать настройку.
Автозапуск
Чтобы сервис мог автоматически запускаться при старте системы, добавим его в systemd.
Для начала, создадим пользователя, под которым будет работать сервис:
useradd —no-create-home —shell /bin/false loki
* данной командой мы создадим пользователя loki. Ему нельзя будет входить в систему в качестве интерактивного пользователя, также для него не будет создана домашняя директория.
Делаем владельцем loki бинарник для запуска сервиса:
Проверить, что он запустился и работает можно командой:
systemctl status loki
Установка серверной части завершена.
Отправка логов на сервер
В нашем примере мы передадим логи веб-сервера NGINX в нашу Grafana Loki. Для этого переходим на сервер с NGINX и выполним следующие действия.
Установка Promtail
Promtail — агент, который читает и отправляет логи на сервер. Его установка во многом напоминает установку сервера — получаем бинарник и добавляем его в автозагрузку. В нашем примере мы загрузим уже скомпилированный файл для запуска.
Для начала, установим следующие пакеты:
yum install unzip wget
* unzip нужен для распаковки архива с бинарником; wget — для скачивания архива.
* в нашем примере загружается бинарник на систему 64-бит. На странице https://github.com/grafana/loki/releases можно скачать файлы для установки под Linux и Windows.
Распаковываем скачанный архив:
unzip promtail-linux-amd64.zip
Переносим бинарник в каталог /usr/local/bin:
mv promtail-linux-amd64 /usr/local/bin/promtail
* обратите внимание, что мы его сразу переименовали в promtail.
Создаем каталог для конфигурационных файлов promtail:
На клиенте в настройки брандмауэра добавляем правило на разрешение порта 9080.
а) если используем iptables (Debian, Ubuntu):
iptables -I INPUT 1 -p tcp —dport 9080 -j ACCEPT
apt-get install iptables-persistent
netfilter-persistent save
б) если используем firewalld (CentOS, Red Hat):
firewall-cmd —permanent —add-port=9080/tcp
firewall-cmd —reload
После установки promtail открываем браузер и переходим на страницу http://192.168.0.25:9080/targets, где 192.168.0.25 — IP-адрес клиентского компьютера с NGINX. Мы должны увидеть страницу:
Promtail работает. Можно приступать к сбору логов.
job — метка для имени задания. Важный параметр для выборки данных.
__path__ — путь до файлов с логами.
Перезапускаем сервис promtail:
systemctl restart promtail
Снова заходим по адресу http://192.168.0.25:9080/targets — мы должны увидеть настроенное нами задание:
Сбор логов настроен.
Настройка Grafana
Переходим к серверу с Grafana. Он может быть установлен на отдельном сервере или на том же сервере с Loki.
Заходим в веб-интерфейс и переходим в Configuration — Data Sources:
Добавляем новый источник, кликая по Add data source:
Среди списка возможных источников выбираем Loki:
В настройках задаем имя и указываем IP-адрес сервера Loki:
* в нашем примере задается имя Loki и подключение к серверу 192.168.0.15.
Нажимаем на Save & Test:
Если мы увидели сообщение «Data source connected and labels found.»:значит подключение выполнено и можно двигаться дальше.
Переходим в раздел Create — Dashboard:
Кликаем по кнопке Add new panel:
В открывшемся окне выбираем в качестве источника данных Loki, затем кликаем по Log labels — выбираем job и nginxlogs:
Мы увидим Unable to graph data (так как логи представляют из себя данные, на основе которых нельзя постоить график) — кликаем по Switch to table view:
Мы должны увидеть строки из логов:
Логи NGINX отображаются в Grafana.
Парсинг лога
Мы увидели логи в графане, но они представленны в неудобном для отбора и фильрации виде. Попробуем это исправить с помощью парсинга логов на стороне promtail.
* обратите внимание, что к имеющейся настройки мы добавили pipeline_stages:
selector — тег для отбора логов, которые нужно парсить.
expression — регулярное выражение для парсинга логов.
labels — список тегов, которые мы будем передавать в loki. Обратите внимание, что названия данных тегов соответствую названиям, которые мы задали в expression.
Перезапускаем сервис для promtail:
systemctl restart promtail
Идем в Grafana — в Log labels мы должны увидеть новые критерии для фильтра по тегам:
Пробуем добавить, например, фильтр по статусу ответа веб-сервера:
Для работы с хостинг-провайдером нам заранее понадобятся авторизационные данные и идентификаторы ресурсов. Их мы будем прописывать в сценариях terraform.
Нам нужно зарегистрироваться на сервисе Yandex.Cloud (в нашем примере, мы будем работать, именно, с ним). После этого, нам нужно получить:
1. OAuth-токен. Используется в процедуре аутентификации для получения IAM-токена и нужен нам для прохождения авторизации при подключении terraform. Выдается на 1 год. Получить можно, отправив запрос со страницы документации Яндекс.
2. Идентификатор облака. После регистрации на хостинге мы заходим в контроль-панель. Мы должны увидеть наши ресурсы, в частности, облако:
А справа от него будет идентификатор.
3. Идентификатор каталога. На той же странице контроль панели, ниже облака мы увидим каталог:
Также, справа мы можем скопировать его идентификатор.
После получения нужных данных просто сохраняем их в отдельный файл. После установки terraform они нам понадобятся.
Установка Terraform
Terraform является клиентом и необходимо выполнить установку на компьютер, с которого планируется управление инфраструктурой. Актуальная инструкция по развертыванию представлена на официальном сайте. На текущий момент клиент может быть установлен из репозитория, с использованием бинарника, собран из исходников, а также с помощью choco на Windows или brew на Mac OS. В нашем примере будут рассмотрены установка на Ubuntu и Rocky Linux из репозитория, а также загрузка бинарника.
Ubuntu (Debian)
Обновляем список пакетов:
apt update
Установим дополнительные пакеты:
apt install gnupg software-properties-common curl
* где:
gnupg — программа для шифровки и дешифровки цифровых подписей. Нужна для работы с репозиториями.
software-properties-common — утилита для работы с репозиториями.
Убедимся, что terraform работает. Для этого вводим команду:
terraform -version
Мы должны получить что-то на подобие:
Terraform v1.1.7 on linux_amd64
Также рекомендуется установить автоподстановки:
terraform -install-autocomplete
Это позволит нам завершать команды terraform с помощью клавиши Tab.
Теперь создадим каталог, в котором будем работать со сценариями для тераформа:
mkdir -p /opt/terraform/yandex
* в моем примере я решил работать в каталоге /opt/terraform/yandex.
Перейдем в созданный каталог:
cd /opt/terraform/yandex
Мы готовы приступить непосредственно к работе с terraform.
Установка провайдера
Чтобы terraform мог корректно взаимодействовать с инфраструктурой провайдера, необходимо использовать набор инструкций, которые будет использовать наша утилита. В терминологии terraform это называется провайдер.
На сайте Hashicorp можно найти все поддерживаемые провайдеры. Как говорилось выше, мы будем работать с Yandex.Cloud. Рассмотрим подробнее установку провайдера для работы с ним.
terraform required_version — версия клиента terraform, для которого должен запускаться сценарий. Параметр не обязательный, но является правилом хорошего тона и может помочь избежать некоторых ошибок, которые возникнут из-за несовместимости при работе в команде.
required_providers version — версия провайдера. Мы можем указать, как в данном примере, необходимость использовать конкретную версию, а можно с помощью знака >= или <= указать не выше или не ниже определенной.
token — OAuth-токен для прохождения авторизации. Был нами получен после регистрации на хостинге
cloud_id — идентификатор для облака, в котором будут создаваться ресурсы. Также получен был нами заранее.
folder_id — идентификатор каталога, который также был получен в начале инструкции.
zone — ресурсы, которые хранятся на мощностях Яндекс разделены по зонам. Каждая зона — это определенная географическая локация центра обработки данных. Список доступных зон можно посмотреть на странице Зоны доступности.
Теперь выполним команду:
terraform init
Система загрузит нужные файлы и установит провайдер:
Initializing the backend...
Initializing provider plugins...
- Finding latest version of yandex-cloud/yandex...
- Installing yandex-cloud/yandex v0.73.0...
- Installed yandex-cloud/yandex v0.73.0 (self-signed, key ID E40F590B50BB8E40)
...
Terraform has been successfully initialized!
...
Мы готовы двигаться дальше.
Работа с ресурсами
Мы рассмотрим небольшие примеры по созданию, редактированию и удалению ресурсов. В большей степени мы будем работать с виртуальными машинами. Большую часть информации по написанию сценариев можно найти на официальном сайте хостинга или самого terraform.
Создание ресурсов
В нашем рабочем каталоге создадим новый файл:
vi infrastructure1.tf
Напишем минимально необходимый сценарий для создания виртуальной машины:
data — позволяет запрашивать данные. В данном примере мы обращаемся к ресурсу yandex_compute_image с целью поиска идентификатора образа, с которого должна загрузиться наша машина.
yandex_compute_image — ресурс образа. Его название определено провайдером.
ubuntu_image — произвольное название ресурса. Его мы определили сами и будем использовать в нашем сценарии.
ubuntu-2004-lts — в нашем примере мы запрашиваем данные ресурса, который ищем по family с названием ubuntu-2004-lts. Данное название можно посмотреть в контроль панели хостинга — нужно выбрать образ и кликнуть по нему. Откроется страница с дополнительной информацией. В данном случае ubuntu-2004-lts соответствуем Ubuntu 20.04 LTS.
resource — позволяет создавать различные ресурсы.
yandex_compute_instance — ресурс виртуальной машины. Его название определено провайдером.
vm-test1 — наше название ресурса для виртуальной машины.
subnet_terraform — наше название для ресурса подсети.
metadata — обратите особое внимание на передачу метеданных. В данном примере мы передаем содержимое файла, а сам файл рассмотрим ниже.
** в нашем примере будет создана виртуальная машина с названием test1, 2 CPU, 2 Gb RAM в сети 192.168.15.0/24 на базе Ubuntu 20.04 LTS. *** обратите внимание, что мы указали идентификатор той подсети для виртуальной машины, которую создали также с помощью нашего сценария terraform.
* в данном файле мы опишем пользователя, под которым мы сможем подключиться к нашему серверу по SSH:
#cloud-config — как выяснилось, этот комментарий обязательный.
name — имя пользователя, который будет создан на виртуальной машине.
groups — в какую группу добавить пользователя.
shell — оболочка shell по умолчанию.
sudo — правило повышения привилений.
ssh-authorized-keys — список ключей, которые будут добавлены в authorized_keys.
Попробуем испытать наш сценарий. Сначала вводим:
terraform plan
Если мы не ошиблись, утилита покажет, что terraform сделает в нашей облачной инфраструктуре. Очень важно внимательно просматривать изменения.
После того, как мы убедимся в корректности действий, применяем настройку:
terraform apply
Мы еще раз увидим, что будет выполнено, а также получим запрос на подтверждение действий — вводим yes:
Enter a value: yes
Terraform выполнит необходимые действия. Мы можем перейти в контроль-панель хостинга и убедиться, что наша виртуальная машина создалась.
Редактирование данных
Если необходимо внести изменения в нашу инфраструктуру, то достаточно просто открыть наш файл со сценарием:
vi infrastructure1.tf
Внести нужные изменения, например:
...
resources {
cores = 4
memory = 4
}
...
* в нашем конкретном случае, мы увеличили количество процессоров и объем памяти для созданной виртуальной машины.
Однако, некоторые изменения требуют остановки виртуальной машины. В этом случае мы получим ошибку при попытке применить новые настройки с текстом:
Error: Changing the `secondary_disk`, `resources`, `platform_id`, `network_acceleration_type` or `network_interfaces` on an instance requires stopping it. To acknowledge this action, please set allow_stopping_for_update = true in your config file.
Мы должны явно разрешить для конкретных ресурсов выполнение остановки их работы для внесения изменений. В нашем файле для конкретного ресурса добавим:
* для нашей машины test1 мы указали опцию allow_stopping_for_update, которая говорит о том, что работу ресурса можно останавливать для внесения изменений.
Строим план:
terraform plan
Мы должны увидеть, что будет изменено в нашей инфраструктуре. В моем случае:
2. Можно закомментировать или удалить строки ресурса из файла tf.
3. Если мы хотим оставить содержимое файлов нетронутым, но при этом удалить все ресурсы, вводим:
terraform destroy
Утилита пройдет по всем файлам tf в директории, найдет ресурсы и выполнит их удаление.
Файл state
Очень важно уметь работать с файлом состояния terraform, а также понять, что это. Данный файл появляется после первого применения сценария в том же рабочем каталоге:
ls
terraform.tfstate
В нем содержатся все изменения, которые происходили с применением terraform. Без него последний не будет знать, что уже было сделано — на практике это приведет к дублированию инфраструктуры, то есть, если мы создали сервер, потеряли файл состояния и снова запустили terraform, он создаст еще один сервер. Для больших инфраструктур с большой историей все намного критичнее.
И так, файл состояния важен с точки зрения понимания инфраструктуры самим terraform. Также у него есть еще одна функция — блокировка параллельных выполнений. Это важно для работы в командах, где одновременные действия могут привести к неожиданным последствиям. Чтобы этого не произошло, terraform создает блокировку, которая запрещает выполнения, если уже идет процесс применения плана.
Из вышесказанного делаем выводы:
Файлы состояния нужно бэкапить.
Они должны находиться в надежном месте.
У всех инженеров, которые работают с инфраструктурой должен быть доступ к файлу состояния. Они не должны его копировать на свои компьютеры и использовать индивидуально.
Рассмотрим возможность хранения данного файла состояния на облачном хранилище Яндекс.
Сначала мы должны создать хранилище. Это можно сделать через веб-интерфейс, но мы это сделаем в terraform.
* где yandex_folder_id — название для нашей переменной; <идентификатор каталога> — тот идентификатор, который мы указали в файле main под аргументом folder_id.
Теперь откроем файл main:
vi main.tf
И отредактируем значение folder_id на:
...
folder_id = var.yandex_folder_id
...
* в данном примере мы теперь задаем folder_id не явно, а через созданную переменную.
yandex_iam_service_account — создание ресурса для учетной записи. В нашем примере она будет иметь название sa-testи входить в системный каталог yandex_folder_id (переменная, которую мы создали ранее).
yandex_resourcemanager_folder_iam_member — создание роли. Она будет иметь доступ для редактирования хранилищ. В состав роли войдет созданная запись sa (с именем sa-test).
yandex_iam_service_account_static_access_key — создаем ключ доступа для нашей сервисной учетной записи.
yandex_storage_bucket — создаем хранилище с названием tf-state-bucket-test.
Создаем еще один файл:
vi outputs.tf
output "access_key" {
value = yandex_iam_service_account_static_access_key.sa-static-key.access_key
sensitive = true
}
output "secret_key" {
value = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
sensitive = true
}
* это делается для получения значений аргументов access_key и secret_key и сохранения данных значений в файле состояния. Если access_key можно посмотреть в панели Яндекса, то secret_key мы увидеть не можем.
Строим план и применяем настройки:
terraform plan
terraform apply
Заходим в контроль-панель Яндекса и видим, что у нас создалось хранилище. Его мы будем использовать для хранения файлов состояний terraform.
* в раздел terraform мы добавили инструкцию для хранения файла state. В нашем примере он будет размещен на бакете tf-state-bucket-test по пути terraform/infrastructure1/terraform.tfstate. ** особое внимание обратите на access_key и secret_key. В разделе terraform мы не можем указать переменные, как это делали при создании хранилища. Сами значения можно найти в нашем локальном файле state.
Используем команду:,
terraform init
Система снова инициализирует состояние текущего каталога и создаст файл state на удаленном хранилище. Чтобы убедиться, можно зайти в контроль панель, найти наше хранилище, а в нем — файл terraform/infrastructure1/terraform.tfstate.
Реальный пример
Мы развернем 2 веб-сервера и поместим их за Network load balancer.
Подразумевается, что все инфраструктура создается с нуля, поэтому нужно либо удалить предыдущие наработки, либо создать новый сервисный аккаунт для storage.
Мы создадим 5 файлов:
main.tf — в нем мы опишем инструкции для init, а именно требования к версии клиента terraform, провайдера.
web-servers.tf — сценарий для создания 2-х веб-серверов.
network-load-balancer.tf — создание Network Load Balancer.
variables.tf — описание переменных.
outputs.tf — вывод значений после отработки terraform на экран и в файл состояния.
variable "yandex_folder_id" {
type = string
default = "<folder_id>"
}
* создадим переменную с folder_id, в котором мы должны работать. Выше мы уже делали такую переменную.
5. outputs.tf:
vi outputs.tf
output "lb_ip_address" {
value = yandex_lb_network_load_balancer.lb-test.*
}
* на самом деле, это не обязательно — информацию о созданном балансировщике можно посмотреть в контроль панели, но для примера мы решили это рассмотреть.
Готово. После применения данного сценария мы получим то, что хотели — две виртуальные машины + балансировщик сети, который будет распределять запросы между данными серверами.
Задача – добавить дашборд для отображения различной статистики с бекенда.
Ниже описывается процесс создания дашборды, рассматриваются примеры запросов из Grafana к Prometheus для получения данных, настройки различных типов панелей, примеры метрик, которые можно использовать.
Соответственно – в дашборде хочется выводить статистику и того, и другого. Для этого – добавим переменную, с помощью которой сможем переключаться между ними.
Переходим в Variables:
в Name задаём имя, которое будет использоваться в запросах
Type – оставляем Query
Label – имя, как оно будет отображаться в дашборде для выбора
Data source – Prometheus
Refresh – при загрузке дашборда
Query – собственно, сам запрос, который вернёт нам значения, и из которого будем получать список окружений в данном случае Prometheus-сервер, который запущен на EC2, добавляет external_label в виде env=mobilebackend-dev, его и используем для получения значений – используем метрику node_boot_time_seconds, фильтруем вывод по метке job="node-exporter" запрос получается: label_values(node_boot_time_seconds{job="node-exporter"}, env)
Сохраняем – Add внизу.
Статусы хоста
Первым добавим блок, в котором убдут выводить % использования CPU, Load Avareage, память и диски.
CPU Busy
node_cpu_seconds_total
Прежде, чем заниматься настройкой отображения CPU Busy – давайте вспомним /proc/stats.
Сначала – получим время с момента запуска системы:
Выполняем сложение всех счётчиков, делим на 100 – получаем общее кол-во секунд.
Потом, аналогично вычислениям с uptime – получаем кол-во дней, вышло 24 – один день (точнее 4 часа) “потерялся”, но не критично – в целом значения сошлись.
Теперь выведем метрики node_exporter, и сравним их с данными из /proc/stat (на самом деле метрики я вывел немного раньше, поэтому будет разница):
root@bm-backed-app-dev:/opt/prometheus-client# curl -s localhost:9100/metrics | grep node_cpu_seconds_total
HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 2.13035164e+06
node_cpu_seconds_total{cpu="0",mode="iowait"} 579.98
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 11.88
node_cpu_seconds_total{cpu="0",mode="softirq"} 298.71
node_cpu_seconds_total{cpu="0",mode="steal"} 1340.68
node_cpu_seconds_total{cpu="0",mode="system"} 4660.78
node_cpu_seconds_total{cpu="0",mode="user"} 14346.37
И сравниваем с stat:
user: stat = 14351.56, exporter = 14346.37
system: stat = 4662.32, exporter = 4660.78
Окей – тут тоже всё более-менее сходится, и значение данных из node_cpu_seconds_total понятно.
Запрос
Теперь рассмотрим запрос, который будем использовать для получения CPU Busy %:
(((count(count(node_cpu_seconds_total{env="$environment"}) by (cpu))) - avg(sum by (mode)(irate(node_cpu_seconds_total{mode='idle',env="$environment"}[5m])))) * 100) / count(count(node_cpu_seconds_total{env="$environment"}) by (cpu))
Тут:
count – считаем кол-во элементов, полученных из запроса
irate – считает значение в секунду, основываясь на двух последних данных
node_cpu_seconds_total – секунды в каждом режиме (system, user, idle etc)
{env=~"$environment"} – выборка по значению переменной $environment
Подсчёт кол-ва ядер
Кол-во ядер мы получаем запросом ((count(count(node_cpu_seconds_total{env="$environment"}) by (cpu))).
Рассмотрим его детальнее.
Сначала сделаем выборку по node_cpu_seconds_total{env=~"mobilebackend-dev"}:
Так мы получим значения node_cpu_seconds_total по каждому типу – iowait, user, system, nice etc.
В count(node_cpu_seconds_total{env=~"mobilebackend-dev"}) считаем общее кол-во элементов (iowait, user, system, nice etc), хотя оно нам не надо – мы просто используем этот массив для следующего запроса.
А следующий запрос – count(node_cpu_seconds_total{env=~"mobilebackend-dev"}) by (cpu) возвращает нам общее кол-во node_cpu_seconds_total по типам для каждого ядра:
Например для Production это будет выглядеть так:
И в конце-концов добавив ещё один счётчик – count, и превратив запрос в count(count(node_cpu_seconds_total{env=~"mobilebackend-dev"}) by (cpu)) – мы получим кол-во ядер:
Coloring – включаем красивую подсветку по значениям, и в Thresholds задаём значения, при которых цвет будет меняться – на оранжевый при 75%, и на красный – при 90%
Stat – Current
Unit – выбираем None > percent 1-100
Получается такое:
Возвращаемся к дашборе, добавляем ещё один елемент – Row:
Задаём имя, меняем размер панельки с CPU Busy:
Load Average
Следующая панелька будет выводить Load Average.
Можно было бы вывести просто значение node_load1{env=~"$environment"} – но на Dev сервере одно ядро, и значение node_load1 == 1 будет являться условными 100% для одного ядра, а на Production с его 8 ядрами node_load1 == 1 будет всего:
>>> 1.0 / 8 * 100
12.5
12.5%
Значит, что бы корректно отрисовывать шкалу – нам потребуется получить значение LA, поделить его на кол-во ядер и умножить на 100 – получим % от “максимального” (в кавычках, потому что LA может быть и выше 1 для 1 ядра или 8 для 8 ядер) значения.
Следовательно – используем такой запрос:
avg(node_load1{env=~"$environment"}) / count(count(node_cpu_seconds_total{env=~"$environment"}) by (cpu)) * 100
в (node_memory_MemTotal_bytes{env="$environment"} - node_memory_MemFree_bytes{env="$environment"}) считаем общее кол-во занятой памяти (active + cache), назовём её busy
и считаем busy / total * 100 – получаем % от свободной памяти
В Options включаем шкалу, настраиваем аналогично примерам выше:
Повторяем для второго диска – /rootfs/data, получаем такую картинку в дашборде:
Текущеее время
Следующим – добавим отображение текущего времени. Во-первых – просто удобно на экране (в комнате висит большой телевизор, на котором выводится борда) видеть текущее время, во-вторых – такая себе проверка на то, что браузер/дашборда не зависли, и обновляются.
Для вывода времени – опять используем Singlestat панели, и функцию timestamp(), которой передадим метрику up (можно любую – нам только требуется получить из метрики время).
Добавим ещё несколько графиков – статистику с AWS Application Load Balancer.
Тут надо добавить ещё одну переменную – Load balancer.
К сожалению – cloudformation_exporter не умеет получать теги, поэтому пока придётся использовать просто имена ALB (надо будет посмотреть – может на стороне Prometheus можно будет сделать им relabel).
Переходим в Axes, и включаем отображение шкалы Y справа, в юнитах используем милисекунды:
Далее переходим в Display > Series overrides > Add override, и в Alias or regex указываем алиас метрики, в данном случае мы хотим выводить время, основываясь на данных из `aws_applicationelb_target_response_time_sum`, который в метриках указывается как response_time ms:
Кликаем на “+” – добавляем желамое действие. Тут указываем отображание времени в Y Right и заодно – можно поиграть со цветом:
И всё вместе теперь выглядит так:
EC2 statistics
И последним – добавим графики EC2.
В принципе – тут ничего такого, что уже не рассматривалось выше.
CPU
Сначала – статистика использования CPU – System, User, IOwait, idle.
В самом простом виде запросы выглядел бы так:
sum by (instance)(rate(node_cpu_seconds_total{mode="system",env="$environment"}[5m])) * 100
Получаем % от времени, которое CPU проёвл в режиме system/user/idle и т.д.
Но в случае, когда у нас несколько ядер – добавляем вычисление % от кол-ва ядер, аналоигчно тому, как мы это делали для отрисовки шкалы с % LA и CPU Busy:
(avg(sum by (instance)(rate(node_cpu_seconds_total{mode="idle",env="$environment"}[5m])) * 100)) / count(count(node_cpu_seconds_total{env="$environment",instance="localhost:9100"}) by (cpu))