Русский
Русский
English
Статистика
Реклама

Серверное администрирование

Перевод Разработка REST-серверов на Go. Часть 1 стандартная библиотека

28.05.2021 16:10:14 | Автор: admin
Это первый материал из серии статей, посвящённой разработке REST-серверов на Go. В этих статьях я планирую описать реализацию простого REST-сервера с использованием нескольких различных подходов. В результате эти подходы можно будет сравнить друг с другом, можно будет понять их относительные преимущества друг перед другом.

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

Задача


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

В нашем случае сервер представляет собой простую бэкенд-систему для приложения, реализующего функционал управления задачами (вроде Google Keep, Todoist и прочих подобных). Сервер предоставляет клиентам следующий REST API:

POST  /task/       : создаёт задачу и возвращает её IDGET  /task/<taskid>   : возвращает одну задачу по её IDGET  /task/       : возвращает все задачиDELETE /task/<taskid>   : удаляет задачу по IDGET  /tag/<tagname>   : возвращает список задач с заданным тегомGET  /due/<yy>/<mm>/<dd> : возвращает список задач, запланированных на указанную дату

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

Наш сервер поддерживает GET-, POST- и DELETE-запросы, некоторые из них с возможностью использования нескольких путей. То, что в описании API приведено в угловых скобках (<...>), обозначает параметры, которые клиент предоставляет серверу в виде части запроса. Например, запрос GET /task/42 направлен на получение с сервера задачи с ID 42. ID это уникальные идентификаторы задач.

Для кодирования данных используется формат JSON. При выполнении запроса POST /task/ клиент отправляет серверу JSON-представление задачи, которую нужно создать. И, аналогично, в ответах на те запросы, в описании которых сказано, что они что-то возвращают, содержатся JSON-данные. В частности, они размещаются в теле HTTP-ответов.

Код


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

$ SERVERPORT=4112 go run .

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

Модель


Начнём с обсуждения модели (или уровня данных) для нашего сервера. Найти её можно в пакете taskstore (internal/taskstore в директории проекта). Это простая абстракция, представляющая базу данных, в которой хранятся задачи. Вот её API:

func New() *TaskStore// CreateTask создаёт новую задачу в хранилище.func (ts *TaskStore) CreateTask(text string, tags []string, due time.Time) int// GetTask получает задачу из хранилища по ID. Если ID не существует -// будет возвращена ошибка.func (ts *TaskStore) GetTask(id int) (Task, error)// DeleteTask удаляет задачу с заданным ID. Если ID не существует -// будет возвращена ошибка.func (ts *TaskStore) DeleteTask(id int) error// DeleteAllTasks удаляет из хранилища все задачи.func (ts *TaskStore) DeleteAllTasks() error// GetAllTasks возвращает из хранилища все задачи в произвольном порядке.func (ts *TaskStore) GetAllTasks() []Task// GetTasksByTag возвращает, в произвольном порядке, все задачи// с заданным тегом.func (ts *TaskStore) GetTasksByTag(tag string) []Task// GetTasksByDueDate возвращает, в произвольном порядке, все задачи, которые// запланированы на указанную дату.func (ts *TaskStore) GetTasksByDueDate(year int, month time.Month, day int) []Task

Вот объявление типа Task:

type Task struct {Id  int    `json:"id"`Text string  `json:"text"`Tags []string `json:"tags"`Due time.Time `json:"due"`}

В пакете taskstore этот API реализован с использованием простого словаря map[int]Task, данные при этом хранятся в памяти. Но несложно представить себе реализацию этого API, основанную на базе данных. В реальном приложении TaskStore, вероятнее всего, будет интерфейсом, реализовать который могут разные бэкенды. Но для нашего простого примера достаточно и такого API. Если вы хотите поупражняться реализуйте TaskStore с использованием чего-то вроде MongoDB.

Подготовка сервера к работе


Функция main нашего сервера устроена довольно просто:

func main() {mux := http.NewServeMux()server := NewTaskServer()mux.HandleFunc("/task/", server.taskHandler)mux.HandleFunc("/tag/", server.tagHandler)mux.HandleFunc("/due/", server.dueHandler)log.Fatal(http.ListenAndServe("localhost:"+os.Getenv("SERVERPORT"), mux))}

Уделим немного времени команде NewTaskServer, а потом поговорим о маршрутизаторе и об обработчиках путей.

NewTaskServer это конструктор для нашего сервера, имеющего тип taskServer. Сервер включает в себя TaskStore, что безопасно с точки зрения конкурентного доступа к данным.

type taskServer struct {store *taskstore.TaskStore}func NewTaskServer() *taskServer {store := taskstore.New()return &taskServer{store: store}}

Маршрутизация и обработчики путей


Теперь вернёмся к маршрутизации. Тут используются стандартный HTTP-мультиплексор, входящий в состав пакета net/http:

mux.HandleFunc("/task/", server.taskHandler)mux.HandleFunc("/tag/", server.tagHandler)mux.HandleFunc("/due/", server.dueHandler)

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

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

Изучим обработчик путей taskHandler:

