概述
谷歌云使用先進的 Andromeda 網絡來實現 VPC 內實例之間的相互訪問,以及 google Kubernetes Engine (GKE) 的 Pod 的跨節點互訪,避免了配置靜態路由或者 Overlay 網絡帶來的運維復雜度以及性能瓶頸。使用谷歌云的 VPC Native(使用 IP Alias 而非靜態路由)方式來實現 Pod 間網絡通訊的集群稱作為 VPC 原生(VPC Native)集群。VPC 原生集群具有以下優勢。
- Pod IP 地址可在集群的 VPC 網絡和通過 VPC 網絡對等互連與之相連的其他 VPC 網絡中進行原生路由。
- 在集群中創建 Pod 之前,Pod IP 會預留在 VPC 網絡中。這可防止與 VPC 網絡中其他資源發生沖突,讓您更好地規劃 IP 地址分配。
- Pod IP 地址范圍不依賴于自定義靜態路由。它們不會消耗系統生成的路由配額和自定義靜態路由配額。自動生成的子網路由處理 VPC 原生集群的路由。
- 您可以創建僅應用于 Pod IP 地址范圍而不是集群節點上任何 IP 地址的防火墻規則。
- 通常,Pod IP 地址范圍和子網次要 IP 地址范圍可以通過 Cloud Router 與連接到 Cloud VPN 或 Cloud Interconnect 的本地網絡訪問。
這些先進的網絡功能,也可以提供給用戶在谷歌云虛機實例上自建的 Kubernetes 集群來使用。本文介紹了相關的配置和測試方法。
一 創建 VPC
1 創建 VPC
首先創建 VPC:
gcloud compute networks create k8s-vpc
--subnet-mode=custom
--bgp-routing-mode=global
--mtu=1500
2 創建 VPC 防火墻規則
在 VPC 中添加防火墻規則:
gcloud compute firewall-rules create k8s-vpc-default-firewall
--network k8s-vpc --allow tcp:22,tcp:80,tcp:3389,icmp
gcloud compute firewall-rules create k8s-vpc-k8s-firewall
--network k8s-vpc
--allow tcp:6443,tcp:2379-2380,tcp:10250-10252,tcp:30000-32767
3 創建子網
創建子網 asia-southeast1-sub-1。為其規劃如下網段。
- Node 網段:10.122.16.0/21
- Pod 網段:192.168.16.0/21
- Service 網段:172.16.16.0/21
gcloud compute networks subnets create asia-southeast1-sub-1
--network=k8s-vpc
--range=10.122.16.0/21
--region=asia-southeast1
給子網配置從屬網段
gcloud compute networks subnets update asia-southeast1-sub-1
--region=asia-southeast1
--add-secondary-ranges=asia-southeast1-sub-1-pod=192.168.16.0/21
gcloud compute networks subnets update asia-southeast1-sub-1
--region=asia-southeast1
--add-secondary-ranges=asia-southeast1-sub-1-svc=172.16.16.0/21
二 創建虛擬機
1 創建 K8s 集群的 Master 和 Node 虛機。
每個 Node 會有一個由 Master 自動分配的 Pod CIDR,需要根據這個網段來配置每個 Node 虛機實例的 Alias IP Range,本例分配的情況如下。
- Node-1
- Pod CIDR: 192.168.17.0/24
- Alias IP: 192.168.17.0/24
- Node-2
- Pod CIDR: 192.168.18.0/24
- Alias IP: 192.168.18.0/24
注意打開 IP Forward 并配置 Alias IP 網段給 Pod 使用。
A Master
注意 Master 需要綁定一個有權限創建負載均衡的 Service Account,以及谷歌云 API 調用范圍,否則,創建 Kubernetes 的 Service 時自動創建谷歌云負載均衡會失敗。
gcloud compute instances create kub-m
--project=youzhi-lab
--zone=asia-southeast1-b
--machine-type=n2-standard-2
--network-interface=network-tier=PREMIUM,subnet=asia-southeast1-sub-1
--can-ip-forward
--maintenance-policy=MIGRATE
--image=centos-7-v20210721
--image-project=centos-cloud
--boot-disk-size=100GB
--no-boot-disk-auto-delete
--boot-disk-type=pd-balanced
--boot-disk-device-name=kub-m
--no-shielded-secure-boot
--shielded-vtpm
--shielded-integrity-monitoring
--reservation-affinity=any
--service-account=247839977271-compute@developer.gserviceaccount.com
--scopes=https://www.googleapis.com/auth/cloud-platform
B Node-1
gcloud compute instances create kub-n-1
--project=youzhi-lab
--zone=asia-southeast1-b
--machine-type=n2-standard-4
--network-interface=network-tier=PREMIUM,subnet=asia-southeast1-sub-1
--can-ip-forward
--maintenance-policy=MIGRATE
--image=centos-7-v20210721
--image-project=centos-cloud
--boot-disk-size=100GB
--no-boot-disk-auto-delete
--boot-disk-type=pd-balanced
--boot-disk-device-name=kub-n-1
--no-shielded-secure-boot
--shielded-vtpm
--shielded-integrity-monitoring
--reservation-affinity=any
C Node-2
gcloud compute instances create kub-n-2
--project=youzhi-lab
--zone=asia-southeast1-b
--machine-type=n2-standard-4
--network-interface=network-tier=PREMIUM,subnet=asia-southeast1-sub-1
--can-ip-forward
--maintenance-policy=MIGRATE
--image=centos-7-v20210721
--image-project=centos-cloud
--boot-disk-size=100GB
--no-boot-disk-auto-delete
--boot-disk-type=pd-balanced
--boot-disk-device-name=kub-n-2
--no-shielded-secure-boot
--shielded-vtpm
--shielded-integrity-monitoring
--reservation-affinity=any
2 安裝 Docker
在所有的 VM 上安裝 Docker:
sudo yum install -y yum-utils
sudo yum-config-manager
--add-repo
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo docker run hello-world
sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
3 安裝 kubeadm 及其工具
系統設置,以及工具安裝:
sudo systemctl stop firewalld.service
sudo systemctl disable firewalld.service
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
# Set SELinux in permissive mode (effectively disabling it)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
配置 kubeadm 初始化參數
cat <<EOF | sudo tee sudo /proc/sys/net/ipv4/ip_forward
1
EOF
4 關閉 IP Alias 的 local route table
在 GCE 中,GCE agent 的 network Daemon 會監控 IP Alias 地址,并添加相應的路由。但在這種情況下,會造成 container 通訊的故障。通過下面的命令在 Master 和各個 Node 系統內修改 GCE agent 配置,并重啟 google guest agent 服務。目的是 Pod 通過 Alias IP 地址互訪時,不通過虛機實例的 Nat,而訪問其他地址時,采用 NAT 的方式。
sudo sed -i 's/ip_aliases = true/ip_aliases = false/'
/etc/default/instance_configs.cfg
sudo systemctl restart google-guest-agent
iptables -P FORWARD ACCEPT
ip route show table local #查看本地路由表, 確保alias IP段沒有在eth0上
三 通過 kubeadm 安裝 kubernetes
1 安裝配置 Master 節點
A 配置 Master 節點
export name="$(hostname)"
export pod_cidr="192.168.16.0/21"
export service_cidr="172.16.16.0/21"
cat <<EOF > /tmp/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
bootstrapTokens:
- groups:
- system:bootstrAppers:kubeadm:default-node-token
token: youzhi.0123456789abcdef
nodeRegistration:
name: $name
kubeletExtraArgs:
cloud-provider: gce
network-plugin: kubenet
non-masquerade-cidr: 0.0.0.0/0
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
networking:
podSubnet: ${pod_cidr}
serviceSubnet: ${service_cidr}
apiServer:
extraArgs:
enable-admission-plugins: DefaultStorageClass,NodeRestriction
cloud-provider: gce
controllerManager:
extraArgs:
cloud-provider: gce
configure-cloud-routes: "false"
address: 0.0.0.0
EOF
B 通過配置文件安裝
sudo kubeadm init
--config=/tmp/kubeadm-config.yaml
如果執行成功,會有以下輸出。
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
sudo kubeadm join 10.122.16.10:6443 --token youzhi.0123456789abcdef
--discovery-token-ca-cert-hash sha256:e5c96b2d0499287b6884c27b8ec7293e6aab1ab09540a0386b91ecbadfb38d4f
C 配置 kubectl 配置文件
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
D 安裝 ip-masq-agent
默認配置下, Pod-Pod 訪問時會進行 SNAT。使用 Alias IP 方式直接路由方式時,可以通過部署 ip-masq-agent 的方式關閉 SNAT。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/ip-masq-agent/master/ip-masq-agent.yaml
2 安裝配置 Node
A Join
在兩個 Node 節點上運行 join 命令:
sudo kubeadm join 10.122.16.10:6443 --token youzhi.0123456789abcdef
--discovery-token-ca-cert-hash sha256:e5c96b2d0499287b6884c27b8ec7293e6aab1ab09540a0386b91ecbadfb38d4f
B 查看 Node 狀態
此時 Node 是 NotReady 狀態,因為 kubelet 的網絡插件配置有問題。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
kub-m Ready control-plane,master 137m v1.22.0
kub-n-1 NotReady <none> 15m v1.22.0
C 修改 Node 上 kubelet 配置
這時 node 的狀態變成 Ready:
$ kubectl get node
NAME STATUS ROLES AGE VERSION
kub-m Ready control-plane,master 147m v1.22.0
kub-n-1 Ready <none> 25m v1.22.0
D 修改 Node providerID
為了 Service 能自動創建和配置谷歌云負載均衡,需要配置每個 Node 的 providerID 參數。對于谷歌云上的 Node,providerID 的格式是 gce://<Project ID>/<Zone>/<Instance Name>。
在 Master 節點,運行 kubectl 修改每個 Node 的 prividerID:
$ kubectl patch node kub-n-1
-p '{"spec":{"providerID":"gce://youzhi-lab/asia-southeast1-b/kub-n-1"}}'
node/kub-n-1 patched
$ kubectl patch node kub-n-2
-p '{"spec":{"providerID":"gce://youzhi-lab/asia-southeast1-b/kub-n-2"}}'
node/kub-n-2 patched
E 給 GCE 添加 Network Tag
在 Kubernetes 通過 cloud-provider 創建實現 Service 的谷歌云負載均衡的時候,需要通過 network tag 創建 firewall rules。所以需要給 GCE 實例添加 network tag。創建的規則是所有 node 相同的前綴,比如這里兩臺 VM 相同的前綴是 kub-n
gcloud compute instances add-tags kub-n-1
--zone asia-southeast1-b --tags kub-n
gcloud compute instances add-tags kub-n-2
--zone asia-southeast1-b --tags kub-n
F 給 Node 虛機實例添加 Alias IP
kubectl get nodes 列出各個 Node 的名稱。
查看每個 Node 的 Pod CIDR,如下。
$ kubectl get node kub-n-1 -o jsonpath={.spec.podCIDR}
192.168.18.0/24
使用谷歌云命令行工具,根據上面的打印結果,分別更新各個 Node 的 Alias IP,使其與該 Node 的 Pod CIDR 一致。
● Node-1
gcloud compute instances network-interfaces update kub-n-1
--zone asia-southeast1-b
--aliases "asia-southeast1-sub-1-pod:192.168.17.0/24"
● Node-2
gcloud compute instances network-interfaces update kub-n-2
--zone asia-southeast1-b
--aliases "asia-southeast1-sub-1-pod:192.168.18.0/24"
3 檢測配置
A 創建 deployment 和 service
kubectl create deploy Nginx --image nginx
kubectl scale deploy/nginx --replicas=6
kubectl expose deployment nginx
--port 80 --target-port 80 --name nginx-lb --type LoadBalancer
B 查看部署情況查看 pod 情況:
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-6799fc88d8-68fld 1/1 Running 0 17h 192.168.18.7 kub-n-2
nginx-6799fc88d8-gssw5 1/1 Running 0 17h 192.168.17.15 kub-n-1
nginx-6799fc88d8-jcdhc 1/1 Running 0 17h 192.168.17.14 kub-n-1
nginx-6799fc88d8-k7sxg 1/1 Running 0 17h 192.168.18.6 kub-n-2
nginx-6799fc88d8-l6nnv 1/1 Running 0 17h 192.168.18.5 kub-n-2
nginx-6799fc88d8-tcbmf 1/1 Running 0 17h 192.168.17.13 kub-n-1
查看 Service:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.16.16.1 <none> 443/TCP 29h
nginx-lb LoadBalancer 172.16.16.153 34.126.129.75 80:32761/TCP 7m31s
獲取 Service 的 LB IP
ip=$(kubectl get svc -l app=nginx
-o jsonpath={.items[0].status.loadBalancer.ingress[0].ip})
測試 Pod 的同 Node 和跨 Node 訪問
$ kubectl exec -it nginx-6799fc88d8-68fld bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-6799fc88d8-68fld:/# curl -I 192.168.18.6
HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Thu, 12 Aug 2021 07:25:29 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT
Connection: keep-alive
ETag: "60e46fc5-264"
Accept-Ranges: bytes
root@nginx-6799fc88d8-68fld:/# curl -I 192.168.17.15
HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Thu, 12 Aug 2021 07:25:35 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT
Connection: keep-alive
ETag: "60e46fc5-264"
Accept-Ranges: bytes
測試通過 Cluser IP 訪問 Service
root@nginx-6799fc88d8-68fld:/# curl -I 172.16.16.153
HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Thu, 12 Aug 2021 07:25:43 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT
Connection: keep-alive
ETag: "60e46fc5-264"
Accept-Ranges: bytes
測試 Service 從公網訪問:
$ curl -I $ip
HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Wed, 11 Aug 2021 14:25:06 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT
Connection: keep-alive
ETag: "60e46fc5-264"
Accept-Ranges: bytes
C 測試從其它子網訪問 Pod
現在集群上的 Pod 除了可以同一子網內互相訪問,也可以讓 VPC 下其它子網(同一區域或者不同區域都可以)以及通過專線或 VPN 與本 VPC 互通的線下機房網絡里的虛機來訪問。下面在不同區域創建一個新子網,以及該子網下的虛機,來訪問集群上的 Pod。
gcloud compute networks subnets create us-central1-sub-1 |
登錄 remote-test1 虛機,并運行以下命令訪問 Pod。
$ curl -I 192.168.18.7 |
可以確認訪問成功。
D 確認 Node 上關閉 Pod 訪問 SNAT
如果檢測結果與下面的結果有差異,確認執行 Master 節點配置的“安裝 ip-masq-agent”一節。
$ kubectl get ds -n kube-system |
在每臺 Node 上查看 NAT, IP-MASQ-AGENT Chain 默認會針對目的地址為 RFC1918 地址段不做地址翻譯。
$ sudo iptables -t nat -L -n --line-numbers |
四 總結
在 GCE 上通過 kubeadm 可以非常方便的安裝 kubernetes 集群,通過 GCP VPC 的各種網絡功能,配合 Kubernetes 本身 cloud-provider 的功能,可以非常方便的實現 Kubernetes 網絡的各種功能。
Appendix
1 kubeadm 創建 token
kubeadm token create --ttl=0 --print-join-command --token xxxx --discovery-token-ca-cert-hash sha256:xxxx |
2 alias IP 模式下的配置
確認刪除 Alias IP 的本地路由:
https://cloud.google.com/vpc/docs/configure-alias-ip-ranges#enabling_ip_alias_on_images_disables_cbr0_bridge_on_self-managed_kubernetes_clusters
通過 GCP Alias IP 實現跨 Node 的 Pod 互通
3 K8s 網絡針對 GCP 的配置注意事項
https://kubernetes.io/docs/concepts/cluster-administration/networking/#google-compute-engine-gce
4 Node, Pod 和 Service 網段配置參考表
https://cloud.google.com/kubernetes-engine/docs/concepts/alias-ips#cluster_sizing_secondary_range_pods
5 Kubadmin 安裝步驟
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
Kubeadmin init 參數
https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/
Ip-masq-agent 部署
https://kubernetes.io/docs/tasks/administer-cluster/ip-masq-agent/
轉載自:
https://gcp.infoq.cn/article.html?id=197373f7-464e-4c9f-b894-365e7883d3e6