Сервис развернут контейнере (Docker desktop). Пожаловались, что иногда он вываливается и единственное решение - полный перезапуск wsl и "docker desktop". Пользователь в будуюшем будет переносить докеры в linux среду, а на текущий момент нужен костыль. Сразу оговорюсь, попытка создать службу docker провалилась, поэтому здесь решение совсем грязное. Но в самом скрипте есть пара интересных, для меня, моментов, поэтому кладу его здесь.
Скрипт проверяет ответ от web-сервиса (внешний адрес и порт), если его нету, то ждет N время, иначе выходит. По истечении N времени идет повторная проверка, если ответа нет, то идет проверка локальная, иначе выход. Если локальная проверка не прошла, то перезапускаем нужные службы и программы, иначе выходим.
Запускать я решил батником в task scheduller, чтобы не править каждый раз задачу. При этом задача должна выполнятся от имени администратора и БЕЗ привязки к пользователю, иначе Desktop manager не запустит контейнеры.
Два триггера
Для автозапуска Docker desktop при загрузке ПК настраиваем автовход пользователя (control userpasswords2) и автозапуск Docker desktop при входе в настройках программы. На данный момент это единственное рабочее решение из найденных :-(
Команда запуска в планировщике (окно скрипта скрыто)
%windir%\system32\cmd.exe
/c start /min C:\usr\WSLCheckStart.bat ^& exit
Будьте осторожны с таким методом скрытия окна. Этот метод открывает скрипт за пределами планировщика. Планировщик не может контролировать выполнение задачи, а значит возможно наложение нескольких задач. Для таких случаев рекомендуется проводить проверку в самом скрипте.
Батник:
@echo off
cd %~dp0
set "pathscript=%~dp0\WSLCheck.ps1"
set "pathlog=%~dp0\log"
mkdir %~dp0\log
IF EXIST %pathscript% (
powershell.exe -NoProfile -ExecutionPolicy Bypass -File %pathscript% -Address "dev.site.com" -Port "443" -LocalPort "8080" -TimeOut 20 -TimeOutHTTP 10 -LogFile %pathlog%
) ELSE (
echo "ERROR! %pathscript% not exist"
echo "ERROR! %pathscript% not exist" >> WSLLogStart.log
)
Сам скрипт Powershell
#Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
#Set-ExecutionPolicy Undefined -Scope CurrentUser
# скрипт на входе принимает ряд параметров
# Address - строка - fqdn проверяемого ресурса
# Port - строка - внешний порт подключения
# LocalPort - строка - локальный порт. Так как скрипт запускается на сервере, где крутится сам сервис, то мы можем проверить доступность сервиса локально и исключить ошибку доступа снаружи (нет интернета, сломался nginx, сломались dns записи)
# TimeOut - число - время в секундах между первой второй проверкой доступности сервиса снаружи. Если обе проверки провались, идет проверка локальной доступности
# TimeOutHTTP - число - время в секундах таймаут проверки доступности сайта
# LogFilePath - строка - куда писать лог папка
# whatif - переключатель - аналог оригинального параметра whatif, в данном случае скрипт не выполняет перезапуск, а только говорит о том, что будет делать
param(
[Parameter()]
[string]$Address='web.site.com',
[Parameter()]
[string]$Port='443',
[Parameter()]
[string]$LocalPort='8080',
[Parameter()]
[int]$TimeOut='20',
[Parameter()]
[int]$TimeOutHTTP='10',
[Parameter()]
[string]$LogFilePath="C:\usr\",
[Parameter()]
[switch]$whatif
)
# Требуется для сравнения внешнего и внутреннего резолва. Избежать такой ситуации мы не можем, а записать об этом информацию - можем
$DNSServer="8.8.8.8"
# Разрешенное время работы ПК без запущенного серивса. Избегаем ошибки когда система еще не запустилась, а скрипт уже работает
$AcceptUptime=600
# localhost может вернуть как IPv4, так и IPv6 адрес, что может привести к ложному срабатыванию, если есть разные сервисы на одном порту, но по разным IP
$localhost="127.0.0.1"
$DockerDesktopPath="C:\Program Files\Docker\Docker\Docker Desktop.exe"
$DateTimeStamp=Get-Date -Format "dd.MM.yyyy"
$LogFile="$LogFilePath\$DateTimeStamp`_WSLCheck.log"
# простенькая функция логирования, если файл есть, то пишет в него
# можно было использовать tee-object, но этот командлет выдает ошибку при отсутствии папки для лога
# level - число -
function Logging($Message,$Level=0,$CheckRepeat=$false){
if ("$Message" -eq ""){
return
}
$mLevel=switch($level){
0 {New-Object psobject -Property @{label="[INF]";color="White"}}
1 {New-Object psobject -Property @{label="[WAR]";color="Yellow"}}
2 {New-Object psobject -Property @{label="[ERR]";color="Red"}}
}
$CurrentTimeStamp=Get-Date -Format "dd.MM.yyyy`tHH:mm:ss"
Write-Host "$Message" -ForegroundColor $mLevel.color
if ($whatif){return}
if (-not (Test-Path $LogFile)) {New-Item -Path $LogFile -ItemType File -ErrorAction SilentlyContinue}
if (Test-Path $LogFile) {
$lastLine=""
if ($CheckRepeat){
$lastLine=$(Get-Content -Path $LogFile)[-1].Split("`t")[-1]
}
if ("$Message" -ne "$lastLine"){
Write-Output("$CurrentTimeStamp`t$($mLevel.label)`t$Message") | Out-File $LogFile -Append
}
}
}
# Проверяем уровень прав пользователя
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if ( -Not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "Error! Run this script as administrtor" -ForegroundColor Red
exit
}
# Проверяем аптайм ПК и выходим, если он меньше $AcceptUptime
$uptime = $(Get-Date)-(Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime
if ($uptime.TotalSeconds -lt $AcceptUptime){
Logging "PC uptime less then $AcceptUptime secundes, break"
exit
}
# Проверяем как резолвится имя сервиса
$ResolveDNSext=$(Resolve-DnsName -Name $Address -Server $DNSServer -DnsOnly).ip4address
$ResolveDNSint=$(Resolve-DnsName -Name $Address).ip4address
if ("$ResolveDNSext" -ne "$ResolveDNSint"){
logging "Resolve error! $DNSServer resolved $address as $ResolveDNSext. Local returned $ResolveDNSint!" 1
}
# Функция проверки доступности сервиса на указанном порту. Построена таким образом, что при успешно подключении завершает скрипт ( таким образом мы исключаем громоздкие конструкции if else листингом ниже)
function TestConnect(){
param(
[Parameter()]
[string]$Address,
[Parameter()]
[string]$Port,
[switch]$Web=$false,
[switch]$SSL=$true
)
if ($Web){
$protocol = if ($SSL) {"https://"} else {"http://"}
$port = if (($SSL) -and ($port -ne 443)) {"`:$port"} else {""}
$url="$protocol$address$port"
try {
$WebRequest=Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec $TimeOutHTTP
$StatusCode=$WebRequest.Statuscode
} catch {
$StatusCode=$_.Exception.Response.StatusCode.value__
}
$Status=$("$StatusCode" -eq "200")
} else {
$Status=$(Test-NetConnection $Address -Port $Port -InformationLevel Quiet)
$url="$Address`:$port"
}
if ($status){
Logging "Service ($url) is available"
exit
}
Logging "Service ($url) is unavailable" 1
}
# Сама программа
TestConnect -Address $Address -Port $Port -Web -SSL
# you are here because the last test failed
Logging "Wait $TimeOut seconds"
sleep $TimeOut
TestConnect -Address $Address -Port $Port -Web -SSL
# you are here because the second test failed
Logging "The service ($Address`:$port) has not been restored" 1
Logging "Check local service ($localhost`:$LocalPort)"
TestConnect -Address $localhost -Port $LocalPort -Web -SSL
Logging "The local service ($localhost`:$LocalPort) has not been restored" 1
# you are here because the third test failed
# Than onlyCheck
function RestartProgramm($ProcessName,$PathExeFile){
$processes = Get-Process "$ProcessName"
if ($processes.Count -gt 0)
{
$processes | ForEach-Object {
$_.Kill()
$_.WaitForExit()
logging "Process $($_.ProcessName) with PID $($_.id)`t ended"
}
logging "Waiting for all processes to shut down (5 sec)"
sleep 5
}
Start-Process -FilePath $PathExeFile -OutVariable SvcMessage -ErrorVariable SvcMessageErr -ErrorAction SilentlyContinue
Logging $SvcMessage
Logging $SvcMessageErr 2
return $($(Get-Process "$ProcessName").Count -gt 0)
}
function WSLRestart(){
logging "Restart WSL Service (LxssManager)...."
if (-not $whatif) {
Restart-Service LxssManager -OutVariable SvcMessage -ErrorVariable SvcMessageErr -ErrorAction SilentlyContinue
Logging $SvcMessage
Logging $SvcMessageErr 2
}
Logging "Restart docker desktop..."
if (-not $whatif) {
if (RestartProgramm "*docker desktop*" "$DockerDesktopPath") {
Logging "Docker desktop running!"
} else {
Logging "Docker desktop NOT running!" 2
}
}
}
WSLRestart
Комментариев нет:
Отправить комментарий