kubernetes——part3-5 核心概念 Service

一、 service作用

使用kubernetes集群運行工作負載時,由于Pod經常處于用后即焚狀態,Pod經常被重新生成,因此Pod對應的IP地址也會經常變化,導致無法直接訪問Pod提供的服務,Kubernetes中使用了Service來解決這一問題,即在Pod前面使用Service對Pod進行代理,無論Pod怎樣變化 ,只要有Label,就可以讓Service能夠聯系上Pod,把PodIP地址添加到Service對應的端點列表(Endpoints)實現對Pod IP跟蹤,進而實現通過Service訪問Pod目的。

  • 通過service為pod客戶端提供訪問pod方法,即可客戶端訪問pod入口
  • 通過標簽動態感知pod IP地址變化等
  • 防止pod失聯
  • 定義訪問pod訪問策略
  • 通過label-selector相關聯
  • 通過Service實現Pod的負載均衡(TCP/UDP 4層)
  • 底層實現由kube-proxy通過userspace、iptables、ipvs三種代理模式

二、kube-proxy三種代理模式

  • kubernetes集群中有三層網絡,一類是真實存在的,例如Node Network、Pod Network,提供真實IP地址;一類是虛擬的,例如Cluster Network或Service Network,提供虛擬IP地址,不會出現在接口上,僅會出現在Service當中

  • kube-proxy始終watch(監控)kube-apiserver上關于Service相關的資源變動狀態,一旦獲取相關信息kube-proxy都要把相關信息轉化為當前節點之上的,能夠實現Service資源調度到特定Pod之上的規則,進而實現訪問Service就能夠獲取Pod所提供的服務

  • kube-proxy三種代理模式:UserSpace模式、iptables模式、ipvs模式

2.1 UserSpace模式

不再使用了解即可
userspace 模式是 kube-proxy 使用的第一代模式,該模式在 kubernetes v1.0 版本開始支持使用。

userspace 模式的實現原理圖示如下:

在這里插入圖片描述

kube-proxy 會為每個 Service 隨機監聽一個端口(proxy port),并增加一條 iptables 規則。所以通過 ClusterIP:Port 訪問 Service 的報文都 redirect 到 proxy port,kube-proxy 從它監聽的 proxy port 收到報文以后,走 round robin(默認) 或是 session affinity(會話親和力,即同一 client IP 都走同一鏈路給同一 pod 服務),分發給對應的 pod。

由于 userspace 模式會造成所有報文都走一遍用戶態(也就是 Service 請求會先從用戶空間進入內核 iptables,然后再回到用戶空間,由 kube-proxy 完成后端 Endpoints 的選擇和代理工作),需要在內核空間和用戶空間轉換,流量從用戶空間進出內核會帶來性能損耗,所以這種模式效率低、性能不高,不推薦使用。

在這里插入圖片描述

2.2 iptables模式

iptables 模式是 kube-proxy 使用的第二代模式,該模式在 kubernetes v1.1 版本開始支持,從 v1.2 版本開始成為 kube-proxy 的默認模式。

iptables 模式的負載均衡模式是通過底層 netfilter/iptables 規則來實現的,通過 Informer 機制 Watch 接口實時跟蹤 Service 和 Endpoint 的變更事件,并觸發對 iptables 規則的同步更新。

iptables 模式的實現原理圖示如下:

在這里插入圖片描述

通過圖示我們可以發現在 iptables 模式下,kube-proxy 只是作為 controller,而不是 server,真正服務的是內核的 netfilter,體現在用戶態的是 iptables。所以整體的效率會比 userspace 模式高。

在這里插入圖片描述

2.3 ipvs模式

ipvs 模式被 kube-proxy 采納為第三代模式,模式在 kubernetes v1.8 版本開始引入,在 v1.9 版本中處于 beta 階段,在 v1.11 版本中正式開始使用。

ipvs(IP Virtual Server) 實現了傳輸層負載均衡,也就是 4 層交換,作為 Linux 內核的一部分。ipvs運行在主機上,在真實服務器前充當負載均衡器。ipvs 可以將基于 TCP 和 UDP 的服務請求轉發到真實服務器上,并使真實服務器上的服務在單個 IP 地址上顯示為虛擬服務。

ipvs 模式的實現原理圖示如下:

在這里插入圖片描述
在這里插入圖片描述

ipvs 和 iptables 都是基于 netfilter 的,那么 ipvs 模式有哪些更好的性能呢?

  • ipvs 為大型集群提供了更好的可拓展性和性能
  • ipvs 支持比 iptables 更復雜的負載均衡算法(包括:最小負載、最少連接、加權等)
  • ipvs 支持服務器健康檢查和連接重試等功能
  • 可以動態修改 ipset 的集合,即使 iptables 的規則正在使用這個集合

ipvs 依賴于 iptables。ipvs 會使用 iptables 進行包過濾、airpin-masquerade tricks(地址偽裝)、SNAT 等功能,但是使用的是 iptables 的擴展 ipset,并不是直接調用 iptables 來生成規則鏈。通過 ipset 來存儲需要 DROP 或 masquerade 的流量的源或目標地址,用于確保 iptables 規則的數量是恒定的,這樣我們就不需要關心有多少 Service 或是 Pod 了。

使用 ipset 相較于 iptables 有什么優點呢?iptables 是線性的數據結構,而 ipset 引入了帶索引的數據結構,當規則很多的時候,ipset 依然可以很高效的查找和匹配。我們可以將 ipset 簡單理解為一個 IP(段) 的集合,這個集合的內容可以是 IP 地址、IP 網段、端口等,iptables 可以直接添加規則對這個“可變的集合進行操作”,這樣就可以大大減少 iptables 規則的數量,從而減少性能損耗。

舉一個例子,如果我們要禁止成千上萬個 IP 訪問我們的服務器,如果使用 iptables 就需要一條一條的添加規則,這樣會在 iptables 中生成大量的規則;如果用 ipset 就只需要將相關的 IP 地址(網段)加入到 ipset 集合中,然后只需要設置少量的 iptables 規則就可以實現這個目標。

