Решение для быстрого развертывания традиционных приложений

Предыстория

У нас есть веб-проект, и метод развертывания — распределенное развертывание, осуществляемое с помощью одного приложения (dotnet без ядра) + балансировщика нагрузки (nginx). В связи с недавним ростом числа пользователей количество загрузочных машин увеличилось с 2 до 8. Это создает еще одну проблему.Каждый раз, когда вы добавляете машину, обновляете программное обеспечение или откатываете версию, это становится очень хлопотно и болезненно.Вы больше не сможете нормально ловить рыбу, и ваша жизнь будет потрачена на повторяющиеся задачи с никакого технического содержания.

Некоторые ветераны, возможно, сказали: "Почему бы нам не создать систему с микросервисной архитектурой? Используйте Kubernetes, чтобы продемонстрировать свои навыки, позволяющие легко управлять сотнями или тысячами машинных кластеров. Пока вы разговариваете и смеетесь, все будет уничтожено. Не было бы" это красиво?!

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

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

Раз готового решения нет, то сделайте его сами!

Вся жизнь

Ручной процесс

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

  • Чтобы избежать ошибок обновления, перед обновлением сделайте резервную копию версии исходного стабильно работающего сайта. Конечно, не все файлы нуждаются в резервном копировании, что приведет к нехватке места. Резервные копии создаются только для ключевых файлов в соответствии с реальной ситуацией. Но что касается ключевых файлов, это необходимо каждый раз определять в зависимости от ситуации.
  • Упаковывать недавно опубликованные файлы
  • Загрузите на сервер и замените оригинальный файл
  • Если каждое обновление включает файлы на стороне сервера, вам необходимо перезапустить сайт iis (в настоящее время наш веб-бизнес работает на iis, но на самом деле его следует распространить на Apache, Tomcat, Nginx и другие серверы сайта).

Автоматический процесс работы

Разобравшись со всем процессом развертывания обновлений, я разбил весь процесс обновления на следующие этапы:

  • Мониторинг: На этом этапе программа регулярно отслеживает изменения в определенном файле. Файл, который я здесь установил, представляет собой файл формата json, в котором записан номер версии и адрес загрузки нового файла. Каждый раз, когда изменяется номер версии, происходит обнаружено, начать автоматизировать последующие процессы;
  • Загрузка файла: эта часть предназначена для загрузки файла в указанное место на основе адреса загрузки, полученного на этапе прослушивания;
  • Приостановить сайт (необязательно): поскольку не каждое обновление требует перезапуска сайта, этот шаг не является обязательным;
  • Резервное копирование: на основе входящих параметров резервного копирования выполните резервное копирование файлов и создайте журналы резервного копирования;
  • Распаковка: после завершения резервного копирования вы можете распаковать второй загруженный файл и завершить замену старых и новых файлов;
  • Перезапустите сайт (необязательно): если работа сайта приостановлена, вам необходимо перезапустить сайт снова после завершения распаковки и перехода;
  • Уведомление. После завершения всего процесса обновления необходимо отправить уведомление по электронной почте соответствующему персоналу по разработке, эксплуатации и техническому обслуживанию, чтобы сообщить им ключевую информацию об этом автоматическом обновлении.

После разъяснения вышеперечисленных основных процессов вы можете приступить к кодированию!

Здесь я использую структуру консоли и несколько важных пакетов инструментов, включая Coravel, Serilog, SharpCompress, Hosting и т. д.

Полный адрес кода указан в конце статьи.

монитор

Поскольку это консольная программа, для отслеживания действий по доступу к URL-адресам, как в веб-программе, вам необходимо ввести пакет Microsoft.Extensions.Hosting.

После внедрения вы можете объединить его с Coravel для выполнения запланированного мониторинга.

public static void UseCoravelService(string[] args)
{
    // Renders each item with own style
    bool intervelFlag = true;
    var process = new Rule().RuleStyle("#FDE047");
    var host = new HostBuilder()
         .ConfigureAppConfiguration((hostContext, configApp) =>
         {
             configApp.AddEnvironmentVariables(prefix: "PREFIX_");
             configApp.AddCommandLine(args);
         })
         .ConfigureServices((hostContext, services) =>
         {
             // Add Coravel's Scheduling...
             services.AddScheduler();
         })
         .Build();

    host.Services.UseScheduler(scheduler =>
        scheduler
        .Schedule(async () =>
        {
            //核心业务
            //...
        })
        .EveryFifteenSeconds()
    );
    host.Run();
}

