通过 CDI 为 KubeVirt 导入虚拟机镜像
CDI 有一个 Pod 用于镜像导入,需要 Service 暴漏 Pod。
公开 cdi-uploadproxy
查看 cdi-uploadproxy pod:
[root@base-k8s-master-1 kubevirt]# kubectl get pod -n cdi -l cdi.kubevirt.io=cdi-uploadproxy -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cdi-uploadproxy-849d7cd798-sv77g 1/1 Running 2 (8d ago) 38d 10.100.171.43 base-k8s-worker-2.example.com <none> <none>
[root@base-k8s-master-1 kubevirt]# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
base-k8s-master-1.example.com Ready control-plane 243d v1.30.2 192.168.50.131 <none> Rocky Linux 8.10 (Green Obsidian) 4.18.0-553.8.1.el8_10.x86_64 containerd://1.7.16
base-k8s-worker-1.example.com Ready <none> 243d v1.30.2 192.168.50.132 <none> Rocky Linux 8.10 (Green Obsidian) 4.18.0-553.8.1.el8_10.x86_64 containerd://1.7.16
base-k8s-worker-2.example.com Ready <none> 243d v1.30.2 192.168.50.133 <none> Rocky Linux 8.10 (Green Obsidian) 4.18.0-553.8.1.el8_10.x86_64 containerd://1.7.16
公开 cdi-uploadproxy pod:
apiVersion: v1
kind: Service
metadata:
labels:
cdi.kubevirt.io: cdi-uploadproxy
name: cdi-uploadproxy-nodeport
namespace: cdi
spec:
ports:
- nodePort: 31001
port: 443
protocol: TCP
targetPort: 8443
selector:
cdi.kubevirt.io: cdi-uploadproxy
type: NodePort
创建后查看 Service 和 Endpoints:
[root@base-k8s-master-1 kubevirt]# kubectl get svc -n cdi -l cdi.kubevirt.io=cdi-uploadproxy
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cdi-uploadproxy ClusterIP 10.96.34.191 <none> 443/TCP 38d
cdi-uploadproxy-nodeport NodePort 10.96.246.254 <none> 443:31001/TCP 4d17h
[root@base-k8s-master-1 kubevirt]# kubectl get endpoints -n cdi cdi-uploadproxy-nodeport
NAME ENDPOINTS AGE
cdi-uploadproxy-nodeport 10.100.171.43:8443 4d17h
导入镜像到 DataVolume
CDI 支持 qemu 支持的 raw
和 qcow2
图像格式。更多详情,可以查看 qemu 文档。也可使用可引导 ISO 映像,其处理方式与原始映像相同。镜像可使用 iso
、 gz
或 xz
格式压缩。
CDI 支持向 DataVolume
和 PersistentVolumeClaim
上传镜像。
virtctl
的 image-upload
参数支持上传镜像:
[root@base-k8s-master-1 kubevirt]# virtctl image-upload --help
Upload a VM image to a DataVolume/PersistentVolumeClaim.
Usage:
virtctl image-upload [flags]
Examples:
# Upload a local disk image to a newly created DataVolume:
virtctl image-upload dv fedora-dv --size=10Gi --image-path=/images/fedora30.qcow2
# Upload a local disk image to an existing DataVolume
virtctl image-upload dv fedora-dv --no-create --image-path=/images/fedora30.qcow2
# Upload a local disk image to a newly created PersistentVolumeClaim
virtctl image-upload pvc fedora-pvc --size=10Gi --image-path=/images/fedora30.qcow2
# Upload a local disk image to a newly created PersistentVolumeClaim and label it with a default instance type and preference
virtctl image-upload pvc fedora-pvc --size=10Gi --image-path=/images/fedora30.qcow2 --default-instancetype=n1.medium --default-preference=fedora
# Upload a local disk image to an existing PersistentVolumeClaim
virtctl image-upload pvc fedora-pvc --no-create --image-path=/images/fedora30.qcow2
# Upload to a DataVolume with explicit URL to CDI Upload Proxy
virtctl image-upload dv fedora-dv --uploadproxy-url=https://cdi-uploadproxy.mycluster.com --image-path=/images/fedora30.qcow2
# Upload a local disk archive to a newly created DataVolume:
virtctl image-upload dv fedora-dv --size=10Gi --archive-path=/images/fedora30.tar
Flags:
--access-mode string The access mode for the PVC.
--archive-path string Path to the local archive.
--datasource Create a DataSource pointing to the created DataVolume/PVC.
--default-instancetype string The default instance type to associate with the image.
--default-instancetype-kind string The default instance type kind to associate with the image.
--default-preference string The default preference to associate with the image.
--default-preference-kind string The default preference kind to associate with the image.
--force-bind Force bind the PVC, ignoring the WaitForFirstConsumer logic.
-h, --help help for image-upload
--image-path string Path to the local VM image.
--insecure Allow insecure server connections when using HTTPS.
--no-create Don't attempt to create a new DataVolume/PVC.
--size string The size of the DataVolume to create (ex. 10Gi, 500Mi).
--storage-class string The storage class for the PVC.
--uploadproxy-url string The URL of the cdi-upload proxy service.
--volume-mode string Specify the VolumeMode (block/filesystem) used to create the PVC. Default is the storageProfile default. For archive upload default is filesystem.
--wait-secs uint Seconds to wait for upload pod to start. (default 300)
Use "virtctl options" for a list of global command-line options (applies to all commands).
在当前节点添加域名解析:
[root@base-k8s-master-1 kubevirt]# tail -n1 /etc/hosts
192.168.50.133 cdi-uploadproxy.example.com
用域名访问是为了避免出现证书问题。
[root@base-k8s-master-1 kubevirt]# echo | openssl s_client -showcerts -connect 192.168.50.132:31001 2>/dev/null \ | openssl x509 -inform pem -noout -text \ | sed -n -e '/Subject.*CN/p' -e '/Subject Alternative/{N;p}' Subject: CN = cdi-uploadproxy X509v3 Subject Alternative Name: DNS:cdi-uploadproxy, DNS:cdi-uploadproxy.cdi, DNS:cdi-uploadproxy.cdi.svc
确保访问 cdi-uploadproxy.example.com
没有走代理:
[root@base-k8s-master-1 kubevirt]# curl -v cdi-uploadproxy.example.com:31001
* Rebuilt URL to: cdi-uploadproxy.example.com:31001/
* Uses proxy env variable no_proxy == 'localhost,127.0.0.1,.example.com,10.96.0.0/16,10.100.0.0/16,192.168.50.0/24,.svc'
* Trying 192.168.50.133...
* TCP_NODELAY set
* Connected to cdi-uploadproxy.example.com (192.168.50.133) port 31001 (#0)
> GET / HTTP/1.1
> Host: cdi-uploadproxy.example.com:31001
> User-Agent: curl/7.61.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 400 Bad Request
<
Client sent an HTTP request to an HTTPS server.
* Closing connection 0
上传一个本地镜像到 DataVolume
:
[root@base-k8s-master-1 kubevirt]# virtctl image-upload dv fedora-upload-dv \
--size 5Gi --storage-class csi-rbd-sc \
--image-path /root/kubevirt/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2 \
--uploadproxy-url https://cdi-uploadproxy.example.com:31001 --insecure
PVC default/fedora-upload-dv not found
DataVolume default/fedora-upload-dv created
Waiting for PVC fedora-upload-dv upload pod to be ready...
Pod now ready
Uploading data to https://cdi-uploadproxy.example.com:31001
468.94 MiB / 468.94 MiB [------------------------------------------------------------------------------------------------------------------------] 100.00% 23.95 MiB p/s 20s
Uploading data completed successfully, waiting for processing to complete, you can hit ctrl-c without interrupting the progress
Processing completed successfully
Uploading /root/kubevirt/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2 completed successfully
不加
--insecure
可能会出现 x509 证书问题。
查看上传 Pod 的日志:
[root@base-k8s-master-1 ~]# kubectl logs cdi-upload-prime-ead86e44-05c0-4dec-b4c0-687fca76fc7d -f
I0316 08:57:55.341145 1 uploadserver.go:81] Running server on 0.0.0.0:8443
I0316 08:57:58.388116 1 uploadserver.go:361] Content type header is ""
I0316 08:57:58.388200 1 data-processor.go:348] Calculating available size
I0316 08:57:58.389750 1 data-processor.go:356] Checking out block volume size.
I0316 08:57:58.389779 1 data-processor.go:373] Target size 5368709120.
I0316 08:57:58.389900 1 data-processor.go:247] New phase: TransferScratch
I0316 08:57:58.390730 1 util.go:96] Writing data...
I0316 08:58:18.131458 1 data-processor.go:247] New phase: ValidatePause
I0316 08:58:18.131529 1 data-processor.go:253] Validating image
E0316 08:58:18.143616 1 prlimit.go:156] failed to kill the process; os: process already finished
I0316 08:58:18.143888 1 data-processor.go:247] New phase: Pause
I0316 08:58:18.143953 1 uploadserver.go:411] Returning success to caller, continue processing in background
I0316 08:58:18.144193 1 data-processor.go:158] Resuming processing at phase Convert
I0316 08:58:18.144356 1 data-processor.go:253] Validating image
E0316 08:58:18.156968 1 prlimit.go:156] failed to kill the process; os: process already finished
I0316 08:58:18.157111 1 qemu.go:115] Running qemu-img with args: [convert -t writeback -p -O raw /scratch/tmpimage /dev/cdi-block-volume]
E0316 09:01:45.994440 1 prlimit.go:156] failed to kill the process; os: process already finished
I0316 09:01:45.994493 1 data-processor.go:247] New phase: Resize
I0316 09:01:45.995788 1 data-processor.go:247] New phase: Complete
I0316 09:01:45.995814 1 uploadserver.go:408] Wrote data to /dev/cdi-block-volume
I0316 09:01:45.995834 1 uploadserver.go:215] Shutting down http server after successful upload
I0316 09:01:45.996478 1 uploadserver.go:115] UploadServer successfully exited
上传完的 dv 可以用于创建虚拟机。
YAML 文件方式上传镜像
可以通过 YAML 文件创建 DataVolume
资源来导入镜像。
DataVolume
支持多种方式上传镜像:
-
HTTP/S3 远程下载
适用于从公共仓库或私有服务器下载 OS 镜像,如 Ubuntu、CentOS、Windows 等。
-
PVC 克隆
适用于复制已有虚拟机磁盘,创建新 VM 时复用已有数据。
-
Registry 容器镜像
适用于从容器镜像仓库拉取 VM 磁盘映像,如
quay.io
或Harbor
。 -
空白(Blank)磁盘
适用于创建新的空磁盘,VM 启动后自行安装系统或格式化。
-
Snapshots(快照恢复)
适用于从存储快照恢复 VM 磁盘。
-
上传(Upload)模式
适用于手动上传本地磁盘镜像到
DataVolume
。 -
数据源(DataSource)
通过一个模板 PVC 或 Snapshot 来克隆磁盘。
详细的例子可以查看 CDI 的 Github:https://github.com/kubevirt/containerized-data-importer/tree/main/manifests/example
下面是从 URL 源导入镜像的 YAML 文件:
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: "fedora"
spec:
storage:
storageClassName: csi-rbd-sc
resources:
requests:
storage: 5Gi
source:
http:
url: "https://download.fedoraproject.org/pub/fedora/linux/releases/41/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2"
通过 DataSource 克隆 DataVolume
DataSource
也是 CDI 的一个 CRD 资源,它的作用是将一个 PVC 或 Snapshot 做成一个模板,然后 DataVolume
可以用这个模板来创建新的磁盘。
目前只能基于 PVC 和 Snapshot 创建。
下面是一个基于 PVC 创建 DataSource 的 YAML 文件:
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataSource
metadata:
name: fedora-datasource
spec:
source:
pvc:
name: fedora-upload-dv
namespace: default
下边是利用 DataSource
创建 DataVolume
的 YAML 文件:
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: fedora-from-das
spec:
sourceRef:
kind: DataSource
name: fedora-datasource
pvc:
storageClassName: csi-rbd-sc
volumeMode: Block
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
这个方式创建的 DataVolume
会从 DataSource
的 PVC 复制出一个新的 PVC:
[root@base-k8s-master-1 kubevirt]# kubectl get dv
NAME PHASE PROGRESS RESTARTS AGE
fedora-from-das Succeeded 100.0% 13m
fedora-upload-dv Succeeded N/A 70m
[root@base-k8s-master-1 kubevirt]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
fedora-from-das Bound pvc-b10d21c4-dc70-4c39-a947-9f16a76cc512 10Gi RWX csi-rbd-sc <unset> 13m
fedora-upload-dv Bound pvc-18f21c39-bdae-48bf-98c0-df9f5fa422d6 5Gi RWX csi-rbd-sc <unset> 70m