下面的表格是 ipvs 模式下維護的 ipset 表集合:

設置名稱成員用法
KUBE-CLUSTER-IP所有服務 IP + 端口在 masquerade-all=true 或 clusterCIDR 指定的情況下對 Service Cluster IP 地址進行偽裝,解決數據包欺騙問題
KUBE-LOOP-BACK所有服務 IP + 端口 + IP解決數據包欺騙問題
KUBE-EXTERNAL-IP服務外部 IP + 端口將數據包偽裝成 Service 的外部 IP 地址
KUBE-LOAD-BALANCER負載均衡器入口 IP + 端口將數據包偽裝成 Load Balancer 類型的 Service
KUBE-LOAD-BALANCER-LOCAL負載均衡器入口 IP + 端口 以及externalTrafficPolicy=local接受數據包到 Load Balancer externalTrafficPolicy=local
KUBE-LOAD-BALANCER-FW負載均衡器入口 IP + 端口 以及loadBalancerSourceRanges使用指定的 loadBalancerSourceRanges 丟棄 Load Balancer 類型 Service 的數據包
KUBE-LOAD-BALANCER-SOURCE-CIDR負載均衡器入口 IP + 端口 + 源 CIDR接受 Load Balancer 類型 Service 的數據包,并指定 loadBalancerSourceRanges
KUBE-NODE-PORT-TCPNodePort 類型服務 TCP 端口將數據包偽裝成 NodePort(TCP)
KUBE-NODE-PORT-LOCAL-TCPNodePort 類型服務 TCP 端口,帶有externalTrafficPolicy=local接受數據包到 NodePort 服務,使用 externalTrafficPolicy=local
KUBE-NODE-PORT-UDPNodePort 類型服務 UDP 端口將數據包偽裝成 NodePort(UDP)
KUBE-NODE-PORT-LOCAL-UDPNodePort 類型服務 UDP 端口,使用externalTrafficPolicy=local接受數據包到 NodePort 服務,使用 externalTrafficPolicy=local

2.4 iptables與ipvs對比

  • iptables

    • 工作在內核空間
    • 優點
      • 靈活,功能強大(可以在數據包不同階段對包進行操作)
    • 缺點
      • 表中規則過多時,響應變慢,即規則遍歷匹配和更新,呈線性時延
  • ipvs

    • 工作在內核空間
    • 優點
      • 轉發效率高
      • 調度算法豐富:rr,wrr,lc,wlc,ip hash…
    • 缺點
      • 內核支持不全,低版本內核不能使用,需要升級到4.0或5.0以上。
  • 使用iptables與ipvs時機

    • 1.10版本之前使用iptables(1.1版本之前使用UserSpace進行轉發)
    • 1.11版本之后同時支持iptables與ipvs,默認使用ipvs,如果ipvs模塊沒有加載時,會自動降級至iptables

三、 service類型

Service類型決定了訪問Service的方法

3.1 service類型

  • ClusterIP

    • 默認,分配一個集群內部可以訪問的虛擬IP
  • NodePort

    • 在每個Node上分配一個端口作為外部訪問入口
    • nodePort端口范圍為:30000-32767
  • LoadBalancer

    • 工作在特定的Cloud Provider上,例如Google Cloud,AWS,OpenStack
  • ExternalName

    • 表示把集群外部的服務引入到集群內部中來,即實現了集群內部pod和集群外部的服務進行通信

3.2 Service參數

  • port 訪問service使用的端口

  • targetPort Pod中容器端口 (容器內的端口,例如nginx,80端口)

  • nodePort 通過Node實現外網用戶訪問k8s集群內service (30000-32767)(適用于nodeport模式)

四、 Service創建

Service的創建在工作中有兩種方式,一是命令行創建,二是通過資源清單文件YAML文件創建。

4.1 ClusterIP類型

ClusterIP根據是否生成ClusterIP又可分為普通Service和Headless Service

Service兩類:

  • 普通Service:

為Kubernetes的Service分配一個集群內部可訪問的固定虛擬IP(Cluster IP), 實現集群內的訪問。

  • Headless Service:

該服務不會分配Cluster IP, 也不通過kube-proxy做反向代理和負載均衡。而是通過DNS提供穩定的網絡ID來訪問,DNS會將headless service的后端直接解析為pod IP列表。

在這里插入圖片描述

4.1.1 普通ClusterIP Service創建

4.1.1.1 命令行創建Service
  • 創建Deployment類型的應用
[root@master01 ~]# cat 01_create_deployment_app_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: c1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
  • 應用資源清單文件
[root@master01 ~]# kubectl apply -f 01_create_deployment_app_nginx.yaml
  • 驗證Deployment類型的創建情況
[root@master01 ~]# kubectl get deployment.apps
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
nginx-server1   2/2     2            2           13s
  • 創建ClusterIP類型service與Deployment類型應用關聯
命令創建service
[root@master01 ~]# kubectl expose deployment.apps nginx-server1 --type=ClusterIP --target-port=80 --port=80
輸出
service/nginx-server1 exposed
說明
expose 創建service
deployment.apps 控制器類型
nginx-server1 應用名稱,也是service名稱
--type=ClusterIP 指定service類型
--target-port=80 指定Pod中容器端口
--port=80 指定service端口
4.1.1.2 通過資源清單文件創建Service
[root@master01 ~]# cat 02_create_deployment_app_nginx_with_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginx-smartimage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-svc
spec:type: ClusterIPports:- protocol: TCPport: 80targetPort: 80selector:app: nginx
[root@master01 ~]# kubectl  apply -f 02_create_deployment_app_nginx_with_service.yaml
  • 驗證
