0%

硬件进行隔离(硬隔离)

需要显卡支持 GPU 虚拟化(如 vGPU)或 MIG(Multi-Instance GPU)功能。

软件进行隔离和共享(软隔离)

硬件不支持可以采用。如:NVIDIA GeForce RTX 3050

方式一:Aliyun gpushare-scheduler-extender

特点:允许多个 Pod 共享同一个 GPU 的资源,通过限制显存使用实现隔离。

方式二:Time-Slicing(时间分片)

时间分片是一种通过 GPU 驱动实现的调度机制,允许多个进程按时间片轮流使用 GPU。

特点:串行执行,简单易用,隔离性强,资源利用率低,延迟增加。

适合场景:边缘计算、轻量级推理任务。

安装:

前提是已经安装k8s-device-plugin

  1. 添加如下配置,在kuboard管理界面的nvidia-device-plugin空间内创建configmap(也可以通过k8s命令创建),名称为gpu-share-configs,key为: time-slicing.yaml,值如下:

    1
    2
    3
    4
    5
    6
    7
    8
    version: v1
    sharing:
    timeSlicing:
    renameByDefault: true #重命名gpu资源名称,为了区分是不是共享gpu,eg:nvidia.com/gpu将被重命名nvidia.com/gpu.shared,限制limits的时候就要用nvidia.com/gpu.shared
    failRequestsGreaterThanOne: true #限制一个容器只能请求一个cpu,这样所有容器都是公平的时间分配
    resources:
    - name: nvidia.com/gpu
    replicas: 10 #表示GPU资源被分成n*10个逻辑单元,n代表gpu个数
  2. 应用配置,在原来安装插件的命令上增加--set config.default=time-slicing.yaml--set config.name=gpu-share-configs,详细命令如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    exxk@exxk:~$ sudo helm upgrade -i nvidia-device-plugin nvdp/nvidia-device-plugin \
    --namespace nvidia-device-plugin \
    --create-namespace \
    --version 0.17.0 \
    --set runtimeClassName=nvidia \
    --set config.default=time-slicing.yaml \
    --set config.name=gpu-share-configs \
    --kubeconfig /etc/rancher/k3s/k3s.yaml
    exxk@exxk:~$ sudo helm upgrade -i nvidia-device-discovery nvdp/gpu-feature-discovery \
    --namespace nvidia-device-plugin \
    --create-namespace \
    --version 0.17.0 \
    --set runtimeClassName=nvidia \
    --set config.default=time-slicing.yaml \
    --set config.name=gpu-share-configs \
    --kubeconfig /etc/rancher/k3s/k3s.yaml
    # 验证是否成功
    exxk@exxk:~$ sudo kubectl describe node | grep nvidia.com
    nvidia.com/cuda.driver-version.full=560.35.03
    nvidia.com/cuda.driver-version.major=560
    nvidia.com/cuda.driver-version.minor=35
    nvidia.com/cuda.driver-version.revision=03
    nvidia.com/cuda.driver.major=560
    nvidia.com/cuda.driver.minor=35
    nvidia.com/cuda.driver.rev=03
    nvidia.com/cuda.runtime-version.full=12.6
    nvidia.com/cuda.runtime-version.major=12
    nvidia.com/cuda.runtime-version.minor=6
    nvidia.com/cuda.runtime.major=12
    nvidia.com/cuda.runtime.minor=6
    nvidia.com/gfd.timestamp=1734514101
    nvidia.com/gpu.compute.major=8
    nvidia.com/gpu.compute.minor=6
    nvidia.com/gpu.count=1
    nvidia.com/gpu.family=ampere
    nvidia.com/gpu.machine=Standard-PC-i440FX-PIIX-1996
    nvidia.com/gpu.memory=4096
    nvidia.com/gpu.mode=graphics
    nvidia.com/gpu.product=NVIDIA-GeForce-RTX-3050-Laptop-GPU
    nvidia.com/gpu.replicas=10 #这里变成了10了
    nvidia.com/gpu.sharing-strategy=time-slicing #这里用时间分片了
    nvidia.com/mig.capable=false
    nvidia.com/mps.capable=false
    nvidia.com/vgpu.present=false
    nvidia.com/gpu: 0
    nvidia.com/gpu.shared: 10
    nvidia.com/gpu: 0
    nvidia.com/gpu.shared: 10
    nvidia.com/gpu 0 0
    nvidia.com/gpu.shared 0 0
  3. 使用,在部署容器时,如果要限制gpu使用,需要修改将nvidia.com/gpu修改为nvidia.com/gpu.shared

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spec:
    containers:
    - command:
    - tail
    - '-f'
    - /dev/null
    image: 'docker.io/nvidia/cuda:11.8.0-base-ubuntu20.04'
    imagePullPolicy: IfNotPresent
    name: cuda
    resources:
    limits:
    nvidia.com/gpu.shared: '1' #默认为nvidia.com/gpu需改为nvidia.com/gpu.shared
  4. 经测试,如果配置nvidia.com/gpu.shared,超过10个,就无法创建pod了,没配置可以超过10个。

方式三:MPS

MPS 是 NVIDIA 提供的 GPU 多进程共享服务,允许多个 CUDA 进程同时在 GPU 上执行。

特点:并行执行,高资源利用率,性能提升,可控分配,复杂性增加,隔离性较弱,兼容不是很强(使用前要验证CUDA内核是否支持MPS)。

适合场景:多任务训练、大规模高效推理。

安装:

