понедельник, 21 ноября 2022 г.

Частичное зеркалирование данных по SFTP

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

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

Для решения этой задачи подошла утилитка lftp, которая поддерживает много протоколов включая SFTP. Список шаблонов для синхронизации записали в файлик, который служит аргументом для --include-glob-from. Закачка самих файлов идет в несколько потоков (--parallel) с удалением тех файлов, которых больше нет на источнике (--delete).

#!/bin/bash

LFTP_PROTOCOL=sftp
LFTP_HOST=sftp.example.com
LFTP_PORT=22
LFTP_USERNAME=sftpuser
SFTP_PASSWORD=sftppass
REMOTE_DIR=/remote/path
LOCAL_DIR=/local/path
INCLUDE_LIST=$(dirname $(readlink -f $0))/sftp-mirror.include

lftp -u ${LFTP_USERNAME},${LFTP_PASSWORD} ${LFTP_PROTOCOL}://${LFTP_HOST}:${LFTP_PORT} <<_EOF_
cd ${REMOTE_DIR}
lcd ${LOCAL_DIR}
mirror --recursion=always --no-empty-dirs --delete --parallel=8 --include-glob-from=${INCLUDE_LIST}
close
_EOF_

Файл sftp-mirror.include с шаблонами имен по одному на строку, которые нужно зеркалировать

*Element=ABA090*.xml.gz
*Element=BAC105*.xml.gz
*Element=DOM288*.xml.gz

Расчет разницы и выкачивание новых файлов происходит очень быстро.

пятница, 18 ноября 2022 г.

Nginx запрашивает / вместо /.well-known/openid-configuration

Настраиваю workload identity federation между on-prem GitLab и GCP согласно документации. Сделал настройки в GCP, взял готовый пример пайплайна, но джоба падает с ошибкой

$ gcloud auth print-access-token
ERROR: (gcloud.auth.print-access-token) ("Error code invalid_grant: Parsing error for OIDC discovery document: [Line 0, column 0: Unexpected end of stream : expected '{']", '{"error":"invalid_grant","error_description":"Parsing error for OIDC discovery document: [Line 0, column 0: Unexpected end of stream : expected \'{\']"}')

Смотрю что выдаёт https://GITLAB/.well-known/openid-configuration и вижу 302 редирект на /users/sign_in - это неожиданное поведение. На этот запрос должно возвращать JSON вида

$ curl -s https://gitlab.com/.well-known/openid-configuration
{"issuer":"https://gitlab.com","authorization_endpoint":"https://gitlab.com/oauth/authorize","token_endpoint":"https://gitlab.com/oauth/token","revocation_endpoint":"https://gitlab.com/oauth/revoke","introspection_endpoint":"https://gitlab.com/oauth/introspect","userinfo_endpoint":"https://gitlab.com/oauth/userinfo","jwks_uri":"https://gitlab.com/oauth/discovery/keys","scopes_supported":["api","read_api","read_user","read_repository","write_repository","read_registry","write_registry","sudo","openid","profile","email"],"response_types_supported":["code"],"response_modes_supported":["query","fragment"],"grant_types_supported":["authorization_code","password","client_credentials","refresh_token"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"],"claim_types_supported":["normal"],"claims_supported":["iss","sub","aud","exp","iat","sub_legacy","name","nickname","email","email_verified","website","profile","picture","groups","groups_direct","https://gitlab.org/claims/groups/owner","https://gitlab.org/claims/groups/maintainer","https://gitlab.org/claims/groups/developer"]}

Нужно разобраться откуда у меня берется этот редирект.

воскресенье, 13 ноября 2022 г.

Spinnaker - день второй

Второй день изучения Spinnaker (почитать про первый день можно тут). На сегодня в планах построить минимальную инфраструктуру вокруг Spinnaker и задеплоить приложение в отдельный GKE кластер.

Spinnaker у меня крутится в VirtualBox, поэтому нужно создать ключ для IAM сервис аккаунта, который будет использоваться для доступа в GCS, GCR и Pub/Sub. Для подключения к GKE я сгенерировал отдельный kubeconfig.

При составлении пайплайна для Spinnaker я пользовался репозитарием spinnaker-for-gcp. Сам туториал у меня не завелся из-за недоступности управления IAM в Cloud Playground.

среда, 9 ноября 2022 г.

Binary grep

В базе материализовалась запись, которая приводит к ошибкам вида org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0xed 0x70 0x69. Возникает такое когда кто-то сделал изменение в таблице, но при этом соединение с базой не было настроено на UTF-8.

По прошлому опыту, данные вставили в кодировке latin1 и там будут символы вроде "í", "é", "á" или им подобные. Можно записать байтики в файлик и использовать его как паттерн для grep, но захотелось возможности грепать сразу в виде байтов.

понедельник, 7 ноября 2022 г.

Spinnaker - день первый

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

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

воскресенье, 30 октября 2022 г.

Подключение к Kafka в изолированном окружении

Есть изолированное от внешнего мира окружение в GCP с кластером Kafka, который живет в GKE. Kafka используется как внутри GKE кластера, так и виртуальными машинами, которым Kafka выставлена через внутренний балансировщик. Часть пользователей не приемлют использование консольных команд чтобы подключиться к Kafka и хотят пользоваться привычными им инструментами вроде Offset Explorer и ему подобными.

Итого у нас есть три брокера Kafka, которые доступны внутри кластера как kafka-0.kafka-headless.default.svc.cluster.local:9092, kafka-1.kafka-headless.default.svc.cluster.local:9092 и kafka-2.kafka-headless.default.svc.cluster.local:9092. Для виртуальных машин создано три балансировщика с адресами 172.16.0.16:19092, 172.16.0.17:19092 и 172.16.0.18:19092.

Если просто пробросить порты на локальную машину, то ничего работать не будет, т.к. после подключения к Kafka брокеру клиент получит метаданные в которых будет фигурировать Kafka advertised listeners и клиент будет пытаться подключиться к ним вместо работы с проброшенными портами.

среда, 5 октября 2022 г.

Лимиты памяти в LXC для CGroupV2

С неделю назад мигрировал ряд сервисов на базе контейнеров LXC в облако. Чтобы не переплачивать за простаивающие ресурсы в облаке взял в два раза меньше памяти и процессорных ядер. Поскольку нагрузка на сервисы минимальная, а памяти на исходном сервере было с запасом, то лимиты по памяти и ядрам не были настроены, но в условиях потенциальной нехватки ресурсов нужно решить проблему "шумного соседа" (когда один сервис может исчерпать ресурсы всего сервера и привести к нестабильной работе или отказу в обслуживании у остальных сервисов).

Для начала настроил сколько RAM и SWAP может использовать каждый из контейнеров.