查看service
[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    4d15h
nginx-svc    ClusterIP   10.101.153.50   <none>        80/TCP    3s
查看endpoints
[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                            AGE
kubernetes   192.168.122.30:6443                  4d15h
nginx-svc    172.16.189.74:80,172.16.235.150:80   8s
查看Pod
[root@master01 ~]# kubectl get pods -l app=nginx
NAME                             READY   STATUS    RESTARTS   AGE
nginx-server1-77d4c485d8-gsrmq   1/1     Running   0          12s
nginx-server1-77d4c485d8-mmc52   1/1     Running   0          12s
4.1.1.3 訪問
[root@master01 ~]# curl http://10.101.153.50:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
4.1.1.4 兩個pod里做成不同的主頁方便測試負載均衡
[root@master01 ~]# kubectl exec -it nginx-server1-77d4c485d8-gsrmq -- /bin/bash
root@deployment-nginx-6fcfb67547-nv7dn:/# cd /usr/share/nginx/html/
root@deployment-nginx-6fcfb67547-nv7dn:/usr/share/nginx/html# echo web1 > index.html
root@deployment-nginx-6fcfb67547-nv7dn:/usr/share/nginx/html# exit
exit
[root@master01 ~]# kubectl exec -it nginx-server1-77d4c485d8-mmc52 -- /bin/bash
root@deployment-nginx-6fcfb67547-rqrcw:/# cd /usr/share/nginx/html/
root@deployment-nginx-6fcfb67547-rqrcw:/usr/share/nginx/html# echo web2 > index.html
root@deployment-nginx-6fcfb67547-rqrcw:/usr/share/nginx/html# exit
exit
4.1.1.5 測試
[root@master01 ~]# curl 10.101.153.50[root@master01 ~]# while true;do curl 10.101.153.50;sleep 1; done

4.1.2 Headless Service

  • 普通的ClusterIP service是service name解析為cluster ip,然后cluster ip對應到后面的pod ip
  • Headless service是指service name 直接解析為后面的pod ip
4.1.2.1 編寫用于創建Deployment控制器類型的資源清單文件
[root@master01 ~]# cat 03_create_deployment_app_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginx-smartimage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
4.1.2.2 通過資源清單文件創建headless Service
編寫YAML文件
命令
[root@master ~]# vim 04_headless-service.yml
apiVersion: v1
kind: Service
metadata:name: headless-servicenamespace: default
spec:type: ClusterIP     # ClusterIP類型,也是默認類型clusterIP: None     # None就代表是無頭serviceports:                                # 指定service 端口及容器端口- port: 80                            # service ip中的端口protocol: TCPtargetPort: 80                      # pod中的端口selector:                             # 指定后端pod標簽app: nginx                    # 可通過kubectl get pod -l app=nginx查看哪些pod在使用此標簽
4.1.2.3 應用資源清單文件創建headless Service
命令
[root@master ~]# kubectl apply -f 04_headless_service.yml
輸出
service/headless-service created
4.1.2.4 查看已創建的headless Service
命令
[root@master ~]# kubectl get svc
輸出
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
headless-service   ClusterIP   None             <none>        80/TCP           2m18s
kubernetes         ClusterIP   10.96.0.1        <none>        443/TCP          5d9h
可以看到headless-service沒有CLUSTER-IP,用None表示
4.1.2.5 DNS

DNS服務監視Kubernetes API,為每一個Service創建DNS記錄用于域名解析

headless service需要DNS來解決訪問問題

DNS記錄格式為: ..svc.cluster.local.

4.1.2.5.1 查看kube-dns服務的IP
命令
[root@master1 ~]# kubectl get svc -n kube-system輸出
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.2      <none>        53/UDP,53/TCP,9153/TCP   5d9h
metrics-server   ClusterIP   10.105.219.44   <none>        443/TCP                  45h
查看到coreDNS的服務地址是10.96.0.2
4.1.2.5.2 在集群主機通過DNS服務地址查找無頭服務的dns解析
命令
[root@master01 ~]# dig -t A headless-service.default.svc.cluster.local. @10.96.0.2輸出
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.2 <<>> -t A headless-service.default.svc.cluster.local. @10.96.0.2
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31371
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;headless-service.default.svc.cluster.local. IN A #被解析域名;; ANSWER SECTION:
headless-service.default.svc.cluster.local. 30 IN A 10.224.235.147 #注意這里IP;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.2)
;; WHEN: Sun May 17 10:58:50 CST 2020
;; MSG SIZE  rcvd: 129
4.1.2.5.3 驗證pod的IP
命令
[root@master ~]# kubectl get pod -o wide
輸出
NAME                                READY   STATUS             RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
nginx-deployment-56bf6c9c8c-jmk7r   1/1     Running            0          35m   10.224.235.147   worker1   <none>           <none>
4.1.2.5.4 在集群中創建一個pod驗證

創建一個鏡像為busyboxplus:curl的pod,pod名稱為bb2,用來解析域名

命令
[root@master01 ~]# kubectl run bbp --image=busyboxplus:curl -it[root@master01 ~]# kubectl run bbp --image=1.28 -it輸出
If you don't see a command prompt, try pressing enter.解析域名
nslookup headless-service.default.svc.cluster.local.
訪問命令
[ root@bbp:/ ]$ curl http://headless-service.default.svc.cluster.local.輸出
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
[ root@bbp:/ ]$ exit
Session ended, resume using 'kubectl attach bbp -c bbp -i -t' command when the pod is running

4.2 NodePort類型

  • 創建資源清單文件
[root@master01 ~]# cat 05_create_nodeport_service_app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-applabels:app: nginx-app
spec:replicas: 2selector:matchLabels:app: nginx-apptemplate:metadata:labels:app: nginx-appspec:containers:- name: c1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-app
spec:type: NodePortselector:app: nginx-appports:- protocol: TCPnodePort: 30001port: 8060targetPort: 80
  • 應用資源清單文件
[root@master01 ~]# kubectl apply -f 05_create_nodeport_service_app.yaml
deployment.apps/nginx-app created
service/nginx-app created
  • 驗證service創建
[root@master01 ~]# kubectl get deployment.apps
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app    2/2     2            2           26s[root@master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          2d22h
nginx-app    NodePort    10.104.157.20    <none>        8060:30001/TCP   36s[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                       AGE
kubernetes   192.168.122.10:6443             2d22h
nginx-app    172.16.1.24:80,172.16.2.20:80   2m10s[root@master01 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=5826,fd=9))[root@worker01 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=4937,fd=11))[root@worker02 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=5253,fd=11))
[root@master01 ~]# kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
nginx-app-ffd5ccc78-cnwbx    1/1     Running   0          8m59s
nginx-app-ffd5ccc78-mz77g    1/1     Running   0          8m59s[root@master01 ~]# kubectl exec -it nginx-app-ffd5ccc78-cnwbx -- bash
root@nginx-app-ffd5ccc78-cnwbx:/# echo "nginx-app-1" > /usr/share/nginx/html/index.html
root@nginx-app-ffd5ccc78-cnwbx:/# exit
exit
[root@master01 ~]# kubectl exec -it nginx-app-ffd5ccc78-mz77g -- bash
root@nginx-app-ffd5ccc78-mz77g:/# echo "nginx-app-2" > /usr/share/nginx/html/index.html
root@nginx-app-ffd5ccc78-mz77g:/# exit
exit
  • 在與kubernetes 節點同一網絡主機中訪問k8s集群內service
[root@bogon ~]# curl http://192.168.10.12:30001
nginx-app-2
[root@bogon ~]# curl http://192.168.10.13:30001
nginx-app-1
[root@bogon ~]# curl http://192.168.10.14:30001
nginx-app-1
[root@bogon ~]# curl http://192.168.10.15:30001
nginx-app-2

4.3 LoadBalancer

負載均衡,類似阿里云的slb

4.3.1 集群外訪問過程

在這里插入圖片描述

4.3.2 自建Kubernetes的LoadBalancer類型服務方案-MetalLB

(如果是kubeadm創建的k8s集群先執行第6部分)
MetalLB可以為kubernetes集群中的Service提供網絡負載均衡功能。

MetalLB兩大功能為:

  • 地址分配,類似于DHCP
  • 外部通告,一旦MetalLB為服務分配了外部IP地址,它就需要使群集之外的網絡意識到該IP在群集中“存在”。MetalLB使用標準路由協議來實現此目的:ARP,NDP或BGP。
4.3.2.1 參考資料

參考網址: https://metallb.universe.tf/installation/

4.3.2.2 應用資源清單文件
資源清單文件下載:
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
4.3.2.3 準備metallb配置文件
[root@nginx metallb]# cat metallb-conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:namespace: metallb-systemname: config
data:config: |address-pools:- name: defaultprotocol: layer2addresses:- 192.168.10.90-192.168.10.100192.168.10.90-192.168.10.100是集群節點服務器IP同一段。
在master01節點應用資源清單文件
[root@master01 ~]# kubectl apply -f metallb-conf.yaml	
驗證配置
# kubectl describe configmap config -n metallb-system
Name:         config
Namespace:    metallb-system
Labels:       <none>
Annotations:  <none>Data
====
config:
----
address-pools:
- name: defaultprotocol: layer2addresses:- 192.168.10.90-192.168.10.100Events:  <none>
4.3.2.4發布Service類型為LoadBalancer的Deployment控制器類型應用
創建Deployment控制器類型應用nginx-metallb及service,service類型為LoadBalancer[root@master01 ~]# vim 02_nginx-metabllb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-metallb
spec:selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginx-metallb1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80---
apiVersion: v1
kind: Service
metadata:name: nginx-metallb
spec:ports:- port: 8090protocol: TCPtargetPort: 80selector:app: nginxtype: LoadBalancer[root@master01 ~]# kubectl apply -f nginx.yaml
4.3.2.5 驗證
[root@master01 ~]# kubectl get ns
NAME                   STATUS   AGE
default                Active   16d
kube-node-lease        Active   16d
kube-public            Active   16d
kube-system            Active   16d
kubernetes-dashboard   Active   13d
metallb-system         Active   130m
test1                  Active   12d
[root@master01 ~]# kubectl get pods -n metallb-system
NAME                         READY   STATUS    RESTARTS   AGE
controller-64f8f944d-qdf8m   1/1     Running   0          110m
speaker-cwzq7                1/1     Running   0          110m
speaker-qk5fb                1/1     Running   0          110m
speaker-wsllb                1/1     Running   0          110m
speaker-x4bwt                1/1     Running   0          110m[root@master01 ~]# kubectl get svc
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
kubernetes      ClusterIP      10.96.0.1       <none>           443/TCP          16d
nginx-metallb   LoadBalancer   10.105.239.69   192.168.10.90   8090:31372/TCP   106m[root@master01 ~]# ping 192.168.10.90
PING 192.168.10.90 (192.168.10.90) 56(84) bytes of data.
64 bytes from 192.168.10.90: icmp_seq=1 ttl=64 time=3.45 ms
64 bytes from 192.168.10.90: icmp_seq=2 ttl=64 time=0.040 ms
4.3.2.6 訪問
[root@master01 ~]# curl http://192.168.122.90:8090
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>

在這里插入圖片描述

注意:使用kubeadm部署kubernetes集群修改方法

如果在IPVS模式下使用kube-proxy,從Kubernetes v1.14.2開始,必須啟用ARP模式。可以通過在當前集群中編輯kube-proxy配置來實現:
# kubectl edit configmap -n kube-system kube-proxy并設置:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:strictARP: true

4.4 ExternalName

4.4.1 ExternalName作用

  • 把集群外部的服務引入到集群內部中來,實現了集群內部pod和集群外部的服務進行通信
  • ExternalName 類型的服務適用于外部服務使用域名的方式,缺點是不能指定端口
  • 還有一點要注意: 集群內的Pod會繼承Node上的DNS解析規則。所以只要Node可以訪問的服務,Pod中也可以訪問到, 這就實現了集群內服務訪問集群外服務

4.4.2 將公網域名引入

1, 編寫YAML文件

 [root@master01 ~]# vim externelname.ymlapiVersion: v1
kind: Service
metadata:name: my-externalnamenamespace: default
spec:type: ExternalNameexternalName: www.baidu.com                  # 對應的外部域名為www.baidu.com

2, 應用YAML文件

 [root@master01 ~]# kubectl apply -f externelname.ymlservice/my-externalname created

3, 查看service

 [root@master01 ~]# kubectl get svc |grep extermy-externalname    ExternalName   <none>         www.baidu.com   <none>         69s

4, 查看my-service的dns解析

 [root@master01 ~]# dig -t A my-externalname.default.svc.cluster.local. @10.96.0.2; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A my-externalname.default.svc.cluster.local. @10.2.0.2;; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31378;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;my-externalname.default.svc.cluster.local. IN A;; ANSWER SECTION:my-externalname.default.svc.cluster.local. 5 IN CNAME www.baidu.com.www.baidu.com.          5       IN      CNAME   www.a.shifen.com.www.a.shifen.com.       5       IN      A       14.215.177.38           解析的是百度的IPwww.a.shifen.com.       5       IN      A       14.215.177.39           解析的是百度的IP;; Query time: 32 msec;; SERVER: 10.2.0.2#53(10.96.0.2);; WHEN: Thu Nov 05 11:23:41 CST 2020;; MSG SIZE  rcvd: 245
 [root@master01 ~]# kubectl exec -it deploy-nginx-6c9764bb69-86gwj -- /bin/sh/ # nslookup www.baidu.com......Name:      www.baidu.comAddress 1: 14.215.177.39Address 2: 14.215.177.38/ # nslookup my-externalname.default.svc.cluster.local         ......Name:      my-externalname.default.svc.cluster.localAddress 1: 14.215.177.38Address 2: 14.215.177.39

解析此my-externalname.default.svc.cluster.local域名和解析www.baidu.com是一樣的結果

4.4.3 不同命名空間訪問

1, 創建ns1命名空間和相關deploy, pod,service

 [root@master01 ~]# vim ns1-nginx.yml
apiVersion: v1                                                  
kind: Namespace                                                 
metadata:                                                             name: ns1                                                     # 創建ns1命名空間
---
apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-nginx                    namespace: ns1                                                # 屬于ns1命名空間
spec:replicas: 1                                  selector:matchLabels:app: nginx                                template:                                        metadata:labels:app: nginx                             spec:containers:                              - name: nginximage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: svc1                                # 服務名namespace: ns1                            # 屬于ns1命名空間
spec:selector:app: nginxclusterIP: None                           # 無頭serviceports:- port: 80                         targetPort: 80                  
---
kind: Service
apiVersion: v1
metadata:name: external-svc1namespace: ns1                            #  屬于ns1命名空間
spec:type: ExternalNameexternalName: svc2.ns2.svc.cluster.local   # 將ns2空間的svc2服務引入到ns1命名空間[root@master1 ~]# kubectl apply -f ns1-nginx.ymlnamespace/ns1 createddeployment.apps/deploy-nginx createdservice/svc1 created

2, 創建ns2命名空間和相關deploy, pod,service

[root@master01 ~]# vim ns1-nginx.yml
apiVersion: v1                                                  
kind: Namespace                                                 
metadata:                                                             name: ns2                                                     # 創建ns2命名空間
---
apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-nginx                    namespace: ns2                                                # 屬于ns2命名空間
spec:replicas: 1                                  selector:matchLabels:app: nginx                                template:                                        metadata:labels:app: nginx                             spec:containers:                              - name: nginximage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: svc2                                # 服務名namespace: ns2                            # 屬于ns2命名空間
spec:selector:app: nginxclusterIP: None                           # 無頭serviceports:- port: 80                         targetPort: 80                  
---
kind: Service
apiVersion: v1
metadata:name: external-svc1namespace: ns2                            #  屬于ns2命名空間
spec:type: ExternalNameexternalName: svc1.ns1.svc.cluster.local   # 將ns1空間的svc1服務引入到ns2命名空間
 [root@master01 ~]# kubectl apply -f ns2-nginx.ymlnamespace/ns2 createddeployment.apps/deploy-nginx createdservice/svc2 createdservice/external-svc2 created

3, 在ns1命名空間的pod里驗證

 [root@master01 ~]# kubectl get pods -n ns1NAME                            READY   STATUS    RESTARTS   AGEdeploy-nginx-6c9764bb69-g5xl8   1/1     Running   0          8m10s
 [root@master01 ~]# kubectl exec -it -n ns1 deploy-nginx-6c9764bb69-g5xl8 -- /bin/sh/ # nslookup svc1......Name:      svc1Address 1: 10.3.166.140 deploy-nginx-6c9764bb69-g5xl8       IP與ns1里的podIP一致(見下面的查詢結果)/ # nslookup svc2.ns2.svc.cluster.local.....Name:      svc2.ns2.svc.cluster.localAddress 1: 10.3.104.17 10-3-104-17.svc2.ns2.svc.cluster.local   IP與ns2里的podIP一致(見下面的查詢結果)/ # exit
 [root@master01 ~]# kubectl get pods -o wide -n ns1NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE             NOMINATED NODE   READINESS GATESdeploy-nginx-6c9764bb69-g5xl8   1/1     Running   0          70m   10.3.166.140   192.168.122.13   <none>           <none>[root@master01 ~]# kubectl get pods -o wide -n ns2NAME                            READY   STATUS    RESTARTS   AGE   IP            NODE             NOMINATED NODE   READI            NESS GATESdeploy-nginx-6c9764bb69-8psxl   1/1     Running   0          68m   10.3.104.17   192.168.122.14   <none>           <none>

反之,在ns2命名空間的pod里訪問svc1.ns1.svc.cluster.local,解析的IP是ns1命名空間里的pod的IP(請自行驗證)

4, 驗證ns2中的pod的IP變化, ns1中的pod仍然可以使用svc2.ns2.svc.cluster.local訪問

 [root@master01 ~]# kubectl get pod -n ns2NAME                            READY   STATUS    RESTARTS   AGEdeploy-nginx-6c9764bb69-8psxl   1/1     Running   0          81m[root@master01 ~]# kubectl delete pod deploy-nginx-6c9764bb69-8psxl -n ns2pod "deploy-nginx-6c9764bb69-8psxl" deleted                   因為有replicas控制器,所以刪除pod會自動拉一個起來[root@master01 ~]# kubectl get pod -o wide -n ns2NAME                            READY   STATUS    RESTARTS   AGE     IP             NODE             NOMINATED NODE   READINESS GATESdeploy-nginx-6c9764bb69-8qbz2   1/1     Running   0          5m36s   10.3.166.141   192.168.122.13   <none>           <none>pod名稱變了,IP也變成了10.3.166.141

回到ns1中的pod驗證

 [root@master01 ~]# kubectl exec -it -n ns1 deploy-nginx-6c9764bb69-g5xl8 -- /bin/sh/ # ping svc2.ns2.svc.cluster.local -c 2PING svc2.ns2.svc.cluster.local (10.3.166.141): 56 data bytes    解析的IP就是ns2中pod的新IP64 bytes from 10.3.166.141: seq=0 ttl=63 time=0.181 ms64 bytes from 10.3.166.141: seq=1 ttl=63 time=0.186 ms--- svc2.ns2.svc.cluster.local ping statistics ---2 packets transmitted, 2 packets received, 0% packet lossround-trip min/avg/max = 0.181/0.183/0.186 ms/ # exit

五、sessionAffinity

會話粘貼

設置sessionAffinity為Clientip (類似nginx的ip_hash算法,lvs的sh算法)

[root@nginx ~]# cat 02_create_deployment_app_nginx_with_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: c1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-svc
spec:type: ClusterIPports:- protocol: TCPport: 80targetPort: 80selector:app: nginx
[root@master01 ~]# kubectl apply -f 02_create_deployment_app_nginx_with_service.yaml
deployment.apps/nginx-server1 created
service/nginx-svc created
[root@master01 ~]# kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
nginx-server1-58845f75f4-9zlnw   1/1     Running   0          2m11s
nginx-server1-58845f75f4-ffqdt   1/1     Running   0          2m11s
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-9zlnw bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx-server1-58845f75f4-9zlnw:/# echo web1 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-9zlnw:/# exit
exit
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-ffqdt bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx-server1-58845f75f4-ffqdt:/# echo web2 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-ffqdt:/# exit
exit
[root@master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   16d
nginx-svc    ClusterIP   10.100.53.31   <none>        80/TCP    3m53s
[root@master01 ~]# curl http://10.100.53.31
web1
[root@master01 ~]# curl http://10.100.53.31
web2
或
[root@master01 ~]# while true;do curl 10.100.53.31;sleep 1; done
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/nginx-svc patched[root@master01 ~]# curl 10.100.53.31
web1
多次訪問,會話粘貼
設置回sessionAffinity為None
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"None"}}'
service/my-service patched
測試
[root@master01 ~]# curl 10.100.53.31
web1
多次訪問,回到負載均衡
或
[root@master01 ~]# while true;do curl 10.100.53.31;sleep 1; done
web1
多次訪問,會話粘貼