前提是已经安装k8s-device-plugin

  1. 添加如下配置,在kuboard管理界面的nvidia-device-plugin空间内创建configmap(也可以通过k8s命令创建),名称为gpu-share-configs,key为: mps.yaml,值如下:

    1
    2
    3
    4
    5
    6
    7
    version: v1
    sharing:
    mps:
    renameByDefault: true #重命名gpu资源名称,为了区分是不是共享gpu,eg:nvidia.com/gpu将被重命名nvidia.com/gpu.shared,限制limits的时候就要用nvidia.com/gpu.shared
    resources:
    - name: nvidia.com/gpu
    replicas: 10 #表示GPU总内存被分成n*10份,n代表gpu个数
  2. 应用配置,在原来安装插件的命令上增加--set config.default=mps.yaml--set config.name=gpu-share-configs,详细命令如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    exxk@exxk:~$ sudo helm upgrade -i nvidia-device-plugin nvdp/nvidia-device-plugin \
    --namespace nvidia-device-plugin \
    --create-namespace \
    --version 0.17.0 \
    --set runtimeClassName=nvidia \
    --set config.default=mps.yaml \
    --set config.name=gpu-share-configs \
    --kubeconfig /etc/rancher/k3s/k3s.yaml
    exxk@exxk:~$ sudo helm upgrade -i nvidia-device-discovery nvdp/gpu-feature-discovery \
    --namespace nvidia-device-plugin \
    --create-namespace \
    --version 0.17.0 \
    --set runtimeClassName=nvidia \
    --set config.default=mps.yaml \
    --set config.name=gpu-share-configs \
    --kubeconfig /etc/rancher/k3s/k3s.yaml
    # 验证是否成功
    exxk@exxk:~$ sudo kubectl describe node | grep nvidia.com
    nvidia.com/cuda.driver-version.full=560.35.03
    nvidia.com/cuda.driver-version.major=560
    nvidia.com/cuda.driver-version.minor=35
    nvidia.com/cuda.driver-version.revision=03
    nvidia.com/cuda.driver.major=560
    nvidia.com/cuda.driver.minor=35
    nvidia.com/cuda.driver.rev=03
    nvidia.com/cuda.runtime-version.full=12.6
    nvidia.com/cuda.runtime-version.major=12
    nvidia.com/cuda.runtime-version.minor=6
    nvidia.com/cuda.runtime.major=12
    nvidia.com/cuda.runtime.minor=6
    nvidia.com/gfd.timestamp=1734573325
    nvidia.com/gpu.compute.major=8
    nvidia.com/gpu.compute.minor=6
    nvidia.com/gpu.count=1
    nvidia.com/gpu.family=ampere
    nvidia.com/gpu.machine=Standard-PC-i440FX-PIIX-1996
    nvidia.com/gpu.memory=4096
    nvidia.com/gpu.mode=graphics
    nvidia.com/gpu.product=NVIDIA-GeForce-RTX-3050-Laptop-GPU
    nvidia.com/gpu.replicas=10 #这里变成了10了
    nvidia.com/gpu.sharing-strategy=mps #这里用mps了
    nvidia.com/mig.capable=false
    nvidia.com/mps.capable=true
    nvidia.com/vgpu.present=false
    nvidia.com/gpu: 0
    nvidia.com/gpu.shared: 10
    nvidia.com/gpu: 0
    nvidia.com/gpu.shared: 10
    nvidia.com/gpu 0 0
    nvidia.com/gpu.shared 0 0
  3. 使用,在部署容器时,如果要限制gpu使用,需要修改将nvidia.com/gpu修改为nvidia.com/gpu.shared

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spec:
    containers:
    - command:
    - tail
    - '-f'
    - /dev/null
    image: 'docker.io/nvidia/cuda:11.8.0-base-ubuntu20.04'
    imagePullPolicy: IfNotPresent
    name: cuda
    resources:
    limits:
    nvidia.com/gpu.shared: '1' #默认为nvidia.com/gpu需改为nvidia.com/gpu.shared
  4. 经测试,如果配置nvidia.com/gpu.shared,超过10个,就无法创建pod了。

方式四:IMEX

GPU虚拟化,需要硬件GPU支持虚拟化,目前有的显卡不支持,暂不考虑。

安装k8s-device-plugin

方式零:这是一个简单的静态守护进程集,旨在演示 的基本功能。 (未验证成功)

1
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.17.0/deployments/static/nvidia-device-plugin.yml

方式一:helm命令方式 (成功)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#添加插件仓库
exxk@exxk:~$ sudo helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
exxk@exxk:~$ sudo helm repo update
#从仓库查找可用版本
exxk@exxk:~$ sudo helm search repo nvdp --devel
NAME CHART VERSION APP VERSION DESCRIPTION
nvdp/gpu-feature-discovery 0.17.0 0.17.0 A Helm chart for gpu-feature-discovery on Kuber...
nvdp/nvidia-device-plugin 0.17.0 0.17.0 A Helm chart for the nvidia-device-plugin on Ku...
#安装nvidia-runtimeclass,因为后面安装插件依赖于他
exxk@exxk:~$ cat nvidia-runtimeclass.yaml
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia
handler: nvidia
exxk@exxk:~$ sudo kubectl apply -f nvidia-runtimeclass.yaml
#验证是否安装成功,或者有就不需要安装了
exxk@exxk:~$ sudo kubectl get runtimeclass
crun crun 11d
lunatic lunatic 11d
nvidia nvidia 11m
#安装nvidia-device-plugin支持k3s里面用gpu
exxk@exxk:~$ sudo helm upgrade -i nvidia-device-plugin nvdp/nvidia-device-plugin \
--namespace nvidia-device-plugin \
--create-namespace \
--version 0.17.0 \
--set runtimeClassName=nvidia \
--kubeconfig /etc/rancher/k3s/k3s.yaml
#安装nvidia-device-discovery自动发现gpu,并标记节点
exxk@exxk:~$ sudo helm upgrade -i nvidia-device-discovery nvdp/gpu-feature-discovery \
--namespace nvidia-device-plugin \
--create-namespace \
--version 0.17.0 \
--set runtimeClassName=nvidia \
--kubeconfig /etc/rancher/k3s/k3s.yaml
#验证,可以执行下面命令,也可以直接看节点的标签,如果有下述标签,代表nvidia-device-plugin和gpu-feature-discovery插件安装成功
#标签详细说明见:https://github.com/NVIDIA/k8s-device-plugin?tab=readme-ov-file#catalog-of-labels
exxk@exxk:~$ sudo kubectl describe node | grep nvidia.com
nvidia.com/cuda.driver-version.full=560.35.03
nvidia.com/cuda.driver-version.major=560
nvidia.com/cuda.driver-version.minor=35
nvidia.com/cuda.driver-version.revision=03
nvidia.com/cuda.driver.major=560
nvidia.com/cuda.driver.minor=35
nvidia.com/cuda.driver.rev=03
nvidia.com/cuda.runtime-version.full=12.6
nvidia.com/cuda.runtime-version.major=12
nvidia.com/cuda.runtime-version.minor=6
nvidia.com/cuda.runtime.major=12
nvidia.com/cuda.runtime.minor=6
nvidia.com/gfd.timestamp=1734424517
nvidia.com/gpu.compute.major=8
nvidia.com/gpu.compute.minor=6
nvidia.com/gpu.count=1 #gpu数量
nvidia.com/gpu.family=ampere
nvidia.com/gpu.machine=Standard-PC-i440FX-PIIX-1996
nvidia.com/gpu.memory=4096
nvidia.com/gpu.mode=graphics
nvidia.com/gpu.product=NVIDIA-GeForce-RTX-3050-Laptop-GPU
nvidia.com/gpu.replicas=1
nvidia.com/gpu.sharing-strategy=none #共享策略none不共享、mps、time-slicing
nvidia.com/mig.capable=false #是否支持 MIG
nvidia.com/mps.capable=false #是否配置了 MPS
nvidia.com/vgpu.present=false #是否使用 vGPU
nvidia.com/gpu: 1
nvidia.com/gpu: 1
nvidia.com/gpu 0 0

方式二:HelmChart方式 (未验证成功)