func (ts *taskServer) taskHandler(w http.ResponseWriter, req *http.Request) {if req.URL.Path == "/task/" {// Запрос направлен к "/task/", без идущего в конце ID.if req.Method == http.MethodPost {ts.createTaskHandler(w, req)} else if req.Method == http.MethodGet {ts.getAllTasksHandler(w, req)} else if req.Method == http.MethodDelete {ts.deleteAllTasksHandler(w, req)} else {http.Error(w, fmt.Sprintf("expect method GET, DELETE or POST at /task/, got %v", req.Method), http.StatusMethodNotAllowed)return}

Мы начинаем работу с проверки на точное совпадение пути с /task/ (это означает, что в конце нет <taskid>). Тут нам нужно понять то, какой HTTP-метод используется, и вызвать соответствующий метод сервера. Большинство обработчиков путей это достаточно простые обёртки для API TaskStore. Посмотрим на один из таких обработчиков:

func (ts *taskServer) getAllTasksHandler(w http.ResponseWriter, req *http.Request) {log.Printf("handling get all tasks at %s\n", req.URL.Path)allTasks := ts.store.GetAllTasks()js, err := json.Marshal(allTasks)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json")w.Write(js)}

Он решает две основные задачи:

  1. Получает данные из модели (TaskStore).
  2. Формирует HTTP-ответ для клиента.

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

Вернёмся теперь к taskHandler. Пока мы видели только то, как он обрабатывает запросы, в которых имеется точное совпадение с путём /task/. А как насчёт пути /task/<taskid>? Именно тут в дело вступает вторая часть функции:

} else {// В запросе есть ID, выглядит он как "/task/<id>".path := strings.Trim(req.URL.Path, "/")pathParts := strings.Split(path, "/")if len(pathParts) < 2 {http.Error(w, "expect /task/<id> in task handler", http.StatusBadRequest)return}id, err := strconv.Atoi(pathParts[1])if err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}if req.Method == http.MethodDelete {ts.deleteTaskHandler(w, req, int(id))} else if req.Method == http.MethodGet {ts.getTaskHandler(w, req, int(id))} else {http.Error(w, fmt.Sprintf("expect method GET or DELETE at /task/<id>, got %v", req.Method), http.StatusMethodNotAllowed)return}}

Когда запрос не в точности соответствует пути /task/, мы ожидаем, что за косой чертой будет идти числовой ID задачи. Вышеприведённый код анализирует этот ID и вызывает соответствующий обработчик (основываясь на методе HTTP-запроса).

Остальной код более или менее похож на тот, что мы уже рассмотрели, понять его должно быть несложно.

Улучшение сервера


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

Одной из используемых нами программных конструкций, которая, очевидно, нуждается в улучшении, и о которой мы уже говорили, является повторяющийся код подготовки JSON-данных при формировании HTTP-ответов. Я создал отдельную версию сервера, stdlib-factorjson, в которой эта проблема решена. Я выделил эту реализацию сервера в отдельную папку для того чтобы её было легче сравнить с первоначальным кодом сервера и проанализировать изменения. Главное новшество этого кода представлено следующей функцией:

// renderJSON преобразует 'v' в формат JSON и записывает результат, в виде ответа, в w.func renderJSON(w http.ResponseWriter, v interface{}) {js, err := json.Marshal(v)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json")w.Write(js)}

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

func (ts *taskServer) getAllTasksHandler(w http.ResponseWriter, req *http.Request) {log.Printf("handling get all tasks at %s\n", req.URL.Path)allTasks := ts.store.GetAllTasks()renderJSON(w, allTasks)}

Более фундаментальное улучшение заключалось бы в том, чтобы сделать код сопоставления запросов и путей чище, и в том, чтобы, по возможности, собрать этот код в одном месте. Хотя текущий подход по сопоставлению запросов и путей упрощает отладку, соответствующий код трудно понять с первого взгляда, так как он разбросан по нескольким функциям. Например, предположим, что мы пытаемся разобраться с тем, как обрабатывается запрос DELETE, который направлен к /task/<taskid>. Для этого выполняются следующие действия:

  1. Во-первых мы находим в main мультиплексор и узнаём, что корневой путь /task/ обрабатывается в taskHandler.
  2. Далее, в taskHandler, нам надо найти выражение else, которое отвечает за обработку путей, не точно совпадающих с /task/. Там нам надо прочитать код преобразования <taskid> в целое число.
  3. И наконец мы смотрим на выражение if, в котором перечислены различные методы, применяемые при обработке запросов, соответствующих этому пути, и выясняем, что метод DELETE обрабатывается в deleteTaskHandler.

Можно поместить весь этот код в одно место. Так работать с ним будет гораздо проще и удобнее. Именно на решение этой задачи направлены HTTP-маршрутизаторы сторонних разработчиков. О них мы поговорим во второй части этой серии статей.

Это первая часть из серии статей, посвящённой разработке серверов на Go. Посмотреть список статей можно в начале оригинала этого материала.


Подробнее..

Перевод Разработка REST-серверов на Go. Часть 2 применение маршрутизатора gorillamux

06.06.2021 14:21:06 | Автор: admin
Перед вами второй материал из серии статей, посвящённой разработке REST-серверов на Go. В первом материале этой серии мы создали простой сервер, пользуясь стандартными средствами Go, а после этого отрефакторили код формирования JSON-данных, вынеся его во вспомогательную функцию. Это позволило нам выйти на достаточно компактный код обработчиков маршрутов.

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



Это проблема, с которой сталкиваются все, кто пишет HTTP-сервера, не используя зависимости. Если только сервер, принимая во внимание систему его маршрутов, не является до крайности минималистичной конструкцией (например это некоторые специализированные серверы, имеющие лишь один-два маршрута), то оказывается, что размеры и сложность организации кода маршрутизатора это нечто такое, на что очень быстро обращают внимание опытные программисты.

Улучшенная система маршрутизации


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

Перед переходом к практическому примеру вспомним о том, как устроен API нашего сервера:

POST  /task/       : создаёт задачу и возвращает её IDGET  /task/<taskid>   : возвращает одну задачу по её IDGET  /task/       : возвращает все задачиDELETE /task/<taskid>   : удаляет задачу по IDGET  /tag/<tagname>   : возвращает список задач с заданным тегомGET  /due/<yy>/<mm>/<dd> : возвращает список задач, запланированных на указанную дату

Для того чтобы сделать систему маршрутизации удобнее, мы можем поступить так:

  1. Можно создать механизм, позволяющий задавать отдельные обработчики для разных методов одного и того же маршрута. Например запрос POST /task/ должен обрабатываться одним обработчиком, а запрос GET /task/ другим.
  2. Можно сделать так, чтобы обработчик маршрута выбирался бы на основе более глубокого, чем сейчас, анализа запросов. То есть, например, у нас при таком подходе должна быть возможность указать, что один обработчик обрабатывает запрос к /task/, а другой обработчик обрабатывает запрос к /task/<taskid> с числовым ID.
  3. При этом система обработки маршрутов должна просто извлекать числовой ID из /task/<taskid> и передавать его обработчику каким-нибудь удобным для нас способом.

Написание собственного маршрутизатора на Go это очень просто. Это так из-за того, что организовывать работу с HTTP-обработчиками можно, используя компоновку. Но тут я не стану потакать своему желанию написать всё самому. Вместо этого предлагаю поговорить о том, как организовать систему маршрутизации с использованием одного из самых популярных маршрутизаторов, который называется gorilla/mux.

Сервер приложения для управления задачами, использующий gorilla/mux


Пакет gorilla/mux представляет собой один из самых старых и самых популярных HTTP-маршрутизаторов для Go. Слово mux, в соответствии с документацией к пакету, расшифровывается как HTTP request multiplexer (Мультиплексор HTTP-запросов) (такое же значение mux имеет и в стандартной библиотеке).

Так как это пакет, нацеленный на решение единственной узкоспециализированной задачи, пользоваться им очень просто. Вариант нашего сервера, в котором для маршрутизации используется gorilla/mux, можно найти здесь. Вот код определения маршрутов:

router := mux.NewRouter()router.StrictSlash(true)server := NewTaskServer()router.HandleFunc("/task/", server.createTaskHandler).Methods("POST")router.HandleFunc("/task/", server.getAllTasksHandler).Methods("GET")router.HandleFunc("/task/", server.deleteAllTasksHandler).Methods("DELETE")router.HandleFunc("/task/{id:[0-9]+}/", server.getTaskHandler).Methods("GET")router.HandleFunc("/task/{id:[0-9]+}/", server.deleteTaskHandler).Methods("DELETE")router.HandleFunc("/tag/{tag}/", server.tagHandler).Methods("GET")router.HandleFunc("/due/{year:[0-9]+}/{month:[0-9]+}/{day:[0-9]+}/", server.dueHandler).Methods("GET")

Обратите внимание на то, что одни только эти определения тут же закрывают первые два пункта вышеприведённого списка задач, которые надо решить для повышения удобства работы с маршрутами. Благодаря тому, что в описании маршрутов используются вызовы Methods, мы можем с лёгкостью назначать в одном маршруте разные методы для разных обработчиков. Поиск совпадений с шаблонами (с использованием регулярных выражений) в путях позволяет нам легко различать /task/ и /task/<taskid> на самом верхнем уровне описания маршрутов.

Для того чтобы разобраться с задачей, которая имеется в третьем пункте нашего списка, посмотрим на использование getTaskHandler:

func (ts *taskServer) getTaskHandler(w http.ResponseWriter, req *http.Request) {log.Printf("handling get task at %s\n", req.URL.Path)// Тут и в других местах мы не проверяем ошибку Atoi, так как маршрутизатор// принимает лишь данные, проверенные регулярным выражением [0-9]+.id, _ := strconv.Atoi(mux.Vars(req)["id"])ts.Lock()task, err := ts.store.GetTask(id)ts.Unlock()if err != nil {http.Error(w, err.Error(), http.StatusNotFound)return}renderJSON(w, task)}

В определении маршрутов маршрут /task/{id:[0-9]+}/ описывает регулярное выражение, используемое для разбора пути и назначает идентификатор переменной id. К этой переменной можно обратиться, вызвав функцию mux.Vars с передачей ей req (эту переменную gorilla/mux хранит в контексте каждого запроса, а mux.Vars представляет собой удобную вспомогательную функцию для работы с ней).

Сравнение различных подходов к организации маршрутизации


Вот как выглядит последовательность чтения кода, применяемая в исходном варианте сервера тем, кто хочет разобраться в том, как обрабатывается маршрут GET /task/<taskid>.


А вот что нужно прочитать тому, кто хочет понять код, в котором применяется gorilla/mux:


При использовании gorilla/mux придётся не только меньше прыгать по тексту программы. Тут, кроме того, читать придётся гораздо меньший объём кода. По моему скромному мнению это очень хорошо с точки зрения улучшения читабельности кода. Описание путей при использовании gorilla/mux это простая задача, при решении которой нужно написать лишь небольшой объём кода. И тому, кто читает этот код, сразу понятно то, как этот код работает. Ещё одно преимущество такого подхода заключается в том, что все маршруты можно увидеть буквально раз взглянув на код, расположенный в одном месте. И, на самом деле, код настройки маршрутов выглядит теперь очень похожим на описание нашего REST API, выполненное в произвольной форме.

Мне нравится пользоваться такими пакетами, как gorilla/mux, из-за того, что подобные пакеты представляют собой узкоспециализированные инструменты. Они решают одну единственную задачу и решают её хорошо. Они не забираются в каждый уголок программного кода проекта, а значит, их, при необходимости можно легко убрать или заменить чем-то другим. Если вы посмотрите полный код того варианта сервера, о котором мы говорим в этой статье, то сможете увидеть, что область использования механизмов gorilla/mux ограничена несколькими строками кода. Если, по мере развития проекта, в пакете gorilla/mux будет обнаружено какое-то ограничение, несовместимое с особенностями этого проекта, задача замены gorilla/mux на другой маршрутизатор стороннего разработчика (или на собственный маршрутизатор) должна решаться достаточно быстро и просто.

Какой маршрутизатор вы использовали бы при разработке REST-сервера на Go?


Подробнее..

Перевод Разработка REST-серверов на Go. Часть 3 использование веб-фреймворка Gin

17.06.2021 16:13:58 | Автор: admin
Сегодня, в третьей части серии материалов, посвящённых разработке серверов на Go, мы займёмся реализацией нашего REST-сервера с использованием Gin одного из самых популярных веб-фреймворков для Go. Вот код, который мы будем тут обсуждать.



Выбор веб-фреймворка


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

Я выбрал именно Gin из-за того, что это один из самых популярных проектов такого рода (если судить по количеству GitHub-звёзд). Этот фреймворк кажется минималистичным, возникает такое ощущение, что с ним будет легко работать. Состояние документации к нему оставляет желать лучшего, но сам фреймворк настолько понятен, что мне, несмотря на это, было достаточно легко в нём разобраться и начать им пользоваться.

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

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

Маршрутизация и Gin


Наша функция main настраивает новый маршрутизатор Gin и регистрирует маршруты:

router := gin.Default()server := NewTaskServer()router.POST("/task/", server.createTaskHandler)router.GET("/task/", server.getAllTasksHandler)router.DELETE("/task/", server.deleteAllTasksHandler)router.GET("/task/:id", server.getTaskHandler)router.DELETE("/task/:id", server.deleteTaskHandler)router.GET("/tag/:tag", server.tagHandler)router.GET("/due/:year/:month/:day", server.dueHandler)

Вызов gin.Default() возвращает новый экземпляр Engine основного типа данных Gin, который не только играет роль маршрутизатора, но и даёт нам другой функционал. В частности, Default регистрирует базовое ПО промежуточного уровня, используемое при восстановлении после сбоев и для логирования. Подробнее о таком ПО мы поговорим позже.

Вышеприведённый код регистрации маршрутов должен показаться вам знакомым. А именно, он немного похож на тот код, который использовался в gorilla-версии нашего сервера. Но в нём есть и некоторые отличия:

  1. Вместо указания HTTP-метода в виде дополнительного (Go) вызова метода в маршруте, метод закодирован в имени функции, используемой для регистрации маршрута. Например тут используется конструкция вида router.POST, а не что-то вроде router.HandleFunc(...).Methods(POST).
  2. Gorilla поддерживает обработку запросов с использованием регулярных выражений. А Gin нет. К этому ограничению мы ещё вернёмся.

Обработчики запросов


Посмотрим на код обработчиков запросов, используемых при применении Gin. Начнём с самых простых, в частности с getAllTasksHandler:

func (ts *taskServer) getAllTasksHandler(c *gin.Context) {allTasks := ts.store.GetAllTasks()c.JSON(http.StatusOK, allTasks)}

Тут стоит обратить внимание на несколько интересных моментов:

  1. У обработчиков, используемых в Gin, нет стандартных сигнатур HTTP-обработчиков Go. Они просто принимают объект gin.Context, который может быть использован для анализа запроса и для формирования ответа. Но в Gin есть механизмы для взаимодействия со стандартными обработчиками вспомогательные функции gin.WrapF и gin.WrapH.
  2. В отличие от ранней версии нашего сервера, тут нет нужды вручную писать в журнал сведения о запросах, так как стандартный механизм логирования Gin, представленный ПО промежуточного уровня, сам решает эту задачу (и делается это с использованием всяческих полезных мелочей, вроде оформления вывода разными цветами и включения в журнал сведений о времени обработки запросов).
  3. Нам, кроме того, больше не нужно самостоятельно реализовывать вспомогательную функцию renderJSON, так как в Gin есть собственный механизм Context.JSON, который позволяет формировать JSON-ответы.

Теперь давайте изучим немного более сложный обработчик запросов, поддерживающий параметры:

func (ts *taskServer) getTaskHandler(c *gin.Context) {id, err := strconv.Atoi(c.Params.ByName("id"))if err != nil {c.String(http.StatusBadRequest, err.Error())return}task, err := ts.store.GetTask(id)if err != nil {c.String(http.StatusNotFound, err.Error())return}c.JSON(http.StatusOK, task)}

Тут особенно интересно выглядит обработка параметров. Gin позволяет обращаться к параметрам маршрута (к тому, что начинается с двоеточия, вроде :id) через Context.Params.

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

Привязка данных запросов


И последний обработчик запросов, который мы рассмотрим, это createTaskHandler. Он обрабатывает запросы, которые включают в себя особые данные, поэтому с ним интересно будет познакомиться поближе:

func (ts *taskServer) createTaskHandler(c *gin.Context) {type RequestTask struct {Text string  `json:"text"`Tags []string `json:"tags"`Due time.Time `json:"due"`}var rt RequestTaskif err := c.ShouldBindJSON(&rt); err != nil {c.String(http.StatusBadRequest, err.Error())}id := ts.store.CreateTask(rt.Text, rt.Tags, rt.Due)c.JSON(http.StatusOK, gin.H{"Id": id})}

В Gin имеется серьёзная инфраструктура для организации привязки запросов к структурам данных Go, содержащих данные из запросов. Тут под привязкой понимается обработка содержимого запросов (которое может быть представлено данными в различных форматах, например JSON и YAML), проверка полученных данных и запись соответствующих значений в структуры Go. Здесь мы пользуемся весьма примитивной формой привязки данных для RequestTask, где проверка данных не используется. Но, полагаю, нам стоит знать не только о базовых, но и о более продвинутых возможностях Gin.

Можно заметить, что Gin-версия createTaskHandler существенно короче более ранних версий аналогичного обработчика, так как за разбор JSON-данных запроса отвечает ShouldBindJSON.

Ещё внимание обратить стоит на то, что теперь нам не нужно пользоваться одноразовой структурой для ID ответа. Вместо этого мы используем gin.H псевдоним для map[string]interface{}; это очень просто, но, всё же, позволяет весьма эффективно конструировать ответы, используя совсем небольшие объёмы кода.

Дополнительные возможности Gin


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

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

Ограничения фреймворков


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

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

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

А теперь давайте представим, что у нас имеется большое веб-приложение, написанное с применением Gin. Мы неожиданно выясняем, что ограничение, связанное с регулярными выражениями, несовместимо с проектом (вряд ли так случится на самом деле, но, всё равно, это хороший пример). Но мы не можем просто взять и быстро заменить Gin на другой фреймворк, так как на Gin основано всё наше приложение. Перевод проекта на другой фреймворк потребует очень много времени и сил.

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

Каким фреймворком вы воспользовались бы при разработке сервера на Go?


Подробнее..

Обучающие вебинары Dell Technologies новые серверы, VDI, хранение и защита данных, модернизация ЦОД, удалённая работа

04.06.2021 14:18:19 | Автор: admin

Мы продолжаем цикл обучающих вебинаров Tech Diving и приглашаем на них всех, кто интересуется указанными в заголовке поста темами. В прошлый раз гостей с Хабра было особенно много: пользуясь случаем, благодарим вас за участие. И напоминаем, что технические сессии Dell Technologies это открытые вебинары, которые проводят наши самые опытные сотрудники. В прямом эфире они подробно раскрывают заявленные темы и отвечают на любые вопросы по ним.

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


Новая линейка серверов Dell EMC PowerEdge

Вебинар доступен в записи

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


Dell Hybrid Client: новая ступень в развитии VDI

10 июня, 11:00 (МСК)

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


Решения Dell Technologies для хранения и защиты данных

24 июня, 11:00 (МСК)

Это самый большой вебинар из всех, запланированных на текущий квартал, в нём будет сразу четыре выступления. Все посвящены современным подходам к хранению и защите данных. Сначала мы посмотрим на серверы PowerEdge в обозначенном контексте: поговорим об оптимизации производительности, использующихся хранилищах данных и масштабировании. Затем изучим Dell EMC PowerScale лидирующее на рынке решение для работы с файловыми и объектными задачами. После этого перейдём к PowerProtect комплексному программно-аппаратному решению для защиты данных. После этого расскажем о SmartFabric, сервисе автоматизации сетевой фабрики Dell EMC для PowerStore и PowerScale.


Модернизация сети ЦОД с решением Dell EMC SmartFabric Director и VMware NSX-T

8 июля, 11:00 (МСК)

На технической сессии эксперты Dell Technologies расскажут, как упростить автоматизацию сетевой фабрики ЦОД и виртуализацию сети на всех этапах во время развёртывания, обслуживания и мониторинга. Особый акцент сделаем на платформе VMware NSX-T: изучим её архитектуру и компоненты, рассмотрим преимущества и сценарии применения, в которых она будет наиболее эффективна. В качестве вишенки на торте мы приготовили разбор реального сценария модернизации сети ЦОД одного из наших заказчиков на основе сети Dell EMC и VMware NSX-T.


Современные подходы к организации удалённых рабочих мест: собственный опыт Dell Technologies

22 июля, 11:00 (МСК)

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

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


Ждём вас на вебинарах, и будем рады любой обратной связи: как во время и после онлайн-встреч, так и в комментариях прямо здесь или в личных сообщениях. Предлагать свои темы для следующих технических сессий, кстати, тоже можно. Спасибо за внимание и до встречи!

Подробнее..

Zabbix OPC DA

25.05.2021 00:13:35 | Автор: admin

В последних релизах Zabbix "из коробки" стал поддерживать некоторые популярные протоколы промышленного оборудования. Имея поддержку Modbus и MQTT, его использование с системами промышленной автоматизации стало чуточку проще. Но подобный подход к мониторингу такого рода оборудования не всегда возможен.

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

Для чего нам Zabbix

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

Взаимодействие с OPC серверами

Самой сложной задачей, которая стоит перед нами, является организация взаимодействия с OPC-серверами. В ходе поисков готового решения такого взаимодействия стало понятно, что подходящих нам вариантов не так много. Из того, что было найдено, наиболее пригодным к использованию оказался консольный клиент OpenOPC.

Установка OpenOPC

Как было сказано ранее, речь идет о стандарте OPC DA, а значит, о технологии DCOM и, соответственно, ОС Windows. В нашем случае установка OpenOPC производилась на машину с Windows XP, где и находится проприетарный OPC сервер. После завершения установки необходимо добавить путь до opc.exe в системную переменную среды PATH.

Проверим работу утилиты. Для начала выведем в консоль список доступных OPC серверов:

C:\Users\Администратор> opc.exe -qMerz.OPC_SAIA_S-BUS.1C:\Users\Администратор>

Теперь попробуем получить теги в удобном нам формате - csv:

C:\Users\Администратор>opc.exe -o csv -s Merz.OPC_SAIA_S-BUS.1 ATP.Register.OAT ATP.Register.OAT,197,Good,05/24/21 07:16:15C:\Users\Администратор>opc.exe -o csv -s Merz.OPC_SAIA_S-BUS.1 ATP.Register.OAT ATP5.Register.T_inlet ATP5.Register.T_outletATP.Register.OAT,198,Good,05/24/21 07:16:41ATP5.Register.T_inlet,627,Good,05/24/21 07:16:41ATP5.Register.T_outlet,654,Good,05/24/21 07:16:41C:\Users\Администратор>

Если что-то пошло не так

В ходе экспериментов с opc.exe выяснились некоторые моменты. Первое: каждый OPC клиент запускал новую копию OPC сервера, а их параллельная работа невозможна. Так как запустить используемый нами OPC сервер как службу не получилось, то через DCOM был настроен запуск OPC сервера от определенного пользователя. Все OPC клиенты - SCADA и агент Zabbix - были также настроены на запуск от этого пользователя. Второе: выявлены некоторые недостатки в работе самого OpenOPC. Например, клиент не вычитывает теги, в названии которых присутствуют символы, отличающиеся от латинских. С этим пока пришлось смириться и решать такие проблемы путем переименования тегов в OPC сервере.

Установка Zabbix агента

На ту же машину установим Zabbix агент, который сможет работать под Windows XP, например, zabbix_agent-5.2.0-windows-i386-openssl.msi. Агент будет выполнять активные проверки. Чтобы облегчить дальнейшую конфигурация агента, во время установки заполним следующие поля:

  • Ноst name - уникальное имя хоста, совпадающее с именем узла сети на Zabbix сервере.

  • Zabbix server IP/DNS - IP-адреса Zabbix сервера.

  • Server or Proxy for active checks - IP-адрес Zabbix сервера для активных проверок.

Конфигурирование Zabbix агента

В конфигурационный файл C:\Program Files\Zabbix Agent\zabbix_agentd.conf были внесены некоторые изменения.

  1. Увеличено время выполнения скрипта.

    ### Option: Timeout#Spend no more than Timeout seconds on processing.## Mandatory: no# Range: 1-30# Default:# Timeout=3Timeout=30
    
  2. Создан параметр для мониторинга.

    #User-defined parameter to monitor. There can be several user-defined parameters.#Format: UserParameter=<key>,<shell command>## Mandatory: no# Default:# UserParameter=UserParameter=opc[*],opc.exe -o csv -s $1 $2
    

Узел сети и элементы данных на сервере Zabbix

На Zabbix сервере создадим узел сети. Имя узла сети должно совпадать с Ноst name, указанном при установке агента, интерфейс - IP-адрес агента.

Далее к созданному узлу сети добавим элемент данных c типом Zabbix агент (активный). Ключом должна являться конструкция типа: opc[<ИМЯ OPC СЕРВЕРА>, <ЗАПРАШИВАЕМЕ ТЕГИ ЧЕРЕЗ ПРОБЕЛ>].

Значениями элемента данных будут строки, разделенные запятыми:

ATP2.Register.OAT,273,Good,05/24/21 15:21:33ATP2.Register.GVS.T_inlet_W,501,Good,05/24/21 15:21:33ATP2.Register.GVS.T_outlet_W,445,Good,05/24/21 15:21:33ATP2.Register.T_outlet_w_com,404,Good,05/24/21 15:21:33ATP2.Register.RAD.T_outlet_W,256,Good,05/24/21 15:21:33ATP2.Register.P_in_W_com,39,Good,05/24/21 15:21:33ATP2.Register.P_out_W_com,36,Good,05/24/21 15:21:33ATP2.Register.RAD.P_outlet_W,43,Good,05/24/21 15:21:33ATP2.Register.FIRE.P_gidrant,68,Good,05/24/21 15:21:33

Зависимые элементы данных

Создадим зависимые элементы данных для того, чтобы распарсить CVS, полученный в самом элементе.

В предобработке используем JavaScript, который получит необходимую нам строку в CVS, проверит качество тега и вернет результат.

function (value){    var nr_line = 4;    var lines = value.split('\n');    var fields = lines[nr_line].split(',');    if(typeof fields[2] != "undefined" &&  fields[2] == "Good"){    return (typeof fields[1] != "undefined") ? fields[1] : null;    }    return null;}

Пример визуализации полученных данных:

Заключение

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

Подробнее..

Перевод Постмортем инцидентов для начинающих

15.06.2021 14:10:21 | Автор: admin

image


Успешные постмортемы без поиска виноватых помогают учиться на инцидентах, чтобы не допускать подобных ошибок в будущем.


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


Зачем нужен постмортем?


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


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


Раз инциденты будут возникать в любом случае, они должны приносить пользу, а не вред.


В каком-то смысле, неопределенность, беспорядок, ошибки и время идут на пользу антихрупким системам
Antifragile, Nassim Nicholas Taleb (2012)

При сбое мы узнаем о системе что-то новое, особенно о скрытых связях между компонентами.
Допустим, у нас есть простая система с тремя компонентами (A, B и C) со следующими свойствами:


  • A связан с B;
  • A связан с C;
  • между B и C никаких связей не наблюдается;
  • любой процесс, порожденный A, открывает соединение с B и C.

Вот как выглядит эта схема:


image


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


Мы открыли скрытую связь между B и C. Вот как выглядит новая схема:


image


В идеале результатом постмортема будет документ, где описано, что нужно изменить в системе, чтобы проблема не повторилась.


А если она будет повторяться, нужно описать, как смягчить ее последствия и ускорить разрешение.


Когда проводить постмортем


Когда в системе происходит достаточно серьезный инцидент.


В теории любой инцидент. На практике вам вряд ли хватит ресурсов, поэтому начните с инцидентов, которые напрямую влияют на клиентов и стейкхолдеров.


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


Что нужно делать


Опишите, что произошло. Четко сформулируйте последствия инцидента:


  • Кто?
  • Что?
  • Как долго?

Составьте хронику событий и коммуникаций между участниками по поводу инцидента.
Попробуйте найти первопричину, если с ней можно что-то сделать:


  • пять почему;
  • практичность важнее истины;
  • процесс поиска первопричины нужно документировать.

Между истиной и практической пользой есть важное различие.
Data & Reality, William Kent (1978)

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


Решайте проблемы коллективно, чтобы быстро учиться новому.
The DevOps Handbook, Gene Kim, Jez Humble, Patrick Debois, John Willis (2006)

Предложите улучшение для системы


Если это случится снова:


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

Обращайте внимание на поток информации, фидбэк и задержки в коммуникациях:


  • Мы вовремя узнали об инциденте?
  • Все нужные люди получили уведомление?
  • Нужные подсистемы (например, автомасштабирование) получили нужный фидбэк?

Измените длительность задержки, и поведение всей системы может серьезно измениться.
Thinking in Systems, Donella H. Meadows (2008)

Чего не нужно делать


Никого не обвиняйте


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


Не копайте слишком глубоко


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


Что делать с документом?


Главная цель извлечь урок для себя и своей организации. Документы по постмортему должны быть:


  • доступны для поиска;
  • открыты максимально широкой аудитории (без раскрытия конфиденциальной информации);
  • понятны аудитории (инженерам, стейкхолдерам, пользователям и т. д.).

Для вдохновения


Вот список общедоступных (и подробных) постмортемов:


Подробнее..

Аптайм 500 дней перезагрузка падение собираем бэкап по частям

09.06.2021 10:16:43 | Автор: admin

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

Все началось с того, что сервер статистики контактного центра заказчика (на тот момент ещё потенциального) сбросил все пользовательские сессии и перестал отвечать на запросы. Соответственно к нему подкатили тележку с монитором и перезагрузили. Это обычно надо делать раз в 90 дней по инструкции от вендора, но тут это не делалось больше 500 дней. В общем, сервер отметил юбилей аптайма.

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

Но после накатывания бэкапа система просто легла.

В этот момент нас позвали отмечать день рождения сервера. Без него не работала балансировка нагрузки на операторов внутри КЦ.

Что это была за система?

Система Avaya Call Management System (CMS). Это кусок колл-центра, который собирает статистику по звонкам, операторам, нагрузке исторические и реал-тайм данные. На этом же сервере каждое утро собираются отчёты о работе. В реальном времени сервер говорит, какие операторы сейчас в каких статусах находятся, какие звонки обрабатываются, сколько звонков висит в очереди. В целом система нужна, чтобы следить за группами операторов, за колл-центром, чтобы правильно распределять нагрузку, потому что можно переносить операторов из ненагруженных линий в нагруженные и так далее. Обычно там просто сидят супервизоры и следят за всем происходящим. Прямых аналогов нет, обычно используются самописные решения или же всё вообще делается вручную. Аваевскую систему выбирают за надёжность и многофункциональность.

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

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

Первый день пятница

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

Приезжаем на место (напомню, что сервер лёг и удалённого доступа нет), подключаемся с монитором и клавиатурой, ещё раз смотрим, как система не стартует.

Я подключился не сразу. Когда подключился увидел, что диск переполнился ошибками из-за проблем бэкапа. Некоторые сервисы не стартовали почистили логи, стартовали руками.

У нас условно есть три части системы: железный сервер, который входит в ПАК, поставляемый сразу с софтом в виде чёрного ящика от вендора, CMS и база данных. Бэкапы CMS (конфигураций) и базы делаются в разные места.

ОК, система запустилась, но только база пустая данных никаких нет.

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

Итак, у нас на руках железный оракловский сервер, с которым что-то не то (но это не посыпавшийся раньше времени диск), на нём Solaris c базjq Informix от IBM + пакет CMS от вендора. Решение продаётся как программно-аппаратный комплекс, то есть всё там как поставил вендор, так никто и не трогал.

Бэкапы БД делались. Итерации были по 180 дней, бэкапирование настроено в планировщике системы. Логи бэкапов никто особо не читал, консистентность не проверяли, назад до этого юбилея сервака накатывать не пытались.

Складировались бэкапы прямо на этот же сервер.

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

Дальнейшее исследование

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

К утру мы всё ещё думали, что справимся быстро (в КЦ уже начались проблемы). Решили не трогать бренную земную оболочку сервера, а сразу снять с него образ и развернуть на виртуалке. Это стандартная процедура и для форензики, и для восстановления чего-то, где может посыпаться дальше диск, и вообще очень удобно в конечном итоге в плане не навреди ещё.

Сначала мы развернули виртуалку на стенде прямо у заказчика и начали препарировать там. Фактически Авая сделала больше, чем должна была, подарив лицензию на виртуальную систему. Ну, точнее, заказчику. Выяснили, что бэкап встаёт с ошибкой устройства, но в остальном норм, правда, система пустая. Довольно быстро стало понятно, что бэкап битый полностью.

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

Откатили виртуалку из снапшота на начальное состояние (до бэкапа системы) и пробуем использовать только бэкап базы. Он восстанавливается удачно, но там нет данных.

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

В лаборатории

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

Сразу стало понятно, что свежий бэкап неконсистентен и вообще похож на записанный прямо из /dev/random. То есть последний месяц (который не бэкапился) пропал просто в силу того, что его никто никуда не резервировал. Следующие полгода пропали из-за битого бэкапа. И только в следующей итерации нашлись таблицы, где были реальные данные. То есть минус семь месяцев от момента аварии, и, как позже выяснилось, целых данных там было не очень много, не больше года, а часто по некоторым показателям и меньше.

Вручную с таблицы перенесли данные в базу данных и скормили всё это нашей виртуалке.

То есть в итоге оставили систему в рабочем режиме со старыми данными, руками настраиваем всё то, что не удалось восстановить из бэкапа системы (пользовательские учётки, коннекторы к другим системам, скрипты).

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

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

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

Выводы

История на самом деле печальная: да, мы частично восстановили систему (вендор был готов в рамках своих сервисных соглашений только поднять с нуля чистую систему). Да, запустили колл-центр в понедельник со сбором статистики очень оперативно (по меркам проблемы).

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

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

Подробнее..

Перевод Tоп 10 PromQL запросов для мониторинга Kubernetes

12.06.2021 10:05:57 | Автор: admin

В этой статье приведены примеры популярных запросов Prometheus для мониторинга Kubernetes.

Если вы только начинаете работать с Prometheus и у вас возникают сложности при создании запросов PromQL, советуем обратиться к руководству по началу работы с PromQL. Здесь мы пропустим теорию и сразу перейдём к практике.

Рейтинг основан на опыте компании Sysdig, ежедневно оказывающей сотням клиентов помощь в настройке мониторинга их кластеров:

1. Количество pods в каждом namespace

Информация о количестве pod в каждом namespace может быть полезна для обнаружения аномалий в кластере, например, слишком большого количества pods в отдельном namespace:

sum by (namespace) (kube_pod_info)

2. Количество контейнеров без CPU limits в каждом namespace

Важно правильно задавать лимиты для оптимизации производительности приложений и кластера. Этот запрос находит контейнеры без CPU limits:

count by (namespace)(sum by (namespace,pod,container)(kube_pod_container_info{container!=""}) unless sum by (namespace,pod,container)(kube_pod_container_resource_limits{resource="cpu"}))

3. Количество перезагрузок pods в каждом namespace

С помощью этого запроса вы получите список pods, которые перезапускались. Это важный показатель, поскольку большое количество перезагрузок pod обычно означает CrashLoopBackOff:

sum by (namespace)(changes(kube_pod_status_ready{condition="true"}[5m]))

4. Pods в статусе Not Ready в каждом namespace

Запрос выводит все pods, при работе которых возникла проблема. Это может быть первым шагом к её локализации и устранению:

sum by (namespace)(kube_pod_status_ready{condition="false"})

5. Превышение ресурсов кластера ЦП

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

sum(kube_pod_container_resource_limits{resource="cpu"}) - sum(kube_node_status_capacity_cpu_cores)

6. Превышение ресурсов кластера Память

Если все Memory limits суммарно превышают ёмкость кластера, то это может привести к PodEviction, если на узле не будет хватать памяти. Для проверки используйте запрос PromQL:

sum(kube_pod_container_resource_limits{resource="memory"}) - sum(kube_node_status_capacity_memory_bytes)

7. Количество исправных узлов кластера

Запрос выведет количество исправных узлов кластера:

sum(kube_node_status_condition{condition="Ready", status="true"}==1)

8. Количество узлов кластера, которые могут работать некорректно

Найти узлы кластера, которые периодически меняют состояние с Ready на Not Ready:

sum(changes(kube_node_status_condition{status="true",condition="Ready"}[15m])) by (node) > 2

9. Обнаружение простаивающих ядер ЦП

Планировании ресурсов кластера Kubernetes не самая простая задача. Этот запрос поможет вам определить, сколько ядер ЦП простаивают:

sum((rate(container_cpu_usage_seconds_total{container!="POD",container!=""}[30m]) - on (namespace,pod,container) group_left avg by (namespace,pod,container)(kube_pod_container_resource_requests{resource="cpu"})) * -1 >0)

10. Обнаружение неиспользуемой памяти

Этот запрос поможет снизить ваши затраты, предоставив информацию о неиспользуемой памяти:

sum((container_memory_usage_bytes{container!="POD",container!=""} - on (namespace,pod,container) avg by (namespace,pod,container)(kube_pod_container_resource_requests{resource="memory"})) * -1 >0 ) / (1024*1024*1024)

Хотите узнать больше?

Рекомендуем изучить нашу шпаргалку по PromQL, чтобы узнать, как писать более сложные запросы PromQL.

Также воспользуйтесь отличной коллекцией Awesome Prometheus alerts collection. Она включает несколько сотен Prometheus alert rules, вы можете изучить их, чтобы узнать больше о PromQL и Prometheus.

Подробнее..

Перевод Контролируем удаление с финализаторами

18.06.2021 08:07:31 | Автор: admin

image


В Kubernetes не так-то просто что-то удалить вы уверены, что удалили объект, но оказывается, что он все еще присутствует в кластере. Вы, конечно, можете выполнять команду kubectl delete в повседневных операциях и надеяться на лучшее, но знание принципов работы delete команд в Kubernetes поможет вам понять, почему некоторые объекты остаются после удаления.


В этой статье мы рассмотрим:


  • Какие свойства ресурса влияют на удаление.
  • Как финализаторы и ссылки на родителя-владельца управляют удалением объектов.
  • Как можно использовать propagationPolicy, чтобы изменить порядок удаления.
  • Как работает удаление, с примерами.

Для простоты во всех примерах мы используем ConfigMaps и базовые команды kubectl. Мы увидим, как работают эти команды, и обсудим результаты их использования на практике.


Базовая команда delete


В Kubernetes есть несколько команд для создания, чтения, обновления и удаления объектов. Здесь мы поговорим о четырех командах kubectl: create, get, patch и delete.
Примеры базовой команды kubectl delete:


kubectl create configmap mymapconfigmap/mymap created

kubectl get configmap/mymapNAME    DATA   AGEmymap   0      12s

kubectl delete configmap/mymapconfigmap "mymap" deleted

kubectl get configmap/mymapError from server (NotFound): configmaps "mymap" not found

Перед командой стоит знак $, далее следует ее результат. Как видите, мы начали с kubectl create configmap mymap, чтобы создать пустой configmap mymap. Теперь нужно выполнить get и убедиться, что он существует. Затем мы удалили configmap. Если снова сделать get, получим ошибку HTTP 404, потому что configmap не найден.


У команды deleteочень простая диаграмма состояний:


image
Диаграмма состояний для delete


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


Как работают финализаторы


Чтобы понять, как удаляются ресурсы в Kubernetes и почему они иногда все-таки не удаляются, полезно разобраться с финализаторами.


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


Скорее всего, вы встречали следующие финализаторы:


  • kubernetes.io/pv-protection
  • kubernetes.io/pvc-protection

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


Ниже приводится configmap без свойств, но с финализатором:


cat <<EOF | kubectl create -f -apiVersion: v1kind: ConfigMapmetadata:  name: mymap  finalizers:  - kubernetesEOF

Контроллер ресурса configmap не понимает, что делать с ключом финализатора kubernetes. Такие финализаторы для configmap я называю мертвыми, и обычно они используются с неймспейсами. Вот что происходит при попытке удалить configmap:


kubectl delete configmap/mymap &configmap "mymap" deletedjobs[1]+  Running kubectl delete configmap/mymap

Kubernetes сообщает, что объект удален, но на самом деле, в традиционном понимании, никуда он не удален. Скорее он находится в процессе удаления. Если мы снова выполним get, то узнаем, что объект изменен и теперь содержит временную метку удаления deletionTimestamp.


kubectl get configmap/mymap -o yamlapiVersion: v1kind: ConfigMapmetadata:  creationTimestamp: "2020-10-22T21:30:18Z"  deletionGracePeriodSeconds: 0  deletionTimestamp: "2020-10-22T21:30:34Z"  finalizers:  - kubernetes  name: mymap  namespace: default  resourceVersion: "311456"  selfLink: /api/v1/namespaces/default/configmaps/mymap  uid: 93a37fed-23e3-45e8-b6ee-b2521db81638

Если в двух словах, объект был изменен, но не удален. Все потому, что Kubernetes увидел, что у объекта есть финализаторы, и поместил его в состояние read-only. Временная метка удаления показывает, что объект можно только читать а еще из него можно удалить апдейты ключа финализатора. Другими словами, удаление будет завершено, только когда мы удалим из объекта финализатор.


Удалить финализаторы можно с помощью команды patch. Фоновое удаление завершится, и объект будет удален. Если мы опять выполним get configmap, то ничего не увидим.


kubectl patch configmap/mymap \    --type json \    --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'configmap/mymap patched[1]+  Done  kubectl delete configmap/mymapkubectl get configmap/mymap -o yamlError from server (NotFound): configmaps "mymap" not found

Диаграмма состояния для финализации выглядит так:


image
Диаграмма состояний для финализации


Если мы попытаемся удалить объект с финализатором, он останется на этапе финализации, пока контроллер не удалит ключи финализаторов или финализаторы не будут удалены через Kubectl. Когда список финализаторов будет пуст, Kubernetes поместит его в очередь на удаление из реестра.


Ссылки на владельца


Ссылки на владельца (owner references) описывают отношения между группами объектов. Это свойства ресурсов, которые указывают, как они связаны друг с другом, чтобы можно было удалять целые деревья ресурсов.


Правила финализатора обрабатываются, если есть ссылки на владельца. Ссылки на владельца состоят из имени и UID. Они связывают ресурсы в одном неймспейсе и им нужен UID. Ссылки на владельца для подов обычно указывают на replica set, которому они принадлежат. Если удалить deploy или stateful set, дочерние replica set и pod тоже удалятся.


Посмотрим на примере, как работают ссылки на владельца. В первом примере мы сначала создаем родительский объект, а потом дочерний. В результате получаем простейший configmap со ссылками на владельца, то есть родителя:


cat <<EOF | kubectl create -f -apiVersion: v1kind: ConfigMapmetadata:  name: mymap-parentEOFCM_UID=$(kubectl get configmap mymap-parent -o jsonpath="{.metadata.uid}")cat <<EOF | kubectl create -f -apiVersion: v1kind: ConfigMapmetadata:  name: mymap-child  ownerReferences:  - apiVersion: v1    kind: ConfigMap    name: mymap-parent    uid: $CM_UIDEOF

Если мы удалим дочерний объект, в котором есть ссылка на владельца, родитель никуда не денется:


kubectl get configmapNAME           DATA   AGEmymap-child    0      12m4smymap-parent   0      12m4skubectl delete configmap/mymap-childconfigmap "mymap-child" deletedkubectl get configmapNAME           DATA   AGEmymap-parent   0      12m10s

В следующем случае мы воссоздали configmap из примера выше. Если мы удалим родителя, а не дочерний объект, в котором есть ссылка на него, а потом сделаем get для configmap, то увидим, что все configmap пропали:


kubectl get configmapNAME           DATA   AGEmymap-child    0      10m2smymap-parent   0      10m2skubectl delete configmap/mymap-parentconfigmap "mymap-parent" deletedkubectl get configmapNo resources found in default namespace.

Получается, что если в дочернем объекте есть ссылка на родителя, он автоматически удаляется при удалении родителя. Это называется cascade. По умолчанию cascade имеет значение true, но можно указать --cascade=false в kubectl delete, чтобы удалить родительский объект, не трогая дочерние.


В следующем примере у нас есть родительский и дочерний объекты, а еще ссылки на владельца. Если мы удалим родителя, указав --cascade=false, дочерние объекты сохранятся:


kubectl get configmapNAME           DATA   AGEmymap-child    0      13m8smymap-parent   0      13m8skubectl delete --cascade=false configmap/mymap-parentconfigmap "mymap-parent" deletedkubectl get configmapNAME          DATA   AGEmymap-child   0      13m21s

Параметр --cascade указывает на политику распространения в API, которая позволяет менять порядок объектов удаления в дереве. В следующем примере используется отправка запроса к API через curl для удаления с фоновой политикой распространения (propagation policy):


kubectl proxy --port=8080 &Starting to serve on 127.0.0.1:8080curl -X DELETE \  localhost:8080/api/v1/namespaces/default/configmaps/mymap-parent \  -d '{ "kind":"DeleteOptions", "apiVersion":"v1", "propagationPolicy":"Background" }' \  -H "Content-Type: application/json"{  "kind": "Status",  "apiVersion": "v1",  "metadata": {},  "status": "Success",  "details": { ... }}

Политику распространения нельзя указать в командной строке с помощью kubectl только при прямом вызове API. Просто создайте прокси, чтобы иметь доступ к серверу API со своего компьютера, и выполните команду curl с одним URL, чтобы послать команду delete.


Есть три варианта политики распространения:


  • Foreground: дочерние объекты удаляются до родительского (обратный порядок).
  • Background: родительский объект удаляется до дочерних (прямой порядок).
  • Orphan: ссылки на владельца игнорируются.

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


Принудительное удаление неймспейса


В некоторых случаях для удаления неймспейсов может потребоваться принудительная финализация: если вы удалили неймспейс и очистили все объекты в нем, но неймспейс по-прежнему существует, его можно удалить принудительно, обновив его подресурс, finalize. Так контроллер неймспейса поймет, что нужно удалить финализатор и выполнить очистку:


cat <<EOF | curl -X PUT \  localhost:8080/api/v1/namespaces/test/finalize \  -H "Content-Type: application/json" \  --data-binary @-{  "kind": "Namespace",  "apiVersion": "v1",  "metadata": {    "name": "test"  },  "spec": {    "finalizers": null  }}EOF

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


Итоги


Как показывают примеры, финализаторы могут помешать удалению ресурсов в Kubernetes, особенно если речь о родительских и дочерних объектах. Обычно финализаторы добавляются в код не просто так, поэтому нужно все проверить, прежде чем удалять их вручную. С помощью ссылок на владельца можно указывать и удалять деревья ресурсов, хотя и в этом случае будут учитываться финализаторы. Наконец, можно использовать политику распространения, чтобы указывать порядок удаления в прямых вызовах API и контролировать процесс удаления объектов. Теперь вы чуть больше знаете о том, как работает удаление в Kubernetes, и можете поэкспериментировать самостоятельно в продакшен-кластере.


Видео от автора:


Подробнее..

VSS для самых маленьких

02.06.2021 10:16:01 | Автор: admin

Снятие снапшота - именно с этого начинается любой бекап. До тех пор, пока мы не знаем, как сбросить все буфера на диск и привести файлы с данными в консистентное состояние, мы не бекапы делаем, а занимаемся копированием файлов с непредсказуемым содержимым внутри. Понимая важность снапшотов, все вендоры стараются дать нам если не полностью готовую функцию (типа Time Mashine в MacOS), то хотя бы набор ручек, за которые можно подёргать (вроде модуля dm-snap в ядре Linux).

Но сегодня речь пойдёт про самую распространённую ОС - Microsoft Windows, где эта задача решается с помощью Volume Shadow Copy сервиса, известного в народе под аббревиатурой VSS (Volume Snapshot Service). А нашего внимания он удостоился из-за того, что, несмотря на всю популярность своего материнского корабля, сам он окутан вуалью из тайн и мистических слухов. Давайте уже как-то разберёмся с этой штукой.

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

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

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

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

Какова роль VSS

Не сомневаюсь, что 90% читающих прекрасно понимают, зачем нужны снапшоты, но ради оставшихся 10% потерпите несколько предложений. Или сразу идите в следующий раздел.

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

Сами снапшоты ничего не знают про ваши файлы и папки. Они работают на уровень ниже файловой системы - с блочными устройствами и блоками данных. Если придерживаться терминологи Microsoft, то снапшот - это место, именуемое Shadow Storage, куда записываются изменённые блоки данных и откуда их можно извлекать с целью переписать данные на оригинальном диске. Тут можно запомнить для себя два нюанса. Первый - только что сделанный спапшот занимает ровно ноль байт. Это просто пре-алоцированное место, куда файловая система может копировать измененные блоки (или наоборот, новые блоки, но не суть). И второй - теневая копия суть есть дифференциальный бекап. Все данные, которые вы изменили, не удаляются, а отправляются на хранение в этой зоне.

Где найти VSS

Обнаружить следы VSS можно двумя классическими способами: через GUI или в консоли. В зависимости от конкретной версии системы пути могут немного отличаться, но суть будет одинакова. Итак, есть у меня в лабе Windows Server 2019, и если сделать ПКМ на любом диске в проводнике, мы увидим два пункта: Configure Shadow Copies и Restore previous versions.

Если зайти в мастер настроек, то можно включить создание теневых копий для любого диска, задать расписание, по которому они будут создаваться и, что самое интересное, указать место хранения этих копий. Строго говоря, даже не самих копий, а так называемой diff area - места, куда сбрасываются перезаписанные на оригинальном томе сектора. То есть мы запускаем создание снапшота одного диска, а его данные физически храним на другом. Функция архиполезная и позволяет не просто снижать нагрузку на конкретном диске, но и делать фокусы а-ля снимаем снапшот одной ноды в кластере и цепляем его к другой.

После того,как вы всё настроите на свой вкус, появляется смысл в пункте Restore previous versions. Чисто технически туда и до этого можно было зайти, однако внутри, скорее всего, будет только гнетущая пустота.

Но всё это баловство с графическим интерфейсом, и как мы знаем, до добра это не доводит, поэтому открываем powershell (или даже cmd, почему нет) - и там у нас имеется два варианта из коробки: vssadmin и diskshadow. Первая утилита есть практически на любой системе, начиная с WinXP/Win2003. Нет её только на Windows 8. По какой-то таинственной причине из восьмёрки вырезали инструменты управления теневыми копиями, но потом осознали свою неправоту и вернули всё на место. А вот diskshadow доступен только на серверных вариантах Windows. Это уже более продвинутый вариант vssadmin, позволяющий работать не только в интерактивном режиме, но и выполнять целые скрипты, написанные на понятном этому интерпретатору языке. Да и просто это более адекватный и поддающийся контролю инструмент.

И запоминаем самое важное: это две разные утилиты, существующие в разных контекстах. Теневая копия, сделанная в одной утилите, будет видна другой, однако статус у неё будет неоперабельный.

Вот отличный пример: мы создали снимок в diskshadow и пытаемся удалить его с помощью vssadmin. Сам снимок мы видим, но он не в нашем контексте, поэтому сорян, у нас нет здесь власти.Вот отличный пример: мы создали снимок в diskshadow и пытаемся удалить его с помощью vssadmin. Сам снимок мы видим, но он не в нашем контексте, поэтому сорян, у нас нет здесь власти.

Технически ничего не мешает одновременно делать снимки с помощью vssadmin и diskshadow. Хотя есть вероятность, что получите сообщение типа Another shadow copy is in progress. Но это так, к слову пришлось. Не надо пытаться одновременно делать несколько снапшотов разными программами.

Как появился VSS

Итак, судя по написанному выше, всё просто: нам надо просто брать появляющиеся блоки и сохранять их куда-то в сторонку, чтобы при необходимости вынимать обратно. Сразу возникает первый вопрос: а что именно надо сохранять в нашем теневом хранилище? Ведь действительно, можно просто писать в него все приходящие новые блоки и сохранять в метаданные, на какое место они (блоки) должны были быть записаны. А можно поступить чуть сложнее и записывать новые блоки сразу на полагающееся им место, а в хранилище отправлять содержимое перезаписываемых блоков. Что лучше и как выбрать? На самом деле право на жизнь имеют оба варианта, и какой выбрать - зависит исключительно от воли вендора. Первый подход (redirect-on-write, RoW, если оперировать грамотными терминами) быстро пишется, но долго читается. Зато если надо откатиться на первоначальное состояние, это делается моментально - мы просто удаляем наше теневое хранилище. Второй подход (copy-on-write, CoW) пишется медленней, читается быстрее и моментально удаляет копии предыдущих состояний. VSS, к слову, придерживается парадигмы CoW, а в снапшотах VMware реализован RoW.

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

Давайте рассмотрим хрестоматийную ситуацию с файлом базы данных. (И если у вас уже заскрипел песок на зубах, смело пропускайте следующие два абзаца.) Итак: у нас есть банальная SQL Server база данных в виде mdf файла, и тут к нам прилетает какой-то запрос. SQL, как порядочное приложение, начинает старательно вносить изменения в файл, а мы старательно перехватываем каждый новый блок данных падающих на диск и пишем в нашу теневую копию. Всё хорошо и здорово, но тут выключили свет. Потом свет включили, сервер запустили и мы даже базу восстановили из нашей теневой копии, но тут оказывается, что SQL не запускается. Говорит - база в не консистентном состоянии. Это значит следующее: во время нормальной работы завершение каждой транзакции помечается специальным флагом. Сервер его видит и знает, что всё хорошо. А тут сервер загружается, видит, что из его базы торчит какой-то кусок данных, флага нет и, следовательно, что с этим всем делать - он понятия не имеет. То ли удалить, то ли дописать, то ли ещё что-то. Но у нас тут не угадайка, а всё должно быть однозначно и консистентно. Поэтому он принимает решение выключиться, дабы не поломать базу ещё сильнее.

Хорошо, но как избежать подобных приключений? Отличным вариантом будет подождать, пока SQL сервер допишет свою транзакцию, пометит её как завершённую, и потом мы быстренько заберём все появившиеся новые блоки. Отличный вариант, который надо срочно реализовывать! Вот только есть небольшая проблема: до этого мы говорили про одно приложение и один файл, с которым оно работает. Научиться общаться с условным SQL Server много ума не надо, но что делать с остальными миллиардами существующих приложений? А что делать, в конце концов, с самой ОС, у которой внутри огромное количество своих процессов и открытых файлов? Вот примерно с такими проблемами и столкнулись учёные мужи из Microsoft, когда пришли к выводу, что надо реализовать некий общий интерфейс, через который можно будет сразу всем прокричать нечто вроде: Сейчас мы будем делать снапшот, так что быстренько сворачиваемся и сбрасываем буфера на диск! Приостанавливайте свою кипучую деятельность и приводите данные в консистентный вид!. Ну а назвать эту штуку они решили, как вы уже догадались, Volume Snapshot Service. Или просто VSS.

И тут можно воскликнуть - но ведь в Windows 2008 был представлен Kernel Transaction Manager! Это разве не то же самое? Он же как раз занимается тем, что приводит файлы на диске в консистентное состояние. А вот и нет! То есть да, KTM приводит, но отвечает только за дисковые операции, а что там происходит с приложениями - его мало волнует. А ведь многим из этих приложений важна не просто целостность файлов, но и что в них записано. Классический пример - это Exchange и Active Directory. И тут мы подошли к важной теме:

Как устроен VSS

Чтобы не прыгать с места в карьер громады страшных терминов и процессов, начнём с высокоуровневого описания. Поэтому ограничимся таким списком компонентов:

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

    Райтер занимается тем, что выстраивает мостик взаимодействия между VSS подсистемой и конкретным приложением. Поэтому а) в любой системе их будет достаточно много (проверьте у себя с помощью vssadmin list writers) б) райтер всегда пишется поставщиком приложения, ибо кроме него никто не знает, что там и как должно происходить во время создания снапшота.

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

    Также хочется отметить, что райтеры - это какие-то невероятно нежные ребята, которые зачастую ломаются без каких-либо внешних признаков. Поэтому если в выводе vssadmin list writers в поле State вы увидите что-то, отличающееся от Stable, это надо чинить, ибо сделать консистентный бекап, увы, не получится.

  • VSS Provider. Тот самый парень, который занимается созданием и управлением снапшотами. Известен тем, что бывает софтовый или хардовый. Список установленных в системе провайдеров можно посмотреть с помощью команды vssadmin lisrt providers. По дефолту, с системой идет Microsoft Software Shadow Copy provider. Он даже отлично и замечательно работает, но до тех пор, пока вы не подключите к системе брендовую СХД. Хорошие вендоры всегда снабжают свои железки управляющим софтом, в составе которого находится и родной провайдер к этой железяке. Благодаря этому можно уже делать всякие хитрые трюки, которые реализованы в вашем оборудовании, и именно поэтому мы в Veeam так гордимся списком интеграций с железом.

  • VSS Requestor. Участник процесса, который инициирует создание VSS снапшота или восстановление данных. Можно сказать, что реквестор - это бекапное приложение, которое общается с райтерами и провайдерами. Может показаться, что его роль незначительна, однако от грамотности реализации реквестора зависит качество получаемого результата. То есть VSS не будет за вас думать, что и в каком виде надо сделать. Чем более чёткие инструкции выдаст реквестор, тем более предсказуемым будет результат.

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

Но на деле, очевидно, всё несколько сложнее. На первом шаге реквестор проверяет, что вообще есть в наличии и с кем предстоит общаться. Затем после составления списка райтеров он обращается к провайдеру, объясняя, что он хочет заснапшотить и где должен располагаться снапшот. Это называется SnapshotSet. В большинстве случаев он будет располагаться на том же вольюме, что и оригинальный диск. А меньшинство случаев - это те самые хардварные провайдеры, которые поставляются вместе с СХД. Для них нормой считается создавать отдельный вольюм для снапшота, который называется storage snapshot. А в определённых случаях можно так и вообще перемещать снапшот на другое физическое устройство, чтобы выкачивать данные уже оттуда, а не с прода. Без хардварных провайдеров сделать такое не выйдет.

Следом начинается стадия, именуемая Prepare for backup. На этом этапе мы должны уже не просто изучить метаданные райтеров, а запросить их реальные статусы и приготовиться к самой жаркой поре: все райтеры должы будут отработать один за другим. Причём каждый должен уложиться в отведённое ему время, которое по умолчанию равно 60 секундам. Так решили в Microsoft, забыв уточнить причины. Но есть ещё приложения-чемпионы, например, Exchange. Его авторы посчитали, что 20 секунд более чем достаточно, и остановились на таком лимите. А чем чревато невыполнение этого этапа, который в документации называется OnFreeze? Тем, что райтер вернёт сообщение об ошибке, и снапшот не будет сделан. После чего в интерфейсе Veeam появится одна из каноничных ошибок вроде VSSControl: Failed to freeze guest, wait timeout". Тут радует одно: в логах VSS всегда будет написано, какой именно райтер завалил задание. А по самим ошибкам уже столько KB написано, что вспоминать страшно. Но если вы вдруг сомневаетесь, то точно вам говорю - написанному в них можно смело верить. И если после всего получается, что у вас слишком медленное хранилище, и за отведённое время не получается сбросить все кэши на диск, ну, значит, так оно и есть. Физику не обманешь, а вот железо надо хоть иногда обновлять.

Но это был пессимистичный вариант (прошу понять меня правильно, но беды с VSS - это очень частная причина обращений в сапорт), а в оптимистичном можно начинать самый важный этап. Как только райтеры рапортуют, что всё, вся деятельность в системе заморожена, а кеши сброшены на диск, у нас есть десять(!!!) секунд на создание снапшота, после чего райтеры будут принудительно разморожены, и всё закрутится вновь. И можно сказать, что на этом процесс бекапа заканчивается, и всё что нужно - это просто импортировать наш снапшот и скачать его куда-то к себе, чтобы сохранить под семью замками. Однако есть одно важное Но - log truncate. Фундаментально это вообще не связанные операции и транкейт зависит только от бекапа логов, но как все мы понимаем - на пользовательском уровне эти вещи связаны в единый процесс. То есть, прежде чем выкачивать снапшот, надо не забыть выдать команду backup log, которая запустит операцию транкейта. И после этого совесть наша чиста.

Но что дальше происходит с данными? Если мы действительно используем какое-то приложение для бекапов, которое запустило весь этот процесс, дождалось его завершения и скачало данные в своё хранилище, то снимок можно просто удалить одной командой. Поскольку VSS пропагандирует CoW подход, то речь здесь действительно о банальном удалении нашей аллоцированной зоны, ведь все новые данные сразу пишутся на оригинальный диск. Это называется non-persistent shadow copy, и она не имеет никакого смысла без оригинального диска.

Чтобы пройти этот путь вручную, достаточно открыть консоль и набрать:

PS C:\Windows\system32> diskshadowMicrosoft DiskShadow version 1.0Copyright (C) 2013 Microsoft CorporationOn computer:  VEEAM,  17.05.2021 19:18:44DISKSHADOW> add volume c: # добавляем в задание диск СDISKSHADOW> create# создаём снапшотAlias VSS_SHADOW_1 for shadow ID {a1eef71e-247e-4580-99bc-ee62c42221d6} set as environment variable.Alias VSS_SHADOW_SET for shadow set ID {cc9fab4d-3e7d-44a5-9a4d-0df11dd7219c} set as environment variable.Querying all shadow copies with the shadow copy set ID {cc9fab4d-3e7d-44a5-9a4d-0df11dd7219c}        * Shadow copy ID = {a1eef71e-247e-4580-99bc-ee62c42221d6}               %VSS_SHADOW_1%                - Shadow copy set: {cc9fab4d-3e7d-44a5-9a4d-0df11dd7219c}       %VSS_SHADOW_SET%                - Original count of shadow copies = 1                - Original volume name: \\?\Volume{7fd0c79d-0000-0000-0000-602200000000}\ [C:\]                - Creation time: 17.05.2021 19:19:45                - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2                - Originating machine: veeam.university.veeam.local                - Service machine: veeam.university.veeam.local                - Not exposed                - Provider ID: {b5946137-7b9f-4925-af80-51abd60b20d5}                - Attributes:  Auto_Release DifferentialNumber of shadow copies listed: 1

Здесь мы видим, что успешно создался снапшот со своим Shadow copy ID, и для удобства ему сразу присвоили алиас VSS_SHADOW_1. Этими данными вполне можно оперировать, если возникает такое желание. Однако не будем уходить в сторону и попробуем прочитать содержимое этого снимка. Для чего подмонтируем его в качестве диска.

DISKSHADOW> expose {a1eef71e-247e-4580-99bc-ee62c42221d6} Z:The shadow copy is a non-persistent shadow copy. Only persistent shadow copies can be exposed.

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

DISKSHADOW> delete shadows all # или только нужный IDDeleting shadow copy {a1eef71e-247e-4580-99bc-ee62c42221d6} on volume \\?\Volume{7fd0c79d-0000-0000-0000-602200000000}\ from provider {b5946137-7b9f-4925-af80-51abd60b20d5} [Attributes: 0x00420000]...Number of shadow copies deleted: 1

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

DISKSHADOW> add volume C:DISKSHADOW> set context persistent # вот этот моментDISKSHADOW> createAlias VSS_SHADOW_1 for shadow ID {346d896b-8722-4c01-bf01-0f38b9abe20a} set as environment variable.Alias VSS_SHADOW_SET for shadow set ID {785983be-e09d-4d2a-b8b7-a4f722899896} set as environment variable.Querying all shadow copies with the shadow copy set ID {785983be-e09d-4d2a-b8b7-a4f722899896}        * Shadow copy ID = {346d896b-8722-4c01-bf01-0f38b9abe20a}               %VSS_SHADOW_1%                - Shadow copy set: {785983be-e09d-4d2a-b8b7-a4f722899896}       %VSS_SHADOW_SET%                - Original count of shadow copies = 1                - Original volume name: \\?\Volume{7fd0c79d-0000-0000-0000-602200000000}\ [C:\]                - Creation time: 17.05.2021 19:38:45                - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3                - Originating machine: veeam.university.veeam.local                - Service machine: veeam.university.veeam.local                - Not exposed                - Provider ID: {b5946137-7b9f-4925-af80-51abd60b20d5}                - Attributes:  No_Auto_Release Persistent DifferentialNumber of shadow copies listed: 1

Как мы видим: Attributes: No_Auto_Release Persistent Differential. Поэтому если теперь вы сделаете expose, то снапшот примаунтится как полноценный диск, по которому можно перемещаться и копировать с него файлы. Диск, само собой, виртуальный и состоит из блоков оригинального диска, плюс блоки изменившихся данных, читая которые, мы можем видеть состояние оригинального диска на момент снапшота. Всё просто.

Только учтите, пожалуйста, такой момент, если вдруг решите, что нашли святой грааль: в таком режиме нельзя занимать данными больше 50% места на диске. Один блок свыше - и всё, диск переполнился.

Что тут хочется ещё сказать, а вернее, спросить: если всё так просто, то почему же я говорю, что всё так сложно? Проблема в том, что, отдавая на боевом сервере команду vssadmin create shadow, мы, конечно, создаём какой-то снимок, но как себя будут чувствовать приложения после отката на этот снимок, мы предсказать не можем. Это не шутка: команда create признаёт наличие ошибок при выполнении как вариант нормы. Райтер не вернул вовремя Ок от приложения? Да кому это надо, го делать снапшот, я создал.

Поэтому когда за дело берётся настоящее бекапное приложение вроде Veeam Backup & Replication, то речь идёт не об одной команде, а о целой россыпи предварительных запросов, в результате которых формируется огромнейшая команда (это не метафора для красного словца, а реальность), в которой учитываются состояния райтеров и приложений на целевой системе, с жестким требованием соответствия всех статусов необходимым. Словом, количество мест, где что-то может пойти не так, вырастает на порядок. Ведь нам главное - не снапшот создать, закрыв глаза на сопутствующие потери, а гарантировать консистентность данных внутри него.

Как лечить VSS

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

Другая проблема - это железо. Помните про временные рамки для райтеров? Про десять секунд на снапшот? Для многих это ограничение становится проблемой из-за того, что СХД физически не успевает сделать требуемые действия за отведённое время. Как это лечится? А вот никак. Или покупаем более мощное железо, или ищем пути снижения нагрузки, чтобы операция была проведена за выделенный промежуток времени.

Если посмотрите одно из самых популярных KB1680: VSS Timeout when backing up Exchange VM, то легко обнаружите, что первые три шага для решения всех проблем с VSS - сделайте снапшот вручную и посмотрите чтобы это заняло менее 20 секунд, перезагрузитесь и попробуйте снизить нагрузку. Вот так и живём, да.

И что же делать, если VSS падает, в ивентах ничего нет, а понять, что происходит надо? Тут я могу порекомендовать три хороших статьи:

  • КВ от Veeam, посвящённое анализу поведения VSS с помощью diskshadow.

  • Другое KB от Veeam, посвящённое сбору информации с помощью vsstrace из Windows SDK. Но скажу сразу, это уже не для слабых духом.

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

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

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

Подробнее..

Антистресс для твоего сервера. Тестируем балансировщик нагрузки от Timeweb

07.06.2021 16:20:09 | Автор: admin

Привет, Хабр!


Сегодня мы расскажем сообществу о запуске нашего нового сервиса балансировщик нагрузки.

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

Ребята, почему только сейчас?


Можете вполне резонно спросить вы. Мы, как и все, привыкаем к новой, постпандемийной (или еще нет?), реальности и отвечаем запросам наших клиентов.

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

Особенно актуальна услуга будет, когда одна VDS уже не справляется с нагрузкой или вы просто хотите повысить отказоустойчивость приложения.

Как это работает?


Балансировщик переправляет клиентские запросы на доступные рабочие серверы из группы. Регулярно опрашивая состояние серверов, балансировщик понимает, какие серверы активны и доступны для обработки клиентских запросов.

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

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

Окей, это всё понятно, а как попробовать?


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

В правилах переадресации задаем параметры проброса трафика, указываем входящий и исходящий порт, а также протокол трафика из доступных: tcp, https, http, http2.



Далее вы можете выбрать один из двух доступных алгоритмов балансировки: Round Robin или Least Connections.

Какой алгоритм выбрать?


Round Robin алгоритм, при котором серверы перебираются по кругу: первый запрос передается на первый сервер, следующий на второй сервер, и так далее до последнего сервера, после чего цикл начинается заново.

Least Connections алгоритм, при котором каждый новый запрос передается на сервер с меньшим количеством активных подключений.

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

Теперь остается только выбрать ваши VDS или указать IP-адреса серверов. Кстати, вы можете использовать балансировщик не только с нашими VDS. Мы будем только за!

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

Всю работу по мониторингу и обеспечению доступности серверов, на которых находится балансировщик, мы берем на себя.

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

Да начнется беспощадный бета-тест!



Подробнее..

Инженеры technical support и места, где они обитают

08.06.2021 10:08:20 | Автор: admin

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

Так что да, эта статья скорее для тех, кто начинает - о том, как может быть на самом деле (нежели для прошедших горнило замены картриджей и теперь пугающих этим молодёжь).

Что за человек такой - инженер Technical Customer Support в Veeam Software?

В идеальном мире это тот самый универсальный человек, требования к которому сформулированы сухим кадровическим текстом в описании вакансии. И швец, и жнец, и на дуде игрец. Вот только есть одна небольшая проблема его не существует. Так что если вы не знали, то держите первое открытие за сегодняшний день: вакансии, как правило, пишутся под идеального кандидата в вакууме, которого никто никогда не видел. А если даже такой вдруг покажется на горизонте, то его с руками оторвут. Отсюда вывод: если вы не подходите под все пункты в описании вакансии, это нормально, и можно смело откликаться. Если только пропущенные пункты не помечены как критически важные. Тут уж действительно мимо.

Но вернёмся к нашему инженеру техподдержки в Veeam. И да, это наш блог, так что простите, но пишем мы про то как всё устроенно именно у нас, а не у соседей. Так вот, все его навыки можно объединить в три группы: это технические скилы, знание языка и умение общаться с клиентами. Сразу возникает вопрос: а что важнее? Можно же взять сисадмина и научить его разговорному английскому. Или выпускника филфака за недельку натаскать по книжкам а-ля VMware for Dummies. А самого последнего грубияна - отправить на курсы придворного этикета, где его научат родину любить и вилкой с ножом пользоваться, и с людьми вежливо общаться. Но вас тут ждёт большое разочарование: мы в Veeam ищем комбинацию всех трёх навыков в одном человеке. Любой и каждый желающий вступить в наши стройные ряды обязательно проходит все три этапа отбора. К нам трудно попасть, легко потерять и . ну вы и сами знаете.

На практике этапы отбора могут идти вразнобой, но давайте представим, что первым будет техническое собеседование. И как вы думаете, что же можно спросить у кандидата, если твои продукты - это корпоративный софт, и вероятность того, что кандидат их хотя бы видел, крайне мала? Про то, что он их использовал хотя бы в рамках домашней лаборатории, даже фантазировать не будем. Правильно, спросить можно всё что угодно, только не про сам софт. Поэтому техническое собеседование -- это разговор про IT-кругозор кандидата и имеющиеся у него навыки. Вся наша работа строится вокруг множества технологий. Среди них гипервизоры VMware и Hyper-V, Nutanix AHV, Azure, AWS, Oracle, SAP HANA и так далее. Но мы не ожидаем, что кандидаты знают их так же, как и мы. Нет, но если они могут хоть как-то поддержать разговор про виртуальные машины, то им сразу плюсик в карму, тут без сомнений. И мы не ожидаем, что они могут хотя бы час заливаться соловьём, сравнивая особенности работы корпоративных СХД. Или что готовы без запинки объяснить разницу между Ms SQL, MySQL, Oracle и Redis. Нет, ничего такого знать совершенно не требуется. Всему, что надо будет, проще потом научить, но вот базу кандидаты знать обязаны.

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

Далее следует проверка уровня владения иностранным языком. Возьмём для примера английский, как самый популярный. (Хотя у нас бывают вакансии и для знающих французский, немецкий и вообще примерно любой, отличный от русского. Но не суть.) Суть в том, что самый частый вопрос в нашу сторону, само собой, про необходимый уровень языкового навыка. И самое типичное уточнение от кандидатов: Ну я документацию нормально читаю. В принципе. А пару раз даже писал в зарубежный саппорт письма. Ну что же, ты большой молодец. Спору нет. Однако есть проблема: этого объективно мало. Наш инженер должен уметь разговаривать с клиентами ртом.

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

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

Из всего вышесказанного вывод язык надо знать на разговорном уровне. Пусть и не идеально грамматически, пусть без RP-прононса, но наш инженер должен смело говорить Welcome, понимать, что ему говорят, и не запинаясь говорить в ответ. Это называется поддерживать диалог. По нашим наблюдениям, такие знания начинаются на уровне intermediate и есть практически у всех, кого стандартные языковые тесты оценивают как upper-intermediate. Но не переживайте, мы не доверяем оценку навыков бездушным тестам. Ведь основная задача любого теста - это проверить способность человека проходить этот тест, а не выявить его реальный уровень знаний. Поэтому основное заключение здесь дают наши внутренние преподаватели английского, проводящие интервью. И, надо признать, на этом этапе проваливается довольно много кандидатов. Но давайте будем честными сами с собой: без английского в наше увлекательное время в IT-индустрии приходится довольно туго.

И завершающим этапом служит так называемый customer care. Вещь пока малоизвестная по стране в целом, но очень важная для всех, кто работает с западными рынками. Заключается она не только в умении быть вежливым и красиво выходить из любой ситуации, но и в том, чтобы любить человека как класс. Чтобы даже самый лютый негативщик сиял от радости после общения с нашим специалистом. Тут ведь штука какая: к нам крайне редко звонят, чтобы просто сказать спасибо за наш супер-крутой софт и отличный сервис. Обычно на звонок людей побуждает наличие какой-то проблемы, которую надо решить здесь и сейчас. То есть звонящий априори раздражён, ему плохо, и он совершенно не против на ком-то сорваться. Возможно, даже поорать. И вот тут ваши навыки общения, умение оставаться вежливым и искреннее желание помочь человеку с его бедой выходят на первый план. И вы не поверите, но мы и этому всему научим, а на входном тестировании кандидатов интервьюируют люди, профессионально занимающиеся проблемами customer care. (Да, бывают и такие.)

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

А теперь зайдем с другой стороны

Чего ради такому замечательному специалисту идти работать к нам в техподдержку? Пусть даже в гордом звании инженера.

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

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

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

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

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

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

Youre in the army now

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

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

Само собой, первым делом ему выделят ментора и начнут подтягивать уровень технических знаний по всем необходимым нам областям. Это гипервизоры, сети, различные операционки, СУБД, СХД, облака и многое другое. Даже если он решит уволиться спустя эти три месяца, с таким набором знаний его с руками отрывают в любую купи-продай контору на должность старшего сисадмина. Но так скоропостижно увольняются только уверенно придерживающиеся методологии Сам Себе Злобный Буратино. Настоящий инженер уже почувствовал, что в IT-мире бывают интересные и нетривиальные задачи, за решение которых платят приятную зарплату, поэтому зачем опять идти торговать помидорами?

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

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

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

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

Итого

Инженер техподдержки, как видите, это не низшее звено в цепи эволюции IT специалиста, а серьёзная работа. Ведь в первую очередь он всё-таки инженер. А как и в любой инженерной специальности, тут всё зависит исключительно от человека. Захочет станет признанным мастером своего дела и посвятит ему всю жизнь. И не важно, будет это работа у станка или со временем захочется научиться руководить другими инженерами. Хороший специалист никогда не пропадёт, а его работа должна (и будет) хорошо оплачена. А даже если со временем он решит кардинально сменить профиль деятельности, то всегда можно легко это сделать, с блеском применяя полученные ранее знания и умения.

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

Сокращённая версия этой статьи была залита ещё и на хх.

Подробнее..

Аварии как опыт 3. Как мы спасали свой мониторинг во время аварии в OVH

09.06.2021 12:21:23 | Автор: admin

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

О мониторинге у нас

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

1. Blackbox-мониторинг для проверки состояния сайтов. Цель проста собирать статистику с определенных endpointов и проверять их состояние по тем условиям, которые требуется установить. Например, это может быть health page в виде JSON-страницы, где отражено состояние всех важных элементов инфраструктуры, или же мониторинг отдельных страниц сайта. У нас принято считать, что данный вид мониторинга самый критичный, так как следит за работоспособностью сайта/сервисов клиента для внешних пользователей.

Вкратце о технической стороне этого мониторинга: он выполняет запросы разного уровня сложности по HTTP/HTTPS. Есть возможность определять размер страницы, ее содержимое, работать с JSON (они обычно используются для построения status page-страниц приложений клиента). Он географически распределен для повышения отказоустойчивости и во избежание всевозможных блокировок (например, от РКН).

Работа данного мониторинга не была затронута аварией благодаря геораспределенности (к тому же, у него вообще нет инсталляций в OVH).

2. Мониторинг Kubernetes-инфраструктуры и приложений клиента, запущенных в ней. С технической точки зрения этот мониторинг основан на связке Prometheus + Grafana + Alertmanager, которые устанавливаются локально на кластеры клиента. Часть данных, собираемых на данных системах мониторинга (например, метрики, напрямую связанные с Kubernetes и Deckhouse), по умолчанию отправляется в нашу общую систему, а остальные могут отправляться опционально (например, для мониторинга приложений и реакции от наших дежурных инженеров).

3. Мониторинг ресурсов, которые находятся вне кластеров Kubernetes. Например, это железные (bare metal) серверы, виртуальные машины и СУБД, запущенные на них. Данную зону мониторинга мы покрываем с помощью стороннего сервиса Okmeter (а с недавних пор уже не очень-то для нас и стороннего). Именно его работа была фатально нарушена в момент аварии OVH.

(А о том, как осуществляется дальнейшая обработка инцидентов, поступающих от всех упомянутых систем, мы рассказывали в этом докладе.)

Таким образом, все проблемы, описанные ниже, связаны с недоступностью одной из используемых систем Okmeter. То есть на некоторое время мы потеряли информацию о некоторой инфраструктуре (вне Kubernetes-кластеров), сохранив при этом доступность blackbox-мониторинга (который гарантирует нам, что главные бизнес-функции работают).

Как мы справлялись с этой аварией? Какие шаги предпринимали во время инцидента? И какие после?

Первые признаки аварии

Проверка доступности внешних средств мониторинга осуществляется с применением метода Dead mans switch (DMS). По своей сути это мониторинг, который работает наоборот:

  • Создается поддельный алерт OK, означающий, что всё хорошо, и он постоянно отправляется с локальных мониторингов (Prometheus, Okmeter и т.п.) в нашу систему инцидент-менеджмента.

  • Пока с мониторингом действительно всё хорошо, алерт OK активен, но в системе не показывается.

  • В обратной ситуации, когда возникают проблемы с мониторингом, алерт OK перестает быть активным, из-за чего автоматически создаётся алерт ERROR о неработающем мониторинге. И вот уже на него надо реагировать.

Данная проверка очень эффективна в ситуациях, которая произошла в роковой день (10 марта): первый алерт о проблеме (ERROR) мы получили как раз от DMS.

События разворачивались следующим образом:

  • Первое сообщение о проблеме алерт от DMS, полученный приблизительно в 3:20 ночи по Москве.

  • Связываемся с коллегами из Okmeter и узнаем, что они испытывают проблемы с ЦОД, в котором расположены. Детальной информации на данный момент не получаем, из-за чего масштабы аварии нам неизвестны. Кроме того, дежурный инженер видит, что у нас корректно работают другие системы мониторинга (blackbox и Kubernetes). Поэтому принимается решение отложить инцидент до утра.

  • Утром (в 8:14) становится известно, что ЦОД сгорел, а Okmeter не будет доступен до тех пор, пока не восстановит свою инфраструктуру в другом ЦОД.

Здесь также стоит остановиться подробнее на том, как была устроена инфраструктура у Okmeter. Основные её компоненты находились в дата-центрах OVH:

  • SBG-2 который был полностью уничтожен пожаром;

  • SBG-1 который был частично поврежден и обесточен.

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

Руководствуясь этой информацией утром 10 марта, мы сделали вывод, что нужно срочно замещать важные для нас функции Okmeter хоть какими-то решениями на временной основе.

Первые действия

В компании была собрана специальная команда, основными целями которой являлись:

  1. Определение масштабов аварии;

  2. Поэтапное планирование, как устранять последствия инцидента;

  3. Дальнейшее внедрение полученных решений.

В неё вошли тимлиды наших DevOps-команд, инженеры нашей платформенной команды и CTO компании. Позже к ней также добавились отдельные инженеры, помогавшие со срочной разработкой и тестированием новых инструментов, заменивших критичные проверки от Okmeter.

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

Матрица критичности алертовМатрица критичности алертов

Эта матрица распространяется на события из всех 3 используемых у нас систем мониторинга. Каждому инциденту, зафиксированному в любой из систем, назначается критичность от S1 (полная потеря работоспособности компонента системы) до S9 (диагностическая информация). Большая часть алертов с критичностью S1 это blackbox-мониторинг, который проверяет состояние сайтов клиента. Однако также к этой категории относится и незначительная часть алертов, отправляемых со стороны Okmeter (подробнее о них см. ниже). Другая незначительная часть приходится на S2, а все остальные имеют более низкую критичность (S3 и т.п.).

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

Оповестив всех клиентов, инфраструктуру которых задела авария у Okmeter, мы приступили к составлению плана восстановления.

Порядок и план восстановления алертов от Okmeter

Первая очередь алертов: S1-S2

Итак, какие именно критичные алерты мы потеряли с недоступностью Okmeter? Чтобы оперативно собрать эту информацию, каждая команда инженеров тех, что сопровождают проекты с мониторингом от Okmeter, подготовила статистику алертов, приходивших с 1 июля 2020 года.

Получился следующий список:

  1. Различные алерты для СУБД.

    1. Проверка работоспособности СУБД в целом (запущен ли процесс).

    2. Состояние репликации.

    3. Состояние запросов к БД (например, сколько запросов находятся в ожидании).

  2. Дисковое потребление на виртуальных машинах.

  3. Доступность виртуальных машин в целом.

Вторая очередь алертов: S3 и далее

Ситуация с алертами категории S3 была проще: их меньше, они менее критичные, да и вообще эта категория оказалась не у всех команд.

По итогам этого аудита получилась вторая очередь. Она в основном состояла из проверок доступности менее критичных серверных приложений, таких как ZooKeeper.

Немного магического Bash

Чтобы реализовать замену проверкам и алертам Okmeter, требовалось уметь деплоить на все серверы актуальные скрипты мониторинга, чтобы поддерживать их в актуальном состоянии. Реализация: с помощью Ansible-плейбуков мы задеплоили все необходимые скрипты, среди которых был скрипт автообновления. Последний раз в 10 минут загружал новые версии других скриптов. Из-за очень сжатых сроков основную часть скриптов мы писали на Bash.

Общий подход получился следующим:

  1. Сделали shell-скрипты, которые запускались на виртуальных машинах и bare metal-серверах. Помимо своей основной функции (проверка работоспособности некоторых компонентов) они должны были доставлять сообщения в наш мониторинг с такими же лейблами и другими элементами, как и у Okmeter: имя триггера, его severity, другие лейблы и т.д. Это требовалось для сохранения той логики работы мониторинга, которая была и до падения. В общем, чтобы процесс работы дежурных инженеров оставался неизменным и чтобы работали прежние правила управления инцидентами.

    Быстрой реализации этого этапа способствовал тот факт, что у нас уже были готовые инструменты для работы с API мониторинга внутренний инструмент под названием flint (flant integration).

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

  3. В течение некоторого времени мы дополнительно проверяли, что алерты корректные, а сами скрипты выполняются правильно.

Результаты

На полную реализацию этого временного решения нам понадобился один рабочий день для алертов типа S1-S2 и еще один для S3. Все остальные инциденты (с более низким приоритетом) команды добавляли в индивидуальном порядке по мере необходимости.

В общей сложности новые скрипты были задеплоены примерно на 3000 хостов.

На каждом этапе решения проблемы мы подробно информировали клиентов о ходе восстановительных работ:

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

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

Выводы

Для нас данная авария стала показательным случаем и проверкой основных процессов, которые мы выстраиваем в компании: инцидент затронул все команды, практически каждого инженера и сотрудника компании. Основной вывод оказался банален: слаженная командная работа вместе с четким, структурированным планом действий (DRP) позволяет решать задачи любой сложности в очень сжатые сроки. И это по-настоящему ценно в те редкие моменты, когда разваливается гораздо больше, чем вы могли себе представить запланировать.

Более практичные выводы таковы:

  1. Если сервис требует повышенной отказоустойчивости, всегда важно разделять инфраструктуру не только на уровне разных ЦОД, но и географически. Казалось бы, разные ЦОДы у OVH? А в реальной жизни они горели вместе

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

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

P.S.

Читайте также в нашем блоге:

Подробнее..

ISPmanager 6. Что нового?

10.06.2021 20:10:36 | Автор: admin

Обзор версии ISPmanager 6


О панели ISPmanager, ее достоинствах и возможностях, кажется, знают все это одно из самых популярных решений для управления VPS и серверами на базе Linux.

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

Что такое ISPmanager?


Сначала поговорим немного о сути сервиса, как он работает.

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

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

Первая версия ISPmanager вышла в 2013 году, и с тех пор продукт активно развивается. За этот период разработчики внесли более 1500 изменений и более чем в пять раз расширили кодовую базу. Команда ISPsystem оперативно подстраивается под новые модули, операционные системы и дополнительные инструменты. ISPmanager 5 начал поддерживать:

  • Ubuntu 18.04 и 20.04,
  • CentOS 8,
  • Stream,
  • Debian 10.

Также подключились сервисы:

  • PHP 7.3 и 7.4,
  • MySQL 8.0,
  • Fail2ban.

ISPmanager улучшает и качество шифрования: теперь пользователи могут работать через Lets Encrypt ACME v2 и DNSSEC; появились новые протоколы: HTTP 2.0 и преобразователь NAT.

ISPsystem работает и над улучшением интерфейса. Сегодня графический интерфейс ISPmanager выглядит современно и удобно.

Возможности ISPmanager


На данный момент ISPmanager предлагает:

  • неограниченное количество пользователей в любом тарифном плане;
  • установка прав доступа;
  • полный контроль над доменами: интеграция CMS, работа с редиректами, SSL-сертификатами и прочими техническими моментами;
  • редактирование и управление DNS;
  • работа с почтовыми системами;
  • создание и администрирование баз данных;
  • подключение пользователей по FTP к определенным директориям;
  • файрвол;
  • резервное копирование;
  • полная статистика;
  • разделение пользователей по правам доступа.

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

Итак, пришло время рассказать о новой версии продукта ISPmanager 6.

Главные изменения в ISPmanager 6


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

Основные изменения коснулись тарифной системы. Розничные цены повысились, однако для партнеров будут специальные предложения. На сайте ISPsystem представлены следующие версии:

  • Lite. Минимальная версия ограничивает количество сайтов до десяти. Остальные функции остались такими же, как и в ISPmanager 5.
  • Pro. Единственное отличие от Lite количество сайтов равняется 50.
  • Host. Пользователь может создавать неограниченное количество сайтов с такой же функциональностью, как и в предыдущих версиях.
  • Business. Самый продвинутый тариф со множеством дополнительных инструментов, таких как Cloudlinux (планируется добавление в Host), управление реселлерами, IP-адресами и так далее.

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

Ближайшие обновления


Хотя на данный момент кажется, что главные изменения только в тарифной системе, до конца 2021 года разработчики добавят множество новых инструментов, которых не было в ISPmanager 5.

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

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

Многие сервисы работают с Telegram, и ISPmanager 6 не исключение. В будущем оповещения о состоянии системы будут приходить прямо в мессенджер.

Ко всему прочему постепенно интегрируются:

  • Python (Django);
  • node.js;
  • OpenVPN;
  • GIT;
  • Lightspeed.

Работаете ли вы с ISPmanager или с другой панелью? Как впечатления?

Подробнее..

Перевод Знакомство с PromQL Cheatsheet

13.06.2021 12:23:01 | Автор: admin

Скачать Cheatsheet по запросам PromQL

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

Поскольку Prometheus хранит данные в виде временных рядов (time-series data model), запросы PromQL радикально отличаются от привычного SQL. Понимание, как работать с данными в Prometheus, является ключом к тому, чтобы научиться писать эффективные запросы.

Не забудьте скачать Cheatsheet по запросам PromQL!

Как работают time-series databases

Временные ряды это потоки значений, связанных с меткой времени.

Каждый временной ряд можно идентифицировать по названию метрики и меткам, например:

mongodb_up{}

или

kube_node_labels{cluster="aws-01", label_kubernetes_io_role="master"}

В приведенном выше примере присутствует имя метрики (kube_node_labels) и метки (cluster и label_kubernetes_io_role). На самом деле, метрики тоже являются метками. Приведенный выше запрос можно записать так:

{__name__ = "kube_node_labels", cluster="aws-01", label_kubernetes_io_role="master"}

В Prometheus есть четыре типа метрик:

  • Gauges(Измеритель) значения, которые могут меняться. Например, метрика mongodb_up позволяет узнать, есть ли у exporter соединение с экземпляром MongoDB.

  • Counters(Счетчик) показывают суммарные значения и обычно имеют суффикс _total. Например, http_requests_total.

  • Histogram (Гистограмма) это комбинация различных счетчиков, используется для отслеживания размерных показателей и их продолжительности, таких как длительность запросов.

  • Summary (Сводка)работает как гистограмма, но также рассчитывает квантили.

Знакомство с выборкой данных PromQL

Выбрать данные в PromQL так же просто, как указать метрику, из которой вы хотите получить данные. В этом примере мы будем использовать метрику http_requests_total.

Допустим, мы хотим узнать количество запросов по пути / api на хосте 10.2.0.4. Для этого мы будем использовать метки host и path из этой метрики:

http_requests_total{host="10.2.0.4", path="/api"}

Запрос вернет следующие значения:

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

98

http_requests_total

10.2.0.4

/api

503

20

http_requests_total

10.2.0.4

/api

401

1

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

Это называетсяinstant vector, самое раннее значение для каждого потока на указанный в запросе момент времени. Поскольку семплы берутся в случайное время, Prometheus округляет результаты. Если длительность не указана, то возвращается последнее доступное значение.

Кроме того, вы можете получить instant vector из другого отрезка времени (например, день назад).

Для этого вам нужно добавить offset (смещение), например:

http_requests_total{host="10.2.0.4", path="/api", status_code="200"} offset 1d

Чтобы получить значение метрики в пределах указанного отрезка времени, необходимо указать его в скобках:

http_requests_total{host="10.2.0.4", path="/api"}[10m]

Запрос вернет следующие значения:

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

641309@1614690905.515

641314@1614690965.515

641319@1614691025.502

http_requests_total

10.2.0.5

/api

200

641319@1614690936.628

641324@1614690996.628

641329@1614691056.628

http_requests_total

10.2.0.2

/api

401

368736@1614690901.371

368737@1614690961.372

368738@1614691021.372

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

Это называется range vector все значения для каждой серии в пределах указанного временного интервала.

Знакомство с агрегаторами и операторами PromQL

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

Представим, что у нас есть метрика node_cpu_cores с меткой cluster. Мы могли бы, например, суммировать результаты, объединяя их по определенной метке:

sum by (cluster) (node_cpu_cores)

Запрос вернет следующие значения:

cluster

value

foo

100

bar

50

С помощью этого простого запроса мы видим, что имеется 100 ядер ЦП для кластера cluster_foo и 50 для cluster_bar.

Кроме того, мы можем использовать в запросах PromQL арифметические операторы. Например, используя метрику node_memory_MemFree_bytes, которая возвращает объем свободной памяти в байтах, мы могли бы получить это значение в мегабайтах с помощью оператора деления:

node_memory_MemFree_bytes / (1024 * 1024)

Мы также можем получить процент доступной свободной памяти, сравнив предыдущую метрику с node_memory_MemTotal_bytes, которая возвращает общий объем памяти, доступной на узле:

(node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100

Теперь мы можем использовать этот запрос для создания оповещения, когда на узле остается менее 5% свободной памяти:

(node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100 < 5

Знакомство с функциями PromQL

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

topk(2, (node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100)

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

Представьте, что вы хотите узнать, сколько свободного места будет доступно на диске в следующие 24 часа. Вы можете применить функцию pred_linear к результатам за прошлую неделю из метрики node_filesystem_free_bytes, которая возвращает доступное свободное место на диске. Это позволяет прогнозировать объем свободного дискового пространства в гигабайтах в ближайшие 24 часа:

predict_linear(node_filesystem_free_bytes[1w], 3600 * 24) / (1024 * 1024 * 1024) < 100

При работе со счетчиками Prometheus удобно использовать функцию rate. Она вычисляет среднюю скорость увеличения временного ряда в векторе диапазона в секунду, сбросы счетчика автоматически корректируются. Кроме того, вычисление экстраполируется к концам временного диапазона.

Что делать, если нам нужно создать оповещение, которое срабатывает, если мы не получали запрос в течение 10 минут. Мы не можем просто использовать метрику http_requests_total, потому что при сбросе счетчика в течение указанного временного диапазона результаты были бы неточными:

http_requests_total[10m]

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

100@1614690905.515

300@1614690965.515

50@1614691025.502

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

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

100@1614690905.515

300@1614690965.515

350@1614691025.502

rate(http_requests_total[10m])

name

host

path

status_code

value

http_requests_total

10.2.0.4

/api

200

0.83

Независимо от сбросов за последние 10 минут в среднем было 0,83 запроса в секунду. Теперь мы можем настроить оповещение:

rate(http_requests_total[10m]) = 0

Что дальше?

В этой статье мы узнали, как Prometheus хранит данные, рассмотрели примеры запросов PromQL для выборки и агрегирования данных.

Вы можете скачать Cheatsheet по PromQL, чтобы узнать больше об операторах и функциях PromQL. Вы также можете проверить все примеры из статьи и Cheatsheet с нашим сервисом Prometheus playground.

Подробнее..

Автоматизация в центрах обработки данных

17.05.2021 12:14:39 | Автор: admin

В большинстве серверов HPE имеется встроенный контроллер управления Integrated Lights Out (iLO). Его первоначальное назначение удаленное управление сервером:
включение/выключение, перехват графической консоли, подключение медиа-устройств что и иллюстрирует название Lights-Out Свет выключен в ЦОД, где трудятся серверы HPE, администратору нет необходимости быть рядом. Все действия с серверами можно выполнить из любой точки мира. Функционал iLO постоянно расширялся и сейчас его можно назвать центром управления полетом сервера, фактически это мини-компьютер внутри большого компьютера. У iLO есть процессор, оперативная и флэш-память, Ethernet порт и, естественно, интерфейс управления: веб-браузер, командная строка, скрипты и программируемые интерфейсы REST API. Через REST API и осуществляется автоматизированное управление серверами HPE в соответствии со стандартом Redfish, пришедшим на смену устаревшему IPMI.

Следующий уровень управления инфраструктурой HPE программный продукт HPE OneView. Для стоечных и блейд-серверов c-Class это виртуальная машина (поддерживаются все основные гипервизоры), для платформы HPE Synergy это аппаратный модуль Composer. Управляется HPE OneView аналогично iLO: веб-интерфейс, скрипты и команды RESTful API / Redfish.

HPE OneView обеспечивает полное низкоуровневое управление серверной инфраструктурой: настройка BIOS, конфигурирование сетевых интерфейсов, подключение к SAN, создание томов на внешних системах хранения (HPE Primera, HPE Nimble, HPE 3PAR), контроль и обновление драйверов и микропрограмм. Все эти действия можно выполнять для одного или нескольких серверов, как используя консоль браузера, так и с помощью скриптов PowerShell или Python. Но самых интересных результатов можно достичь путем интеграции OneView со средствами развертывания операционных систем и приложений. В этом случае администратору вообще не нужно обращаться к OneView, все необходимые действия выполняются в вышестоящей консоли управления. Например, для среды VMware единой консолью служит vCenter, для Microsoft Windows Admin Center.

REST и Redfish

Если говорить о REST (Representational State Transfer), то он представляет собой обычный HTTP(s) запрос, передавая необходимые данные в качестве параметров запроса. В отличие от Redfish (более современной версии REST), REST никак не стандартизирован, он лишь является архитектурным стилем, позволяющим придерживаться определенных последовательностей, таких как запрос, тело запроса и параметры запроса. При этом какое дерево запроса, по какому стандарту передается тело запроса (JSON, XML или другой), каждый производитель решает на свое усмотрение. В итоге это привело к тому, что если пользователь работал с REST-интерфейсами от нескольких вендоров, то к ним требовался разный подход, а часто и разный набор кода, что не позволяло масштабировать решения основанные на REST-запросах.

В отличие от REST, Redfish является стандартизированным интерфейсом и позволяет работать пользователю с разными производителями с одинаковым подходом и тем самым, обеспечивать масштабируемость решения. В решениях HPE стандарт Redfish появился в ILO4 (v2.30) и более поздних продуктах.

Решение HPE по автоматизации (Deployment Automation Solution)

При преодолении определенной численности информационных систем и нарастании запросов со стороны бизнеса, сотрудники отдела сопровождения часто приходят к целесообразности автоматизации ежедневных, рутинных операций. Это помогает вводить и обслуживать информационные системы быстрее, а сотрудникам сконцентрироваться на более важных задачах. Обычно администраторы пытаются автоматизировать задачи собственными силами и привычными им средствами. В этом им помогает широкий набор инструментов (https://github.com/hewlettpackard/), таких как Ansible, Python, Puppet и других. При этом, как правило самостоятельно написанные скрипты приходится часто править, особенно при масштабировании решения в условиях продуктивной среды.

Deployment Automation Solution представляет собой услугу по настройке решения автоматизации ежедневных операций, построенного на открытом исходном коде, либо их коммерческих аналогов, которые уже используются на предприятии. Таким образом потребители решения смогут вносить правки, как в само решение, делая его более заточенным под конкретную организацию, так и добавлять в решение собственные наработки, тем самым расширяя функционал базового решения. Deployment Automation Solution основан на стандартных программных компонентах, таких как Ansible, для автоматизации и оркестрации, Nginx для предоставления библиотеки образов микрокодов, операционных систем и файлов конфигураций и GitLab как способ централизованной доставки скриптов и Ansible playbooks. Таким образом, использование стандартных отраслевых инструментов с помощью сценариев Ansible, связанных с базовым репозиторием кода и инфраструктурным конвейером DevOps с помощью GitLab делает подход системным, а масштабирование удобным. Большинство компонент работает в контейнерах, что дает возможность быстро развертывать и обновлять само решение.

Весь процесс взаимодействия построен на программно-определяемой инфраструктуре посредством использования существующих богатых функций OneView Ansible collection / REST API, предназначенных для среды управления HPE OneView, или Redfish / iLO для управляемых сред, без OneView, а также API-интерфейсов хранилищ данных. Также используются API конкретного программного производителя, например:

  • Ansible Playbooks от RHEL могут связываться с серверами Linux через SSH;

  • Подключение к VMware может осуществляться через REST API или SSH;

  • Связь с Windows может быть через WinRM.

Для удобства оркестрации решения и построения сложных рабочих процессов автоматизации используется AWX (https://github.com/ansible/awx, upstream project для Ansible Tower) или Ansible Automation Platform (https://www.ansible.com/integrations/infrastructure/hpe), для объединения и инкапсуляции атомарной инфраструктуры в виде базовых операций кода в рабочие процессы автоматизации для реализации задач выделения ресурсов и управления жизненным циклом. Этот модульный подход позволяет гибко настраивать интеграцию аппаратных и программных элементов решения. При этом AWX, или Ansible Automation Platform не является обязательным атрибутом. Все рабочие процессы доступны через REST API и могут быть вызваны из любого существующего решения, такого как HPE ServiceNow или Morpheus. решение достаточно гибкое, чтобы интегрироваться с порталом управления, выбранным каждым клиентом, и обеспечивает интеграцию с любым сторонним решением.

В базовом варианте решения HPE предоставляет два основных сценария использования:

  • Установка операционных систем, включая настройку аппаратных компонент: презентация томов СХД, настройка зонинга для SAN и т.д, а также программных компонент, включая настройки безопасности и манипуляции с ПО;

  • Обновление микрокодов, в том числе и без прерывания работы серверов.

При этом заказчик получит доступ к репозиторию с обновлениями playbooks для поддержки новых сценариев и компонент. Из коробки решение заточено под аппаратную платформу HPE, включая новейшие аппаратные ресурсы: DL Gen10, Synergy, Apollo и 3PAR / Primera / Nimble, однако открытый исходный код и поддержка разнообразных API позволит пользователям интегрировать решения сторонних производителей.

Заключение

Инфраструктура Hewlett Packard Enterprise предоставляет широкие возможности по автоматизации ежедневных ИТ-операций: подготовка и развертывание новых серверов, подключение к сетям передачи данных и системам хранения, установка операционных систем, контроль и обновление драйверов и firmware, реконфигурирование систем под изменяющиеся требования приложений. Заказчики сами выбирают уровень автоматизации: от простых сценариев групповых операций с iLO до решений Инфраструктура как код с HPE OneView и Ansible AWX / Automation Platform.

Подробнее..

Recovery mode Как ускорить сайт в 4 раза, просто перенастроив сервер

02.06.2021 12:04:43 | Автор: admin

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

Исходная ситуация

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

Поиск проблемы

Мы провели аудит настроек сервера и сайта, разделив работы на два этапа: анализ back-end и front-end, и обнаружили низкую скорость загрузки страниц на back-ende - порядка 80 секунд на самых посещаемых страницах, что в итоге приводило к существенному снижению конверсии.

Мы выяснили, что основная проблема заключалась в неправильно настроенном кэше и настройке базы данных.

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

Решение

Шаг 1. Настройка баз данных

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

Шаг 2. Смена типа хранения на InnoDB

Почему мы выбрали InnoDB?

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

Главное преимущество InnoDB заключается в скорости работы при выполнении запроса к базе InnoDB происходит блокировка только строки, при выполнении же запроса к базе MyISAM блокируется вся таблица. Дело в том, что пока запрос не будет выполнен, никакие другие обращения к таблице/строке будут невозможны. А поскольку строки значительно меньше целых таблиц, InnoDB обрабатывает запросы быстрее.

Также была произведена оптимизация работы самой базы данных InnoDB. Например, были оптимизированы параметры:

# InnoDB parameters

innodb_file_per_table

innodb_flush_log_at_trx_commit

innodb_flush_method

innodb_buffer_pool_size

innodb_log_file_size

innodb_buffer_pool_instances

innodb_file_format

innodb_locks_unsafe_for_binlog

innodb_autoinc_lock_mode

transaction-isolation

innodb-data-file-path

innodb_log_buffer_size

innodb_io_capacity

innodb_io_capacity_max

innodb_checksum_algorithm

innodb_read_io_threads

innodb_write_io_threads

Промежуточные результаты

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

Это в свою очередь привело к уменьшению потребляемой оперативной памяти.

Шаг 3. Перенастройка Nginx и установка модулей кэширования brotli, pagespeed, proxy_buffering

Nginx позиционируется как простой, быстрый и надежный сервер, неперегруженный функциями. Уже длительное время Nginx обслуживает серверы многих высоконагруженных российских сайтов, например, Яндекс, Mail.Ru, ВКонтакте и Рамблер. Для улучшения производительности при использовании дополнительных серверов, Nginx поддерживает буферизацию (proxy_buffering) и кеширование (proxy_cache), чем мы и воспользовались.

Не обошлось и без курьезов настроек Nginx. У клиента был обычный интернет-магазин с товарами, тогда как настройки буферизации, которые мы обнаружили во время аудита, позволяли ему быть чуть ли ни стриминговым сервисом. Мы существенно уменьшили значения в параметре client_max_body_size, что в совокупности с перенастройкой Nginx еще больше снизило потребление памяти.

Шаг 4. Оптимизация настроек PHP-FPM и Memcache и отключение Apache

PHP-FPM нередко используется в паре с веб-сервером Nginx. Последний обрабатывает статические данные, а обработку скриптов отдает PHP-FPM. Такая реализация работает быстрее, чем распространенная модель Nginx + Apache.

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

Необходимым шагом стал перевод работы PHP-FPM на unix socket. Зачем это понадобилось? Nginx сам по себе довольно быстрый веб-сервер, однако самостоятельно он не может обрабатывать скрипты. Для этого необходим бэкенд в виде PHP-FPM. Чтобы вся эта связка работала без потери скорости, мы использовали unix socket способ подключения к PHP-FPM, позволяющий избегать сетевые запросы и дающий значительный прирост в скорости работы сайта.

Результаты работ

1. Время отклика главной страницы уменьшилось с 24 секунд до чуть более 3 секунд, внутренних до 5-8 сек.

2. Уменьшилось потребление серверных ресурсов.

3. Стабилизировалось поведение сервера - он перестал зависать.

4. Глубина просмотров увеличилась на 30%, и как следствие, это дало улучшение в SЕО, а также последующих продаж: растут поведенческие показатели => растут позиции сайта в выдаче => растет трафик => растут продажи.

5. Клиенту были даны рекомендации по оптимизации front-end части сайта для ускорения работы сайта. Например:

  • оптимизировать графики и настройку выдачи изображений в формате webp;

  • настроить lazyload-загрузки данных;

  • вынести все некритические для отображения страницы скрипты в конец страницы.

Вывод

Мы ускорили сайт и устранили проблемы с его загрузкой без изменения кода. Скорость работы сайта влияет на многие показатели: начиная с удобства для пользователя и заканчивая ранжированием сайта в поисковой выдаче, что в конечно итоге сказывается на конверсии.

Подробнее..

Установка и настройка терминального сервера на Windows Server Оптимизация настроек для 1С ч.3

02.06.2021 16:12:10 | Автор: admin

Предисловие

Наконец то я смог перебороть свою лень и написать третью часть. По итогу мы имеем настроенный терминальный сервер, с разграниченными доступами к данным и списками разрешенных программ. В данной части закончим тонкую настройку рабочих столов пользователей, как и обещал рассмотрим Установку, Настройку, и оптимизацию 1С, а так же разграничение доступа к БД. Приступим.

Очищаем рабочий стол от лишних ярлыков

Создадим Групповую политику с названием "Очистить рабочий стол" и свяжем ее с подразделением в котором расположены пользователи нашего сервера

Зададим параметры политики > Конфигурация пользователя > политики > административные шаблоны > Меню Пуск и панель задач там находим Скрыть общие группы программ в меню "Пуск"

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

Размещаем на рабочем столе пользователя необходимые ярлыки приложений

Создадим Групповую политику с названием "Публикация ярлыков" и свяжем ее с подразделением в котором расположены пользователи нашего сервера

Зададим параметры политики > Конфигурация пользователя > политики > Настройка > Конфигурация Windows > Ярлыки > ПКМ создать > ярлык

Заполняем открывшуюся форму, Данные можно скопировать с существующего ярлыка, нажав по нему ПКМ и выбрав свойства, в поле "Размещение" выбираем Рабочий стол

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

Очищаем содержимое Меню ПУСК и задаем начальный макет

Создадим Групповую политику с названием "Настройка Меню Пуск" и свяжем ее с подразделением в котором расположены пользователи нашего сервера

Зададим параметры политики > Конфигурация пользователя > политики > административные шаблоны > Меню Пуск и панель задач > выбираем "Очистка списка недавно использовавшихся программ для новых пользователей" и переводим параметр в состояние Включена

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

Создадим макет

Заходим на наш сервер под локальным администратором и настройте вручную нужный вид макета начального экрана, после чего запускаем PowerShell под правами администратора и выполняем команду Export-StartLayout -Path d:\123.xml где в параметре path указываем путь который мы задали ранее в политике

В результате мы имеем полностью готовые к работе рабочие места для сотрудников компании

Оптимизация 1С

Включаем высокую производительность

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

идем Пуск > панель управления > оборудование > электропитание > выбираем высокая производительность

Отключаем DFSS для нормальной работы 1С

В ОС Windows Server 2012 бывает полезно выключать службу Dynamic Fair Share Scheduling (DFSS позволяет балансировать и распределять ресурсы между пользователями) чтобы повысить производительность 1С:Преприятие 8 в ряде случаев. На момент написания заметки платформа может неудачно взаимодействовать с Dynamic Fair Share Scheduling. Одним из таких признаков может быть долгое открытие конфигуратора в терминальном сервере. Предположительно эта служба Dynamic Fair Share Scheduling думает что 1С:Предприятие потенциально окажет негативное влияния сессией текущего пользователя, захватившего большое количество вычислительных ресурсов, на сессии других пользователей. Служба старается предотвратить чрезмерное использования например дисков одним пользователем, пытаясь организовать равномерное распределение дисковых операций I/O между сессиями.

Чтобы выключить балансировку ресурсов надо выполнить следующие шаги:

Шаг первый. Определить что служба включена, для этого открываем PowerShell и запускаем команду:

(gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices").enabledfss

1 включено, 0 выключено.

Если получаем 0, то дополнительно действий не требуется.

Шаг второй. Если предыдущий шаг вернул 1, то продолжаем. После чего открываем реестр windows (regedit) и меняем в следующих ветках некоторые значения:*1. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Quota System параметр EnableCpuQuota на 0.

2. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TSFairShare\Disk параметр EnableFairShare на 0. Этот параметр особенно сильно влияет.

После этого конфигуратор может открываться значительно быстрее в терминальном сервере. В реально произошедшем в нашей практике случае скорость открытия конфигурации с 40 секунд изменилась до 10 секунд (при наличии кэша конфигурации)

Для этого выполним команды

Set-Itemproperty -Path Registry::"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Quota System\" -name EnableCpuQuota -Value 0  
Set-Itemproperty -Path Registry::"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TSFairShare\Disk\" -name EnableFairShare -Value 0

после чего проверим

Get-Itemproperty -Path Registry::"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Quota System\" -name EnableCpuQuota
Get-Itemproperty -Path Registry::"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TSFairShare\Disk\" -name EnableFairShare 

Результатом должен вернуться 0

Это 2 основных пункта которые влияют на производительность 1с, осталось нам научиться понимать где узкое горлышко производительности

Мониторинг Загрузки сервера

в работе сервера с 1с как показала практика основным показателем является средняя длина очереди диска и загрузка ЦП

Смотрим очередь диска

Заходим Управление компьютером > Производительность > Средства наблюдения > Системный монитор > Добавить > выбираем "Физический диск" > средняя длина очереди диска > выбираем диск на котором лежат базы
Нормальным режимом работы является очередь не превышающая значения 1, все что выше уже будут заметны подтормаживания, при значениях выше 2.5 работа в 1 с становится не комфортной.

За данным параметром крайне важно следить так как высокая очередь на диск тянет за собой высокую загрузку ЦП (которому приходится ждать пока диск ответит)

Формирование списка баз 1С, для пользователей

Будем использовать уже заезженный метод формирования списка на основе NTFS прав, но внедрим немного своего

первым делом определимся с местом где будут лежать файлы запуска БД 1С и укажем путь до этого места, пусть это будет d:\access\1cestart.cfg

Откроем файл C:\ProgramData\1C\1CEStart\1cestart.cfg

и добавим в конец файла строку "CommonCfgLocation=d:\access\1cestart.cfg" после чего сохраним

Далее нам необходимо скачать powershell script отсюда

на 160 строке указываем путь до расположения файловых баз 1с

на 163 задаем путь до подразделения домена в котором будут лежать у вас группы безопасности доступа к БД

после чего можем запустить скрипт и создать каталог для нашей базы 1С, После чего останется только положить БД в данный каталог и добавить пользователей в группу доступа 1с

На этом настройку терминального сервера 1с, можно считать законченно, как итог мы имеем сервер готовый к приему клиентов

Подробнее..

Уютный VPS-сервер для маленьких проектов за минимум денег как настроить

30.05.2021 16:05:01 | Автор: admin

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

Если вам тоже хочется создать в сети свое личное пространство, но вы не знаете, с чего начать, или вам просто интересны такие замечательные программные продукты как Docker, Portainer, Traefik добро пожаловать под кат.

Введение


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

Когда я учился в институте (это то время, когда у меня в городе только появился интернет по карточкам и первое интернет-кафе), мой друг, который к тому времени умудрился устроится лаборантом на кафедру информатики, активно пытался подсадить меня на Линукс. И вот я, считающий себя продвинутым компьютерщиком, имеющий опыт, наверное, сотни установок винды, прихожу домой после института и уверенным движением вставляю в дисковод диск с дистрибутивом линукс И что? И ничего.

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

Были и еще попытки освоить линукс, жизнь раз за разом сводила меня с его фанатами, которые пытались меня перетянуть в свой лагерь, я даже как-то попытался поставить генту (неудачно естественно, хотя у меня была распечатка с пошаговым руководством как это сделать), но проклятье консоли витало надо мной и с каждой неудачей то самое чувство беспомощности все усиливалось. После графического интерфейса винды, где все настройки перед тобой как на ладони, сталкиваясь с консолью я чувствовал себя ослепшим, пытающимся найти дорогу на ощупь в незнакомом месте. Так что я очень долго оставался приверженцем технологического стека Microsoft, программировал на .net, используя VisualStudio (она шикарна, и никакой консоли). Прошу не судить строго, возможно, если бы в то время у меня была возможность поставить линукс на виртуалку, чтобы спокойно с ней разбираться и приличный интернет под рукой, эта история приняла бы совсем другой оборот.

Сейчас все поменялось. С приходом в нашу жизнь веба в его современном виде я пересел на Node.js и волей-неволей стал проникаться идеологией консоли и Linux. Для хостинга своих разработок мне понадобился VPS, и тут оказалось, что VPS с виндой стоят гораздо дороже, так что моя жаба перевесила мои фрустрации относительно консоли, да и наличие скоростного интернета позволило мгновенно находить ответы на возникающие вопросы.

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

Подготовка


Я создал VPS минимальной конфигурации (vCPU: 1 core, RAM: 1 ГБ, NVMe: 20 ГБ) на macloud. Для установки на VPS я выбрал дистрибутив Debian 10. При установке я сразу добавил через панель управления SSH-ключ, чтобы было удобно заходить в консоль с помощью SSH-клиента. Для дальнейших экспериментов понадобится следующее:

  1. Обновить систему
  2. Установить docker и docker-compose
  3. Включить файл подкачки.

Обновить операционную систему можно следующими командами:

# apt updateОбновит список доступных пакетов# apt upgradeОбновит систему, установив свежие версии ПО.

Для установки docker следуем официальной инструкции https://docs.docker.com/engine/install/debian/

Устанавливаем необходимые зависимости:

# apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

Добавляем официальный GPG ключ Dockerа:

# curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Добавляем репозиторий:

# echo deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable | tee /etc/apt/sources.list.d/docker.list > /dev/null

Теперь осталось обновить список пакетов:

# apt-get update

и установить докер:
# apt-get install docker-ce docker-ce-cli containerd.io

Проверить, что все корректно установилось можно, запустив команду:

# docker run hello-world

Если появилось приветствие, значит все прошло хорошо. У меня на момент написания данной статьи установилась следующая версия:

# docker -vDocker version 20.10.6, build 370c289

Теперь надо установить docker-compose. Для этого воспользуемся официальной инструкцией:

https://docs.docker.com/compose/install/

Для начала нам нужно получить ссылку на свежий релиз docker-compose. Список релизов можно посмотреть тут: https://github.com/docker/compose/releases

На момент написания статьи наиболее свежей была версия 1.29.2. Нам нужна версия для linux, поэтому выбираем файл с названием docker-compose-Linux-x86_64. Скопируем ссылку на него. Теперь надо в консоли ввести следующую команду (вставьте в нужное место ссылку, полученную выше):

# curl -L "<ссылка на релиз>" -o /usr/local/bin/docker-compose

В моем случае получилось:

# curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64 -o /usr/local/bin/docker-compose

Запустим команду и загрузится бинарный файл docker-compose.

Последний шаг надо установить для него разрешение на исполнение. Это можно сделать следующей командой:

# chmod +x /usr/local/bin/docker-compose

Если всё прошло нормально, то на этом процесс установки окончен, теперь можно проверить версию docker-compose. У меня получилось вот так:

# docker-compose -vdocker-compose version 1.29.2, build 5becea4c

Последний шаг это включение файла подкачки, учитывая малый объем памяти он точно не будет лишним:

Создадим файл размером 4 Гб

# fallocate -l 4G /swapfile

Назначим ему необходимые права:

# chmod 600 /swapfile

Инициализируем его как файл подкачки:

# mkswap /swapfile

Наконец активируем:

# swapon /swapfile

Проверить, появился ли файл подкачки в системе можно командой free. У меня все получилось:

# freetotal    used    free   shared buff/cache  availableMem:    1010900   150500   143788    2892   716612   714916Swap:    4194300      0   4194300

Осталось последнее действие: для того, чтобы файл подкачки оставался активным после перезагрузки надо добавить в файл /etc/fstab следующую строку:

/swapfile swap swap defaults 0 0


Для подобных задач мне нравится использовать файловый менеджер Midnight Commander. Это консольный файловый менеджер с классическим интерфейсом. Если вы сталкивались с Norton Commander/FAR/TotalCommander вы легко поймете, как им пользоваться. Установить его можно следующей командой:

# apt-get install mc


А запустить с помощью команды

# mc

Увидим до боли знакомую картину:


Теперь найдем нужный файл и отредактируем его:


На этом предварительная настройка закончена, можно двигаться дальше.

Portainer


Первый инструмент, с которым мне бы хотелось вас познакомить это Portainer. Portainer это инструмент для управления контейнерами в Docker, Swarm, Kubernetes и Azure ACI. Как написано в документации Portainerа:

Отрицая необходимость для пользователей использовать интерфейс командной строки, писать YAML или понимать манифесты, Portainer делает развертывание приложений и устранение неполадок настолько простым, что любой может это сделать.

Для моих целей Portainer подходит просто идеально. Давайте познакомимся с ним поближе. В соответствии с документацией https://documentation.portainer.io/v2.0/deploy/ceinstalldocker/ проще всего это сделать следующим образом:

Создадим том для хранения данных:

# docker volume create portainer_data

Теперь можно запустить Portainer следующей командой:

# docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce

После запуска Portainer будет доступен по адресу http://<ip серевера>:9000/

При первом запуске Portainer попросит вас указать пароль администратора, после чего спросит, каким образом подключится к окружению:


Я выбрал вариант подключится к локальному Dockerу, после чего появился домашний экран Portainerа:


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

Зайдем в него, и увидим удобный дэшбоард со сводной информацией:


Здесь мы можем управлять всеми аспектами работы Dockerа. Давайте посмотрим, что у нас в контейнерах:


Здесь пока один контейнер это сам Portainer. Интерфейс очень удобно позволяет просматривать и управлять контейнерами, а также есть возможность добавлять новые. Можете пройтись по остальным вкладкам и убедится, насколько удобный и продуманный интерфейс имеет Portainer.

Наибольший интерес представляет вкладка Stacks. Стэк это совокупность взаимосвязанных контейнеров, которые запускаются и работают совместно. По сути, это тоже самое, что композиция Docker Compose, конфигурацию которой мы описываем в файле docker-compose.yml и потом запускаем командой docker-compose up.

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


Для определения стека используется формат docker-compose, именно он работает здесь под капотом. Мне при помощи этой функции удобнее всего построить из контейнеров необходимую инфраструктуру.

На этом предлагаю пока отвлечься от изучения возможностей portainerа. Думаю, вы уже увидели, что это серьезный инструмент, благодаря которому можно практически полностью отказаться от использования CLI dockerа. Давайте теперь кратко рассмотрим, что же я хочу получить в результате на этом VPS.

У меня периодически возникает потребность в разработке быстрых проектов. Я так называю проекты, которые не требуют глубокой проработки. Это могут быть эксперименты, небольшие сайты, боты, сборщики информации и т.п. Все то, что не требует выстраивания цепочки CI/CD. Мне было бы крайне удобно разрабатывать и отлаживать такие приложения прямо там, где они будут работать. Также у меня довольно часто бывает ситуация, когда я нахожусь вдали от своего рабочего места с настроенной средой разработки, и, если что-то в этих моих проектах начинает работать не так как надо, хотелось бы иметь возможность быстро разобраться в ситуации и пофиксить проблему, или просто поработать над проектами пока есть свободная минутка с любого компьютера, даже если на нем нет ничего, кроме браузера и доступа в интернет.

Для удобства доступа у меня есть купленное доменное имя, и я хочу настроить для различных инструментов домены третьего уровня, так, чтобы например portainer был доступен по адресу portainer.example.com. Также я хочу, чтобы всё работало через https, и, чтобы не заморачиваться с покупкой сертификатов SSL, воспользоваться Lets Encrypt. Еще одно требование, чтобы всё, к чему не предполагается публичный доступ было закрыто аутентификацией.

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

Traefik


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

  • обновление конфигурации на лету
  • поддержка dockerа в качестве провайдера конфигурации
  • работа с Lets encrypt из коробки

Для того, чтобы запустить traefik совместно с portainerом воспользуемся примером docker-compose.yml, приведенном в документации portainer: https://documentation.portainer.io/v2.0/ad/traefik/rp-traefik/

version: 3.9services:traefik:container_name: traefikimage: traefik:latestcontainer_name: traefikcommand:- --entrypoints.web.address=:80- --entrypoints.websecure.address=:443- --providers.docker=true- --providers.docker.exposedbydefault=false- --log.level=ERROR- --certificatesresolvers.leresolver.acme.httpchallenge=true- --certificatesresolvers.leresolver.acme.email=user@mymail.com- --certificatesresolvers.leresolver.acme.storage=./acme.json- --certificatesresolvers.leresolver.acme.httpchallenge.entrypoint=web- --entrypoints.web.http.redirections.entryPoint.to=websecure- --entrypoints.web.http.redirections.entryPoint.scheme=https- --metrics.prometheus=trueports:- 80:80- 443:443volumes:- /var/run/docker.sock:/var/run/docker.sock:ro- ./acme.json:/acme.jsonnetworks:- intranetlabels:- traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)- traefik.http.routers.http-catchall.entrypoints=web- traefik.http.routers.http-catchall.middlewares=redirect-to-https- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=httpsportainer:image: portainer/portainer-ce:2.5.0-alpinecontainer_name: portainercommand: -H unix:///var/run/docker.sockrestart: alwaysvolumes:- /var/run/docker.sock:/var/run/docker.sock- portainer_data:/datanetworks:- intranetlabels:- traefik.enable=true- traefik.http.routers.frontend.rule=Host(`portainer.example.com`)- traefik.http.routers.frontend.entrypoints=websecure- traefik.http.services.frontend.loadbalancer.server.port=9000- traefik.http.routers.frontend.service=frontend- traefik.http.routers.frontend.tls.certresolver=leresolvervolumes:portainer_data:networks:intranet:name: intranet

Чтобы процесс получения сертификата Lets encrypt прошел успешно, перед запуском надо убедится, что записи DNS корректно настроены. Я для этих целей использую cloudflare, и в нем конфигурация должна выглядеть примерно так:


В графе Content должен находится адрес нашего VPS.

Если теперь скопировать получившийся docker-compose.yml на сервер выполнить следующую команду:

# docker-compose up -d

То после запуска по адресу portainer.example.com будет такая картина:


Причем он уже будет защищен сертификатом Lets Encrypt:


У traefik есть очень удобный дашборд, который помогает понять, правильно ли применились настройки конфигурации. Для того, чтобы его активировать, надо добавить в docker-compose.yml следующие строки:

services:traefik:...command:...- --api.dashboard=truelabels:...- traefik.enable=true- traefik.http.routers.traefik.entrypoints=websecure- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)- traefik.http.routers.traefik.tls=true- traefik.http.routers.traefik.service=api@internal- traefik.http.routers.traefik.tls.certresolver=leresolver- traefik.http.services.traefik.loadbalancer.server.port=8080

Также надо в настройках DNS добавить домен третьего уровня traefik.example.com. Это можно сделать по аналогии с тем, как ранее был добавлен домен для portainer. После применения настроек по адресу traefik.example.com увидим дашборд:


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

Теперь предлагаю немного отвлечься от настройки базовых сервисов и добавить в систему среду разработки. Это будет

Visual Studio Code Server


Для меня всегда среда разработки или IDE, была чем-то таким серьезным. Мощный программный пакет, который устанавливается на машине разработчика, занимает много гигабайт на диске и в оперативной памяти. Пример такой IDE, которой я пользовался много лет, и до сих пор считаю, что это лучший выбор, если вы работаете со стеком технологий Microsoft, это Microsoft VisualStudio. Когда я начал изучать Node.js, я открыл для себя VSCode, и, несмотря на родственные названия, это совсем другая IDE, с совершенно иной концепцией и возможностями. Тот факт, что для отображения своего интерфейса VSCode использует движок Chrome, позволяет разнести интерфейс и сам VSCode. Благодаря такой архитектуре возник Visual Studio Code Server, который может работать на VPS, при этом интерфейс VSCode будет доступен через браузер. И нет, это не очередной онлайн редактор кода, это полноценная IDE VSCode, которая обладает всеми ее замечательными возможностями.

Чтобы добавить VSCode Server на свой VPS я в Portainerе создам новый stack, назову его code-server и добавлю туда следующую конфигурацию:

version: 3.9volumes:codeserverdata:codeappdir:networks:intranet:external: trueservices:code-server:image: ghcr.io/linuxserver/code-servercontainer_name: code-serverenvironment:- PUID=1000- PGID=1000- TZ=Europe/London#    PASSWORD=password #optional- SUDO_PASSWORD=password #optional- PROXY_DOMAIN=code.example.comvolumes:- codeserverdata:/config- codeappdir:/appextra_hosts:host.docker.internal: host-gatewayrestart: alwaysnetworks:- intranetlabels:- traefik.enable=true- traefik.http.routers.code.rule=Host(`code.example.com`)- traefik.http.routers.code.tls=true- traefik.http.routers.code.tls.certresolver=leresolver


Также перед запуском надо не забыть добавить в записи DNS домен третьего уровня code.example.com. Теперь осталось нажать кнопку Deploy the stack.

После окончания процесса в portainerе появится новый stack, и, если мы зайдем по адресу code.example.com, то увидим такую картину (я сразу включил dark theme):


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

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

В данном образе уже установлен Node.js, так что мне не пришлось ничего делать, и я могу сразу приступить к работе над своими проектами. Если же вам в работе нужны другие ЯП, то обратите внимание, что создатели данного образа поддерживают каталог модов, которые позволяют добавить поддержку различных платформ. О том, как их использовать, можно почитать в описании образа на Docker Hub, а со списком официальных модов можно ознакомиться здесь: mods.linuxserver.io/?mod=code-server

Обратите также внимание на то, что в настройках контейнера указан пароль sudo. Для демонстрации я оставил его простым, но на практике лучше сделать его сложным, а еще лучше использовать свойство SUDO_PASSWORD_HASH, чтобы не хранить пароль в открытом виде. Как это сделать, можно почитать в описании образа здесь: hub.docker.com/r/linuxserver/code-server.

Как вы наверное уже заметили на данный момент доступ к code-server никак не защищен и сейчас любой, кто зайдет по адресу code.example.com получит доступ. Это очень плохой вариант, и, хотя в настройках образа можно включить доступ по паролю, мне бы хотелось иметь единый логин для доступа ко всем ресурсам, расположенным на сервере. Для этого предлагаю познакомиться со следующим инструментом. Это будет

KeyCloak


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

Для того, чтобы добавить его в мою систему, я создал в portainerе новый стек с названием auth и добавил в него следующую конфигурацию:

version: '3.9'networks:intranet:external: trueservices:keycloak:image: jboss/keycloakcontainer_name: keycloakrestart: alwaysnetworks:- intranetenvironment:KEYCLOAK_PASSWORD: passwordPROXY_ADDRESS_FORWARDING: truelabels:- traefik.enable=true- traefik.http.routers.keycloak.rule=Host(`auth.yourdomain.com`)- traefik.http.routers.keycloak.tls=true- traefik.http.routers.keycloak.tls.certresolver=leresolver


После нажатия кнопки Deploy the stack, KeyCloak будет доступен по адресу auth.example.com. Если мы зайдем туда, нас встретит приветственное окно KeyCloak:



Зайдем в консоль администратора:


Имя пользователя будет admin, а начальный пароль тот, что мы установили в конфигурации стека переменной окружения KEYCLOAK_PASSWORD. После логина попадем в админку KeyCloak:


Рекомендации по первоначальной настройке KeyCloak для dockerа можно подчерпнуть в официальной документации вот здесь www.keycloak.org/getting-started/getting-started-docker.

Вкратце, надо создать новый пользовательский Realm, в нем создать пользователя и добавить нового клиента.

Для клиента необходимо установить Access Type: confidential и добавить в Valid Redirect URIs наши домены, пока это будут https://traefik.example.com/* и code.example.com*:



После установки Access Type: confidential появится вкладка Credentials, в которой можно будет забрать Secret, он нам пригодится далее при настройке.

На этом пока закончим настройку KeyCloak. Теперь нам надо подружить его с Traefikом. Напомню, что мы хотим закрыть от неаутентифицированных пользователей доступ к узлам code.example.com и traefik.example.com. Для этих целей у traefik есть ForwardAuth middleware, которое позволяет организовать авторизацию через внешний сервис. Чтобы обеспечить его взаимодействие KeyCloak нам понадобится промежуточный сервис, я буду использовать github.com/thomseddon/traefik-forward-auth. Он доступен также в качестве образа на Docker Hub, поэтому я просто дополню конфигурацию стека auth в portainerе таким сервисом:

traefik-forward-auth:image: thomseddon/traefik-forward-authcontainer_name: traefik-forward-authenvironment:- DEFAULT_PROVIDER=oidc- PROVIDERS_OIDC_ISSUER_URL=https://auth.example.com/auth/realms/example- PROVIDERS_OIDC_CLIENT_ID=traefik- PROVIDERS_OIDC_CLIENT_SECRET=d7fb86f0-71a9-44f7-ab04-967f086cd89e- SECRET=something-random- LOG_LEVEL=debuglabels:- traefik.enable=true- traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181- traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User- traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4181restart: always

Здесь в переменной PROVIDERS_OIDC_ISSUER_URL должен быть путь к ранее созданному нами Realm в Keycloak, PROVIDERS_OIDC_CLIENT_ID должен содержать имя клиента, созданного мной ранее в данном realmе, а PROVIDERS_OIDC_CLIENT_SECRET надо взять из вкладки Credentials данного клиента. В переменной SECRET надо забить рандомную строку.

Теперь, чтобы закрыть сервис, роутинг в который обеспечивает Traefik достаточно добавить к нему в labels следующую строку:

- "traefik.http.routers.<имя роутера>.middlewares=traefik-forward-auth"


Для начала я решил закрыть аутентификацией code server, для чего зашел в его стек и дополнил конфигурацию его конфигурацию. Получилось следующее (для краткости привожу только секцию labels):

labels:- traefik.enable=true- traefik.http.routers.code.rule=Host(`code.example.com`)- traefik.http.routers.code.tls=true- traefik.http.routers.code.tls.certresolver=leresolver     - traefik.http.routers.code.middlewares=traefik-forward-auth


Нажмем кнопку Update Stack и попробуем зайти по адресу code.example.com. Если все сделано правильно, то появится окно логина:


После ввода корректных имени пользователя и пароля (которые до этого настроил в KeyCloak) я попал в интерфейс Code server. Все работает!

Подобным образом я закрыл от посторонних глаз дашборд traefikа. Для этого пришлось сходить в консоль (Portainer не может вносить изменения в конфигурацию стека, который был создан не им, а Traefik я поднимал из консоли) и аналогичным образом отредактировать docker-compose.yml:

labels:- traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)- traefik.http.routers.http-catchall.entrypoints=web- traefik.http.routers.http-catchall.middlewares=redirect-to-https- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https- traefik.enable=true- traefik.http.routers.traefik.entrypoints=websecure- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)- traefik.http.routers.traefik.tls=true- traefik.http.routers.traefik.service=api@internal- traefik.http.routers.traefik.tls.certresolver=leresolver- traefik.http.routers.traefik.middlewares=traefik-forward-auth- traefik.http.services.traefik.loadbalancer.server.port=8080


Для проверки я зашел по адресу traefik.example.com. Чтобы удостоверится, что все работает как надо, мне пришлось открыть окно браузера в режиме инкогнито, иначе система меня узнавала и не спрашивала пароль, поскольку я ранее уже логинился для доступа к code-server и поэтому KeyCloak аутентифицировал меня автоматически.

Таким образом, при помощи связки KeyCloak и Traefik мне удалось защитить от несанкционированного доступа чувствительные элементы моей системы. Преимущество данного подхода в том, что он позволяет сделать это даже там, где не предусмотрены собственные механизмы аутентификации. Есть конечно и недостатки KeyCloak достаточно тяжелый, занимает много ресурсов, в первую очередь памяти, да и по возможностям это явный overkill, мне скорее всего не потребуется большая часть того, что он умеет. В качестве альтернативы можно бы было использовать облачный сервис, например traefik-forward-auth имеет встроенную поддержку Google OAuth.

Выводы


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

  • Подключение доменных имен
  • Настройка TLS
  • Получение и установка сертификатов
  • Аутентификация

делаются в несколько строчек прямо в конфигурации сервиса.

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

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

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

Для удобства файлы конфигураций я разместил в репозитории вот тут: https://github.com/debagger/vps-docker-workspace

Благодарю за внимание!



Облачные серверы от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Уютный VPS-сервер для маленьких проектов как настроить

30.05.2021 18:13:46 | Автор: admin

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

Если вам тоже хочется создать в сети свое личное пространство, но вы не знаете, с чего начать, или вам просто интересны такие замечательные программные продукты как Docker, Portainer, Traefik добро пожаловать под кат.

Введение


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

Когда я учился в институте (это то время, когда у меня в городе только появился интернет по карточкам и первое интернет-кафе), мой друг, который к тому времени умудрился устроится лаборантом на кафедру информатики, активно пытался подсадить меня на Линукс. И вот я, считающий себя продвинутым компьютерщиком, имеющий опыт, наверное, сотни установок винды, прихожу домой после института и уверенным движением вставляю в дисковод диск с дистрибутивом линукс И что? И ничего.

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

Были и еще попытки освоить линукс, жизнь раз за разом сводила меня с его фанатами, которые пытались меня перетянуть в свой лагерь, я даже как-то попытался поставить генту (неудачно естественно, хотя у меня была распечатка с пошаговым руководством как это сделать), но проклятье консоли витало надо мной и с каждой неудачей то самое чувство беспомощности все усиливалось. После графического интерфейса винды, где все настройки перед тобой как на ладони, сталкиваясь с консолью я чувствовал себя ослепшим, пытающимся найти дорогу на ощупь в незнакомом месте. Так что я очень долго оставался приверженцем технологического стека Microsoft, программировал на .net, используя VisualStudio (она шикарна, и никакой консоли). Прошу не судить строго, возможно, если бы в то время у меня была возможность поставить линукс на виртуалку, чтобы спокойно с ней разбираться и приличный интернет под рукой, эта история приняла бы совсем другой оборот.

Сейчас все поменялось. С приходом в нашу жизнь веба в его современном виде я пересел на Node.js и волей-неволей стал проникаться идеологией консоли и Linux. Для хостинга своих разработок мне понадобился VPS, и тут оказалось, что VPS с виндой стоят гораздо дороже, так что моя жаба перевесила мои фрустрации относительно консоли, да и наличие скоростного интернета позволило мгновенно находить ответы на возникающие вопросы.

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

Подготовка


Я создал VPS минимальной конфигурации (vCPU: 1 core, RAM: 1 ГБ, NVMe: 20 ГБ) на macloud. Для установки на VPS я выбрал дистрибутив Debian 10. При установке я сразу добавил через панель управления SSH-ключ, чтобы было удобно заходить в консоль с помощью SSH-клиента. Для дальнейших экспериментов понадобится следующее:

  1. Обновить систему
  2. Установить docker и docker-compose
  3. Включить файл подкачки.

Обновить операционную систему можно следующими командами:

# apt updateОбновит список доступных пакетов# apt upgradeОбновит систему, установив свежие версии ПО.

Для установки docker следуем официальной инструкции https://docs.docker.com/engine/install/debian/

Устанавливаем необходимые зависимости:

# apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

Добавляем официальный GPG ключ Dockerа:

# curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Добавляем репозиторий:

# echo deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable | tee /etc/apt/sources.list.d/docker.list > /dev/null

Теперь осталось обновить список пакетов:

# apt-get update

и установить докер:
# apt-get install docker-ce docker-ce-cli containerd.io

Проверить, что все корректно установилось можно, запустив команду:

# docker run hello-world

Если появилось приветствие, значит все прошло хорошо. У меня на момент написания данной статьи установилась следующая версия:

# docker -vDocker version 20.10.6, build 370c289

Теперь надо установить docker-compose. Для этого воспользуемся официальной инструкцией:

https://docs.docker.com/compose/install/

Для начала нам нужно получить ссылку на свежий релиз docker-compose. Список релизов можно посмотреть тут: https://github.com/docker/compose/releases

На момент написания статьи наиболее свежей была версия 1.29.2. Нам нужна версия для linux, поэтому выбираем файл с названием docker-compose-Linux-x86_64. Скопируем ссылку на него. Теперь надо в консоли ввести следующую команду (вставьте в нужное место ссылку, полученную выше):

# curl -L "<ссылка на релиз>" -o /usr/local/bin/docker-compose

В моем случае получилось:

# curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64 -o /usr/local/bin/docker-compose

Запустим команду и загрузится бинарный файл docker-compose.

Последний шаг надо установить для него разрешение на исполнение. Это можно сделать следующей командой:

# chmod +x /usr/local/bin/docker-compose

Если всё прошло нормально, то на этом процесс установки окончен, теперь можно проверить версию docker-compose. У меня получилось вот так:

# docker-compose -vdocker-compose version 1.29.2, build 5becea4c

Последний шаг это включение файла подкачки, учитывая малый объем памяти он точно не будет лишним:

Создадим файл размером 4 Гб

# fallocate -l 4G /swapfile

Назначим ему необходимые права:

# chmod 600 /swapfile

Инициализируем его как файл подкачки:

# mkswap /swapfile

Наконец активируем:

# swapon /swapfile

Проверить, появился ли файл подкачки в системе можно командой free. У меня все получилось:

# freetotal    used    free   shared buff/cache  availableMem:    1010900   150500   143788    2892   716612   714916Swap:    4194300      0   4194300

Осталось последнее действие: для того, чтобы файл подкачки оставался активным после перезагрузки надо добавить в файл /etc/fstab следующую строку:

/swapfile swap swap defaults 0 0


Для подобных задач мне нравится использовать файловый менеджер Midnight Commander. Это консольный файловый менеджер с классическим интерфейсом. Если вы сталкивались с Norton Commander/FAR/TotalCommander вы легко поймете, как им пользоваться. Установить его можно следующей командой:

# apt-get install mc


А запустить с помощью команды

# mc

Увидим до боли знакомую картину:


Теперь найдем нужный файл и отредактируем его:


На этом предварительная настройка закончена, можно двигаться дальше.

Portainer


Первый инструмент, с которым мне бы хотелось вас познакомить это Portainer. Portainer это инструмент для управления контейнерами в Docker, Swarm, Kubernetes и Azure ACI. Как написано в документации Portainerа:

Отрицая необходимость для пользователей использовать интерфейс командной строки, писать YAML или понимать манифесты, Portainer делает развертывание приложений и устранение неполадок настолько простым, что любой может это сделать.

Для моих целей Portainer подходит просто идеально. Давайте познакомимся с ним поближе. В соответствии с документацией https://documentation.portainer.io/v2.0/deploy/ceinstalldocker/ проще всего это сделать следующим образом:

Создадим том для хранения данных:

# docker volume create portainer_data

Теперь можно запустить Portainer следующей командой:

# docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce

После запуска Portainer будет доступен по адресу http://<ip серевера>:9000/

При первом запуске Portainer попросит вас указать пароль администратора, после чего спросит, каким образом подключится к окружению:


Я выбрал вариант подключится к локальному Dockerу, после чего появился домашний экран Portainerа:


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

Зайдем в него, и увидим удобный дэшбоард со сводной информацией:


Здесь мы можем управлять всеми аспектами работы Dockerа. Давайте посмотрим, что у нас в контейнерах:


Здесь пока один контейнер это сам Portainer. Интерфейс очень удобно позволяет просматривать и управлять контейнерами, а также есть возможность добавлять новые. Можете пройтись по остальным вкладкам и убедится, насколько удобный и продуманный интерфейс имеет Portainer.

Наибольший интерес представляет вкладка Stacks. Стэк это совокупность взаимосвязанных контейнеров, которые запускаются и работают совместно. По сути, это тоже самое, что композиция Docker Compose, конфигурацию которой мы описываем в файле docker-compose.yml и потом запускаем командой docker-compose up.

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


Для определения стека используется формат docker-compose, именно он работает здесь под капотом. Мне при помощи этой функции удобнее всего построить из контейнеров необходимую инфраструктуру.

На этом предлагаю пока отвлечься от изучения возможностей portainerа. Думаю, вы уже увидели, что это серьезный инструмент, благодаря которому можно практически полностью отказаться от использования CLI dockerа. Давайте теперь кратко рассмотрим, что же я хочу получить в результате на этом VPS.

У меня периодически возникает потребность в разработке быстрых проектов. Я так называю проекты, которые не требуют глубокой проработки. Это могут быть эксперименты, небольшие сайты, боты, сборщики информации и т.п. Все то, что не требует выстраивания цепочки CI/CD. Мне было бы крайне удобно разрабатывать и отлаживать такие приложения прямо там, где они будут работать. Также у меня довольно часто бывает ситуация, когда я нахожусь вдали от своего рабочего места с настроенной средой разработки, и, если что-то в этих моих проектах начинает работать не так как надо, хотелось бы иметь возможность быстро разобраться в ситуации и пофиксить проблему, или просто поработать над проектами пока есть свободная минутка с любого компьютера, даже если на нем нет ничего, кроме браузера и доступа в интернет.

Для удобства доступа у меня есть купленное доменное имя, и я хочу настроить для различных инструментов домены третьего уровня, так, чтобы например portainer был доступен по адресу portainer.example.com. Также я хочу, чтобы всё работало через https, и, чтобы не заморачиваться с покупкой сертификатов SSL, воспользоваться Lets Encrypt. Еще одно требование, чтобы всё, к чему не предполагается публичный доступ было закрыто аутентификацией.

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

Traefik


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

  • обновление конфигурации на лету
  • поддержка dockerа в качестве провайдера конфигурации
  • работа с Lets encrypt из коробки

Для того, чтобы запустить traefik совместно с portainerом воспользуемся примером docker-compose.yml, приведенном в документации portainer: https://documentation.portainer.io/v2.0/ad/traefik/rp-traefik/

version: 3.9services:traefik:container_name: traefikimage: traefik:latestcontainer_name: traefikcommand:- --entrypoints.web.address=:80- --entrypoints.websecure.address=:443- --providers.docker=true- --providers.docker.exposedbydefault=false- --log.level=ERROR- --certificatesresolvers.leresolver.acme.httpchallenge=true- --certificatesresolvers.leresolver.acme.email=user@mymail.com- --certificatesresolvers.leresolver.acme.storage=./acme.json- --certificatesresolvers.leresolver.acme.httpchallenge.entrypoint=web- --entrypoints.web.http.redirections.entryPoint.to=websecure- --entrypoints.web.http.redirections.entryPoint.scheme=https- --metrics.prometheus=trueports:- 80:80- 443:443volumes:- /var/run/docker.sock:/var/run/docker.sock:ro- ./acme.json:/acme.jsonnetworks:- intranetlabels:- traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)- traefik.http.routers.http-catchall.entrypoints=web- traefik.http.routers.http-catchall.middlewares=redirect-to-https- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=httpsportainer:image: portainer/portainer-ce:2.5.0-alpinecontainer_name: portainercommand: -H unix:///var/run/docker.sockrestart: alwaysvolumes:- /var/run/docker.sock:/var/run/docker.sock- portainer_data:/datanetworks:- intranetlabels:- traefik.enable=true- traefik.http.routers.frontend.rule=Host(`portainer.example.com`)- traefik.http.routers.frontend.entrypoints=websecure- traefik.http.services.frontend.loadbalancer.server.port=9000- traefik.http.routers.frontend.service=frontend- traefik.http.routers.frontend.tls.certresolver=leresolvervolumes:portainer_data:networks:intranet:name: intranet

Чтобы процесс получения сертификата Lets encrypt прошел успешно, перед запуском надо убедится, что записи DNS корректно настроены. Я для этих целей использую cloudflare, и в нем конфигурация должна выглядеть примерно так:


В графе Content должен находится адрес нашего VPS.

Если теперь скопировать получившийся docker-compose.yml на сервер выполнить следующую команду:

# docker-compose up -d

То после запуска по адресу portainer.example.com будет такая картина:


Причем он уже будет защищен сертификатом Lets Encrypt:


У traefik есть очень удобный дашборд, который помогает понять, правильно ли применились настройки конфигурации. Для того, чтобы его активировать, надо добавить в docker-compose.yml следующие строки:

services:traefik:...command:...- --api.dashboard=truelabels:...- traefik.enable=true- traefik.http.routers.traefik.entrypoints=websecure- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)- traefik.http.routers.traefik.tls=true- traefik.http.routers.traefik.service=api@internal- traefik.http.routers.traefik.tls.certresolver=leresolver- traefik.http.services.traefik.loadbalancer.server.port=8080

Также надо в настройках DNS добавить домен третьего уровня traefik.example.com. Это можно сделать по аналогии с тем, как ранее был добавлен домен для portainer. После применения настроек по адресу traefik.example.com увидим дашборд:


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

Теперь предлагаю немного отвлечься от настройки базовых сервисов и добавить в систему среду разработки. Это будет

Visual Studio Code Server


Для меня всегда среда разработки или IDE, была чем-то таким серьезным. Мощный программный пакет, который устанавливается на машине разработчика, занимает много гигабайт на диске и в оперативной памяти. Пример такой IDE, которой я пользовался много лет, и до сих пор считаю, что это лучший выбор, если вы работаете со стеком технологий Microsoft, это Microsoft VisualStudio. Когда я начал изучать Node.js, я открыл для себя VSCode, и, несмотря на родственные названия, это совсем другая IDE, с совершенно иной концепцией и возможностями. Тот факт, что для отображения своего интерфейса VSCode использует движок Chrome, позволяет разнести интерфейс и сам VSCode. Благодаря такой архитектуре возник Visual Studio Code Server, который может работать на VPS, при этом интерфейс VSCode будет доступен через браузер. И нет, это не очередной онлайн редактор кода, это полноценная IDE VSCode, которая обладает всеми ее замечательными возможностями.

Чтобы добавить VSCode Server на свой VPS я в Portainerе создам новый stack, назову его code-server и добавлю туда следующую конфигурацию:

version: 3.9volumes:codeserverdata:codeappdir:networks:intranet:external: trueservices:code-server:image: ghcr.io/linuxserver/code-servercontainer_name: code-serverenvironment:- PUID=1000- PGID=1000- TZ=Europe/London#    PASSWORD=password #optional- SUDO_PASSWORD=password #optional- PROXY_DOMAIN=code.example.comvolumes:- codeserverdata:/config- codeappdir:/appextra_hosts:host.docker.internal: host-gatewayrestart: alwaysnetworks:- intranetlabels:- traefik.enable=true- traefik.http.routers.code.rule=Host(`code.example.com`)- traefik.http.routers.code.tls=true- traefik.http.routers.code.tls.certresolver=leresolver


Также перед запуском надо не забыть добавить в записи DNS домен третьего уровня code.example.com. Теперь осталось нажать кнопку Deploy the stack.

После окончания процесса в portainerе появится новый stack, и, если мы зайдем по адресу code.example.com, то увидим такую картину (я сразу включил dark theme):


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

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

В данном образе уже установлен Node.js, так что мне не пришлось ничего делать, и я могу сразу приступить к работе над своими проектами. Если же вам в работе нужны другие ЯП, то обратите внимание, что создатели данного образа поддерживают каталог модов, которые позволяют добавить поддержку различных платформ. О том, как их использовать, можно почитать в описании образа на Docker Hub, а со списком официальных модов можно ознакомиться здесь: mods.linuxserver.io/?mod=code-server

Обратите также внимание на то, что в настройках контейнера указан пароль sudo. Для демонстрации я оставил его простым, но на практике лучше сделать его сложным, а еще лучше использовать свойство SUDO_PASSWORD_HASH, чтобы не хранить пароль в открытом виде. Как это сделать, можно почитать в описании образа здесь: hub.docker.com/r/linuxserver/code-server.

Как вы наверное уже заметили на данный момент доступ к code-server никак не защищен и сейчас любой, кто зайдет по адресу code.example.com получит доступ. Это очень плохой вариант, и, хотя в настройках образа можно включить доступ по паролю, мне бы хотелось иметь единый логин для доступа ко всем ресурсам, расположенным на сервере. Для этого предлагаю познакомиться со следующим инструментом. Это будет

KeyCloak


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

Для того, чтобы добавить его в мою систему, я создал в portainerе новый стек с названием auth и добавил в него следующую конфигурацию:

version: '3.9'networks:intranet:external: trueservices:keycloak:image: jboss/keycloakcontainer_name: keycloakrestart: alwaysnetworks:- intranetenvironment:KEYCLOAK_PASSWORD: passwordPROXY_ADDRESS_FORWARDING: truelabels:- traefik.enable=true- traefik.http.routers.keycloak.rule=Host(`auth.yourdomain.com`)- traefik.http.routers.keycloak.tls=true- traefik.http.routers.keycloak.tls.certresolver=leresolver


После нажатия кнопки Deploy the stack, KeyCloak будет доступен по адресу auth.example.com. Если мы зайдем туда, нас встретит приветственное окно KeyCloak:



Зайдем в консоль администратора:


Имя пользователя будет admin, а начальный пароль тот, что мы установили в конфигурации стека переменной окружения KEYCLOAK_PASSWORD. После логина попадем в админку KeyCloak:


Рекомендации по первоначальной настройке KeyCloak для dockerа можно подчерпнуть в официальной документации вот здесь www.keycloak.org/getting-started/getting-started-docker.

Вкратце, надо создать новый пользовательский Realm, в нем создать пользователя и добавить нового клиента.

Для клиента необходимо установить Access Type: confidential и добавить в Valid Redirect URIs наши домены, пока это будут https://traefik.example.com/* и code.example.com*:



После установки Access Type: confidential появится вкладка Credentials, в которой можно будет забрать Secret, он нам пригодится далее при настройке.

На этом пока закончим настройку KeyCloak. Теперь нам надо подружить его с Traefikом. Напомню, что мы хотим закрыть от неаутентифицированных пользователей доступ к узлам code.example.com и traefik.example.com. Для этих целей у traefik есть ForwardAuth middleware, которое позволяет организовать авторизацию через внешний сервис. Чтобы обеспечить его взаимодействие KeyCloak нам понадобится промежуточный сервис, я буду использовать github.com/thomseddon/traefik-forward-auth. Он доступен также в качестве образа на Docker Hub, поэтому я просто дополню конфигурацию стека auth в portainerе таким сервисом:

traefik-forward-auth:image: thomseddon/traefik-forward-authcontainer_name: traefik-forward-authenvironment:- DEFAULT_PROVIDER=oidc- PROVIDERS_OIDC_ISSUER_URL=https://auth.example.com/auth/realms/example- PROVIDERS_OIDC_CLIENT_ID=traefik- PROVIDERS_OIDC_CLIENT_SECRET=d7fb86f0-71a9-44f7-ab04-967f086cd89e- SECRET=something-random- LOG_LEVEL=debuglabels:- traefik.enable=true- traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181- traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User- traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4181restart: always

Здесь в переменной PROVIDERS_OIDC_ISSUER_URL должен быть путь к ранее созданному нами Realm в Keycloak, PROVIDERS_OIDC_CLIENT_ID должен содержать имя клиента, созданного мной ранее в данном realmе, а PROVIDERS_OIDC_CLIENT_SECRET надо взять из вкладки Credentials данного клиента. В переменной SECRET надо забить рандомную строку.

Теперь, чтобы закрыть сервис, роутинг в который обеспечивает Traefik достаточно добавить к нему в labels следующую строку:

- "traefik.http.routers.<имя роутера>.middlewares=traefik-forward-auth"


Для начала я решил закрыть аутентификацией code server, для чего зашел в его стек и дополнил конфигурацию его конфигурацию. Получилось следующее (для краткости привожу только секцию labels):

labels:- traefik.enable=true- traefik.http.routers.code.rule=Host(`code.example.com`)- traefik.http.routers.code.tls=true- traefik.http.routers.code.tls.certresolver=leresolver     - traefik.http.routers.code.middlewares=traefik-forward-auth


Нажмем кнопку Update Stack и попробуем зайти по адресу code.example.com. Если все сделано правильно, то появится окно логина:


После ввода корректных имени пользователя и пароля (которые до этого настроил в KeyCloak) я попал в интерфейс Code server. Все работает!

Подобным образом я закрыл от посторонних глаз дашборд traefikа. Для этого пришлось сходить в консоль (Portainer не может вносить изменения в конфигурацию стека, который был создан не им, а Traefik я поднимал из консоли) и аналогичным образом отредактировать docker-compose.yml:

labels:- traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)- traefik.http.routers.http-catchall.entrypoints=web- traefik.http.routers.http-catchall.middlewares=redirect-to-https- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https- traefik.enable=true- traefik.http.routers.traefik.entrypoints=websecure- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)- traefik.http.routers.traefik.tls=true- traefik.http.routers.traefik.service=api@internal- traefik.http.routers.traefik.tls.certresolver=leresolver- traefik.http.routers.traefik.middlewares=traefik-forward-auth- traefik.http.services.traefik.loadbalancer.server.port=8080