六、修改為ipvs調度方式(拓展)

部署方式不同,修改方法不一樣。

本次主要介紹使用kubeadm部署集群方式,二進制部署較為簡單。

二進制部署修改:/etc/kubernetes/kube-proxy.yaml文件即可。

從kubernetes1.8版本開始,新增了kube-proxy對ipvs的支持,在kubernetes1.11版本中被納入了GA.

6.1 修改為IPVS調度方式前升級內核

現使用Centos7u6發布版本,默認內核版本為3.10.0,使用kubernetes為1.18.0時,可升級內核版本至4.18.0或5.6.0版本。

在所有節點中安裝,需要重啟操作系統更換內核。以下升級方法供參考。

[root@localhost ~]# yum -y install perl[root@localhost ~]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org[root@localhost ~]# yum -y install https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm[root@localhost ~]# yum  --enablerepo="elrepo-kernel"  -y install kernel-ml.x86_64 
此處升級為5.0以上版本。[root@localhost ~]# grub2-set-default 0[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg[root@localhost ~]# reboot

6.2 修改kube-proxy的配置文件

[root@master01 ~]# kubectl edit configmap kube-proxy -n kube-system26     iptables:27       masqueradeAll: false28       masqueradeBit: 1429       minSyncPeriod: 0s30       syncPeriod: 30s31     ipvs:32       excludeCIDRs: null33       minSyncPeriod: 0s34       scheduler: ""	  # 可以在這里修改ipvs的算法,默認為rr輪循算法35       strictARP: false36       syncPeriod: 30s37     kind: KubeProxyConfiguration38     metricsBindAddress: 127.0.0.1:1024939     mode: "ipvs"	  # 默認""號里為空,加上ipvs

