更新 2019-12-05

更新 2019-12-05

我无法使用数据库的私有 IP 从 GKE 集群访问运行 Postgres 的 Cloud SQL 实例。我找到的所有文档都建议使用启用 VPC 的集群来实现这一点,但我仍然无法访问数据库。

具体来说,我可以从集群中的节点访问数据库,但除非我使用主机的网络运行 docker 容器,否则我无法从节点上的容器内访问数据库。这让我相信我对 GCP VPC 和 Kubernetes 的网络组件如何相互交互存在误解。

私有云平台

我的 VPC 有一个子网,其中包含两个次要范围:

IP 范围:10.0.0.0/16
次要射程 - 吊舱:10.1.0.0/16
次要范围 - 服务: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 进行连接。我已与一组全局计算地址建立了对等连接,以允许从我的 VPC 访问云 SQL 实例。在这种情况下,我最终得到了以下值:

私人服务连接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 原生集群,并使用clusterVPC 子网中的次要范围。以下是一些相关的集群信息:

主版本:1.14.8-gke.17
网络:我的 VPC
子网:
VPC 原生:已启用
Pod 地址范围: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
    }
  }
}

连接尝试

我尝试从许多不同的环境连接到数据库以试图找出问题所在。

独立实例

我在我的 VPC 中启动了一个新的 Ubuntu 计算 VM,并且能够使用和连接到nping数据库psql

从节点上的容器

通过kubectl attach在我的集群中使用 pod 或通过 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'

有什么建议吗?

鉴于大多数关于通过私有 IP 从 GKE 连接到 Cloud SQL 实例的问题在他们将集群配置为 VPC 原生时得到解决,我认为我的问题出在我的网络配置中。我很感激任何建议,我很乐意提供任何其他信息。谢谢。

相关问题

使用 GKE 中的私有 IP 连接到 Cloud SQL Postgres 时出现问题

更新 2019-12-05

将命令从相关问题通过将上面链接的配置导入 Terraform(称为 MVP 配置),我能够使用私有 IP 连接到 Postgres 实例,因此我现在认为问题在于我的配置中。我仍然无法确定我的基础设施中究竟哪一部分与 MVP 配置不同。

我的下一次尝试可能是增强 MVP 配置以使用单独配置的节点池而不是默认节点池,看看是否能解释我所看到的行为。

答案1

对于我来说,这是一个完全可用的版本:

  • 使用 GCP GKE VPC 原生集群
  • 与私有 GCP PGSQL 实例配合使用

resource "google_compute_subnetwork" "gke-subnet" {
  name          = "gke-subnet"
  region        = var.region
  network       = google_compute_network.vpc.name
  ip_cidr_range = "10.10.0.0/16"
}

resource "google_container_cluster" "the_cluster" {
  provider            = google-beta
  name                = "gke"
  project             = var.project_id
  # single-zone cluster
  location            = var.zone
  # we need 1.17.6+ to use NEGs
  # https://cloud.google.com/kubernetes-engine/docs/concepts/ingress
  # min_master_version  = data.google_container_engine_versions.default.latest_master_version
  min_master_version = "1.17.12-gke.2502"

  remove_default_node_pool = true
  initial_node_count       = 1

  # Create a VPC-native GKE cluster instead of route-based cluster
  network    = google_compute_network.vpc.name
  subnetwork = google_compute_subnetwork.gke-subnet.name
  networking_mode = "VPC_NATIVE"

  ip_allocation_policy {
    cluster_ipv4_cidr_block = "/20"
    services_ipv4_cidr_block = "/20"
  }

  master_auth {
    username = var.gke_username
    password = var.gke_password

    client_certificate_config {
      issue_client_certificate = false
    }
  }
}

# Separately Managed Node Pool
resource "google_container_node_pool" "the_cluster_nodes" {
  name       = "node-pool"
  project    = var.project_id
  # single-zone cluster
  location   = var.zone
  cluster    = google_container_cluster.the_cluster.name
  node_count = var.gke_num_nodes

  node_config {
    oauth_scopes = [
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring",
      # needed for Container Image pulling
      "https://www.googleapis.com/auth/devstorage.read_only"
    ]

    machine_type = "g1-small"

    tags         = [ "${data.google_project.project.name}-gke" ]
    metadata = {
      disable-legacy-endpoints = "true"
    }
  }
}

答案2

通过私有连接进行通信时,Cloud SQL 实例必须遵守特定的网络要求。其中之一是您的 CloudSQL 和 GKE 实例位于同一区域和 VPC 网络中。[1]

关于“我无法从节点上的容器内访问数据库”,这是否意味着您的数据库和容器位于不同的网络中?如果是这样,您无法使用 Cloud VPN 隧道、基于实例的 VPN 或 Cloud 互连从另一个网络访问其私有 IP 地址上的 Cloud SQL 实例。

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

答案3

我已经使用以下 terraform VPC 设置完成了这项工作,我可以看到与 OP 设置的主要区别是,我正在定义一个顶级网络(见下文 {“google_compute_network” “gke-sql-vpc-impl”}),而不是 OP 使用“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,我可以使用“mysql-private-ip-address-impl”上方的私有 IP 从 pod 连接到 Cloud SQL 实例。此外,我还为 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
  }
 }
}

答案4

容器在网络方面的工作方式与虚拟机(主机和客户机)相同。virtualbox 的示例展示了不同的网络类型https://www.nakivo.com/blog/virtualbox-network-setting-guide/它们在其他网络场景(例如容器化)中非常有用。我相信,GKE 可以内部网络因此您应该在节点上使用 iptables。例如,在 GCP 中,当创建为所有其他虚拟机提供 Internet 访问的 NAT 实例时,此内容用于 NAT 网关。

此外,节点应与 CloudSQL 位于同一区域,否则使用私有 IP 将不起作用。PS 如果您考虑将来在 CloudSQL 实例中强制使用 SSL,请不要这样做,除非您想永久失去私有连接。我刚刚向 GCP 支持提交了一张票,因为我认为这是一个 Bug。

相关内容