Назад | Перейти на главную страницу

Не удается подключиться к Cloud SQL Postgres из GKE через частный IP-адрес

У меня проблемы с доступом к экземпляру Cloud SQL, на котором запущен Postgres, из кластера GKE с использованием частного IP-адреса базы данных. Вся найденная мною документация предлагает использовать для этого кластер с поддержкой VPC, но у меня все еще возникают проблемы с доступом к базе данных.

В частности, я могу получить доступ к базе данных с узлов в моем кластере, но я не могу получить доступ к базе данных из контейнера на узле, если я не запустил контейнер докеров, используя сеть хоста. Это заставляет меня думать, что я неправильно понимаю, как сетевые компоненты GCP VPC и Kubernetes взаимодействуют друг с другом.

VPC

В моем VPC есть одна подсеть с двумя дополнительными диапазонами:

Диапазон IP: 10.0.0.0/16
Вторичный диапазон - стручки: 10.1.0.0/16
Secondary Range - услуги: 10.2.0.0/16

Он создается с использованием следующей конфигурации Terraform:

resource "google_compute_subnetwork" "cluster" {
  ip_cidr_range            = "10.0.0.0/16"
  name                     = "cluster"
  network                  = google_compute_network.vpc.self_link

  secondary_ip_range {
    ip_cidr_range = "10.1.0.0/16"
    range_name    = "pods"
  }

  secondary_ip_range {
    ip_cidr_range = "10.2.0.0/16"
    range_name    = "services"
  }
}

База данных

Моя облачная база данных SQL работает под управлением Postgres 11 и настроена так, чтобы разрешать соединения только через частный IP. Я установил пиринговое соединение с набором глобальных вычислительных адресов, чтобы разрешить доступ к экземпляру Cloud SQL из моего VPC. В этом случае я получил следующие значения:

Диапазон IP-адресов подключения к частной службе: 172.26.0.0/16
Частный IP-адрес базы данных: 172.26.0.3

Эти ресурсы предоставляются со следующей конфигурацией Terraform:

resource "google_compute_global_address" "db_private_ip" {
  provider = "google-beta"

  name          = "db-private-ip"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = google_compute_network.vpc.self_link
}

resource "google_service_networking_connection" "db_vpc_connection" {
  network                 = google_compute_network.vpc.self_link
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.db_private_ip.name]
}


resource "google_sql_database_instance" "db" {
  depends_on = [google_service_networking_connection.db_vpc_connection]

  database_version = "POSTGRES_11"

  settings {
    availability_type = "ZONAL"
    tier              = "db-f1-micro"

    ip_configuration {
      ipv4_enabled    = false
      private_network = google_compute_network.vpc.self_link
    }
  }
}

Кластер

Мой кластер GKE настроен как собственный VPC и использует дополнительные диапазоны из cluster подсеть VPC. Некоторая важная информация о кластере:

Основная версия: 1.14.8-гке.17
Сеть: мой-vpc
Подсеть: кластер
VPC-native: Включено
Диапазон адресов пакета: 10.1.0.0/16
Диапазон адресов службы: 10.2.0.0/16

Кластер создается с использованием следующей конфигурации Terraform:

resource "google_container_cluster" "primary" {
  location           = var.gcp_region
  min_master_version = data.google_container_engine_versions.latest_patch.latest_master_version
  name               = "my-cluster"
  network            = google_compute_network.vpc.self_link
  subnetwork         = google_compute_subnetwork.cluster.self_link

  # We can't create a cluster with no node pool defined, but we want to only use
  # separately managed node pools. So we create the smallest possible default
  # node pool and immediately delete it.
  remove_default_node_pool = true
  initial_node_count       = 1

  ip_allocation_policy {
    use_ip_aliases                = true
    cluster_secondary_range_name  = "pods"
    services_secondary_range_name = "services"
  }

  master_auth {
    username = ""
    password = ""

    client_certificate_config {
      issue_client_certificate = false
    }
  }
}

Попытки подключения

Я делал попытки подключиться к базе данных из разных контекстов, чтобы попытаться выяснить проблему.

Автономный экземпляр

Я создал новую вычислительную виртуальную машину Ubuntu в своем VPC и смог подключиться к базе данных, используя оба nping и psql.

Из контейнера на узле

Либо используя kubectl attach на модуле в моем кластере или подключении SSH к узлу и выполнении моей собственной команды docker, я вижу, что все пакеты в базу данных не проходят.

# SSH-ing and running a docker container.
docker run -it ubuntu /bin/bash -c 'apt update && apt install -y nmap && nping --tcp -p 5432 172.26.0.3'

Из контейнера на узле в сети хоста

Если я повторю команду сверху, но использую сеть хоста, я могу подключиться к базе данных.

docker run -it --net host ubuntu /bin/bash -c 'apt update && apt install -y nmap && nping --tcp -p 5432 172.26.0.3'

Предложения?

Поскольку большинство вопросов о подключении к экземпляру Cloud SQL из GKE через частный IP-адрес решаются, когда они настраивают свой кластер как VPC-native, я предполагаю, что моя проблема кроется где-то в моей сетевой конфигурации. Буду признателен за любые предложения и рад предоставить любую дополнительную информацию. Спасибо.

Связанные вопросы

Проблема с подключением к Cloud SQL Postgres с использованием частного IP-адреса от GKE

Обновление 2019-12-05

Преобразование команд из связанный вопрос связанный выше с Terraform (назовите это конфигурацией MVP), я могу подключиться к экземпляру Postgres, используя частный IP-адрес, поэтому теперь я считаю, что проблема лежит глубже в моей конфигурации. Я до сих пор не определил, какая именно часть моей инфраструктуры отличается от конфигурации MVP.

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

У меня это работает со следующей настройкой VPC terraform, основная разница, которую я вижу в настройке OP, заключается в том, что я определяю сеть верхнего уровня, см. Ниже {"google_compute_network" "gke-sql-vpc-impl"} в отличие от OPs используют 'google_compute_network.vpc.self_link'

variable "public-subnet-cidr" {
default = "10.1.0.0/24"
}
resource "google_compute_network" "gke-sql-vpc-impl" {
name                    = "${var.network}"
auto_create_subnetworks = "false"
}

resource "google_compute_global_address" "mysql-private-ip-address-impl" {
name          = "mysql-private-ip-address"
purpose       = "VPC_PEERING"
address_type  = "INTERNAL"
prefix_length = 16
network       = "${google_compute_network.gke-sql-vpc-impl.name}"
}

resource "google_service_networking_connection" "private-mysql-vpc-connection-impl" {
network                 = "${google_compute_network.gke-sql-vpc-impl.self_link}"
service                 = "servicenetworking.googleapis.com"
reserved_peering_ranges = ["${google_compute_global_address.mysql-private-ip-address-impl.name}"]
}

resource "google_compute_subnetwork" "public-subnet-impl" {
name          = "${var.network}-public-subnet"
ip_cidr_range = "${var.public-subnet-cidr}"
network       = "${var.network}"
depends_on    = ["google_compute_network.gke-sql-vpc-impl"]
region        = "${var.region}"

secondary_ip_range {
ip_cidr_range = "10.2.0.0/16"
range_name    = "pods"
}

secondary_ip_range {
ip_cidr_range = "10.3.0.0/16"
range_name    = "services"
 }
}

с помощью этого VPC я могу подключиться из модуля к экземпляру Cloud SQL, используя частный IP-адрес, указанный выше mysql-private-ip-address-impl. Также у меня настроены правила брандмауэра для tcp и порт базы данных экземпляра Cloud SQL, привязанный к узлам кластера.

resource "google_container_cluster" "primary" {
name                     = "${var.cluster_name}"
location                 = "${var.zone}"
remove_default_node_pool = false
initial_node_count       = "${var.node_count_simple}"
network            = "${google_compute_network.gke-sql-vpc-impl.name}"
subnetwork         = "${google_compute_subnetwork.public-subnet-impl.name}"  

ip_allocation_policy {
cluster_secondary_range_name  = "pods"
services_secondary_range_name = "services"
}

node_config {
machine_type = "${var.pool_machine_type}"
preemptible  = true
oauth_scopes = [
  "https://www.googleapis.com/auth/compute",
  "https://www.googleapis.com/auth/devstorage.read_only",
  "https://www.googleapis.com/auth/logging.write",
  "https://www.googleapis.com/auth/monitoring"
 ]

 tags = ["default-nodeport-http", "default-nodeport-https", "default-firewall-mysql"]
  }

 master_auth {
 username = ""
 password = ""
 client_certificate_config {
  issue_client_certificate = false
  }
 }
}

Существуют определенные сетевые требования, которым должны соответствовать экземпляры Cloud SQL при обмене данными через частное соединение. Во-первых, ваши экземпляры CloudSQL и GKE расположены в одном регионе и в одной сети VPC. [1]

Что касается «Я не могу получить доступ к базе данных из контейнера на узле», означает ли это, что ваша база данных и контейнер расположены в разных сетях? В таком случае вы не можете получить доступ к экземпляру Cloud SQL по его частному IP-адресу из другой сети, используя туннель Cloud VPN, VPN на основе экземпляра или межсоединение Cloud.

[1] https://cloud.google.com/sql/docs/mysql/private-ip#network_requirements.

Когда дело касается сети, контейнеры работают так же, как виртуальные машины (хост и гость). На примере виртуального бокса показаны разные типы сетей https://www.nakivo.com/blog/virtualbox-network-setting-guide/ и они очень полезны в других сетевых сценариях, например, в контейнеризации. Что у вас есть с GKE, я считаю Внутренняя сеть поэтому вы должны использовать iptables на узле. В GCP, например, этот материал используется для шлюзов NAT при создании экземпляра NAT, который обеспечивает доступ в Интернет для всех других виртуальных машин.

Кроме того, узел должен находиться в том же регионе, что и CloudSQL, потому что в противном случае использование частного IP-адреса не будет работать. P.S. Если вы думаете о принудительном использовании SSL в будущем в своем экземпляре CloudSQL, не делайте этого, если вы не хотите навсегда потерять частное подключение. Я только что обратился в службу поддержки GCP, так как считаю это ошибкой.