6.3 查看kube-system的namespace中kube-proxy有關的pod

[root@master01 ~]# kubectl get pods -n kube-system |grep kube-proxy
kube-proxy-69mv6                           1/1     Running   6          2d18h
kube-proxy-jpc6c                           1/1     Running   4          4d16h
kube-proxy-kq65l                           1/1     Running   4          4d16h
kube-proxy-lmphf                           1/1     Running   5          4d16h

6.4 驗證kube-proxy-xxx的pod中的信息

[root@master01 ~]# kubectl logs kube-proxy-jpc6c -n kube-system
W0517 00:55:10.914754       1 server_others.go:559] Unknown proxy mode "", assuming iptables proxy
I0517 00:55:10.923228       1 node.go:136] Successfully retrieved node IP: 192.168.122.32
I0517 00:55:10.923264       1 server_others.go:186] Using iptables Proxier.
I0517 00:55:10.923567       1 server.go:583] Version: v1.18.2
I0517 00:55:10.923965       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_max' to 131072
I0517 00:55:10.924001       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 00:55:10.924258       1 conntrack.go:83] Setting conntrack hashsize to 32768
I0517 00:55:10.927041       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_established' to 86400
I0517 00:55:10.927086       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_close_wait' to 3600
I0517 00:55:10.927540       1 config.go:315] Starting service config controller
I0517 00:55:10.927556       1 shared_informer.go:223] Waiting for caches to sync for service config
I0517 00:55:10.927576       1 config.go:133] Starting endpoints config controller
I0517 00:55:10.927594       1 shared_informer.go:223] Waiting for caches to sync for endpoints config
I0517 00:55:11.027749       1 shared_informer.go:230] Caches are synced for service config
I0517 00:55:11.027858       1 shared_informer.go:230] Caches are synced for endpoints config

