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

Server

Сыграем в DOOM на серверах

06.10.2020 20:18:31 | Автор: admin


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

В чём фишка?


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

Разворачиваем мастерсервер


Для этого проекта выбрал сервер со следующими параметрами.



Думаю, для наших задач такой конфигурации более чем достаточно. Изначально хотел использовать Windows Server 2003, но Doom наотрез отказался на ней работать, поэтому всё же решил остановиться на 2016.
Спустя несколько минут, после разворачивания сервера и загрузки операционной системы, мы увидим готовую панель, а главное IP адрес нашего сервера.



В качестве сетевого DOOM я использовал какую-то хитрую сборку Zandronum, DoomSeeker, BrutalDoom, которую мне дали друзья. Но, по сути, вам нужен будет один Zandronum и DoomSeeker для создания сервера, плюс оригинальный .wad-файл, если хотите поиграть на тех самых картах. Ну или найти подобную сборку на просторах сети. Сразу признаюсь, я не большой знаток модов DOOM, попробовал несколько сборок, поэтому показываю работающий вариант. Возможно, если вы захотите это повторить, у вас должно получиться и с другими сборками. Тот же BrutalDoom намного более весёлый и резвый для игры по сети.
Итак, копируем эту сборку на наш сервер (я рекомендую использовать папку c:\game\doom), запускаем zandronum.exe.



И выбираем папку, содержащую WAD-файлы, на которых будем играть. Именно они и определят те карты, на которых вы будете играть. У меня они лежат в папке files вместе с игрой.





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

Создание копии серверов и объединение в единую локальную сеть


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



И выбрать Сделать снапшот. Если сервер не выключен, то его предложат выключить в интерактивном режиме, так как снимок сервера для переноса осуществляется в выключенном состоянии (фактически копия диска).



В результате будет создан снапшот нашего сервера.



Основной сервер после этого можно запустить, а на базе данного снапшота мы можем создать новые сервера. Для этого идём во вкладку Заказать



В разделе, где выбирается Шаблон сервера, в самом низу будет наш Snapshot, выбираем его.



Обратите внимание, что можно выбрать сервер с другими параметрами. Это очень удобно, если вам необходимо увеличить объём жёсткого диска, ОЗУ и прочего. Разве, что нет возможности сохранить IP-адрес.
В результате, после описанных операций, через некоторое время мы получаем копию нашего сервера. Копия от оригинала отличается только паролём входа, и другими IP и MAC-адресами.



После создания второго сервера, давайте объединим их единую локальную сеть Для это переходим во вкладку Сеть любого сервера.



Там выбираем Настроить локальные сети.



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



И окончательно сеть разворачивается после нажатия на кнопку Развернуть локальную сеть.



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


Установка проклятых обновлений в момент создания сети.

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


Сервера в единой сети.

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

Создаём игровой сервер и играем.


Всё, теперь нам осталось только запустить сервер DOOM и играть. На мастер-сервере запускаем doomseeker.exe.



Выбираем Create Server.



После чего выбираем для какого движка создаём сервер, какой wad-файл использовать и карту.



И жмём Start server.



После этого на главной машине и на клиентских запускаем zandronum.exe и идём в Multiplayer. Browse servers->internal browse, там выбрать local. Это меню не всегда срабатывает, поэтому в него надо заходить несколько раз.



Не забываем выбрать наш сервер. Жмём join game и мы в игре!





Итог



Коллеги играют в DOOM на рабочем месте.

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



Подробнее..

Angular Universal проблемы реального приложения

17.03.2021 14:12:14 | Автор: admin

Angular Universal это опенсорсный проект, который расширяет функциональность @angular/platform-server. Он делает возможным Server Side Rendering в Angular.

Angular Universal поддерживает несколько бэкендов:

  1. Express.

  2. ASP.NET Core.

  3. hapi.

Еще один пакет Socket Engine это фреймворк-агностик, который теоретически позволяет подключать к SSR-серверу любой бэкенд. В этой статье мы разберем проблемы, с которыми мы столкнулись при разработке реального приложения с Angular Universal и Express, и их решения.