通过 HelmChart CR 配置实现自动安装。这种方式无需手动运行 helm 命令。

  1. 创建 HelmChart 配置文件

    nvidia-device-plugin.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    apiVersion: helm.cattle.io/v1
    kind: HelmChart
    metadata:
    name: nvdp
    namespace: kube-system
    spec:
    chart: https://github.com/NVIDIA/k8s-device-plugin/releases/download/v0.17.0/nvidia-device-plugin-0.17.0.tgz #这里从https://github.com/NVIDIA/k8s-device-plugin/releases找到对应的包覆之下载地址到这里
    version: 0.17.0 # Chart 版本号,和压缩包的一致
    targetNamespace: nvidia-device-plugin #插件将被部署到的命名空间
    set:
    - name: runtimeClassName #如果需要自定义安装参数,可以在此处设置键值对。
    value: nvidia
  2. 执行下面命令进行安装

    1
    2
    3
    4
    5
    6
    #创建命名空间
    exxk@exxk:~$ kubectl create namespace nvidia-device-plugin
    #执行安装
    exxk@exxk:~$ sudo kubectl apply -f nvidia-device-plugin.yaml
    #如果要删除执行
    exxk@exxk:~$ sudo kubectl delete -f nvidia-device-plugin.yaml

使用或验证

创建一个Deployment,可以在kuboard界面上创建,关键信息:

镜像(界面上):docker.io/nvidia/cuda:11.8.0-base-ubuntu20.04
持久化命令(界面上):tail -f /dev/null

指定gpu运行(yaml添加):runtimeClassName: nvidia

进入容器执行nvidia-smi ,就可以看到显卡相关信息,如果找不到命令,代表前面配置有问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
            欢迎使用 HCYTech - Kubernetes 多集群管理工具。
您在终端界面中执行的操作将被记录到审计日志。

root@cudatest-549f4f49f8-ltblq:/# nvidia-smi
Tue Dec 17 10:03:34 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.35.03 Driver Version: 560.35.03 CUDA Version: 12.6 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3050 ... Off | 00000000:00:10.0 Off | N/A |
| N/A 48C P8 4W / 60W | 2MiB / 4096MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+

完整的yaml示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
apiVersion: apps/v1
kind: Deployment
metadata:
annotations: {}
labels:
k8s.kuboard.cn/name: cudatest
name: cudatest
namespace: default
resourceVersion: '3843602'
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/name: cudatest
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
k8s.kuboard.cn/name: cudatest
spec:
containers:
- command:
- tail
- '-f'
- /dev/null
image: 'docker.io/nvidia/cuda:11.8.0-base-ubuntu20.04'
imagePullPolicy: IfNotPresent
name: cuda
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
nodeSelector:
nvidia.com/gpu.count: '1'
restartPolicy: Always
runtimeClassName: nvidia # 注意这句,这句在kuboard界面无法添加,需要编辑yaml,添加到这里
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30

k3s节点设计

节点 系统 资源 类型 ip
exxk Ubuntu server 20.04 4c/8g内存/100g硬盘/4g显存 工作+控制+cuda 172.16.80.80
node1 fedora-coreos-41 2c/4g内存/20g硬盘 工作+控制 172.16.80.163
node2 fedora-coreos-41 2c/4g内存/20g硬盘 工作+控制 172.16.80.179
nfs alpine3.20 1c/512m内-1g交/100g硬盘 nfs 172.16.80.144

k3s各节点安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# -----------------------节点Node1虚拟机-----------------------
core@node1:~$ sudo hostnamectl set-hostname node1
core@node1:~$ sudo reboot
core@node1:~$ sudo yum install -y curl
core@node1:~$ curl -sfL https://get.k3s.io | K3S_TOKEN=EXXK_SECRET sh -s - server --cluster-init
core@node1:~$ sudo reboot
core@node1:~$ sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready control-plane,etcd,master 119s v1.30.6+k3s1
#如果容器挂载失败时,需要安装
core@node1:~$ sudo rpm-ostree install nfs-utils
# -----------------------节点Node2虚拟机-----------------------
core@node2:~$ sudo hostnamectl set-hostname node2
core@node2:~$ sudo reboot
core@node2:~$ sudo yum install -y curl
core@node2:~$ curl -sfL https://get.k3s.io | K3S_TOKEN=EXXK_SECRET sh -s - server --server https://172.16.80.163:6443
core@node1:~$ sudo reboot
core@node2:~$ sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready control-plane,etcd,master 17m v1.30.6+k3s1
node2 Ready control-plane,etcd,master 34s v1.30.6+k3s1
#如果容器挂载失败时,需要安装
core@node2:~$ sudo rpm-ostree install nfs-utils
# -----------------------节点exxk虚拟机-----------------------
exxk@exxk:~$ curl -sfL https://get.k3s.io | K3S_TOKEN=EXXK_SECRET sh -s - server --server https://172.16.80.163:6443
exxk@exxk:~$ sudo reboot
exxk@exxk:~$ sudo kubectl get nodes
[sudo] password for exxk:
NAME STATUS ROLES AGE VERSION
exxk Ready control-plane,etcd,master 3m4s v1.30.6+k3s1
node1 Ready control-plane,etcd,master 25m v1.30.6+k3s1
node2 Ready control-plane,etcd,master 8m19s v1.30.6+k3s1
#如果容器挂载失败时,需要安装
exxk@exxk:~$ sudo apt install nfs-common
# 安装显卡驱动,这里已知安装的版本,详情见:https://www.iexxk.com/2024/11/19/ubuntu-intall-cuda/
exxk@exxk:~$ sudo add-apt-repository ppa:graphics-drivers/ppa
exxk@exxk:~$ sudo apt update
exxk@exxk:~$ sudo apt install -y nvidia-driver-560 --no-install-recommends
exxk@exxk:~$ sudo reboot
exxk@exxk:~$ nvidia-smi #验证
# 安装 NVIDIA Container Toolkit见https://www.iexxk.com/2024/11/19/ubuntu-intall-cuda/
#注意下下面这句用containerd
exxk@exxk:~$ sudo nvidia-ctk runtime configure --runtime=containerd
exxk@exxk:~$ sudo reboot #重启
#验证
exxk@exxk:~$ sudo sudo ctr run --rm --gpus 0 docker.io/nvidia/cuda:11.8.0-base-ubuntu20.04 bash
nvidia-smi #执行
Fri Dec 13 10:05:41 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.35.03 Driver Version: 560.35.03 CUDA Version: 12.6 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3050 ... Off | 00000000:00:10.0 Off | N/A |
| N/A 45C P8 3W / 60W | 2MiB / 4096MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
exit #退出
#安装k8s-device-plugin插件见:https://www.iexxk.com/2024/12/17/k8s-use-cuda/#方式一:helm命令方式-成功
# -----------------------nfs虚拟机-----------------------
# 安装参考:https://wiki.alpinelinux.org/wiki/Setting_up_an_NFS_server
nfs:~# apk add nfs-utils
nfs:~# mkdir /nfsdata
nfs:/nfs# vi /etc/exports
#增加如下内容
/nfsdata 172.16.80.0/24(rw,nohide,no_subtree_check,no_root_squash)
nfs:~# rc-update add nfs
nfs:~# rc-service nfs start

