במאמר הזה מוסבר איך להגדיר רשתות עם וירטואליזציה של קלט/פלט (SR-IOV) עם שורש יחיד ב-Google Distributed Cloud. SR-IOV מספק וירטואליזציה של קלט/פלט כדי להפוך כרטיס ממשק רשת (NIC) לזמין כמכשירי רשת בקרנל של Linux. כך תוכלו לנהל את חיבורי הרשת ולהקצות אותם לפודים. הביצועים משתפרים כי החבילות עוברות ישירות בין כרטיס הרשת לבין ה-pod.
כדאי להשתמש בתכונה הזו אם אתם צריכים רשת מהירה לעומסי העבודה של ה-Pod. SR-IOV ב-Google Distributed Cloud מאפשר להגדיר את הפונקציות הווירטואליות (VF) במכשירים הנתמכים של צמתי האשכול. אפשר גם לציין את מודול הליבה הספציפי שרוצים לקשר ל-VF.
התכונה הזו זמינה לאשכולות שמריצים עומסי עבודה, כמו אשכולות היברידיים, עצמאיים ומשתמשים. כדי להשתמש בתכונת הרשת SR-IOV, באשכול צריכים להיות לפחות שני צמתים.
תהליך ההגדרה כולל את השלבים הכלליים הבאים:
- מגדירים את האשכול כדי להפעיל רשת SR-IOV.
- מגדירים את אופרטור SR-IOV, שהוא משאב מותאם אישית של
SriovOperatorConfig. - הגדרת כללי מדיניות של SR-IOV והגדרת VFs.
- יוצרים
NetworkAttachmentDefinitionמשאב בהתאמה אישית שמפנה אל ה-VF.
דרישות
כדי להשתמש בתכונת הרשת SR-IOV, צריך לוודא שהדרייברים הרשמיים של מתאמי הרשת קיימים בצמתי האשכול. צריך להתקין את מנהלי ההתקנים לפני שמשתמשים באופרטור SR-IOV. בנוסף, כדי להשתמש במודול vfio-pci עבור הפונקציות הווירטואליות, צריך לוודא שהמודול זמין בצמתים שבהם רוצים להשתמש בו.
הפעלת רשת SR-IOV באשכול
כדי להפעיל רשת SR-IOV ב-Google Distributed Cloud, מוסיפים את השדה multipleNetworkInterfaces ואת השדה sriovOperator לקטע clusterNetwork של אובייקט Cluster ומגדירים את שני השדות לערך true.
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
name: cluster1
spec:
clusterNetwork:
multipleNetworkInterfaces: true
sriovOperator: true
...
השדה sriovOperator ניתן לשינוי, ואפשר לשנות אותו אחרי יצירת האשכול.
הגדרת אופרטור SR-IOV
SriovOperatorConfig המשאב המותאם אישית מספק הגדרה גלובלית לתכונת הרישות SR-IOV. למשאב המותאם אישית הזה יש שם חבילה default והוא נמצא במרחב השמות gke-operators. המשאב המותאם אישית SriovOperatorConfig תקף רק לשם ולמרחב השמות האלה.
אפשר לערוך את האובייקט הזה באמצעות הפקודה הבאה:
kubectl -n gke-operators edit sriovoperatorconfigs.sriovnetwork.k8s.cni.cncf.io defaultדוגמה להגדרה של SriovOperatorConfig משאב בהתאמה אישית:
apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovOperatorConfig
metadata:
name: default
namespace: gke-operators
spec:
configDaemonNodeSelector:
nodePool: "withSriov"
disableDrain: false
logLevel: 0
בקטע configDaemonNodeSelector אפשר להגביל את הצמתים שאליהם האופרטור SR-IOV יכול לגשת. בדוגמה הקודמת, המפעיל מוגבל רק לצמתים עם התווית nodePool: withSriov. אם לא מציינים את השדה configDaemonNodeSelector, המערכת מוסיפה את תוויות ברירת המחדל הבאות:
beta.kubernetes.io/os: linux
node-role.kubernetes.io/worker: ""
בשדה disableDrain מציינים אם לבצע ניקוי של צומת Kubernetes לפני הפעלה מחדש של הצומת או לפני שינוי של הגדרת VF ספציפית.
יצירת מדיניות SR-IOV
כדי להגדיר VFs ספציפיים באשכול, צריך ליצור SriovNetworkNodePolicy משאב בהתאמה אישית במרחב השמות gke-operators.
דוגמה למניפסט של SriovNetworkNodePolicy משאב בהתאמה אישית:
apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodePolicy
metadata:
name: policy-1
namespace: gke-operators
spec:
deviceType: "netdevice"
mtu: 1600
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0
deviceID: "1015"
rootDevices:
- 0000:01:00.0
vendor: "15b3"
numVfs: 4
priority: 80
resourceName: "mlnx"
בקטע nodeSelector אפשר להגביל עוד יותר את הצמתים שבהם צריך ליצור את הפונקציות הווירטואליות. המגבלה הזו היא בנוסף לסלקטורים מתוך SriovOperatorConfig שמתוארים בקטע הקודם.
השדה deviceType מציין את מודול הליבה שבו יש להשתמש עבור ה-VF. האפשרויות הזמינות ל-deviceType הן:
-
netdeviceעבור מודול ליבת תקני ספציפי ל-VF -
vfio-pciלדרייבר VFIO-PCI
הפרמטר resourceName מגדיר את השם שבו הממשקים הווירטואליים מיוצגים בצומת Kubernetes.
אחרי שמסיימים את תהליך ההגדרה, הצמתים של האשכול שבחרתם מכילים את המשאב שהוגדר, כמו שמוצג בדוגמה הבאה (שימו לב ל-gke.io/mlnx):
apiVersion: v1
kind: Node
metadata:
name: worker-01
spec:
…
status:
allocatable:
cpu: 47410m
ephemeral-storage: "210725550141"
gke.io/mlnx: "4"
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 59884492Ki
pods: "250"
capacity:
cpu: "48"
ephemeral-storage: 228651856Ki
gke.io/mlnx: "4"
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 65516492Ki
pods: "250"
האופרטור תמיד יוסיף את הקידומת gke.io/ לכל משאב שתגדירו באמצעות SriovNetworkNodePolicy.
ציון בורר NIC
כדי שהתג SriovNetworkNodePolicy יפעל בצורה תקינה, צריך לציין לפחות בורר אחד בקטע nicSelector. השדה הזה מכיל כמה אפשרויות לזיהוי פונקציות פיזיות (PF) ספציפיות בצמתי האשכול. רוב המידע שנדרש בשדה הזה מתגלה עבורכם ונשמר במשאב המותאם אישית SriovNetworkNodeState. יהיה אובייקט לכל צומת שהאופרטור הזה יכול לטפל בו.
כדי לראות את כל הצמתים הזמינים, משתמשים בפקודה הבאה:
kubectl -n gke-operators get sriovnetworknodestates.sriovnetwork.k8s.cni.cncf.io -o yamlדוגמה לצומת:
apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodeState
metadata:
name: worker-01
namespace: gke-operators
spec:
dpConfigVersion: "6368949"
status:
interfaces:
- deviceID: "1015"
driver: mlx5_core
eSwitchMode: legacy
linkSpeed: 10000 Mb/s
linkType: ETH
mac: 1c:34:da:5c:2b:9c
mtu: 1500
name: enp1s0f0
pciAddress: "0000:01:00.0"
totalvfs: 4
vendor: 15b3
- deviceID: "1015"
driver: mlx5_core
linkSpeed: 10000 Mb/s
linkType: ETH
mac: 1c:34:da:5c:2b:9d
mtu: 1500
name: enp1s0f1
pciAddress: "0000:01:00.1"
totalvfs: 2
vendor: 15b3
syncStatus: Succeeded
הגדרת חלוקה למחיצות של פונקציות פיזיות
חשוב לשים לב במיוחד לשדה pfNames בקטע nicSelector. בנוסף להגדרת ה-PF המדויק לשימוש, המדיניות מאפשרת לציין את ה-VF המדויק לשימוש עבור ה-PF שצוין והמשאב שהוגדר במדיניות.
הנה דוגמה:
apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodePolicy
metadata:
name: policy-1
namespace: gke-operators
spec:
deviceType: "netdevice"
mtu: 1600
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0#3-6
deviceID: "1015"
rootDevices:
- 0000:01:00.0
vendor: "15b3"
numVfs: 7
priority: 80
resourceName: "mlnx"
בדוגמה הקודמת, המשאב gke.io/mlnx משתמש רק ב-VF שמספרו 3 עד 6, ומוצגים רק ארבעה VF זמינים. מכיוון ש-VF נוצרים תמיד מאינדקס אפס, מספר ה-VF המבוקש, numVfs, צריך להיות לפחות גבוה כמו ערך הסגירה של הטווח (ספירה מאפס). הלוגיקה הזו של המספור מסבירה למה הערך של numVfs מוגדר כ-7 בדוגמה הקודמת. אם מגדירים טווח של 3 עד 4 (enp65s0f0#3-4), הערך של numVfs חייב להיות לפחות 5.
אם לא מציינים את החלוקה למחיצות, השדה numVfs מגדיר את טווח הפונקציות הווירטואליות שנעשה בהן שימוש, שתמיד מתחיל מאפס. לדוגמה, אם מגדירים numVfs=3
בלי לציין חלוקה למחיצות, נעשה שימוש ב-VFs 0-2.
הסבר על סדר העדיפויות של המדיניות
אפשר לציין כמה אובייקטים של SriovNetworkNodePolicy כדי לטפל בספקים שונים או בהגדרות שונות של VF. ניהול של כמה אובייקטים וספקים עלול להיות בעייתי אם כמה כללי מדיניות מפנים לאותו PF. כדי לטפל במצבים כאלה, השדה priority פותר את הקונפליקטים על בסיס כל צומת.
הנה לוגיקת קביעת העדיפות למדיניות PF חופפת:
מדיניות בעדיפות גבוהה יותר דורסת מדיניות בעדיפות נמוכה יותר רק אם חל חפיפה בין חלוקת המדיניות.
כללי מדיניות עם אותה עדיפות ימוזגו:
- המדיניות ממוינת לפי שם ומעובדת בסדר הזה
- כללי מדיניות עם חלוקת PF חופפת נכתבים מחדש
- מדיניות עם חלוקת PF לא חופפת מאוחדת וכל הנוכחים
מדיניות בעדיפות גבוהה היא מדיניות עם ערך מספרי נמוך יותר בשדה priority. לדוגמה, העדיפות של מדיניות עם priority: 10 גבוהה יותר מהעדיפות של מדיניות עם priority: 20.
בקטעים הבאים מופיעות דוגמאות למדיניות עבור תצורות שונות של חלוקה למחיצות.
PF מחולק למחיצות
פריסת שני המניפסטים הבאים של SriovNetworkNodePolicy יוצרת שני משאבים זמינים: gke.io/dev-kernel ו-gke.io/dev-vfio. לכל משאב יש שני VFs שלא חופפים.
kind: SriovNetworkNodePolicy
metadata:
name: policy-1
spec:
deviceType: "netdevice"
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0#0-1
numVfs: 2
priority: 70
resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
name: policy-2
spec:
deviceType: "vfio-pci"
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0#2-3
numVfs: 4
priority: 70
resourceName: "dev-vfio"
חלוקה למחיצות של PF עם חפיפה
פריסה של שני המניפסטים הבאים של SriovNetworkNodePolicy תגרום לכך שרק המשאב gke.io/dev-vfio יהיה זמין. טווח ה-VF policy-1 הוא 0-2, ויש חפיפה בינו לבין policy-2. בגלל השם, המידע על policy-2 מעובד אחרי policy-1. לכן, זמין רק המשאב שצוין ב-policy-2, gke.io/dev-vfio.
kind: SriovNetworkNodePolicy
metadata:
name: policy-1
spec:
deviceType: "netdevice"
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0
numVfs: 3
priority: 70
resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
name: policy-2
spec:
deviceType: "vfio-pci"
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0#2-3
numVfs: 4
priority: 70
resourceName: "dev-vfio"
חלוקת PF לא חופפת עם עדיפויות שונות
פריסת שני המניפסטים הבאים של SriovNetworkNodePolicy יוצרת שני משאבים זמינים: gke.io/dev-kernel ו-gke.io/dev-vfio. לכל משאב יש שני VFs שלא חופפים. למרות של-policy-1 יש עדיפות גבוהה יותר מ-policy-2, מכיוון שהחלוקה של PF לא חופפת, אנחנו ממזגים את שתי המדיניות.
kind: SriovNetworkNodePolicy
metadata:
name: policy-1
spec:
deviceType: "netdevice"
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0
numVfs: 2
priority: 10
resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
name: policy-2
spec:
deviceType: "vfio-pci"
nodeSelector:
baremetal.cluster.gke.io/node-pool: node-pool-1
nicSelector:
pfNames:
- enp65s0f0#2-3
numVfs: 4
priority: 70
resourceName: "dev-vfio"
בדיקת סטטוס ההגדרה של מדיניות SR-IOV
כשמחילים את כללי המדיניות של SR-IOV, אפשר לעקוב אחרי ההגדרה הסופית של הצמתים ולהציג אותה במשאב המותאם אישית SriovNetworkNodeState של הצומת הספציפי. בקטע status, השדה syncStatus מייצג את השלב הנוכחי של דמון ההגדרה. המצב Succeeded מציין שההגדרה הסתיימה. בקטע spec של המשאב המותאם אישית SriovNetworkNodeState מוגדר המצב הסופי של הגדרת ה-VF עבור הצומת הזה, על סמך מספר המדיניות והעדיפויות שלהן. כל ה-VF שנוצרו יופיעו בקטע status של ה-PF שצוינו.
דוגמה למשאב מותאם אישית SriovNetworkNodeState:
apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodeState
metadata:
name: worker-02
namespace: gke-operators
spec:
dpConfigVersion: "9022068"
interfaces:
- linkType: eth
name: enp1s0f0
numVfs: 2
pciAddress: "0000:01:00.0"
vfGroups:
- deviceType: netdevice
policyName: policy-1
resourceName: mlnx
vfRange: 0-1
status:
interfaces:
- Vfs:
- deviceID: "1016"
driver: mlx5_core
mac: 96:8b:39:d8:89:d2
mtu: 1500
name: enp1s0f0np0v0
pciAddress: "0000:01:00.2"
vendor: 15b3
vfID: 0
- deviceID: "1016"
driver: mlx5_core
mac: 82:8e:65:fe:9b:cb
mtu: 1500
name: enp1s0f0np0v1
pciAddress: "0000:01:00.3"
vendor: 15b3
vfID: 1
deviceID: "1015"
driver: mlx5_core
eSwitchMode: legacy
linkSpeed: 10000 Mb/s
linkType: ETH
mac: 1c:34:da:5c:2b:9c
mtu: 1500
name: enp1s0f0
numVfs: 2
pciAddress: "0000:01:00.0"
totalvfs: 2
vendor: 15b3
- deviceID: "1015"
driver: mlx5_core
linkSpeed: 10000 Mb/s
linkType: ETH
mac: 1c:34:da:5c:2b:9d
mtu: 1500
name: enp1s0f1
pciAddress: "0000:01:00.1"
totalvfs: 2
vendor: 15b3
syncStatus: Succeeded
יצירת NetworkAttachmentDefinition משאב בהתאמה אישית
אחרי שמגדירים בהצלחה את ה-VF באשכול, והוא מופיע בצומת Kubernetes כמשאב, צריך ליצור NetworkAttachmentDefinition שמפנה למשאב. יוצרים את קובץ העזר עם הערה מסוג k8s.v1.cni.cncf.io/resourceName.
זו דוגמה לקובץ מניפסט של NetworkAttachmentDefinition שמפנה למשאב gke.io/mlnx:
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: gke-sriov-1
annotations:
k8s.v1.cni.cncf.io/resourceName: gke.io/mlnx
spec:
config: '{
"cniVersion": "0.3.0",
"name": "mynetwork",
"type": "sriov",
"ipam": {
"type": "whereabouts",
"range": "21.0.108.0/21",
"range_start": "21.0.111.16",
"range_end": "21.0.111.18"
}
}'
ב-NetworkAttachmentDefinition צריך להגדיר את sriov כסוג ה-CNI.
אפשר להפנות למשאבים מותאמים אישית מסוג NetworkAttachmentDefinition שנפרסו בתרמילים באמצעות הערה מסוג k8s.v1.cni.cncf.io/networks.
דוגמה לאופן ההפניה למשאב מותאם אישית NetworkAttachmentDefinition שמופיע למעלה ב-pod:
apiVersion: v1
kind: Pod
metadata:
name: samplepod
annotations:
k8s.v1.cni.cncf.io/networks: gke-sriov-1
spec:
containers:
...
כשמפנים לNetworkAttachmentDefinitionמשאב מותאם אישית בעומסי עבודה,
לא צריך לדאוג להגדרות המשאבים של ה-Pods או למיקום שלהם ב
צמתים ספציפיים, כי הפעולות האלה מתבצעות באופן אוטומטי.
בדוגמה הבאה מוצג משאב בהתאמה אישית NetworkAttachmentDefinition עם הגדרת VLAN. בדוגמה הזו, כל VF שייך ל-VLAN 100:
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: gke-sriov-vlan-100
annotations:
k8s.v1.cni.cncf.io/resourceName: gke.io/mlnx
spec:
config: '{
"cniVersion": "0.3.0",
"name": "mynetwork",
"type": "sriov",
"vlan": 100,
"ipam": {
"type": "whereabouts",
"range": "21.0.100.0/21"
}
}'
מידע נוסף
בקטעים הבאים מופיע מידע שיעזור לכם להגדיר רשת SR-IOV.
הפעלות מחדש של צמתים
כשמפעיל SR-IOV מגדיר את הצמתים, יכול להיות שיהיה צורך להפעיל מחדש את הצמתים. יכול להיות שתצטרכו להפעיל מחדש את הצמתים במהלך ההגדרה של VF או של ליבת המערכת. הגדרת הליבה כוללת הפעלה של תמיכה בפונקציונליות של SR-IOV במערכת ההפעלה.
מתאמי רשת נתמכים
בטבלה הבאה מפורטים מתאמי הרשת הנתמכים באשכולות מגרסה 1.36.x:
| שם | מזהה הספק | מזהה המכשיר | מזהה מכשיר וירטואלי |
|---|---|---|---|
| Intel i40e XXV710 | 8086 | 158a | 154c |
| Intel i40e 25G SFP28 | 8086 | 158b | 154c |
| Intel i40e 10G X710 SFP | 8086 | 1572 | 154c |
| Intel i40e XXV710 N3000 | 8086 | 0d58 | 154c |
| Intel i40e 40G XL710 QSFP | 8086 | 1583 | 154c |
| Intel ice Columbiaville E810-CQDA2 2CQDA2 | 8086 | 1592 | 1889 |
| Intel ice Columbiaville E810-XXVDA4 | 8086 | 1593 | 1889 |
| Intel ice Columbiaville E810-XXVDA2 | 8086 | 159b | 1889 |
| Nvidia mlx5 ConnectX-4 | 15b3 | 1013 | 1014 |
| Nvidia mlx5 ConnectX-4LX | 15b3 | 1015 | 1016 |
| Nvidia mlx5 ConnectX-5 | 15b3 | 1017 | 1018 |
| Nvidia mlx5 ConnectX-5 Ex | 15b3 | 1019 | 101a |
| Nvidia mlx5 ConnectX-6 | 15b3 | 101b | 101c |
| Nvidia mlx5 ConnectX-6_Dx | 15b3 | 101d | 101e |
| Nvidia mlx5 MT42822 BlueField-2 integrated ConnectX-6 Dx | 15b3 | a2d6 | 101e |
| Broadcom bnxt BCM57414 2x25G | 14e4 | 16d7 | 16dc |
| Broadcom bnxt BCM75508 2x100G | 14e4 | 1750 | 1806 |