Как работает Angular Universal

Для рендеринга на сервере Angular использует имплементацию DOM для node.js domino. На каждый GET-запрос domino создает объект, аналогичный браузерному документу.

В контексте этого объекта Angular инициализирует приложение. Приложение делает необходимые запросы на бэкенд, выполняет различные асинхронные задачи и мутирует DOM, находясь в серверном окружении. Затем движок рендера сериализует DOM в строку и отдает эту строку серверу. Сервер отправляет HTML в качестве ответа на GET-запрос. Angular-приложение на сервере после рендера разрушается.

Проблемы SSR в Angular

1. Бесконечная загрузка страницы

Ситуация

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

Почему так происходит

Скорее всего, проблема кроется в специфичном для Angular механизме SSR. Прежде чем понять, в какой момент происходит рендеринг страницы, дадим определение Zone.js и ApplicationRef.

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

ApplicationRef это ссылка на запущенное приложение (docs). Из всего функционала этого класса нас интересует свойство ApplicationRef#isStable. Это Observable, который испускает boolean. isStable равен true тогда, когда в зоне Angular отсутствуют выполняющиеся асинхронные задачи, а false когда таких задач нет.

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

Итак, в момент первого наступления стабильности Angular рендерит текущее состояние приложения и дестроит платформу. А платформа дестроит приложение.

Теперь мы можем сделать предположение, что пользователь пытается открыть приложение, которое не может достичь стабильности. setInterval, rxjs.interval или любая другая рекурсивная асинхронная операция, запущенная в зоне Angular, сделают наступление стабильности невозможным. HTTP-запросы так же влияют на стабильность. Затянувшийся запрос на сервере оттягивает момент рендеринга страницы.

Возможное решение

Чтобы избежать ситуации с долгими запросами, используйте оператор timeout:

import { timeout, catchError } from 'rxjs/operators';import { of } from 'rxjs/observable/of';http.get('https://example.com').pipe(timeout(2000),catchError(e => of(null))).subscribe()

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

У такого подхода есть два минуса:

  • нет удобного разделения логики по платформам;

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

Как более простое решение можно использовать модуль NgxSsrTimeoutModule из пакета @ngx-ssr/timeout. Импортируйте модуль со значением таймаута в корневой модуль приложения. Если модуль будет импортирован в AppServerModule, то таймауты HTTP-запросов будут работать только для сервера.

import { NgModule } from '@angular/core';import {ServerModule,} from '@angular/platform-server';import { AppModule } from './app.module';import { AppComponent } from './app.component';import { NgxSsrTimeoutModule } from '@ngx-ssr/timeout';@NgModule({imports: [AppModule,ServerModule,NgxSsrTimeoutModule.forRoot({ timeout: 500 }),],bootstrap: [AppComponent],})export class AppServerModule {}

Для выведения асинхронных операций из зоны Angular используйте сервис NgZone.