6.5 重新啟動kube-proxy

刪除kube-proxy-xxx的所有pod,讓它重新拉取新的kube-proxy-xxx的pod

[root@master01 ~]# kubectl delete pod kube-proxy-69mv6 -n kube-system
pod "kube-proxy-69mv6" deleted[root@master01 ~]# kubectl delete pod kube-proxy-jpc6c -n kube-system
pod "kube-proxy-jpc6c" deleted[root@master01 ~]# kubectl delete pod kube-proxy-kq65l -n kube-system
pod "kube-proxy-kq65l" deleted[root@master01 ~]# kubectl delete pod kube-proxy-lmphf -n kube-system
pod "kube-proxy-lmphf" deleted
[root@master01 ~]# kubectl get pods -n kube-system |grep kube-proxy
kube-proxy-2mk2b                           1/1     Running   0          2m23s
kube-proxy-5bj87                           1/1     Running   0          30s
kube-proxy-7qq9l                           1/1     Running   0          52s
kube-proxy-tjtqf                           1/1     Running   0          80s
隨意查看其中1個或3個kube-proxy-xxx的pod,驗證是否為IPVS方式了[root@master1 ~]# kubectl logs kube-proxy-tjtqf -n kube-system
I0517 02:32:26.557696       1 node.go:136] Successfully retrieved node IP: 192.168.122.32
I0517 02:32:26.557745       1 server_others.go:259] Using ipvs Proxier.
W0517 02:32:26.557912       1 proxier.go:429] IPVS scheduler not specified, use rr by default
I0517 02:32:26.560008       1 server.go:583] Version: v1.18.2
I0517 02:32:26.560428       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 02:32:26.561094       1 config.go:315] Starting service config controller
I0517 02:32:26.562251       1 shared_informer.go:223] Waiting for caches to sync for service config
I0517 02:32:26.561579       1 config.go:133] Starting endpoints config controller
I0517 02:32:26.562271       1 shared_informer.go:223] Waiting for caches to sync for endpoints config
I0517 02:32:26.662541       1 shared_informer.go:230] Caches are synced for service config
I0517 02:32:26.662566       1 shared_informer.go:230] Caches are synced for endpoints config

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/897545.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/897545.shtml
英文地址,請注明出處:http://en.pswp.cn/news/897545.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從零開始 | C語言基礎刷題DAY1