客户端使用

kubeconfig获取,可以从其中一个主节点sudo cat /etc/rancher/k3s/k3s.yaml拷贝或下载下来这个文件,修改里面的server ip为节点外网的ip,然后保存。

Lens

  1. 下载mac版本
  2. Lens客户端打开,点击左侧菜单Local KubeConfigs上面的+号,然后导入kubeconfig

kuboard

  1. 我这里直接用的另一个集群的kuboard,就么有安装,直接导入即可。
  2. 登录进入Home Page->Add kubernetes,填入kebeconfig配置。

安装

  1. 生成SSH密钥对,一般都有

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ➜  ~ ls ~/.ssh | grep 'id'
    id_rsa #私钥
    id_rsa.pub #公钥
    #如果没有,执行下面命令生成,尽量用新系统的,新系统不行采用旧系统
    #新系统
    ➜ ~ ssh-keygen -t ed25519 -C "your_email@example.com"
    #旧系统
    ➜ ~ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
    #如果不想用之前的,可以新生成一个,但要-f参数指定文件名,不然会覆盖默认的id_rsa和id_rsa.pub文件
    ➜ ~ ssh-keygen -t ed25519 -C "exxk.lx@gmail.com" -f ~/.ssh/id_ed25519
    id_ed25519 #私钥
    id_ed25519.pub #公钥
    #查看公钥
    ➜ ~ cat .ssh/id_ed25519.pub
    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBRY5NvpBIemtf+8eoaNa3K7TKxnGsK4do4t2WeM1xqM exxk.lx@gmail.com
  2. 准备配置文件fedora-core-config.yaml,将上面的公钥复制粘贴到ssh_authorized_keys下面

    1
    2
    3
    4
    5
    6
    7
    variant: fcos
    version: 1.4.0
    passwd:
    users:
    - name: core
    ssh_authorized_keys:
    - ssh-ed25519 AAAAC3NzaC1lZDI1... exxk.lx@gmail.com
  3. 有两个方案:推荐方案二

    • 方案一:在mac电脑上安装butane,执行brew install butanebutane --pretty --strict fedora-core-config.yaml > fedora-core-config.ign,然后将ign文件上传到github或其他可以拿到链接的地方,得到文件链接。

    • 方案二:通过github:iexxk/iexxk项目里面的自动执行butane进行生产有链接的配置文件。

  4. 将上一步骤的链接放到该执行命令sudo coreos-installer install /dev/sda --ignition-url https://raw.githubusercontent.com/iexxk/iexxk/refs/heads/main/fedora-core-config.ign

  5. 在加载了fedora-coreos-xxxx-live.x86_64.iso镜像的实体机或虚拟机的界面,执行上一步的命令进行安装系统。

  6. 安装之后,卸载iso镜像加载,重新启动,启动过后能在登录界面看到ip,但是没有密码只能通过ssh进行登录

  7. 通过私钥进行ssh登录:

    • 方案一(命令):配置ssh登录信息,执行vim ~/.ssh/config,增加如下内容

      1
      2
      3
      4
      Host fc-server
      HostName 172.16.80.168
      User core
      IdentityFile ~/.ssh/id_ed25519

      执行ssh fc-server即可进行远程登录了

    • 方案二(工具):使用royal-tsx工具,先创建一个Credential,配置usernamecorePrivate Key File~/.ssh/id_ed25519,然后在新建个ssh Terminal,配置Computer Name172.16.80.168Credential选择刚刚创建的。

需求

需要对java8+Spingboot项目进行编译后的jar包混淆。

方案一:ClassFinal

ClassFinal是一款java class文件安全加密工具,支持直接加密jar包,无需修改任何项目代码,兼容spring,可避免源码泄漏或字节码被反编译。

使用步骤

  1. ClassFinal下载classfinal-fatjar.jar

  2. 在dockerfile里面添加,这里面的关键命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    进行加密jar包:
    -file 加密的jar/war完整路径
    -packages 加密的包名(可为空,多个用","分割)
    -exclude 排除的类名(可为空,多个用","分割),一般排除启动类即可
    -pwd 加密密码,如果是#号,则使用无密码模式加密,CF_PWD通过dokcer build的构建参数进行传递
    java -jar classfinal-fatjar-1.2.1.jar -file app.jar -packages cn.com.exxk,com.manager -exclude cn.com.exxk.Application -pwd ${CF_PWD}
    进行解密启动:
    // 控制台输入密码:-javaagent:app-encrypted.jar
    // 命令行指定密码:-javaagent:app-encrypted.jar='-pwd 123456'
    // 环境变量指定密码:-javaagent:app-encrypted.jar='-pwdname CF_PWD',设置环境变量CF_PWD=123456
    java -javaagent:app-encrypted.jar='-pwdname CF_PWD' -jar app-encrypted.jar

    完整的dockerfile如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    FROM exxk/java:8-jre-alpine-cst-font

    ARG JAR_FILE
    ARG CF_PWD
    ADD target/${JAR_FILE}.jar app.jar
    ADD src/main/docker/classfinal-fatjar-1.2.1.jar classfinal-fatjar-1.2.1.jar
    RUN java -jar classfinal-fatjar-1.2.1.jar -file app.jar -packages cn.com.exxk,com.manager -exclude cn.com.exxk.Application -pwd ${CF_PWD} -Y && \
    rm classfinal-fatjar-1.2.1.jar app.jar

    ENV JAVA_OPTS -Xms128m -Xmx256m
    ENV BOOT_PARAMS ""

    EXPOSE 8080

    ENTRYPOINT [ "sh", "-c", "java -javaagent:app-encrypted.jar='-pwdname CF_PWD' $JAVA_OPTS $JAVA_OPTS_AGENT -Djava.security.egd=file:/dev/./urandom -jar app-encrypted.jar $BOOT_PARAMS" ]
  3. 因为我才用的是maven插件进行打包,所以对应的插件配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>1.4.13</version>
    <executions>
    <execution>
    <id>default</id>
    <phase>none</phase>
    </execution>
    <execution>
    <id>after-deploy</id>
    <phase>deploy</phase>
    <goals>
    <goal>build</goal>
    </goals>
    </execution>
    </executions>
    <configuration>
    <repository>exxk/base/${project.name}</repository>
    <tag>${project.version}</tag>
    <buildArgs>
    <JAR_FILE>${project.build.finalName}</JAR_FILE>
    <CF_PWD>123456(这里是设置的密码)</CF_PWD>
    </buildArgs>
    <dockerfile>src/main/docker/Dockerfile</dockerfile>
    </configuration>
    </plugin>

方案二:ProGuard