import { Injectable, NgZone } from "@angular/core";@Injectable()export class SomeService {constructor(private ngZone: NgZone){this.ngZone.runOutsideAngular(() => {interval(1).subscribe(() => {// somo code})});}}

Для решения этой задачи можно использовать оператор tuiZonefree из пакета @taiga-ui/cdk:

import { Injectable, NgZone } from "@angular/core";import { tuiZonefree } from "@taiga-ui/cdk";@Injectable()export class SomeService {constructor(private ngZone: NgZone){interval(1).pipe(tuiZonefree(ngZone)).subscribe()}}

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

2. Нет кэша из коробки

Ситуация

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

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

Возможное решение

На помощь приходят разные техники кэширования. Мы рассмотри две: in-memory cache и браузерный кэш.

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

Cache-Control: max-age=31536000

Этот вариант подойдет для неавторизованной зоны и при наличии долго не меняющихся данных.

Более подробно о браузерном кэше можно почитать тут.

In-memory cache. In-memory cache можно использовать как для отрендеренных страниц, так и для API-запросов в самом приложении. Обе возможности предоставляет пакет @ngx-ssr/cache.

Для кэширования API-запросов и на сервере, и в браузере добавьте модуль NgxSsrCacheModule в AppModule.

Свойство maxSize отвечает за максимальный размер кэша. Значение 50 говорит о том, что кэш будет содержать не больше 50 последних GET-запросов, совершенных из приложения.

Свойство maxAge отвечает за срок хранения кэша, указывается в миллисекундах.

import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { AppComponent } from './app.component';import { NgxSsrCacheModule } from '@ngx-ssr/cache';import { environment } from '../environments/environment';@NgModule({declarations: [AppComponent],imports: [BrowserModule,NgxSsrCacheModule.configLruCache({ maxAge: 10 * 60_000, maxSize: 50 }),],bootstrap: [AppComponent],})export class AppModule {}

Можно пойти дальше и кэшировать сам html.

Например, все в том же пакете @ngx-ssr/cache есть сабмодуль @ngx-ssr/cache/express. Он импортирует единственную функцию withCache. Функция представляет собой обертку над движком рендера.

import { ngExpressEngine } from '@nguniversal/express-engine';import { LRUCache } from '@ngx-ssr/cache';import { withCache } from '@ngx-ssr/cache/express';server.engine('html',withCache(new LRUCache({ maxAge: 10 * 60_000, maxSize: 100 }),ngExpressEngine({bootstrap: AppServerModule,})));

3. Ошибки на сервере типа ReferenceError: localStorage is not defined

Ситуация

Разработчик обращается к localStorage прямо в теле сервиса. Он достает из локального хранилища браузера данные по ключу. Но на сервере этот код падает с ошибкой: ReferenceError: localStorage is not defined.

Почему так происходит

При запуске Angular-приложения на сервере в глобальном пространстве отсутствует привычный браузерный API. Например, в node.js нет глобального объекта document. Но его можно получить по токену DOCUMENT через DI.

Возможное решение

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

Для решения этой проблемы можно обратиться к Web APIs for Angular.

Например:

import {Component, Inject, NgModule} from '@angular/core';import {LOCAL_STORAGE} from '@ng-web-apis/common';@Component({...})export class SomeComponent {constructor(@Inject(LOCAL_STORAGE) localStorage: Storage) {localStorage.getItem('key');}}

В примере выше использован токен LOCAL_STORAGE из пакета @ng-web-apis/common. Но при запуске этого кода на сервере мы получим ошибку из описания. Просто добавьте UNIVERSAL_LOCAL_STORAGE из пакета @ng-web-apis/universal в провайдеры AppServerModule и по токен LOCAL_STORAGE вы будете получать имплементацию localStorage для сервера.

import { NgModule } from '@angular/core';import {ServerModule,} from '@angular/platform-server';import { AppModule } from './app.module';import { AppComponent } from './app.component';import { UNIVERSAL_LOCAL_STORAGE } from '@ngx-ssr/timeout';@NgModule({imports: [AppModule,ServerModule,],providers: [UNIVERSAL_LOCAL_STORAGE],bootstrap: [AppComponent],})export class AppServerModule {}

4. Неудобное разделение логики

Ситуация

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

@Component({selector: 'ram-root',template: '<some-сomp *ngIf="isServer"></some-сomp>',styleUrls: ['./app.component.less'],})export class AppComponent {isServer = isPlatformServer(this.platformId);constructor(@Inject(PLATFORM_ID) private platformId: Object){}}

Компонент должен получить PLATFORM_ID, понять целевую платформу и добавить публичное свойство класса. Это свойство будет использовано в шаблоне в связке с директивой ngIf.

Возможное решение

C помощью структурных директив и DI можно сильно упростить вышеописанный механизм.

Для начала завернем в токен определение сервера.

export const IS_SERVER_PLATFORM = new InjectionToken<boolean>('Is server?', {factory() {return isPlatformServer(inject(PLATFORM_ID));},});

Создаем структурную директиву с использованием токена IS_SERVER_PLATFORM с одной простой задачей: рендерить компонент только на сервере.

@Directive({selector: '[ifIsServer]',})export class IfIsServerDirective {constructor(@Inject(IS_SERVER_PLATFORM) isServer: boolean,templateRef: TemplateRef<any>,viewContainer: ViewContainerRef) {if (isServer) {viewContainer.createEmbeddedView(templateRef);}}}

Аналогично выглядит код для директивы IfIsBowser.

Теперь рефакторим компонент.

@Component({selector: 'ram-root',template: '<some-сomp *ifIsServer"></some-сomp>',styleUrls: ['./app.component.less'],})export class AppComponent {}

Из компонента удалены лишние свойства. Шаблон компонента стал немного проще. Такие директивы помогут декларативно скрывать и отображать контент в зависимости от платформы. Чтобы не таскать реализацию токенов и директив между проектами, мы собрали их в пакет @ngx-ssr/platform.

5. Memory leak

Ситуация

Сервис при инициализации запускает interval и выполняет некоторые действия.

import { Injectable, NgZone } from "@angular/core";import { interval } from "rxjs";@Injectable()export class LocationService {constructor(ngZone: NgZone) {ngZone.runOutsideAngular(() => interval(1000).subscribe(() => {...}));}}

Этот код не влияет на стабильность приложения, но при разрушении приложения на сервере колбэк, переданный в subscribe, продолжит вызываться. Каждый запуск приложения на сервере оставит за собой артефакт в виде интервала. А это потенциальная утечка памяти.

Возможное решение

В нашем случае проблема решается использованием хука ngOnDestoroy. Он работает как для компонентов, так и для сервисов. Нам нужно лишь сохранить подписку и завершить ее при дестрое сервиса. Есть много техник по отписке, но здесь мы приведем лишь одну:

import { Injectable, NgZone, OnDestroy } from "@angular/core";import { interval, Subscription } from "rxjs";@Injectable()export class LocationService implements OnDestroy {private subscription: Subscription;constructor(ngZone: NgZone) {this.subscription = ngZone.runOutsideAngular(() =>interval(1000).subscribe(() => {}));}ngOnDestroy(): void {this.subscription.unsubscribe();}}

6. Нельзя прервать рендер

Ситуация

Мы перехватываем критическую ошибку. Дальнейший рендеринг и ожидание стабильности не имеют смысла. Нужно прервать процесс и отдать клиенту дефолтный index.html.

Почему так происходит

Еще раз обратимся к моменту рендеринга приложения. Он происходит при наступлении стабильности приложения. Мы можем ускорить наступление стабильности решениями из проблемы 1. Но что, если мы хотим прервать процесс рендеринга при первой перехваченной ошибке? А если мы хотим установить лимит времени на попытку отрендерить приложение?

Возможное решение

Решения этой проблемы сейчас не существует.

7. Нет регидрации

Ситуация

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

Почему так происходит

Angular не умеет переиспользовать то, что он отрендерил на сервере. Он вырезает весь html из корневого элемента и начинает рисовать все заново.

Возможное решение

Его все еще не существует. Но есть надежда, что решение все же будет. В roadmap Angular Universal есть пункт Full client rehydration strategy that reuses DOM elements/CSS rendered on the server.

Выводы

Фактически Angular Universal единственное поддерживаемое и самое распространенное решение для рендера вашего приложения на сервере. Сложность интеграции в существующее приложение во многом зависит от разработчика.

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

Подробнее..

Чего ожидать от бета-версии Proxmox Backup Server

15.07.2020 12:10:08 | Автор: admin

10 июля 2020 года австрийская компания Proxmox Server Solutions GmbH представила публичную бета-версию нового решения по резервному копированию.

Мы уже рассказывали, как использовать штатные методы бэкапа в Proxmox VE и выполнять инкрементальный бэкап с помощью стороннего решения Veeam Backup & Replication. Теперь же, с появлением Proxmox Backup Server (PBS) процесс резервного копирования должен стать удобнее и проще.


Распространяется PBS на условиях лицензии GNU AGPL3, разработанной Фондом свободного программного обеспечения (Free Software Foundation). Это позволит без проблем использовать и модифицировать ПО под свои нужды.


Инсталляция PBS практически ничем не отличается от стандартного процесса установки Proxmox VE. Точно так же задаем FQDN, сетевые настройки и другие требуемые данные. После завершения инсталляции можно перезагрузить сервер и зайти в веб-интерфейс, используя ссылку вида:

https://<IP-address or hostname>:8007

Основное предназначение PBS выполнение резервного копирования виртуальных машин, контейнеров и физических хостов. Для выполнения этих операций предоставляется соответствующий RESTful API. Поддерживается три основных типа резервного копирования:

  • vm копирование виртуальной машины;
  • ct копирование контейнера;
  • host копирование хоста (реального или виртуальной машины).

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

Помимо привычного формата img для хранения объемных данных и образов виртуальных машин, появился формат pxar (Proxmox File Archive Format), предназначенный для хранения файлового архива. Он спроектирован таким образом, чтобы обеспечить высокую производительность для выполнения ресурсоемкого процесса дедупликации данных.

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

Управляется сервер традиционно с помощью веб-интерфейса и/или утилит командной строки. Подробные описания команд CLI приведены в соответствующей документации. Веб-интерфейс лаконичен и знаком всем, кто хоть раз использовал Proxmox VE.


В PBS можно настроить задания синхронизации локальных и удаленных хранилищ данных, поддержку ZFS, шифрование AES-256 на стороне клиента и прочие полезные опции. Судя по дорожной карте, скоро появится возможность импорта существующих бэкапов, хоста с Proxmox VE или Proxmox Mail Gateway целиком.

Также с помощью PBS можно организовать бэкап любого хоста на базе Debian, установив клиентскую часть. Добавляем репозитории в /etc/apt/sources.list:

deb http://ftp.debian.org/debian buster main contribdeb http://ftp.debian.org/debian buster-updates main contrib# security updatesdeb http://security.debian.org/debian-security buster/updates main contrib

Обновляем список ПО:

apt-get update

Устанавливаем клиент:

apt-get install proxmox-backup-client

В дальнейшем появится поддержка и других дистрибутивов Linux.

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

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

Обзор возможностей Kubespray Отличие оригинальной версии и нашего форка

20.09.2020 14:22:27 | Автор: admin

23 сентября 20.00 МСК Сергей Бондарев проведёт бесплатный вебинар Обзор возможностей Kubespray, где расскажет, как готовят kubespray, чтобы получилось быстро, эффективно и отказоустойчиво.


Сергей Бондарев расскажет отличие оригинальной версии и нашего форка:



Отличие оригинальной версии и нашего форка.


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


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


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

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


В итоге разница между кластерами, созданными моим форком и оригинальным это kube-proxy и сроки действия сертификатов.


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


В Kubeadm куб-прокси запускается, как daemonset, а сертификаты выписываются на 1 год, и их надо периодически продлевать. kubeadm наконец-то научился это делать одной командой.


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


Особенности (недостатки) при промышленной эксплуатации:


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


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


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


Например у меня была проблема с кубадмом, когда он падал в момент добавления второго и третьего мастера, и после этого кубспрей делал kubeadm reset на узле, и пробовал добавить мастер еще раз.


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


Opensource как он есть.


Всё это и многое другое на бесплатном вебинаре Обзор возможностей Kubespray 23 сентября 20.00 МСК.


Присоединяйтесь!

Подробнее..

Знакомство с exsc (EXtensible Server Core). Часть 1

06.03.2021 22:12:47 | Автор: admin
ПРИВЕТСТВИЕ
image
Всем привет! Хочу поделиться с общественностью библиотекой, на основе которой в данный момент множество серверов, обслуживают тысячи клиентов в различных серверных системах. exsc (EXtensible Server Core) это библиотека, написанная на языке C и позволяет в рамках одного приложения, иметь один или несколько серверных потоков. Каждый серверный поток способен обслужить большое количество клиентов. Хотя библиотеку, можно использовать в модели типа запрос-ответ, в первую очередь она была рассчитана на поддержание постоянного соединения с большим количеством клиентов и обменом сообщений в реальном времени. Поскольку я и сам люблю взять готовый HelloWorld проект, скомпилировать его и посмотреть как всё работает, то в конце статьи я выложу ссылку на такой проект.

ДОКУМЕНТАЦИЯ

Многие операции делаются для определённого соединения. В рамках данной библиотеки за соединение отвечает структура exsc_excon. У этой структуры есть следующие поля:

ix индекс соединения. Это порядковый номер соединения, которое было свободно в момент подключения клиента.
id идентификатор соединения. Это уникальный номер соединения. В отличие от индекса он не повторяется.
addr IP адрес клиента
name имя соединения. Несколько соединений можно назвать одним именем и затем отослать какое-либо сообщение всем соединениям с одинаковым именем (смотрите функцию exsc_sendbyname).

Инициализация ядра

Для того, чтобы работать с ядром, нам необходимо его инициализировать с помощью функции
void exsc_init(int maxsrvcnt);
Параметр maxsrvcnt сообщает ядру, сколько серверных потоков мы будем использовать в рамках нашего приложения.

Запуск серверного потока

Далее нам нужно запустить серверный поток с помощью функции
int exsc_start(uint16_t port, int timeout, int timeframe, int recvbufsize, int concnt,
void newcon(struct exsc_excon excon),
void closecon(struct exsc_excon excon),
void recv(struct exsc_excon excon, char *buf, int bufsize),
void ext());


port порт который будет прослушивать серверный поток.

timeout указывает сколько времени серверный поток будет ожидать какой-либо активности от клиента. Если в течении этого времени клиент не прислал ни одного сообщения, то серверный поток закрывает такое соединение. Поэтому если мы хотим держать постоянную связь и выставили этот параметр на пример 30 секунд, то необходимо раз в 10-15 секунд присылать какое-либо сообщение типа ping.

timeframe временные рамки, за которое мы позволяем выполнить запрос.Так на пример, если это значение выставлено на 100 миллисекунд и серверный поток обработал все текущие запросы от пользователей за 10 секунд, то он оставшиеся 90 миллисекунд оставит процессору для выполнения других задач. Таким образом, чем меньше это значение, тем быстрее серверный поток будет обрабатывать запросы, но тем больше он нагрузит процессор.

recvbufsize размер буфера который серверный поток будет вычитывать за один раз.

concnt максимальное количество соединений с которым серверный поток работает одновременно.

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

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

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

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

Функция exsc_start возвращает дескриптор серверного потока, который понадобится для вызова некоторых функций.

Отправка сообщений
За отправку сообщений отвечает функция
void exsc_send(int des, struct exsc_excon *excon, char *buf, int bufsize);
Эта функция потокобезопасная (её можно вызывать её из любого потока). В качестве параметров необходимо передать ей дескриптор серверного потока (который мы получили как возвращаемое значение функции exsc_start), соединение на которое мы хотим отправить сообщение, указатель на буфер с сообщением и размер буфера.

Так же мы имеем возможность отправить сообщение группе клиентов. Для этого есть функция
void exsc_sendbyname(int des, char *conname, char *buf, int bufsize);
Она аналогична функции exsc_send, за исключением второго параметра, в который передаётся имя подключений которым будет отправлено сообщение.

Задание имени подключения
Для тог, чтобы в будущем как то дополнительно идентифицировать подключение, либо хранить вместе с подключением некоторую информацию о нём, либо отправлять сообщения группе клиентов, используется функция
void exsc_setconname(int des, struct exsc_excon *excon, char *name);
Эта функция потокобезопасная. В качестве первого параметра передаётся дескриптор серверного потока, вторым параметром передаём само подключение и третьим параметром передаём имя этого подключения.

Подключение серверного потока к другому серверу
Иногда, серверная логика требует того, чтобы подключиться к другому серверу, для того чтобы запросить или передать какие либо данные. Для таких задач была введена функция, которая создаёт такое подключение.
void exsc_connect(int des, const char *addr, uint16_t port, struct exsc_excon *excon);
Эта функция потокобезопасная. В качестве параметров нам необходимо передать дескриптор серверного потока, адресс сервера к которому нам необходимо подключиться, потр сервера к которому нам необходимо подключиться и последним параметром мы передаём указатель на соединение с помощью которого мы в дальнейшем сможем вызывать другие функции библиотеки. Стоит отметить что нам нет необходимости дожидаться, пока подключение состоится. Мы можем вызвать функции exsc_connect и exsc_send одну за другой и система сама проследит за тем, чтобы сообщение было отослано сразу после того как сможет подключиться к удалённому серверу.

ПРИМЕР СЕРВЕРА С КОММЕНТАРИЯМИ

#include <stdio.h>  // fgets#include <string.h> // strcmp#include "../exnetwork/exsc.h" // подключаем исходники ядраint g_des; // дескриптор серверного потока// ловим новое подключениеvoid exsc_newcon(struct exsc_excon con){    printf("the connection was open  %s\n", con.addr);}// подключение закрываетсяvoid exsc_closecon(struct exsc_excon con){    printf("the connection was closed  %s\n", con.addr);}// принимаем сообщение от клиентаvoid exsc_recv(struct exsc_excon con, char *buf, int bufsize){    char msg[512] = { 0 };    memcpy(msg, buf, bufsize);    printf("receive data from %s\n%s\n", con.addr, msg);    if (strcmp(msg, "say hello") == 0)    {        strcpy(msg, "hello");        exsc_send(g_des, &con, msg, strlen(msg));    }}void exsc_ext(){}int main(){    printf("server_test_0 is started\n");    exsc_init(2); // инициализируем ядро с расчётом на два серверных потока    // запускаем серверный поток на порту 7777    // он будет держать неактивные соединения 30 секунд    // будет обрабатывать входящие сообщения в рамках 10 миллисекунд    // размер буфера для приёма задаём 1024 байта    // максимальное количество подключений ограничиваем до 10000    g_des = exsc_start(7777, 30, 10, 1024, 10000, exsc_newcon, exsc_closecon, exsc_recv, exsc_ext);    // тормозим главный поток, чтобы программа не завершилась раньше времени    // программа завершится когда мы введём команду exit и нажмём клавишу ENTER    while (1)    {        const int cmdmaxlen = 256;        char cmd[cmdmaxlen];        fgets(cmd, cmdmaxlen, stdin);        if (strcmp(cmd, "exit\n") == 0)        {            break;        }    }    return 0;}


ЗАКЛЮЧЕНИЕ
Ядро exsc осуществляет только низкий уровень взоимодействия с клиентами. Хоть это и самый важный элемент серверной системы, основа на которой всё строится, помимо него нужно строить более верхние уровни, которые будут отвечать за управление подключений, генерирование сообщений, сборку сообщений (которые вероятно будут приходить за несколько этапов). Если статья будет иметь положительный отклик то я напишу вторую чать, в которой разовью тему более верхнего уровня этой библиотеки написанной с использованием Qt, а именно про класс ExServer.

Ссылка на библиотеку github.com/extenup/exnetwork

Пример расположен в архиве exsc_test_0.zip
Подробнее..

Из песочницы Миграция Jira Service Desk из облака на сервер

15.11.2020 18:09:06 | Автор: admin
Не буду спорить, что использование SaaS-ов, и в частности Jira Service Desk Cloud, удобно и облегчает работу системным администраторам. В целях безопасности или более гибкого управления сервисом, которое не предоставляет облако, может потребоваться перенос сервиса из облака на сервер организации.

Процесс миграции Jira Service Desk(JSD) можно условно разделить на три этапа:

  1. Подготовка резервной копии(бэкапа).
  2. Подготовка сервера. Установка программного обеспечения. Настройка.
  3. Развертывание бэкапа из облака на сервере.

К подготовке сервера можно отнести установку операционной системы на сервер, установку программного обеспечения, настройку. Сервер может быть как физическим, так и виртуальным. В моем случае будет использоваться CentOS 7, а программное обеспечение будет автоматически устанавливаться простым скриптом. Установка CentOS 7 описана не будет. Будем считать, что ОС уже установлена.

Технические требования к серверу можно посмотреть по ссылке.


1) Подготовка резервной копии.

Сделаем бэкап нашего облачного JSD.

Заходим в системные настройки облачного JSD, вкладка Управление резервным копированием.

image

Сделаем резервную копию сервера.

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

2) Подготовка сервера. Установка программного обеспечения. Настройка.

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

Запускаем терминал или подключаемся к серверу по SSH.

Добавим права на выполнение скрипту командой:

sudo chmod +x soft_install_c7.sh

Запускаем скрипт командой:

sudo bash soft_install_c7.sh

image

Начнется обновление и затем установка программного обеспечения.

Кроме установки ПО скрипт создаст базу данных(БД) в Postgre Sql

При создании БД скрипт может ругнуться на доступ. Ничего страшного, база будет создана.

image

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

image

В процессе исполнение скрипта необходимо будет ввести e-mail и пароль для настройки pgAdmin 4 и ответить на несколько вопросов.

image

Бинарный файл для установки JSD скачается и запустится автоматически. Необходимо будет ответить на несколько вопросов.

image

Порты для работы JSD можно оставить по умолчанию или выбрать другие.

Правила брандмауэра для корректной работы Apache, pgAdmin 4 и JSD добавятся автоматически. По умолчанию скрипт откроет порты 80, 8080 и 5432.

Добавить порт по своему усмотрению можно командой:

sudo firewall-cmd --zone=public add-port=порт/tcp permanent

Удалить порт можно командой:

sudo firewall-cmd --zone=public --remove-port=порт/tcp --permanent

Посмотреть все правила брандмауэра можно командой:

sudo firewall-cmd list-all или sudo iptables -L -n -v line-numbers

Для перезагрузки брандмауэра используйте команду:

sudo firewall-cmd --reload

image

Исполнение скрипта завершится сообщением DONE!

В завершении подготовки сервера можно подключить pgAdmin 4 к серверу Postgre Sql через адрес локальной петли 127.0.0.1, или как вам больше нравится. Измените настройки в pg_hba.conf на актуальные для вашей конфигурации, если это необходимо.

image

Логин и пароль для базы можно посмотреть в скрипте:

База: jsd_db
Пользователи:
Логин:jira Пароль:123
Логин:postgres Пароль:postgres

Можете изменить на свои значения перед запуском скрипта или после, непосредственно в Postgre Sql.

Не забудьте отключить SSL, если вы его не используете. Если pgAdmin 4 не будет соединяться с сервером, попробуйте перезагрузить службу.

sudo service postgresql-11 restart 

Информацию по базам данных вы можете найти в документации Atlassian.

3) Развертывание бэкапа из облака на сервере.

В браузере переходим по ip-адресу сервера с указанием порта. По умолчанию порт 8080. У меня это выглядит так 192.168.1.25:8080

Вы должны увидеть следующее.

image

Я выбираю пункт выполнить настройку самостоятельно и на следующей странице указываю настройки для базы данных. После подключение начнется создание базы данных это займет некоторое время.

image

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

image

Выбираем импортировать данные.

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

image

Можно сгенерировать триальную лицензию на месяц на сайте Atlassian. Для этого нужно будет зарегистрироваться на сайте. При генерации лицензии необходимо выбрать jira service desk (server).

Перед восстановлением JSD из бэкапа разместите бэкап на сервере в каталоге /var/atlassian/application-data/jira/import

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

image

Вас приветствует страница входа, если все прошло хорошо. Осталось ввести логин и пароль.

image

По умолчанию логин sysadmin, пароль sysadmin.

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

На этом перенос JSD из облака на сервер закончен.

Еще почитать о миграции можно тут.

Спасибо за внимание, всего хорошего и удачи!
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    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