?個人主頁&#xff1a;折枝寄北的博客 DAY1[2025.3.11] 1. 求兩個數的較大值2.從鍵盤輸入的兩個數的大小關系3.一個整數的奇偶性&#xff0c;請判斷4. 考試分數是否通過5.考試成績是否完美&#xff0c;請判斷 1. 求兩個數的較大值 題目&#xff1a; 寫一個函數求兩個整數的較…

開源模型時代的 AI 開發革命:Dify 技術深度解析

開源模型時代的AI開發革命&#xff1a;Dify技術深度解析 引言&#xff1a;AI開發的開源新紀元 在生成式AI技術突飛猛進的2025年&#xff0c;開源模型正成為推動行業創新的核心力量。據統計&#xff0c;全球超過80%的AI開發者正在使用開源模型構建應用&#xff0c;這一趨勢不僅…

Dify Web 前端獨立部署指南(與后端分離,獨立部署)

背景:單獨拆分前端出來部署,二開前后端 本文檔專注于 Dify Web 前端的部署流程和配置,適用于需要將項目部署到各種環境的運維人員和開發者。 1. 環境準備 1.1 部署環境要求 Node.js >= 18.17.0Nginx 或其他Web服務器(生產環境推薦)Docker(可選,用于容器化部署)1.…

《蒼穹外賣》SpringBoot后端開發項目核心知識點整理(DAY1 to DAY3)

目錄 一、在本地部署并啟動Nginx服務1. 解壓Nginx壓縮包2. 啟動Nginx服務3. 驗證Nginx是否啟動成功&#xff1a; 二、導入接口文檔1. 黑馬程序員提供的YApi平臺2. YApi Pro平臺3. 推薦工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api與ApiModel1.2 ApiModelProperty與Ap…

大數據hadoop課程筆記

1.課程導入 柯潔 Alpha Go是人工智能領域的里程碑。 深度學習 大模型deepseek chatgpt 大模型 和 大數據 之間有著非常緊密的關系。可以說&#xff0c;大數據是大模型發展的基石&#xff0c;而大模型是大數據價值挖掘的重要工具。 https://youtu.be/nN-VacxHUH8?sifj7Ltk…

架構學習第八周--Kubernetes博客搭建

目錄 一、整體架構 二、部署MySQL主從 三、部署Redis哨兵 四、部署WordPress 五、注意事項 一、整體架構 本項目為在一主三從的Kubernetes集群上部署WordPress博客。因為WordPress部分容器版本自行集成Apache和PHP服務&#xff0c;因此在Kubernetes上部署WordPress只需提供…