常见问题

  1. 进行加密后,用 tar -zxvf app-encrypted.jar解压之后,发现里面有.java的文件

    解决:检查xml里面的配置,有下面类似配置,一定要注释,因为打包的时候,把源码也copy进去了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     <build> 
    <resources>
    <!-- <resource>-->
    <!-- <directory>src/main/java</directory>-->
    <!-- <includes>-->
    <!-- <include>**/**</include>-->
    <!-- </includes>-->
    <!-- <filtering>false</filtering>-->
    <!-- </resource>-->
    </resources>
    </build>

Ubuntu20.04如何安装CUDA

  1. 安装显卡驱动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#更新系统,安装必须用到的工具
exxk@exxk:~$ sudo apt update && sudo apt upgrade -y
exxk@exxk:~$ sudo apt install -y curl wget gnupg lsb-release
#添加 NVIDIA 驱动的 PPA
exxk@exxk:~$ sudo add-apt-repository ppa:graphics-drivers/ppa
exxk@exxk:~$ sudo apt update
#检测可用驱动: 它会列出所有设备(如显卡)和相应的推荐驱动。如果知道安装什么去驱动了,可以不用安装
exxk@exxk:~$ sudo apt install -y ubuntu-drivers-common
exxk@exxk:~$ ubuntu-drivers devices
ERROR:root:could not open aplay -l
Traceback (most recent call last):
File "/usr/share/ubuntu-drivers-common/detect/sl-modem.py", line 35, in detect
aplay = subprocess.Popen(
File "/usr/lib/python3.8/subprocess.py", line 858, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/lib/python3.8/subprocess.py", line 1704, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'aplay' #系统试图使用aplay来检测音频设备,但该工具未安装,可以忽略该错误
== /sys/devices/pci0000:00/0000:00:10.0 ==
modalias : pci:v000010DEd000025E2sv000017AAsd0000382Dbc03sc00i00
vendor : NVIDIA Corporation
driver : nvidia-driver-470 - distro non-free
driver : nvidia-driver-535-server - distro non-free
driver : nvidia-driver-535 - distro non-free
driver : nvidia-driver-550-open - third-party non-free
driver : nvidia-driver-535-open - distro non-free
driver : nvidia-driver-550 - third-party non-free
driver : nvidia-driver-560 - third-party non-free recommended #推荐的驱动
driver : nvidia-driver-535-server-open - distro non-free
driver : nvidia-driver-545-open - third-party non-free
driver : nvidia-driver-470-server - distro non-free
driver : nvidia-driver-555-open - third-party non-free
driver : nvidia-driver-545 - third-party non-free
driver : nvidia-driver-555 - third-party non-free
driver : nvidia-driver-560-open - third-party non-free
driver : xserver-xorg-video-nouveau - distro free builtin
# exxk@exxk:~$ sudo apt install -y nvidia-driver-560 该安装方式会安装桌面,其实用不到,因此采用下面的安装方式
exxk@exxk:~$ sudo apt install -y nvidia-driver-560 --no-install-recommends
exxk@exxk:~$ sudo reboot
exxk@exxk:~$ nvidia-smi
Tue Nov 19 07:27:03 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.35.03 Driver Version: 560.35.03 CUDA Version: 12.6 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3050 ... Off | 00000000:00:10.0 Off | N/A |
| N/A 45C P8 3W / 60W | 15MiB / 4096MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 933 G /usr/lib/xorg/Xorg 4MiB |
+-----------------------------------------------------------------------------------------+
  1. 安装docker(可以在安装系统时勾选上docker,这一步就可以省略,建议不要省略,安装系统勾选安装的docker 版本较低)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#安装 Docker 仓库密钥和工具
exxk@exxk:~$ sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
exxk@exxk:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
#添加 Docker 仓库
exxk@exxk:~$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
exxk@exxk:~$ sudo apt update
#安装 Docker
exxk@exxk:~$ sudo apt install -y docker-ce docker-ce-cli containerd.io
#将当前用户添加到 Docker 组
exxk@exxk:~$ sudo usermod -aG docker $USER
exxk@exxk:~$ sudo reboot
#查看docker版本,如果没有添加当前用户到docker组,需要加sudo
exxk@exxk:~$ docker version
Client: Docker Engine - Community
Version: 27.3.1
API version: 1.47
Go version: go1.22.7
Git commit: ce12230
Built: Fri Sep 20 11:41:03 2024
OS/Arch: linux/amd64
Context: default

Server: Docker Engine - Community
Engine:
Version: 27.3.1
API version: 1.47 (minimum version 1.24)
Go version: go1.22.7
Git commit: 41ca978
Built: Fri Sep 20 11:41:03 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.23
GitCommit: 57f17b0a6295a39009d861b89e3b3b87b005ca27
runc:
Version: 1.1.14
GitCommit: v1.1.14-0-g2c9f560
docker-init:
Version: 0.19.0
GitCommit: de40ad0
  1. 安装 NVIDIA Container Toolkit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 配置生产存储库:
exxk@exxk:~$ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
&& curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
#(可选)配置存储库以使用实验性软件包:
exxk@exxk:~$ sudo sed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list
#从存储库更新包列表:
exxk@exxk:~$ sudo apt-get update
#安装 NVIDIA Container Toolkit 软件包:
exxk@exxk:~$ sudo apt-get install -y nvidia-container-toolkit
#配置并重启 Docker
exxk@exxk:~$ sudo nvidia-ctk runtime configure --runtime=docker
exxk@exxk:~$ sudo systemctl restart docker
#运行一个简单的容器测试 GPU 是否可用
exxk@exxk:~$ docker run --rm --gpus all nvidia/cuda:11.8.0-base-ubuntu20.04 nvidia-smi
Tue Nov 19 07:58:08 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.35.03 Driver Version: 560.35.03 CUDA Version: 12.6 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3050 ... Off | 00000000:00:10.0 Off | N/A |
| N/A 39C P8 3W / 60W | 15MiB / 4096MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
+-----------------------------------------------------------------------------------------+

CUDA使用

镜像如何选择

NVIDIA 提供了官方的 nvidia/cuda Docker 镜像,用于构建和运行 GPU 加速的容器化应用。

镜像说明: nvidia/cuda:<CUDA版本>--<镜像类型>-<基础系统>

  • 镜像类型:

    名称 标识 介绍 大小
    基础镜像 nvidia/cuda:-base 不包含运行时库,只包含基本的 CUDA 工具链(不包含运行时库,只包含基本的 CUDA 工具链) 100MB
    运行时镜像 nvidia/cuda:-runtime 部署已经编译好的应用程序(不包含开发工具) >2G
    开发镜像 nvidia/cuda:-devel 开发和调试 CUDA 应用程序 >3G
    完整镜像 nvidia/cuda:-full 包含开发镜像的所有内容,并添加了额外的示例代码和文档 没有
  • CUDA版本:运行和驱动对应版本,一般可以向下兼容,根据我的驱动推荐使用 CUDA 12.6(与您的驱动版本一致),也可以使用 CUDA 12.x 或 11.x

  • cuDNN:包含 NVIDIA 的 cuDNN 库(深度学习加速库),这是深度学习框架(如 TensorFlow、PyTorch)的核心组件

  • 基础系统:推荐使用宿主机的系统,例如:宿主机是Ubuntu就Ubuntu,宿主机 CentOS就 CentOS

根据我的环境,推荐镜像docker pull nvidia/cuda:12.6.2-cudnn-devel-ubuntu20.04

使用

1
2
3
4
5
6
7
8
9
#-w /workspace 指定工作目录,-p 8888:8888提前预设Jupyter的端口
docker run -it --gpus all --name cuda-dev \
-v /home/exxk/workspace:/workspace \
-w /workspace \
-p 8888:8888 \
nvidia/cuda:12.6.2-cudnn-devel-ubuntu20.04 bash
root@287c0288ad93:/workspace# apt update
root@287c0288ad93:/workspace# apt install -y python3 python3-pip
#上传代码到/home/exxk/workspace

PVE简介

安装

环境准备

安装步骤

  1. 复制安装包proxmox-ve_8.2-2.iso到启动盘。

  2. 启动电脑(Legion Y7000P IAH7)时按F2,调整U盘为第一启动,如果没有U盘,可以换一个U盘制作,有的U盘会不识别。

  3. 进入ventoy引导界面,依次点击proxmox-ve_8.2-2.iso->Boot in normal node,如果该模式没有进入下一个界面,可以换一个启动模式。

  4. 进入proxmox安装界面,点击Install Proxmox VE (Graphical)进行界面安装,Terminal是终端安装模式。

  5. 一直点击下一步即可,注意下面几个选项

    • country选择China

    • 如果电脑有多个硬盘,注意选择要安装的硬盘

    • 密码需要自己设置一个

    • 网络配置主要选择有线网卡

      Hostname:pve.iexxk.io

      IP Address(CIDR):分配一个未使用的ip,后面24默认不用改,我设置的是172.16.80.244/24

      Gateway:路由器的网关,一般为分配ip后面一位改为xx.xx.xx.1,我设置的是172.16.80.1

      DNS Server: 该网络能访问的一个dns服务器,我设置的是8.8.8.8

  6. 我的因为是笔记本电脑,安装完成后,显示的是命令行界面,可以直接在电脑上输入root及密码就能进入系统,该系统就相当于是个linux

  7. 正式使用,在其他电脑访问https://172.16.80.244:8006/,输入root及密码就能进入管理平台了

  8. 额外配置,针对笔记本,ssh 进172.16.80.244,用户名和密码同管理平台,执行下面命令

    1
    2
    3
    4
    5
    6
    #设置合上盖子不休眠
    sed -i '/^#*HandleLidSwitch/s/^#*//;s/\bHandleLidSwitch=\w*/HandleLidSwitch=ignore/' /etc/systemd/logind.conf
    #设置合上盖子并外接显示器,不挂起(节能)
    sed -i '/^#*HandleLidSwitchExternalPower/s/^#*//;s/\bHandleLidSwitchExternalPower=\w*/HandleLidSwitchExternalPower=ignore/' /etc/systemd/logind.conf
    #重启服务,生效上面的配置
    systemctl restart systemd-logind

平台使用

介绍

登录进去可以看到,资源使用情况,什么都还没安装的情况:

CPU:显示20个,使用0%

内存:1.35 GiB的15.41 GiB,使用9%

存储:2.42 GiB的442.75 GiB,使用1%

服务器视图下菜单目录介绍

1
2
3
4
5
|--数据中心
|--pve #表示一个节点,因为只安装了一台,这里取的是Hostname里面域名的前面部分
|--localnetwork(pve) #网络管理
|--local(pve) #存储VZDump备份文件, ISO镜像, 容器模板等
|--local-lvm(pve) #磁盘映像, 容器

基础使用

  • 配置IOS镜像:点击数据中心->pve->local->ISO镜像,在ISO镜像页面,点击上传从URL下载,将镜像放进PVE。

    • 废弃,docker版本太旧,且没有yum等2020就停止更新了Centos7 atomic镜像URL地址 CentOS-Atomic-Host-7-Installer.iso,CentOS Atomic 是一个专为执行 Docker 容器而设的轻量操作系统,它创建自标准的 CentOS 7 组件,并追随 Red Hat 企业级 Linux Atomic 主机的组件版本。

    • fedora-coreos-41.20241109.3.0-live.x86_64.iso:支持docker和k8s,docker自动更新最新版本,系统资源占用小。安装方式见:Fedora CoreOS安装与基础使用

    • Win10-LTSC-64-21h2.iso:LTSC 版本去掉了许多不必要的功能(例如 Microsoft Store、Cortana、动态磁贴等),非常适合追求性能的用户,系统本身对内存的占用较低。(window安装时注意看提示,按任何键加载CD磁盘)

    • ubuntu-20-04-6-live-server-amd64.iso:Server install image服务器安装映像允许您在计算机上永久安装 Ubuntu 以用作服务器。它不会安装图形用户界面。

    • alpine-virt-3.21.0-x86_64.iso:极小化系统,虚拟机选Virtual,实体或标准选Standard版本。

      安装,一路下一步即可,注意硬盘的时候要选择不能默认,输入上面展示的,然后依次会提示输入磁盘->磁盘格式->是否格式化:sda->sys->y,其他步骤可以默认,然后执行poweroff,移除cd-dvd,然后开机即可。额外:PermitRootLogin可以设置为yes,支持密码ssh,如果安装的时候没设置,后期可以在vi /etc/ssh/sshd_config里面修改,然后执行service sshd restart重启sshd就行了。

  • 显卡直通:VM->硬件->添加->PCI设备->原始设备->选择RTX3050->添加

    如果是添加到win10的,windows更新界面更新即可使用显卡了。

    进入PVE->Shell(废弃,以下shell命令都废弃,现在直接在界面上面配置就可以了,配置之后,Kernel driver in use自动就变成了vfio-pci)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #-----------------1. 修改-------------------------------------------------
    root@pve:~# nano /etc/default/grub
    #GRUB_CMDLINE_LINUX_DEFAULT="quiet" #注释该配置
    GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on" #新增该配置
    #按^O Write Out(写入保存)和^X Exit(退出nano)
    #-----------------2. 检查显卡被谁在用,以及设备地址---------------------------
    root@pve:~# lspci -nnk | grep -i nvidia -A 2
    01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GA107BM [GeForce RTX 3050 Mobile] [10de:25e2] (rev a1)
    Subsystem: Lenovo GA107BM [GeForce RTX 3050 Mobile] [17aa:382d]
    Kernel driver in use: nouveau
    Kernel modules: nvidiafb, nouveau
    01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:2291] (rev a1)
    Kernel driver in use: snd_hda_intel
    Kernel modules: snd_hda_intel
    #-----------------3. 添加需要直通的设备地址-----------------------------------
    root@pve:~# nano /etc/modprobe.d/vfio.conf
    #设置优先级
    softdep nouveau pre: vfio-pci
    softdep snd_hda_intel pre: vfio-pci
    #绑定直通地址
    options vfio-pci ids=10de:25e2,10de:2291
    #-----------------4. 更新initramfs-----------------------------------------
    root@pve:~# update-initramfs -u
    #-----------------5. 重启--------------------------------------------------
    root@pve:~# reboot
    #-----------------6. 检查显卡被谁在使用,Kernel driver in use-----------------
    root@pve:~# lspci -nnk | grep -i nvidia -A 2
    01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GA107BM [GeForce RTX 3050 Mobile] [10de:25e2] (rev a1)
    Subsystem: Lenovo GA107BM [GeForce RTX 3050 Mobile] [17aa:382d]
    Kernel driver in use: vfio-pci
    Kernel modules: nvidiafb, nouveau
    01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:2291] (rev a1)
    Kernel driver in use: vfio-pci
    Kernel modules: snd_hda_intel
  • 配置CT模版:点击数据中心->pve->local->CT模版->模版,选择一个模版,例如alpine-3.20,然后点击下载。(CT不好用,容易提示没权限例如:nfs)

