Change docker restart
This commit is contained in:
parent
38ab8369cb
commit
853ada564b
1 changed files with 38 additions and 41 deletions
|
|
@ -14,28 +14,51 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// isAngieEstabOnPort проверяет есть ли активные ESTAB соединения Angie на данном порту
|
// getBusyPortsFromList проверяет список портов одним вызовом ss и возвращает занятые
|
||||||
func isAngieEstabOnPort(port int) bool {
|
func getBusyPortsFromList(ports []int) []int {
|
||||||
cmd := exec.Command("ss", "-tnap")
|
cmd := exec.Command("ss", "-tnap")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
portStr := fmt.Sprintf(":%d", port)
|
|
||||||
|
// Строим set портов для быстрого поиска
|
||||||
|
portSet := make(map[int]bool, len(ports))
|
||||||
|
for _, p := range ports {
|
||||||
|
portSet[p] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
busy := make(map[int]bool)
|
||||||
for _, line := range strings.Split(string(output), "\n") {
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) < 4 {
|
if len(fields) < 4 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if fields[0] != "ESTAB" {
|
localAddr := fields[3]
|
||||||
|
lastColon := strings.LastIndex(localAddr, ":")
|
||||||
|
if lastColon < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
localAddr := fields[3]
|
var port int
|
||||||
if strings.HasSuffix(localAddr, portStr) && strings.Contains(line, "angie") {
|
if _, err := fmt.Sscanf(localAddr[lastColon+1:], "%d", &port); err != nil {
|
||||||
return true
|
continue
|
||||||
|
}
|
||||||
|
if !portSet[port] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
state := fields[0]
|
||||||
|
if state == "LISTEN" {
|
||||||
|
busy[port] = true
|
||||||
|
} else if state == "ESTAB" && strings.Contains(line, "docker-proxy") {
|
||||||
|
busy[port] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
|
result := make([]int, 0, len(busy))
|
||||||
|
for p := range busy {
|
||||||
|
result = append(result, p)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPortBusyByAnyProcess проверяет занят ли порт процессом который мешает биндингу.
|
// isPortBusyByAnyProcess проверяет занят ли порт процессом который мешает биндингу.
|
||||||
|
|
@ -115,50 +138,24 @@ func recreateContainer(containerFullName, composeFile, containerDir, clientTitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload Angie после остановки контейнера чтобы закрыть keepalive ESTAB соединения
|
// Reload Angie после остановки контейнера чтобы закрыть keepalive соединения
|
||||||
log.Printf(" → Reload Angie для закрытия keepalive соединений к остановленному контейнеру...")
|
log.Printf(" → Reload Angie для закрытия keepalive соединений к остановленному контейнеру...")
|
||||||
reloadAngie()
|
reloadAngie()
|
||||||
|
|
||||||
// Ждём пока Angie закроет ESTAB соединения к портам старого контейнера
|
|
||||||
log.Printf(" → Ожидаем закрытия ESTAB соединений Angie на портах %v...", portsToFree)
|
|
||||||
for attempt := 0; attempt < 30; attempt++ {
|
|
||||||
angieEstab := false
|
|
||||||
for _, port := range portsToFree {
|
|
||||||
if isAngieEstabOnPort(port) {
|
|
||||||
angieEstab = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !angieEstab {
|
|
||||||
log.Printf(" ✓ Все ESTAB соединения Angie закрыты (попытка %d)", attempt+1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if attempt%5 == 0 && attempt > 0 {
|
|
||||||
log.Printf(" → Angie ещё держит соединения (попытка %d/30)...", attempt+1)
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
if len(portsToFree) > 0 {
|
if len(portsToFree) > 0 {
|
||||||
log.Printf(" → Ожидаем освобождения %d портов...", len(portsToFree))
|
log.Printf(" → Ожидаем освобождения %d портов...", len(portsToFree))
|
||||||
allPortsFree := false
|
allPortsFree := false
|
||||||
for attempt := 0; attempt < 180; attempt++ {
|
for attempt := 0; attempt < 180; attempt++ {
|
||||||
portsBusy := 0
|
// Один вызов ss для всех портов сразу
|
||||||
busyPortsList := make([]int, 0)
|
busyPortsList := getBusyPortsFromList(portsToFree)
|
||||||
for _, port := range portsToFree {
|
if len(busyPortsList) == 0 {
|
||||||
if isPortBusyByAnyProcess(port) {
|
|
||||||
portsBusy++
|
|
||||||
busyPortsList = append(busyPortsList, port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if portsBusy == 0 {
|
|
||||||
allPortsFree = true
|
allPortsFree = true
|
||||||
log.Printf(" ✓ Все порты освобождены (попытка %d)", attempt+1)
|
log.Printf(" ✓ Все порты освобождены (попытка %d)", attempt+1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if attempt%5 == 0 && attempt > 0 {
|
if attempt%10 == 0 {
|
||||||
log.Printf(" → Ещё заняты %d портов: %v (попытка %d/180)", portsBusy, busyPortsList, attempt+1)
|
log.Printf(" → Ещё заняты %d портов: %v (попытка %d/180)", len(busyPortsList), busyPortsList, attempt+1)
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue