diff --git a/containers_part2.go b/containers_part2.go index 6f8f3ca..55f1901 100644 --- a/containers_part2.go +++ b/containers_part2.go @@ -212,22 +212,28 @@ func getContainerDrainInfo(containerName string) (timestamp int64, isMigration b return ts, migration, true } -func markAngieConfigForDrain(clientTitle string) error { +func markAngieConfigForDrain(clientTitle string, isMigration bool) error { markerFile := fmt.Sprintf("/tmp/ptaf-angie-drain-%s", clientTitle) - return os.WriteFile(markerFile, []byte(fmt.Sprintf("%d", time.Now().Unix())), 0644) + content := fmt.Sprintf("%d", time.Now().Unix()) + if isMigration { + content += ":migration" + } + return os.WriteFile(markerFile, []byte(content), 0644) } -func getAngieConfigDrainTimestamp(clientTitle string) (int64, bool) { +func getAngieConfigDrainInfo(clientTitle string) (timestamp int64, isMigration bool, found bool) { markerFile := fmt.Sprintf("/tmp/ptaf-angie-drain-%s", clientTitle) data, err := os.ReadFile(markerFile) if err != nil { - return 0, false + return 0, false, false } - timestamp, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64) + parts := strings.SplitN(strings.TrimSpace(string(data)), ":", 2) + ts, err := strconv.ParseInt(parts[0], 10, 64) if err != nil { - return 0, false + return 0, false, false } - return timestamp, true + migration := len(parts) == 2 && parts[1] == "migration" + return ts, migration, true } func stopAndRemoveContainer(containerName, composeFile, containerDir string) error { @@ -635,6 +641,10 @@ func generateDockerCompose(filePath string, config Config, clientTitle string, c {{- end}} sysctls: kernel.sem: "32000 1024000000 500 32000" + ulimits: + nofile: + soft: 1048576 + hard: 1048576 ports: {{- range .SortedHTTPPorts}} - 127.0.0.1:{{.DockerPort}}:{{.CustomPort}}/tcp diff --git a/drain.go b/drain.go index a75fa01..8cd17d9 100644 --- a/drain.go +++ b/drain.go @@ -43,7 +43,6 @@ func getActualContainerCount(clientTitle string) int { func processDrainingAngieConfigs() { currentTime := time.Now().Unix() - timeout := int64(MigrationDrainTimeout) hostname, err := os.Hostname() if err != nil { log.Printf("⚠ Ошибка получения hostname: %v", err) @@ -65,26 +64,40 @@ func processDrainingAngieConfigs() { continue } clientTitle := strings.Join(parts[3:], "-") - drainTimestamp, found := getAngieConfigDrainTimestamp(clientTitle) + drainTimestamp, isMigration, found := getAngieConfigDrainInfo(clientTitle) if !found { continue } + + var timeout int64 + timeoutName := "масштабирование" + if isMigration { + timeout = int64(MigrationDrainTimeout) + timeoutName = "миграция" + } else { + timeout = int64(ContainerDrainTimeout) + } + elapsedTime := currentTime - drainTimestamp remainingTime := timeout - elapsedTime angieConfigPath := fmt.Sprintf("/etc/angie/http.d/angie-ptaf-%s.conf", clientTitle) if elapsedTime >= timeout { - log.Printf(" Конфиг Angie для %s завершил drain (прошло %d сек), проверяю актуальность...", clientTitle, elapsedTime) - clientInfo, err := getClientInfoByClientTitle(db, clientTitle) - if err == nil && clientInfo.WAFInstance != "" { - belongsNow, checkErr := checkHostBelongsToInstance(db, hostname, clientInfo.WAFInstance) - if checkErr == nil && belongsNow { - log.Printf(" ⚠ Клиент %s снова принадлежит этому хосту, ОТМЕНЯЮ удаление конфига", clientTitle) - os.Remove(markerFile) - continue + log.Printf(" Конфиг Angie для %s завершил drain [%s] (прошло %d сек), проверяю актуальность...", clientTitle, timeoutName, elapsedTime) + if isMigration { + clientInfo, err := getClientInfoByClientTitle(db, clientTitle) + if err == nil && clientInfo.WAFInstance != "" { + belongsNow, checkErr := checkHostBelongsToInstance(db, hostname, clientInfo.WAFInstance) + if checkErr == nil && belongsNow { + log.Printf(" ⚠ Клиент %s снова принадлежит этому хосту, ОТМЕНЯЮ удаление конфига", clientTitle) + os.Remove(markerFile) + continue + } } + log.Printf(" → Клиент %s не принадлежит этому хосту, удаляю конфиг", clientTitle) + } else { + log.Printf(" → Удаляю конфиг Angie для %s", clientTitle) } - log.Printf(" → Клиент %s не принадлежит этому хосту, удаляю конфиг", clientTitle) if _, err := os.Stat(angieConfigPath); err == nil { if err := os.Remove(angieConfigPath); err != nil { log.Printf(" ⚠ Ошибка удаления конфига Angie: %v", err) @@ -98,7 +111,7 @@ func processDrainingAngieConfigs() { os.Remove(markerFile) } } else { - log.Printf(" ○ Конфиг Angie для %s в процессе drain [миграция] (осталось %d сек)", clientTitle, remainingTime) + log.Printf(" ○ Конфиг Angie для %s в процессе drain [%s] (осталось %d сек)", clientTitle, timeoutName, remainingTime) } } } @@ -169,7 +182,7 @@ func processAllDrainingContainersGlobally(db *sql.DB, hostname string) { } angieConfigPath := fmt.Sprintf("/etc/angie/http.d/angie-ptaf-%s.conf", clientTitle) if _, err := os.Stat(angieConfigPath); err == nil { - if err := markAngieConfigForDrain(clientTitle); err != nil { + if err := markAngieConfigForDrain(clientTitle, true); err != nil { log.Printf(" ⚠ Ошибка пометки Angie конфига: %v", err) } else { log.Printf(" ✓ Angie конфиг помечен для удаления") diff --git a/main.go b/main.go index c494bcf..b143d5e 100644 --- a/main.go +++ b/main.go @@ -303,7 +303,7 @@ func handleClientMigration(clientInfo ClientInfo, hostname string) { angieConfigPath := fmt.Sprintf("/etc/angie/http.d/angie-ptaf-%s.conf", clientInfo.ClientTitle) if _, err := os.Stat(angieConfigPath); err == nil { log.Printf(" → Помечаю конфиг Angie для удаления (миграция, таймаут %d сек)", MigrationDrainTimeout) - if err := markAngieConfigForDrain(clientInfo.ClientTitle); err != nil { + if err := markAngieConfigForDrain(clientInfo.ClientTitle, true); err != nil { log.Printf(" ⚠ Ошибка пометки конфига: %v", err) } else { log.Printf(" ✓ Конфиг Angie помечен для удаления") diff --git a/ptaf_processor.go b/ptaf_processor.go index 6ee22d5..2ec30cb 100644 --- a/ptaf_processor.go +++ b/ptaf_processor.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net" + "os" "strings" "time" ) @@ -53,6 +54,23 @@ func processPTAFClient( log.Printf("✓ Клиент %s принадлежит instance '%s', обрабатываю", clientInfo.ClientTitle, clientInfo.WAFInstance) } + // Если контейнеров 0 — помечаем все существующие для drain и выходим + if clientInfo.ContainersCount == 0 { + log.Printf("⚠ Количество контейнеров равно 0 для %s — помечаю существующие контейнеры для drain", clientInfo.ClientTitle) + processDrainingContainers(clientInfo.ClientTitle, 0) + + angieConfigPath := fmt.Sprintf("/etc/angie/http.d/angie-ptaf-%s.conf", clientInfo.ClientTitle) + if _, err := os.Stat(angieConfigPath); err == nil { + log.Printf(" → Помечаю конфиг Angie для удаления (контейнеров 0)") + if err := markAngieConfigForDrain(clientInfo.ClientTitle, false); err != nil { + log.Printf(" ⚠ Ошибка пометки конфига Angie: %v", err) + } else { + log.Printf(" ✓ Конфиг Angie помечен для удаления") + } + } + return false + } + // Автоочистка устаревших маркеров drain cleanStaleDrainMarkers(clientInfo)