SRS简介

SRS是一个开源的(MIT协议)简单高效的实时视频服务器,支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpegOBSVLCWebRTC等客户端配合使用,提供流的接收和分发的能力,是一个典型的发布 (推流)和订阅(播放)服务器模型。 SRS支持互联网广泛应用的音视频协议转换,比如可以将RTMPSRT, 转成HLSHTTP-FLVWebRTC等协议。

k8s安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
相关设置:
Container Image: ossrs/srs:5
Command/Args:
命令: ./objs/srs -c conf/flv/rtmp2rtc.conf #配置见文尾
# 命令: ./objs/srs -c conf/flv/realtime.flv.conf //废弃,由上面的配置替换
Environments:
CANDIDATE: iexxk.com #替换成域名,这样能同时兼容内外网,内网做个host映射可以直接走内网
TZ: Asia/Shanghai
Container Ports(Host端口): 1935 默认推流端口,地面站那边修改不了,导致只能用host进行映射暴露
数据卷:
配置目录: /usr/local/srs/conf/flv
数据目录:/usr/local/srs/srs_dvr_data
NodePort端口映射:
1935 #默认推流端口
# 18080 // realtime.flv.conf配置才需要
8080 #web、安卓拉流
1985 #ios拉流(webrtc)
30353 #udp端口,webrtc拉流需要

nginx代理

1
2
3
4
5
6
7
8
9
10
11
# ossrs代理地址
upstream ossrs_server {
server ossrs:8080;
}
location /view-live/ {
rewrite ^/view-live/(.*) /$1 break;
proxy_pass http://ossrs_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

流程

虚拟ip处需要映射

Web: 外网ip80/443绑定节点的ingress的80/443

Ossrs: 外网ip1935绑定k8s里面的ossrs服务的Container Ports(Host端口)1935或者nodeport,不采用nodeport是因为要内网外网都要能访问ossrs,关键是内网对外网域名做了隔离,因此这里用本机的hosts映射(可以升级到dns下发)

graph LR
G[OBS推流]-->C
C[域名] -->|解析| A[移动光猫]
A -->|LAN| B(飞塔防火墙)
B -->|虚拟ip| E[K8S的Ingress]
E -->|域名匹配| F[前端web/nginx]
F -->|nginx代理|U[ossrs]
C-->|hosts映射节点ip|E

V[VLC]-->|web flv拉流|U
K[IOS]-->|ios webrtc拉流|U

测试

  1. 安装obs,用srs在线的测试工具也可以。

  2. 来源->加号->浏览器->url里面输入要直播的网址https://www.baidu.com/s?word=在线时间

  3. 控制按钮->设置->直播->

    服务:自定义

    服务器:rtmp://iexxk.com/drone/

    推码流:1

  4. 点击开始直播

播放:

内网测试(ok):

内网域名测试(ok):

外网测试:

webrtc和WHEP区别

WHEP:可以代理,但是也无法将一个域名根据环境解析为内网ip和外网ip,内网和外网是通过dns解析的,只能解析一个。在rtc里面启用保留域名,也无法解决,candidate里面会出现2个域名一个ip,优先还是走的ip

1
2
3
4
5
6
7
8
rtc_server {
enabled on;
listen 30353; # UDP port
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
candidate $CANDIDATE;
# 启用保留域名
keep_api_domain on;
}

webrtc:直接连接,延迟更低,必须开放1985,无法修改

使用webrtc时,需要在web前端(nginx)做个代理,并要将该端口映射到外网1985上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ossrs webrtc代理地址
upstream ossrs_webrtc {
server ossrs:1985;
}
server {
listen 1985 ssl;
server_name iexxk.com;

ssl_certificate /etc/nginx/cert/iexxk.com.pem;
ssl_certificate_key /etc/nginx/cert/iexxk.com.key;

location /rtc/v1/play/ {
proxy_pass http://ossrs_webrtc;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

常见问题

  1. 在内网无法访问外网域名的时候,虽然通过host映射到内网,但是webrtc播放的时候还是解析成了外网ip

    使用webrtc播放时可以在浏览器控制台能看到如下信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    Got answer:  v=0
    o=SRS/5.0.213(Bee) 140129754604224 2 IN IP4 0.0.0.0
    s=SRSPlaySession
    t=0 0
    a=ice-lite
    a=group:BUNDLE 0 1
    a=msid-semantic: WMS drone/1
    m=audio 9 UDP/TLS/RTP/SAVPF 111
    c=IN IP4 0.0.0.0
    a=ice-ufrag:881501t3
    a=ice-pwd:d11em20o3z9k02c97228yq5937ptj776
    a=fingerprint:sha-256 35:65:58:9A:E6:78:8F:D5:E6:F1:8F:E5:74:AD:A4:1E:3A:DF:B4:CE:21:3C:C9:CB:4A:9D:25:7A:87:53:FB:47
    a=setup:passive
    a=mid:0
    a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
    a=sendonly
    a=rtcp-mux
    a=rtcp-rsize
    a=rtpmap:111 opus/48000/2
    a=rtcp-fb:111 transport-cc
    a=ssrc:10186 cname:2yaj11875760968e
    a=ssrc:10186 label:audio-803h25y4
    a=candidate:0 1 udp 2130706431 172.16.10.44 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0
    m=video 9 UDP/TLS/RTP/SAVPF 106
    c=IN IP4 0.0.0.0
    a=ice-ufrag:881501t3
    a=ice-pwd:d11em20o3z9k02c97228yq5937ptj776
    a=fingerprint:sha-256 35:65:58:9A:E6:78:8F:D5:E6:F1:8F:E5:74:AD:A4:1E:3A:DF:B4:CE:21:3C:C9:CB:4A:9D:25:7A:87:53:FB:47
    a=setup:passive
    a=mid:1
    a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
    a=sendonly
    a=rtcp-mux
    a=rtcp-rsize
    a=rtpmap:106 H264/90000
    a=rtcp-fb:106 transport-cc
    a=rtcp-fb:106 nack
    a=rtcp-fb:106 nack pli
    a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
    a=ssrc:10187 cname:2yaj11875760968e
    a=ssrc:10187 label:video-29515r30
    a=candidate:0 1 udp 2130706431 172.16.10.44 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0

    注意最后两行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    使用内网ip的时候,输出如下信息
    a=candidate:0 1 udp 2130706431 172.16.10.102 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0
    使用内网域名的时候,输出如下信息,内网做了dns解析,假域名能解析到内网主机
    a=candidate:0 1 udp 2130706431 172.16.10.44 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0
    使用外网域名的时候,输出如下信息,17.176.159.182这个域名刚好在内网无法访问,因此内网无法播放外网地址
    a=candidate:0 1 udp 2130706431 17.176.159.182 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 exxk.com 30353 typ host generation 0

    真域名做了host映射,但是似乎不会从host拿,应该是从dns里面拿取了

    从下图可以知道,是通过1985的接口,拿到了udp的端口数据。

配置

rtmp2rtc.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
listen              1935;
max_connections 1000;
daemon off;
srs_log_tank console;

http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}

http_api {
enabled on;
listen 1985;
}
stats {
network 0;
}
rtc_server {
enabled on;
listen 30353; # UDP port
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
candidate $CANDIDATE;
}

vhost __defaultVhost__ {
rtc {
enabled on;
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtmp-to-rtc
rtmp_to_rtc on;
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtc-to-rtmp
rtc_to_rtmp on;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}

hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 20;
hls_wait_keyframe off;
}

tcp_nodelay on min_latency on;

play {
gop_cache off;
queue_length 10;
mw_latency 100;
}

publish {
mr off;
}

dvr {
enabled on;
dvr_apply all;
dvr_plan session;
dvr_path ./srs_dvr_data/[app]/[stream]/[2006]-[01]-[02]/[timestamp].[2006]-[01]-[02]_[15].[04].[05]_[999].mp4;
dvr_duration 30;
dvr_wait_keyframe on;
time_jitter full;
}

}

realtime.flv.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
http_server {
enabled on;
listen 18080;
dir ./objs/nginx/html;
}
vhost __defaultVhost__ {
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}

hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 20;
hls_wait_keyframe off;
}