Для проверки я зашел по адресу traefik.example.com. Чтобы удостоверится, что все работает как надо, мне пришлось открыть окно браузера в режиме инкогнито, иначе система меня узнавала и не спрашивала пароль, поскольку я ранее уже логинился для доступа к code-server и поэтому KeyCloak аутентифицировал меня автоматически.

Таким образом, при помощи связки KeyCloak и Traefik мне удалось защитить от несанкционированного доступа чувствительные элементы моей системы. Преимущество данного подхода в том, что он позволяет сделать это даже там, где не предусмотрены собственные механизмы аутентификации. Есть конечно и недостатки KeyCloak достаточно тяжелый, занимает много ресурсов, в первую очередь памяти, да и по возможностям это явный overkill, мне скорее всего не потребуется большая часть того, что он умеет. В качестве альтернативы можно бы было использовать облачный сервис, например traefik-forward-auth имеет встроенную поддержку Google OAuth.

Выводы


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

  • Подключение доменных имен
  • Настройка TLS
  • Получение и установка сертификатов
  • Аутентификация

делаются в несколько строчек прямо в конфигурации сервиса.

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

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

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

Для удобства файлы конфигураций я разместил в репозитории вот тут: https://github.com/debagger/vps-docker-workspace

Благодарю за внимание!



Облачные серверы от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru