Kubernetes的網絡結構
K8s的網絡相對比較復雜, 包含了如下幾類IP地址:
Host Network
運行K8s集群的宿主服務器的內網IP, 其網段在配置宿主機時設置. 這些服務器可能是物理機, 也可能是ESXi或KVM虛機. 可以根據這個IP在K8s初始化時設置--apiserver-advertise-address, 配置外網訪問時, 前端的負載均衡要通過這些IP訪問服務.
Docker Bridge Network
運行Docker服務時啟動的虛擬網卡docker0的IP, 通常為 172.17.0.1/16, 對應docker內部默認的bridge網段. 這個網絡在K8s中不會用到.
Pod Network
K8s中Pod單元的IP, 其網段在K8s初始化時使用--pod-network-cidr設置, 此處使用172.16.0.0/16, 在每個宿主(node節點)上, 都會有一個對應的二級網段, 例如 172.16.1.0/24, 如果使用的是flannel, 那么在宿主機上會對應成對出現的兩個虛擬網卡 cni0 和 flannel.1 (如果宿主機上還沒部署pod, cni0可能不會出現)
Pod網絡在集群內可以跨節點相互ping通, 在master和node主機上也可以直接訪問Pod的IP
Service Network
K8s中Service單元的IP, 其網段在K8s初始化時使用--service-cidr設置, 在master和node主機上不能直接訪問. 這里使用10.1.0.0/16.
Ingress的機制
要解決的問題
因為K8s中Pod是易變的, Pod IP在更新中會自動修改, 使用Service能使訪問入口相對固定, 但是Service IP在集群外不能訪問, 要對外提供訪問, 只能把Service以NodePort, LoadBalancer這些方式Expose出去, 但是NodePort會與每一個Node主機綁定, 而LoadBalancer需要雲服務商提供相應的服務(或自己安裝).
原理
Ingress 啟動一個獨立的Pod來運行七層代理, 可以是 Nginx, Traefik 或者是 Envoy. Ingress Pod會直接代理后端提供服務的Pod, 為了能監聽后端Pod的變化, 需要一個 Headless Service 通過Selector選擇指定的Pod, 並收集到Pod對應的IP. 一旦后端Pod產生變化, Headless Service 會自動根據變化更改配置文件並重載.
如果使用的是 Nginx 類型的 Ingress Pod, 則每次變化后通過reload修改過的配置文件實現規則更新.
Ingress Controller
在kubernetes集群內節點上運行web七層代理所對應的Pod, 由此Pod代理集群內部的Service, Service再把流量轉發給集群內部對應的Pod, 這就叫做 Ingress Controller, Ingress Controller 基於 DaemonSet 控制器實現, DaemonSet用於保證集群內部每個節點上都運行一個指定的Pod.
部署Ingress Nginx
軟件版本
這里使用的環境是 K8s 1.17, Docker 18.06.3, Ingress Nginx 0.26.2
Ingress Nginx項目地址: https://github.com/kubernetes/ingress-nginx/
Ingress Nginx的安裝文檔: https://kubernetes.github.io/ingress-nginx/deploy/ 使用 https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/
安裝前提
已經配置好K8s集群
部署公共部分
現在最新的標簽是0.26.2, 使用部署模板
https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.26.2/deploy/static/mandatory.yaml
下載后在master主機上執行
kubectl apply -f mandatory.yaml
可以使用下面的命令查看部署的結果
kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch kubectl get services
部署Nodeport部分
因為不使用雲服務商的服務, 所以要使用Nodeport的方式, 對應的部署模板在
這一步實際上是創建一個Nodeport將ingress-nginx服務發布到Node節點的Host Network上, 原模板中未指定端口, 創建后會隨機設置端口, 可以修改一下, 只能使用端口范圍 3000 ~ 32767. 修改后的service-nodeport.yaml, 將80端口映射到了30080, 443映射到了30443
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
nodePort: 30080
- name: https
port: 443
targetPort: 443
protocol: TCP
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
可以使用下面的命令查看發布的結果, 以及映射出去的實際端口
kubectl get services -n ingress-nginx
創建服務並測試
以下都是使用defalut的namespace. 都使用kubectl apply -f 模板名 命令進行發布
Deployment, 創建兩個nginx的pod
# nginx-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-shanghai.aliyuncs.com/jovi/nginx:alpine
ports:
- containerPort: 80
Service, 將上面創建的兩個Pod發布為Servce, 將Pod的80端口映射到Service的8080端口
# nginx-service.yml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 8080
targetPort: 80
查看service詳情
$ kubectl describe service my-service
Name: my-service
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"my-service","namespace":"default"},"spec":{"ports":[{"port":8080,...
Selector: app=nginx
Type: ClusterIP
IP: 10.1.116.99
Port: <unset> 8080/TCP
TargetPort: 80/TCP
Endpoints: 172.16.1.6:80,172.16.1.7:80
Session Affinity: None
Events: <none>
Ingress, 將上面的Service的8080端口映射到Ingress的http
# ingress-test.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- http:
paths:
- backend:
serviceName: my-service
servicePort: 8080
查看Ingress詳情
$ kubectl get services -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.1.60.152 <none> 80:30080/TCP,443:30443/TCP 69m
milton@k8s00:~/backup$ kubectl describe ingress test-ingress
Name: test-ingress
Namespace: default
Address: 10.1.60.152
Default backend: default-http-backend:80 (<none>)
Rules:
Host Path Backends
---- ---- --------
*
my-service:8080 (172.16.1.6:80,172.16.1.7:80)
Annotations:
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"test-ingress","namespace":"default"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"my-service","servicePort":8080}}]}}]}}
kubernetes.io/ingress.class: nginx
Events: <none>
這時候, 就可以通過 http://宿主機IP:30080 訪問到這兩個Pod的Nginx默認頁.