После внедрения сетевого прокси и Coravel следующей операцией является бизнес-код.

/// <summary>
/// 监听
/// </summary>
internal class StepMonitor
{
    public static async Task<bool> getJsonFile(string address)
    {            
        try
        {
            if (string.IsNullOrEmpty(address))
                address = "<我这里给了一个默认地址,也可以不要>";
            HttpClient hc = new HttpClient();
            var content = await hc.GetStringAsync(address);
            var json = JsonHelper.JsonDeserialize<VersionModel>(content);
            string versionFile = "currVersion.txt";
            string currVersion = "0";

            currVersion = await MainScheduling.ReadFile(versionFile);
            if(currVersion.Trim()==json.Version) 
            {
                return false;//线上版本和本地版本相同,继续等待;
            }
            
            await MainScheduling.WriteFile("currVersion.txt", json.Version);
            await MainScheduling.WriteFile("DownloadList.json", JsonHelper.JsonSerialize(json.Items));
            return true;
        }
        catch (Exception ex)
        {
            AnsiConsole.WriteLine($"[red]下载更新索引文件失败,{ex.Message}[/]");
            throw;
        }

    }
}

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

host.Services.UseScheduler(scheduler =>
        scheduler
        .Schedule(async () =>
        {
            string cache = CacheManager.Default.Get<string>("step");
            AnsiConsole.MarkupLine($"[#1E9FFF]当前状态:【{cache}】,{DateTime.Now.ToString()}[/]");
            if (cache == "waiting")
            {
                intervelFlag = false;
                OutputStep(0, "监听中(waiting),正在执行...");
                string file = GetParamValue(args, "file");
                if (await StepMonitor.getJsonFile(file))
                {
                    //CacheManager.Default.Set_SlidingExpire<string>("step", "download", TimeSpan.FromMinutes(10));
                    await SetStep("download");
                }
                intervelFlag = true;
            }
        })

Конечный эффект мониторинга заключается в следующем.

0a1229313e7688cd09e543bba68dea07.png

скачать

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

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

ca1d62e533538b8a846594a29b53981d.png

 

Закрыть сайт (необязательно)

Здесь я решаю, стоит ли закрывать сайт, исходя из того, содержит ли файл версии ключевое слово static.

string currVersion = await ReadFile("currVersion.txt");
if (currVersion.Contains("static"))
{
    OutputStep(2, "仅更新静态文件,无需重启站点");
}
else
{
    OutputStep(2, "站点关闭中(stopweb),正在执行...");                            
    string appSite = GetParamValue(args, "appSite");
    string appPool = GetParamValue(args, "appPool");
    StepIISManager.Stop(appSite, appPool);                                                    
}

Скриншоты двух ситуаций следующие:

 

2acbd9f5e29b5110e29b61d657749d0a.png

45ae0898e89be29028930798c789f268.png

файл резервной копии

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

//这里的参数是解压地址
string inputPath = GetParamValue(args, "output");
string outputPath = GetParamValue(args, "backuppath");

string currVersion = await ReadFile("currVersion.txt");
string subPath = GetParamValue(args, "subpath");
OutputStep(3, "站点备份中(backup),正在执行...");
if (!string.IsNullOrEmpty(subPath))
{
    AnsiConsole.MarkupLine("[#FDE047]检测到子目录参数,不再进行全量备份,正在顺序备份[/]");
    if (!string.IsNullOrEmpty(subPath))
    {
        string[] parts = subPath.Split(',');
        var paths = parts.Where(u => !u.Contains(".")).ToList();
        var files = parts.Where(u => u.Contains(".")).ToList();
        if (files.Any()&&paths.Any(u=>!u.Equals("_temp")))
        {
            paths.Add("_temp");
        }
        foreach(var file in files)
        {
            AnsiConsole.MarkupLine($"[#FDE047]文件{file}备份中...[/]");
            string subInputPath = Path.Combine(inputPath, file);
            if (File.Exists(subInputPath))
            {
                string tempPath = Path.Combine(inputPath, "_temp");
                if (!Directory.Exists(tempPath))
                {
                    Directory.CreateDirectory(tempPath);
                }
                File.Copy(subInputPath, Path.Combine(tempPath, file), true);                                                                                
            }
        }
        foreach (var item in paths)
        {
            
            AnsiConsole.MarkupLine($"[#FDE047]{item}备份中...[/]");
            string subInputPath = Path.Combine(inputPath, item);                                    
            await StepDeCompress.ZipCompress(subInputPath, outputPath, item);
        }
    }
}
else
{
    await StepDeCompress.ZipCompress(inputPath, outputPath);
}

6e773434141f2bdf78f3c886a46d1bf7.png

 

Разархивировать

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

/// <summary>
/// 解压文件
/// </summary>
/// <param name="inputFile">解压文件路径</param>
/// <param name="outputFile">解压文件后路径</param>
public static void Decompression(string inputFile, string outputFile)
{
    try
    {
        if (!inputFile.Contains(":"))
        {
            inputFile = Path.Combine(Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName), inputFile);
        }
        SharpCompress.Readers.ReaderOptions options = new SharpCompress.Readers.ReaderOptions();
        options.ArchiveEncoding.Default = Encoding.GetEncoding("utf-8");
        var archive = ArchiveFactory.Open(inputFile, options);
        AnsiConsole.Status()
            .Start("解压文件...", ctx =>
            {
                foreach (var entry in archive.Entries)
                {
                    if (!entry.IsDirectory)
                    {                        
                        entry.WriteToDirectory(outputFile, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
                    }
                }
                AnsiConsole.MarkupLine("[#1E9FFF]解压完成[/]");
            });
    }
    catch (Exception ex)
    {
        AnsiConsole.WriteLine($"[red]{ex.Message}[/]");
        throw;
    }
}

визуализации

f6a30980c4a55eb22a1be0b2dd39ed03.png

 

Перезапустить сайт (необязательно)

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

if (currVersion.Contains("static"))
{
    OutputStep(5, "仅更新静态文件,无需重启站点");
}
else
{
    OutputStep(5, "站点启动中(startweb),正在执行...");                            
    string appSite = GetParamValue(args, "appSite");
    string appPool = GetParamValue(args, "appPool");
    StepIISManager.Start(appSite, appPool);
    Console.WriteLine(DateTime.Now.ToString());
}

Эффект

6bcad7bf550556a31f6962cb7a61cff7.png

 

Отправить уведомление

Эта часть на самом деле само собой разумеется. Речь идет об отправке электронного письма назначенному менеджеру. Содержание электронного письма должно включать подробную информацию об обновлении.

Код выкладывать сюда не буду, посмотрим на рендеры.

ac36f149aa68988b468ee10a6f725971.png

 

3927d101fdadac9e5824a49f9e9b9032.png

Подведем итог

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

Лично я отношусь к микросервисам в основном как верующий, и я активно принимаю трансформацию.Руководитель группы также поддерживает нас в преобразовании существующего бизнеса в микросервисную архитектуру шаг за шагом, исходя из реальной ситуации.Однако, в конце концов, это — это проект, который запущен в производство, и нам все еще нужно, чтобы Стабильность — наш главный приоритет, поэтому мы двигаемся гораздо медленнее. Большое количество предприятий по-прежнему работают на основе структуры одного приложения, поэтому основные задачи разработки и обслуживания по-прежнему основаны на реальном бизнесе.Мы с осторожным оптимизмом смотрим на трансформацию. Я думаю, что это объективное, позитивное и правильное отношение.Инновации сами по себе — увлекательная вещь с неопределенным будущим, но слишком активное участие или даже выполнение каких-то экстремальных операций приведет к непредсказуемым рискам. Правильный путь — начинать с реальности, комбинировать бизнес-условия и действовать шаг за шагом. Я также верю, что в 2023 году мы, наконец, сделаем самый важный шаг на пути к трансформации.

 

прикрепил

Адрес кода: For Yourself_Bring Salt/AutoDeploy · GitCode

 

рекомендация

отblog.csdn.net/juanhuge/article/details/128677380