Google Cloud External Load Balancer 的後端服務隨機失敗並出現 502 伺服器錯誤
我有以下外部Google云負載均衡器配置:
- GlobalNetworkEndpointGroupToClusterByIp是 Internet NEG,類型
INTERNET_IP_PORT
指向 Kubernetes 集群的 IP。- GlobalNetworkEndpointGroupToManagedS3是 Internet NEG,類型
INTERNET_FQDN_PORT
指向由 Yandex S3 服務管理。由於某種原因,某些後端服務無法工作,當我嘗試連接它們時,它們會響應 HTML 頁面顯示502 Server Error:
錯誤:伺服器錯誤
伺服器遇到臨時錯誤,無法完成您的請求。
請在 30 秒後重試。
在失敗的後端服務日誌中總是有以下錯誤:
jsonPayload: { cacheId: "GRU-c0ee45d8" @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry" statusDetails: "failed_to_pick_backend" }
對後端服務的請求在 1 毫秒內失敗(如日誌中所述),因此它們似乎甚至沒有嘗試連接到我的 Kubernetes 集群的 IP 或託管 S3 並立即失敗。
在發布此問題時,S3 和 Imgproxy 後端服務狀況良好,但其他服務無法正常工作:
如果我重新部署所有內容,其他一些服務可能會失敗,例如:
- API 和 Docs 會起作用,其他會失敗
- API、Docs、FPS 和 Imgproxy 將工作,S3 將失敗
- S3 會工作,其他人會失敗
所以這絕對是隨機的,我不明白為什麼會發生。如果我足夠幸運,重新部署後所有後端服務都會執行良好。也有可能它們都不起作用。
Kubernetes 集群可以正常工作,它接受連接,託管 S3 也可以正常工作。它看起來像一個錯誤,但我在 Google 中找不到任何關於此的內容。
這是我的 Terraform 配置的外觀:
resource "google_compute_global_network_endpoint_group" "kubernetes-cluster" { name = "kubernetes-cluster-${var.ENVIRONMENT_NAME}" network_endpoint_type = "INTERNET_IP_PORT" depends_on = [ module.kubernetes-resources ] } resource "google_compute_global_network_endpoint" "kubernetes-cluster" { global_network_endpoint_group = google_compute_global_network_endpoint_group.kubernetes-cluster.name port = 80 ip_address = yandex_vpc_address.kubernetes.external_ipv4_address.0.address } resource "google_compute_global_network_endpoint_group" "s3" { name = "s3-${var.ENVIRONMENT_NAME}" network_endpoint_type = "INTERNET_FQDN_PORT" } resource "google_compute_global_network_endpoint" "s3" { global_network_endpoint_group = google_compute_global_network_endpoint_group.s3.name port = 443 fqdn = trimprefix(local.s3.endpoint, "https://") } resource "google_compute_backend_service" "s3" { name = "s3-${var.ENVIRONMENT_NAME}" backend { group = google_compute_global_network_endpoint_group.s3.self_link } custom_request_headers = [ "Host:${google_compute_global_network_endpoint.s3.fqdn}" ] cdn_policy { cache_key_policy { include_host = true include_protocol = false include_query_string = false } } enable_cdn = true load_balancing_scheme = "EXTERNAL" log_config { enable = true sample_rate = 1.0 } port_name = "https" protocol = "HTTPS" timeout_sec = 60 } resource "google_compute_backend_service" "imgproxy" { name = "imgproxy-${var.ENVIRONMENT_NAME}" backend { group = google_compute_global_network_endpoint_group.kubernetes-cluster.self_link } cdn_policy { cache_key_policy { include_host = true include_protocol = false include_query_string = false } } enable_cdn = true load_balancing_scheme = "EXTERNAL" log_config { enable = true sample_rate = 1.0 } port_name = "http" protocol = "HTTP" timeout_sec = 60 } resource "google_compute_backend_service" "api" { name = "api-${var.ENVIRONMENT_NAME}" custom_request_headers = [ "Access-Control-Allow-Origin:${var.ALLOWED_CORS_ORIGIN}" ] backend { group = google_compute_global_network_endpoint_group.kubernetes-cluster.self_link } load_balancing_scheme = "EXTERNAL" log_config { enable = true sample_rate = 1.0 } port_name = "http" protocol = "HTTP" timeout_sec = 60 } resource "google_compute_backend_service" "front" { name = "front-${var.ENVIRONMENT_NAME}" backend { group = google_compute_global_network_endpoint_group.kubernetes-cluster.self_link } cdn_policy { cache_key_policy { include_host = true include_protocol = false include_query_string = true } } enable_cdn = true load_balancing_scheme = "EXTERNAL" log_config { enable = true sample_rate = 1.0 } port_name = "http" protocol = "HTTP" timeout_sec = 60 } resource "google_compute_url_map" "default" { name = "default-${var.ENVIRONMENT_NAME}" default_service = google_compute_backend_service.front.self_link host_rule { hosts = [ local.hosts.api, local.hosts.fps ] path_matcher = "api" } host_rule { hosts = [ local.hosts.s3 ] path_matcher = "s3" } host_rule { hosts = [ local.hosts.imgproxy ] path_matcher = "imgproxy" } path_matcher { default_service = google_compute_backend_service.api.self_link name = "api" } path_matcher { default_service = google_compute_backend_service.s3.self_link name = "s3" } path_matcher { default_service = google_compute_backend_service.imgproxy.self_link name = "imgproxy" } test { host = local.hosts.docs path = "/" service = google_compute_backend_service.front.self_link } test { host = local.hosts.api path = "/" service = google_compute_backend_service.api.self_link } test { host = local.hosts.fps path = "/" service = google_compute_backend_service.api.self_link } test { host = local.hosts.s3 path = "/" service = google_compute_backend_service.s3.self_link } test { host = local.hosts.imgproxy path = "/" service = google_compute_backend_service.imgproxy.self_link } } # See: https://github.com/hashicorp/terraform-provider-google/issues/5356 resource "random_id" "managed-certificate-name" { byte_length = 4 prefix = "default-${var.ENVIRONMENT_NAME}-" keepers = { domains = join(",", values(local.hosts)) } } resource "google_compute_managed_ssl_certificate" "default" { name = random_id.managed-certificate-name.hex lifecycle { create_before_destroy = true } managed { domains = values(local.hosts) } } resource "google_compute_ssl_policy" "default" { name = "default-${var.ENVIRONMENT_NAME}" profile = "MODERN" } resource "google_compute_target_https_proxy" "default" { name = "default-${var.ENVIRONMENT_NAME}" url_map = google_compute_url_map.default.self_link ssl_policy = google_compute_ssl_policy.default.self_link ssl_certificates = [ google_compute_managed_ssl_certificate.default.self_link ] } resource "google_compute_global_forwarding_rule" "default" { name = "default-${var.ENVIRONMENT_NAME}" load_balancing_scheme = "EXTERNAL" port_range = "443-443" target = google_compute_target_https_proxy.default.self_link }
**UPD。**我發現重新創建 NEG 將解決這個問題:
- 等到 Terraform 完成部署。
- 通過具有相同配置的 Google Cloud Platform Console NEG 創建。
- 編輯後端服務以使用新創建的 NEG。
- 有用!
但這絕對是 hack,似乎沒有辦法用 Terraform 自動化它。我會繼續調查這個問題。
很高興聽到您的問題已得到解決,我了解您已通過 GCP 控制台手動創建 NEG 並隨後編輯後端服務而不是使用 Terraform 來實現它。這個問題最可能的原因似乎是競速條件,即在 Terraform 中,我們通常在鏈中定義資源,因此定義的每個資源都依賴於另一個資源。通常在通過 Terraform 定義資源時,後端服務創建和 NE 附件依賴於 NEG 創建。
因此,在 Terraform 中創建後端服務時,我們必須將其定義為依賴(元參數)
$$ 1 $$NE 連接(即後端服務應僅在 NE 連接後執行)。 $$ 1 $$ https://www.terraform.io/docs/language/meta-arguments/depends_on.html 希望這能澄清你的疑問。