Application.OnTime如何引用帶參數的過程

Application.OnTime方法本身并不直接支持傳遞參數給被調用的過程。不過&#xff0c;有幾種方法可以間接實現這個需求。 方法1&#xff1a;使用單引號表達式 使用單引號表達式來傳遞參數時&#xff0c;不能在表達式中使用變量&#xff0c;需要把參數值直接寫到表達中&am…

網絡安全之tcpdump工具

引言 wireshark是一款非常不錯的抓包軟件&#xff0c;在圖形化界面占絕對統治地位&#xff1b;盡管其在字符界面下有些許選項可供使用&#xff0c;但終究不太方便&#xff0c;下面我再介紹一款NB的終端抓包工具 tcpdump 1、混雜模式 linux的網卡有混雜模式一說&#xff0c;當開…

VC++ 獲取目的IP的路由

GetBestRoute 函數獲取到目的IP的最佳匹配路由。 第一個參數為&#xff1a;destination&#xff08;目的IP&#xff09; 第二個參數為&#xff1a;source&#xff08;源IP&#xff09; 通常不需要指定第二個source&#xff0c;這個一般用來匹配具體某一個網卡接口路由的&…

JavaScript 模塊 vs C# 類:封裝邏輯的兩種哲學

引言 在現代軟件開發中&#xff0c;模塊化和面向對象設計是代碼組織的核心課題。本文通過對比 JavaScript 模塊&#xff08;ES6 Module&#xff09;與 C# 類&#xff08;Class&#xff09;的實現方式&#xff0c;探討兩種語言在封裝邏輯時的不同哲學&#xff0c;并給出實際應用…

大模型在甲狀腺癌診療全流程預測及方案制定中的應用研究

目錄 一、引言 1.1 研究背景與意義 1.2 研究目的與創新點 1.3 國內外研究現狀 二、大模型預測甲狀腺癌的理論基礎 2.1 甲狀腺癌相關醫學知識 2.2 大模型技術原理與特點 2.3 大模型在醫療領域的應用潛力 三、術前預測方案 3.1 預測模型構建 3.1.1 數據收集與預處理 …

electron+vue+webview內嵌網頁并注入js

vue內嵌網頁可以使用iframe實現內嵌網頁&#xff0c;但是只能通過postMessage間接通信&#xff0c;在electron環境下&#xff0c;vue可以直接使用webview來內嵌網頁&#xff0c;支持 executeJavaScript、postMessage、send 等豐富的通信機制。 使用 webview的優勢 性能更佳&…

leetcode日記(95)將有序數組轉換為二叉搜索樹

很簡單&#xff0c;感覺自己越來越適應數據結構題目了…… /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : va…

【threejs實戰教程一】初識Three.js,場景Scene、相機Camera、渲染器Renderer

Three.js是一個基于WebGL的JavaScript 3D圖形庫&#xff0c;用于在瀏覽器中創建和顯示3D內容 Three.js中最基礎的三個關鍵要素就是場景Scene、相機Camera、渲染器Renderer 通俗一點理解&#xff0c;場景就是我們生活中一個具體的場景&#xff0c;比如自然環境中的一棟建筑&…

【leetcode hot 100 138】隨機鏈表的復制

解決一&#xff1a;回溯 哈希表 本題要求我們對一個特殊的鏈表進行深拷貝。如果是普通鏈表&#xff0c;我們可以直接按照遍歷的順序創建鏈表節點。而本題中因為隨機指針的存在&#xff0c;當我們拷貝節點時&#xff0c;「當前節點的隨機指針指向的節點」可能還沒創建&#xf…

木馬查殺之AST初識篇

一、AST 定義 抽象語法樹&#xff08;Abstract Syntax Tree&#xff0c;AST&#xff09;是源代碼的一種抽象表示形式。它以樹狀結構描述源代碼的語法構成&#xff0c;樹上的每個節點都對應源代碼中的一個語法結構或元素&#xff0c;像變量聲明、函數調用、表達式等。通過這種結…

vscode接入DeepSeek 免費送2000 萬 Tokens 解決DeepSeek無法充值問題

1. 在vscode中安裝插件 Cline 2.打開硅基流動官網 3. 注冊并登陸&#xff0c;邀請碼 WpcqcXMs 4.登錄后新建秘鑰 5. 在vscode中配置cline (1) API Provider 選擇 OpenAI Compatible &#xff1b; (2) Base URL設置為 https://api.siliconflow.cn](https://api.siliconfl…

如何在保持安全/合規的同時更快地構建應用程序:DevOps 指南

隨著敏捷思維方式的興起&#xff0c;開發和 DevOps 團隊都面臨著持續的壓力&#xff0c;他們需要以迭代方式縮短發布周期并加快部署速度&#xff0c;以滿足不斷增長的客戶期望。隨著這種對速度的追求越來越強烈&#xff0c;維護安全性和合規性標準的復雜性也隨之增加。 當今 D…

Java中常見的PO、VO、DAO、BO、DO、DTO、POJO、Query類解釋(通俗易懂)

文章目錄 先點擊收藏和點贊,切勿白嫖,感謝一丶PO(persistant object)持久對象二丶VO(value object)值對象三丶DAO(Data Access Objects) 數據訪問對象接口四丶BO/DO(Business Object) 業務對象層五丶DTO(Data Transfer Object) 數據傳輸對象六丶POJO(Plain Old Java Objects) 簡…

Websocket的基本使用

1. WebSocket WebSocket 是一種在單個TCP連接上進行全雙工通信的協議&#xff0c;它在現代 Web 開發和網絡應用中發揮著重要作用。在 WebSocket 出現之前&#xff0c;實現服務器與客戶端實時通信主要采用輪詢Polling和長輪詢Long - Polling等技術。輪詢是客戶端定時向服務器發…