tcp_nodelay on min_latency on;

play {
gop_cache off;
queue_length 10;
mw_latency 100;
}

publish {
mr off;
}

dvr {
enabled on;
dvr_apply all;
dvr_plan session;
dvr_path ./srs_dvr_data/[app]/[stream]/[2006]-[01]-[02]/[timestamp].[2006]-[01]-[02]_[15].[04].[05]_[999].mp4;
dvr_duration 30;
dvr_wait_keyframe on;
time_jitter full;
}
}

基础环境信息

飞塔防火墙版本:FortiGate-100F

kubernates版本: v1.26.4

k8s界面工具kuboard:v3.5.2.4

网络架构图:

graph LR
C[域名] -->|解析| A[移动光猫]
A -->|LAN| B(飞塔防火墙)
B -->|虚拟ip| E[K8S的Ingress]
E -->|域名匹配| F[应用路由]

飞塔防火墙配置步骤:

  1. 策略&对象->虚拟IP->新建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ---------------------新建配置1------------------------------
    虚拟IP/服务器: k8s_ingress_https
    接口: 移动出口2 (port1)
    映射自: 17.176.159.182(移动光猫的外网ip)
    映射的IP地址/范围: 172.16.10.44(k8s任意一个节点的ip)
    外部服务端口: TCP 443 (移动光猫外网端口,需要备案)
    映射到端口: 443 (ingress对应的端口)
    ----------------------新建配置2------------------------------
    虚拟IP/服务器: k8s_ingress_http
    接口: 移动出口2 (port1)
    映射自: 17.176.159.182(移动光猫的外网ip)
    映射的IP地址/范围: 172.16.10.44(k8s任意一个节点的ip)
    外部服务端口: TCP 80 (移动光猫外网端口,需要备案)
    映射到端口: 80 (ingress对应的端口)
  2. 配置https证书(可选-废弃,后面在k8s进行管理证书,这里管理比较麻烦)

    • 系统管理->证书->新建->证书->导入证书->证书->上传申请的免费证书

    • 安全配置文件->SSL/SSH检测->新建

    1
    2
    3
    名称: k8s_ingress_ssl
    启用SSL检测: 保护SSL服务器
    服务器证书:上一步上传的证书
  3. 策略&对象->虚拟IP->新建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    名称: k8s_ingress
    流入接口: 移动出口2
    流出接口: lan
    源地址: all
    目标地址: k8s_ingress_https,k8s_ingress_http(上一步的两个虚拟ip)
    计划任务: always
    服务: ALL
    启用NAT: 关闭
    SSL检测: no-inspection(如果要配置证书,在这里进行关联k8s_ingress_ssl)
    策略过期:关闭

k8s-ingress配置

  1. 新建应用路由,配置成阿里云购买的域名,并在阿里云上面做域名解析,解析到k8s的ingress所在的节点ip端口上,开启https证书,上传申请的免费证书

配置

endpoint代理k8s之外的服务,让其能在k8s内访问,或可以通过ingress进行访问。

1. 创建 Service 和 Endpoint

外部服务地址:http://172.16.10.240:8580

ingress地址: ailabel.iexxk.io

1.1 定义一个 Endpoint(这个在kuboard界面没有地方创建,只有通过yaml进行创建)

endpoint.yaml:

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Endpoints
metadata:
name: ailabel-service #注意名称的一致性
namespace: middleware #注意名称的一致性
subsets:
- addresses:
- ip: 172.16.10.240
ports:
- port: 8580

1.2 定义一个 Service(这个可以在kuboard界面创建,可以不用下面的yaml)

service.yaml:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: ailabel-service #注意名称的一致性
namespace: middleware #注意名称的一致性
spec:
ports:
- protocol: TCP
port: 80
targetPort: 8580
type: ClusterIP

2. 配置 Ingress(这个可以在kuboard界面创建,可以不用下面的yaml)

定义 Ingress

ingress.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ailabel-ingress
namespace: middleware #注意名称的一致性
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: ailabel.hcytech.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ailabel-service #注意名称的一致性
port:
number: 80

然后访问http://ailabel.iexxk.io即可。

常见操作

1
2
3
4
5
6
7
8
# 应用资源,可以在kuboard界面上通过yaml创建资源,这个命令用不上
kubectl apply -f endpoint.yaml
# 查询middleware命名空间下所有endpoints资源
kubectl get endpoints -n middleware
# 查询指定endpoints资源
kubectl get endpoints ailabel-service -n middleware
# 删除指定endpoints资源
kubectl delete endpoints ailabel-service -n middleware