当前位置: 首页 > news >正文

K8S上安装LongHorn(分布式块存储) --use

要在 Kubernetes上安装 LongHorn,您可以按照以下步骤进行操作:

准备工作

参考

  • 官网教程
  • LongHorn只部署在k8s-worker5节点上。
  • https://github.com/longhorn/longhorn

安装要求

Each node in the Kubernetes cluster where Longhorn is installed must fulfill the following requirements:

  • A container runtime compatible with Kubernetes (Docker v1.13+, containerd v1.3.7+, etc.)
  • Kubernetes >= v1.21
  • open-iscsi is installed, and the iscsid daemon is running on all the nodes. This is necessary, since Longhorn relies on iscsiadm on the host to provide persistent volumes to Kubernetes. For help installing open-iscsi, refer to this section.
  • RWX support requires that each node has a NFSv4 client installed.
    • For installing a NFSv4 client, refer to this section.
  • The host filesystem supports the file extents feature to store the data. Currently we support:
    • ext4
    • XFS
  • bash, curl, findmnt, grep, awk, blkid, lsblk must be installed.
  • Mount propagation must be enabled.

The Longhorn workloads must be able to run as root in order for Longhorn to be deployed and operated properly.

使用环境检查脚本

# use
curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.6.0/scripts/environment_check.sh | bash# 参考
curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.6.1/scripts/environment_check.sh | bash

创建命名空间

# vi longhorn-ns.yaml
# kubectl apply -f longhorn-ns.yaml
# kubectl delete -f longhorn-ns.yaml
apiVersion: v1
kind: Namespace
metadata:name: longhorn-system

安装 open-iscsi(可选)

# use
apt-get install open-iscsisystemctl enable iscsid --now
systemctl status iscsidmodprobe iscsi_tcp$. wget https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/prerequisite/longhorn-iscsi-installation.yaml$. vi longhorn-iscsi-installation.yaml# 添加如下内容metadata:namespace: longhorn-system# nodeselectorspec:template:spec:nodeSelector:longhorn: deploy
$. kubectl apply -f longhorn-iscsi-installation.yaml
$. kubectl get DaemonSet longhorn-iscsi-installation -n longhorn-system
$. kubectl get pod \
-o wide \
-n longhorn-system |\grep longhorn-iscsi-installation
$. kubectl delete -f longhorn-iscsi-installation.yaml# 查看log
kubectl logs longhorn-iscsi-installation-44h92 \
-c iscsi-installation \
-n longhorn-system# ========================== 官网 =========================== #
# SUSE and openSUSE: Run the following command:
zypper install open-iscsi# Debian and Ubuntu: Run the following command:
apt-get install open-iscsi# RHEL, CentOS, and EKS (EKS Kubernetes Worker AMI with AmazonLinux2 image): Run the following commands:
yum --setopt=tsflags=noscripts install iscsi-initiator-utils
echo "InitiatorName=$(/sbin/iscsi-iname)" > /etc/iscsi/initiatorname.iscsi
systemctl enable iscsid
systemctl start iscsid# 验证
$. iscsiadm --version# =============================== 参考 =============================== #
# 前言:这里二选一要么直接安装命令,要么使用容器去进行安装,这里选择之间安装的命令。
# open-iscsi
​kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.1/deploy/prerequisite/longhorn-iscsi-installation.yaml
# nfs
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.1/deploy/prerequisite/longhorn-nfs-installation.yaml

安装 NFSv4 client(可选)

# Check NFSv4.1 support is enabled in kernel
cat /boot/config-`uname -r`| grep CONFIG_NFS_V4_1# Check NFSv4.2 support is enabled in kernel
cat /boot/config-`uname -r`| grep CONFIG_NFS_V4_2## The command used to install a NFSv4 client differs depending on the Linux distribution.# For Debian and Ubuntu, use this command:apt-get install nfs-common# For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command:yum install nfs-utils# For SUSE/OpenSUSE you can install a NFSv4 client via:zypper install nfs-client# For Talos Linux, the NFS client is part of the kubelet image maintained by the Talos team.# We also provide an nfs installer to make it easier for users to install nfs-client automatically:
# use
$. wget https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/prerequisite/longhorn-nfs-installation.yaml
$. vi longhorn-nfs-installation.yaml# 添加如下内容metadata:namespace: longhorn-system# nodeselectorspec:template:spec:nodeSelector:longhorn: deploy
$. kubectl apply -f longhorn-nfs-installation.yaml
$. kubectl get DaemonSet longhorn-nfs-installation -n longhorn-system
$. kubectl get pod \
-o wide \
-n longhorn-system \
| grep longhorn-nfs-installation$. kubectl delete -f longhorn-nfs-installation.yaml# ===================== 参考 ===================== #
$. kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.1/deploy/prerequisite/longhorn-nfs-installation.yaml# After the deployment, run the following command to check pods’ status of the installer:
$. kubectl get pod | grep longhorn-nfs-installation
NAME                                  READY   STATUS    RESTARTS   AGE
longhorn-nfs-installation-t2v9v   1/1     Running   0          143m
longhorn-nfs-installation-7nphm   1/1     Running   0          143m
And also can check the log with the following command to see the installation result:$. kubectl logs longhorn-nfs-installation-t2v9v -c nfs-installation
...
nfs install successfully

给节点打标签

$. kubectl label node k8s-infra01 longhorn=deploy
$. kubectl get no k8s-infra01 --show-labels# 参考
$. kubectl label node k8s-worker2 longhorn-
$. kubectl label node k8s-infra01 longhorn=deploy
$. kubectl label node k8s-infra01 longhorn-
$. kubectl get no k8s-worker5 --show-labels# ======================== 参考 ======================== #
# 查询node标签
# kubectl get no -o wide --show-labels | grep k8s-worker5# 删除label
# kubectl label nodes k8s-worker5 k8s-worker5-# 修改label
# kubectl label nodes k8s-worker5 longhorn=deploy --overwrite
# or 
# kubectl edit nodes k8s-worker5

部署LongHorn

官网地址: longhorn-官网安装

下载longhorn.yaml

# use
$. wget https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
$. cp longhorn.yaml longhorn.yaml-bak# old
$. kubectl apply \
-f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml# ========================= 参考 ======================== #
# 官网地址: https://longhorn.io/docs/1.6.0/deploy/install/install-with-kubectl/

vi longhorn.yaml

注释掉其中的affinity

查找 kind: Deployment, 并在注释掉其中的affinity:

# 注释掉其中的affinity
...    
spec:template:spec:#affinity:#  podAntiAffinity:#    preferredDuringSchedulingIgnoredDuringExecution:#    - weight: 1#      podAffinityTerm:#        labelSelector:#          matchExpressions:#          - key: app#            operator: In#            values:#            - longhorn-ui#        topologyKey: kubernetes.io/hostname
...

设置Node Selector

using kubectl to apply the deployment YAML, modify the node selector section for Longhorn Manager, Longhorn UI, and Longhorn Driver Deployer. Then apply the YAMl files.

查找 kind: Deployment, 并在添加nodeselector

spec:template:spec:# lpfnodeSelector:longhorn: deploy

修改存储路径

默认存储路径为:/var/lib/longhorn,可修改为自己想要路径
找到名为 longhorn-manager的DaemonSet资源下的 spec.template.spec.[containers].[volumes].hostPath.path字段。

修改pv为保留策略

修改pv为保留策略,否则删除pvc的时候pv就会被删除。
data:storageclass.yaml: |kind: StorageClassapiVersion: storage.k8s.io/v1metadata:name: longhornannotations:storageclass.kubernetes.io/is-default-class: "true"provisioner: driver.longhorn.ioallowVolumeExpansion: true# 找到文件中的StorageClass.data.reclaimPolicy字段,修改为Retain# reclaimPolicy: "Delete"reclaimPolicy: "Retain"volumeBindingMode: Immediate

修改资源类型和端口

修改longhorn-frontend 服务的svc资源类型和端口,便于web界面查看。

kind: Service
apiVersion: v1
metadata:labels:app.kubernetes.io/name: longhornapp.kubernetes.io/instance: longhornapp.kubernetes.io/version: v1.3.2app: longhorn-uiname: longhorn-frontendnamespace: longhorn-system
spec:# 修改为 NodePort,默认为ClusterIP#type: ClusterIPtype: NodePortselector:app: longhorn-uiports:- name: httpport: 80targetPort: http# 修改端口号,默认为 null#nodePort: nullnodePort: 32183

开始部署

$. kubectl apply -f longhorn.yaml# 命令试执行(不会真的创建或修改任何集群中的资源。)
$. kubectl --dry-run=client apply -f longhorn.yaml# 查看部署效果
$. kubectl get all -o wide -n longhorn-system
$. kubectl get pod -o wide -n longhorn-system# ds
kubectl get ds -n longhorn-system# ========================= 参考 ========================== #
# 删除longhorn
# 步骤1
$. kubectl delete -f longhorn.yaml
# 步骤2
# 删除k8s各个node下的/var/lib/longhorn目录(若改为自定义目录, 则删除相关自定义目录即可)

设置nodeselector

给所有daemonset和deployment设置nodeselector.

$. kubectl get deploy,ds,rs -n longhorn-system
# 给下面所有资源设置 nodeselector
# spec:
#  template:
#    spec:
#      # lpf
#      nodeSelector:
#        longhorn: deploy
# 设置命令:
# kubectl edit deploy csi-attacher -n longhorn-system
$. kubectl patch \
deploy csi-attacher \
-n longhorn-system \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"longhorn": "deploy"}}}}}'# kubectl edit deploy csi-provisioner -n longhorn-system
$. kubectl patch \
deploy csi-provisioner \
-n longhorn-system \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"longhorn": "deploy"}}}}}'# kubectl edit deploy csi-resizer -n longhorn-system
$. kubectl patch \
deploy csi-resizer \
-n longhorn-system \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"longhorn": "deploy"}}}}}'# kubectl edit deploy csi-snapshotter -n longhorn-system
$. kubectl patch \
deploy csi-snapshotter \
-n longhorn-system \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"longhorn": "deploy"}}}}}'# kubectl edit ds engine-image-ei-acb7590c -n longhorn-system
$. kubectl patch \
ds engine-image-ei-b907910b \
-n longhorn-system \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"longhorn": "deploy"}}}}}'# kubectl edit ds longhorn-csi-plugin -n longhorn-system
$. kubectl patch \
ds longhorn-csi-plugin \
-n longhorn-system \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"longhorn": "deploy"}}}}}'# 验证
# kubectl get all -o wide -n longhorn-systemNAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/csi-attacher               3/3     3            3           49m
deployment.apps/csi-provisioner            3/3     3            3           49m
deployment.apps/csi-resizer                3/3     3            3           49m
deployment.apps/csi-snapshotter            3/3     3            3           49m
deployment.apps/longhorn-driver-deployer   1/1     1            1           49m
deployment.apps/longhorn-ui                2/2     2            2           49mNAME                                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR     AGE
daemonset.apps/engine-image-ei-acb7590c      1         1         1       1            1           longhorn=deploy   49m
daemonset.apps/longhorn-csi-plugin           9         9         9       9            9           <none>            49m
daemonset.apps/longhorn-iscsi-installation   1         1         1       1            1           longhorn=deploy   49m
daemonset.apps/longhorn-manager              1         1         1       1            1           longhorn=deploy   49m
daemonset.apps/longhorn-nfs-installation     1         1         1       1            1           longhorn=deploy   48mNAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/csi-attacher-5984dd5fb4               3         3         3       49m
replicaset.apps/csi-provisioner-56cf669464            3         3         3       49m
replicaset.apps/csi-resizer-644fd596d5                3         3         3       49m
replicaset.apps/csi-snapshotter-78596646cf            3         3         3       49m
replicaset.apps/longhorn-driver-deployer-5f886cb8cb   1         1         1       49m
replicaset.apps/longhorn-ui-5f766d554b                2         2         2       49m

查看pod状态

等待Pod启动:

一旦存储库创建成功,LongHorn系统将启动一系列的Pod

检查Pod的状态:

$ kubectl get pods -n longhorn-system  -o wide
# use
kubectl get pods -n longhorn-system -o wide kubectl get svc -n longhorn-system

确认所有的Pod都处于"Running"状态。

# 全部是 Running和状态READY左右两边一致就可以了
[root@master ~]# kubectl get pod \
-n longhorn-system \
-o wide 
NAME                                                  READY   STATUS    RESTARTS       AGE     IP               NODE    NOMINATED NODE   READINESS GATES
csi-attacher-7bf4b7f996-ffhxm                         1/1     Running   0              45m     10.244.166.146   node1   <none>           <none>
csi-attacher-7bf4b7f996-kts4l                         1/1     Running   0              45m     10.244.104.20    node2   <none>           <none>
csi-attacher-7bf4b7f996-vtzdb                         1/1     Running   0              45m     10.244.166.142   node1   <none>           <none>
csi-provisioner-869bdc4b79-bjf8q                      1/1     Running   0              45m     10.244.166.150   node1   <none>           <none>
csi-provisioner-869bdc4b79-m2swk                      1/1     Running   0              45m     10.244.104.18    node2   <none>           <none>
csi-provisioner-869bdc4b79-pmkfq                      1/1     Running   0              45m     10.244.166.143   node1   <none>           <none>
csi-resizer-869fb9dd98-6ndgb                          1/1     Running   0              8m47s   10.244.104.28    node2   <none>           <none>
csi-resizer-869fb9dd98-czvzh                          1/1     Running   0              45m     10.244.104.16    node2   <none>           <none>
csi-resizer-869fb9dd98-pq2p5                          1/1     Running   0              45m     10.244.166.149   node1   <none>           <none>
csi-snapshotter-7d59d56b5c-85cr6                      1/1     Running   0              45m     10.244.104.19    node2   <none>           <none>
csi-snapshotter-7d59d56b5c-dlwjk                      1/1     Running   0              45m     10.244.166.148   node1   <none>           <none>
csi-snapshotter-7d59d56b5c-xsc6s                      1/1     Running   0              45m     10.244.166.147   node1   <none>           <none>
engine-image-ei-f9e7c473-ld6zp                        1/1     Running   0              46m     10.244.104.15    node2   <none>           <none>
engine-image-ei-f9e7c473-qw96n                        1/1     Running   1 (6m5s ago)   8m13s   10.244.166.154   node1   <none>           <none>
instance-manager-e-16be548a213303f54febe8742dc8e307   1/1     Running   0              8m19s   10.244.104.29    node2   <none>           <none>
instance-manager-e-1e8d2b6ac4bdab53558aa36fa56425b5   1/1     Running   0              7m58s   10.244.166.155   node1   <none>           <none>
instance-manager-r-16be548a213303f54febe8742dc8e307   1/1     Running   0              46m     10.244.104.14    node2   <none>           <none>
instance-manager-r-1e8d2b6ac4bdab53558aa36fa56425b5   1/1     Running   0              7m31s   10.244.166.156   node1   <none>           <none>
longhorn-admission-webhook-69979b57c4-rt7rh           1/1     Running   0              52m     10.244.166.136   node1   <none>           <none>
longhorn-admission-webhook-69979b57c4-s2bmd           1/1     Running   0              52m     10.244.104.11    node2   <none>           <none>
longhorn-conversion-webhook-966d775f5-st2ld           1/1     Running   0              52m     10.244.166.135   node1   <none>           <none>
longhorn-conversion-webhook-966d775f5-z5m4h           1/1     Running   0              52m     10.244.104.12    node2   <none>           <none>
longhorn-csi-plugin-gcngb                             3/3     Running   0              45m     10.244.166.145   node1   <none>           <none>
longhorn-csi-plugin-z4pr6                             3/3     Running   0              45m     10.244.104.17    node2   <none>           <none>
longhorn-driver-deployer-5d74696c6-g2p7p              1/1     Running   0              52m     10.244.104.9     node2   <none>           <none>
longhorn-manager-j69pn                                1/1     Running   0              52m     10.244.166.139   node1   <none>           <none>
longhorn-manager-rnzwr                                1/1     Running   0              52m     10.244.104.10    node2   <none>           <none>
longhorn-recovery-backend-6576b4988d-l4lmb            1/1     Running   0              52m     10.244.104.8     node2   <none>           <none>
longhorn-recovery-backend-6576b4988d-v79b4            1/1     Running   0              52m     10.244.166.138   node1   <none>           <none>
longhorn-ui-596d5f6876-ms4dn                          1/1     Running   0              52m     10.244.166.137   node1   <none>           <none>
longhorn-ui-596d5f6876-td7ww                          1/1     Running   0              52m     10.244.104.7     node2   <none>           <none>
[root@master ~]# 

设置svc服务(可选)

## 安装好后名为longhorn-frontend的svc服务默认是clusterip模式,
## 除了集群之外的网络是访问不到此服务的,所以要将此svc服务改为nodeport模式
$. kubectl edit svc longhorn-frontend -n longhorn-system
##type: NodePort    
# 将type的ClusterIP改为 NodePort 即可
# 设置 spec.[ports].nodePort: 32183
# 保存退出
$. kubectl get svc -n longhorn-system# 过滤
[root@master ~]# kubectl get svc -n longhorn-system|grep longhorn-frontend 
longhorn-frontend             ClusterIP   10.106.154.54    <none>        80/TCP      55m
[root@master ~]# 
# 查询刚才变更为 NodePort 暴露的端口
[root@master ~]# kubectl get svc \
-n longhorn-system|grep longhorn-frontend 
longhorn-frontend             NodePort    10.106.154.54    <none>        80:32146/TCP   58m
[root@master ~]# 

浏览器访问

在浏览器访问此端口即可

 http://ip:32183  # 根据自己的k8s宿主机ip地址输入
# rpp
http://192.168.1.190:32183

使用iscsi类型的volume

参考: cilium-cew-longhorn

创建 iscsi volume

使用 UI 创建新卷,将frontend设置为“iSCSI”,并attached 到集群中主机, 步骤如下:

步骤1

步骤2

步骤3

步骤4

验证状态

$. kubectl get lhv test-volume-iscsi -n longhorn-system
NAME                DATA ENGINE   STATE      ROBUSTNESS   SCHEDULED   SIZE         NODE          AGE
test-volume-iscsi   v1            attached   healthy                  2147483648   k8s-infra01   105m# ======================== 参考 ============================ #
# 注: lhv 是 longhorn volume 资源的简称
$ kubectl get lhv test -n longhorn-system
NAME   STATE      ROBUSTNESS   SCHEDULED   SIZE          NODE             AGE
test   attached   healthy      True        21474836480   192.168.20.184   25s

获取iSCSI volume endpoint

通过 UI(在“卷详细信息”下)或kubectl, 获取volume的 iSCSI endpoint.

通过kubectl的方式为:

$. kubectl get lhe -n longhorn-system
NAME                    DATA ENGINE   STATE     NODE          INSTANCEMANAGER                                     IMAGE                                    AGE
test-volume-iscsi-e-0   v1            running   k8s-infra01   instance-manager-1388698f2508ae1055185ec20ce07491   longhornio/longhorn-engine:master-head   8m7s$. kubectl get lhe test-volume-iscsi-e-0 \
-n longhorn-system \
-o jsonpath='{.status.endpoint}'
# 输出
iscsi://10.233.94.197:3260/iqn.2019-10.io.longhorn:test-volume-iscsi/1# use
$. kubectl get lhe sts-iscsi-volume01-e-0 \
-n longhorn-system \
-o jsonpath='{.status.endpoint}'# ======================== 参考 ============================ #
# 注: lhe 是 longhorn endpoint 资源的简称
$ kubectl get lhe -n longhorn-system
NAME              STATE     NODE             INSTANCEMANAGER               IMAGE                               AGE
test-e-b8eb676b   running   192.168.20.184   instance-manager-e-baea466a   longhornio/longhorn-engine:v1.1.2   17m$ kubectl get lhe test-e-b8eb676b -n longhorn-system -o jsonpath='{.status.endpoint}'
iscsi://10.0.2.24:3260/iqn.2019-10.io.longhorn:test/1

目录挂载卷(方式1,可选)

通过 iSCSI 启动器(客户端)连接到 Longhorn 卷。

创建 iSCSI 启动器(客户端)

Connect iSCSI initiator (client) to Longhorn volume

将集群外部虚拟机连接到目标集群中的 Longhorn 卷:

# iscsi://10.233.94.197:3260/iqn.2019-10.io.longhorn:test-volume-iscsi/1
# 在客户端机器节点执行
$. iscsiadm --mode discoverydb \
--type sendtargets \
--portal 10.233.94.197 \
--discover 10.233.94.197:3260,1 \
iqn.2019-10.io.longhorn:test-volume-iscsi$. iscsiadm --mode node \
--targetname iqn.2019-10.io.longhorn:test-volume-iscsi \
--portal 10.233.94.197:3260 \
--login$. iscsiadm --mode node
10.0.2.24:3260,1 iqn.2019-10.io.longhorn:test# ======================== 参考 ============================ #
$ iscsiadm --mode discoverydb --type sendtargets --portal 10.0.2.24 --discover
10.0.2.24:3260,1 iqn.2019-10.io.longhorn:test$ iscsiadm --mode node --targetname iqn.2019-10.io.longhorn:test --portal 10.0.2.24:3260 --login$ iscsiadm --mode node
10.0.2.24:3260,1 iqn.2019-10.io.longhorn:test

验证卷

该卷可用作 /dev/sdb:

$. lsblk
NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
...
sdc                         8:32   0    2G  0 disk$. journalctl -xn 100 | grep sdc
# 输出
Aug 07 16:52:41 k8s-worker2 kernel: sd 34:0:0:1: [sdc] 4194304 512-byte logical blocks: (2.15 GB/2.00 GiB)
Aug 07 16:52:41 k8s-worker2 kernel: sd 34:0:0:1: [sdc] Write Protect is off
Aug 07 16:52:41 k8s-worker2 kernel: sd 34:0:0:1: [sdc] Mode Sense: 69 00 10 08
Aug 07 16:52:41 k8s-worker2 kernel: sd 34:0:0:1: [sdc] Write cache: disabled, read cache: enabled, supports DPO and FUA
Aug 07 16:52:41 k8s-worker2 kernel: sd 34:0:0:1: [sdc] Attached SCSI disk$. lsblk /dev/sdc
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdc    8:32   0   2G  0 disk# 接下来挂载该硬盘, 挂载步骤# 建立分区$. fdisk /dev/sdc# 直接默认回车即可# 查看已有分区: $. fdisk -lDevice     Boot Start     End Sectors Size Id Type/dev/sdc1        2048 4194303 4192256   2G 83 Linux# 格式化分区, 建立文件系统$. mkfs.xfs -f /dev/sdc1# 挂载到 /test 目录下$. mount /dev/sdc1 /test# 卸载: umount /dev/sdc1
# ======================== 参考 ============================ #
$ journalctl -xn 100 | grep sdb
Aug 12 09:05:11 longhorn-client kernel: sd 3:0:0:1: [sdb] 41943040 512-byte logical blocks: (21.5 GB/20.0 GiB)
Aug 12 09:05:11 longhorn-client kernel: sd 3:0:0:1: [sdb] Write Protect is off
Aug 12 09:05:11 longhorn-client kernel: sd 3:0:0:1: [sdb] Mode Sense: 69 00 10 08
Aug 12 09:05:11 longhorn-client kernel: sd 3:0:0:1: [sdb] Write cache: enabled, read cache: enabled, supports DPO and FUA
Aug 12 09:05:11 longhorn-client kernel: sd 3:0:0:1: [sdb] Attached SCSI disk$ lsblk /dev/sdb
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdb    8:16   0  20G  0 disk 

k8s pod挂载卷(方式2,可选)

参考: Kubernetes接入iSCSI存储

首先参考《创建iscsi volume》章节,创建名为test-iscsi-volume的volume.

创建pv, pvc

注: 该pvc只能被一个pod挂载

# vi pvc-longhorn-iscsi.yaml
# kubectl apply -f pvc-longhorn-iscsi.yaml
# kubectl delete -f pvc-longhorn-iscsi.yaml
# kubectl get pvc -n rpp-ns
# kubectl delete pvc pvc-longhorn-iscsi -n rpp-ns
# kubectl describe pvc pvc-longhorn-iscsi -n rpp-ns
# iscsi://10.233.94.197:3260/iqn.2019-10.io.longhorn:test-iscsi-volume/1
apiVersion: v1
kind: PersistentVolume
metadata:name: pv-longhorn-iscsi
spec:capacity:storage: 7GiaccessModes:- ReadWriteOnce#- ReadWriteManyiscsi:targetPortal: 10.233.94.197:3260 # Target IP:Portiqn: iqn.2019-10.io.longhorn:test-iscsi-volume # Target IQNlun: 1 # 对应到Target LUN号fsType: ext4#fsType: xfsreadOnly: false
---
apiVersion: "v1"
kind: PersistentVolumeClaim
metadata:name: pvc-longhorn-iscsinamespace: rpp-ns
spec:accessModes:- "ReadWriteOnce" # iSCSI不支持ReadWriteManyresources:requests:storage: 2GivolumeName: "pv-longhorn-iscsi"storageClassName: "" #由于设置了默认的sc,需要强制指定为空,才会使用上面的pv去创建pvc# ======================== 参考 ============================ #
apiVersion: v1
kind: PersistentVolume
metadata:name: test
spec:capacity:storage: 200GiaccessModes:- ReadWriteOnceiscsi:targetPortal: 172.16.28.141:3260 #Target IP:Portiqn: iqn.2004-12.com.inspur:mcs.as5300g2.node1 # Target IQNlun: 0 # 对应到Target LUN号fsType: ext4readOnly: false
---
apiVersion: "v1"
kind: PersistentVolumeClaim
metadata:name: "test-pvc"
spec:accessModes:- "ReadWriteOnce" # iSCSI不支持ReadWriteManyresources:requests:storage: "200Gi"volumeName: "test"storageClassName: "" #由于设置了默认的sc,需要强制指定为空,才会使用test pv去创建pvc

创建POD

# vi pod-rpp-longhorn-iscsi.yaml
# kubectl apply -f pod-rpp-longhorn-iscsi.yaml
# kubectl get pod -n rpp-ns# kubectl describe pod pod-rpp-longhorn-iscsi -n rpp-ns
# kubectl exec -it -n rpp-ns pod-rpp-longhorn-iscsi -- sh
# kubectl delete -f pod-rpp-longhorn-iscsi.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-rpp-longhorn-iscsinamespace: rpp-ns
spec:nodeSelector:#kubernetes.io/hostname: k8s-infra01  # 必须与 longhorn 存储在同一个node上kubernetes.io/hostname: k8s-worker2 containers:- name: springboot-rpp-longhorn-iscsi  # 容器名image: harbor.echo01.tzncloud.com/my-project/spring-boot-docker2:0.0.1-SNAPSHOTvolumeMounts:- name: loghorn-volumemountPath: /data_loghornports:                 # 端口- containerPort: 8600  # 容器暴露的端口name: business-port- containerPort: 8800name: actuator-portvolumes:- name: loghorn-volumepersistentVolumeClaim:claimName: pvc-longhorn-iscsi

k8s sts挂载卷(方式3, use)

创建 pv

注: 该pvc只能被一个pod挂载

# vi pv-sts-longhorn-iscsi.yaml
# kubectl apply -f pv-sts-longhorn-iscsi.yaml
# kubectl delete -f pv-sts-longhorn-iscsi.yaml
# kubectl get pv---
# iscsi://10.233.94.197:3260/iqn.2019-10.io.longhorn:sts-iscsi-volume01/1
apiVersion: v1
kind: PersistentVolume
metadata:name: pv-sts-iscsi-volume01
spec:storageClassName: sts-manualcapacity:storage: 1GiaccessModes:- ReadWriteOnce#- ReadWriteManyiscsi:targetPortal: 10.233.94.197:3260 # Target IP:Portiqn: iqn.2019-10.io.longhorn:sts-iscsi-volume01 # Target IQNlun: 1 # 对应到Target LUN号fsType: ext4#fsType: xfsreadOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv-sts-iscsi-volume02
spec:storageClassName: sts-manualcapacity:storage: 1GiaccessModes:- ReadWriteOnce#- ReadWriteManyiscsi:targetPortal: 10.233.94.197:3260 # Target IP:Portiqn: iqn.2019-10.io.longhorn:sts-iscsi-volume02 # Target IQNlun: 1 # 对应到Target LUN号fsType: ext4#fsType: xfsreadOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv-sts-iscsi-volume03
spec:storageClassName: sts-manualcapacity:storage: 1GiaccessModes:- ReadWriteOnce#- ReadWriteManyiscsi:targetPortal: 10.233.94.197:3260 # Target IP:Portiqn: iqn.2019-10.io.longhorn:sts-iscsi-volume03 # Target IQNlun: 1 # 对应到Target LUN号fsType: ext4#fsType: xfsreadOnly: false

创建statefulset

# vi sts-rpp-longhorn-iscsi.yaml
# kubectl apply -f sts-rpp-longhorn-iscsi.yaml
# kubectl get sts,pod,pvc -n rpp-ns
# kubectl get pod -n rpp-ns# kubectl describe sts-rpp-longhorn-iscsi -n rpp-ns
# kubectl exec -it -n rpp-ns sts-rpp-longhorn-iscsi -- sh
# kubectl delete -f sts-rpp-longhorn-iscsi.yaml
apiVersion: v1
kind: Service
metadata:name: springboot-docker2-sts-svcnamespace: rpp-ns
spec:type: NodePortselector:     # 标签选择,符合这个标签的 Pod 会作为这个 Service 的 backend。app: sts-springboot-dockerports:- protocol: TCPport: 8610        # service暴露在cluster ip上的端口, clusterIP:port 是提供给集群内部客户访问service的入口targetPort: 8610  # pod的端口, 从port和nodePort来的流量经过kube-proxy流入到后端pod的targetPort上, 最后进入容器nodePort: 30020   # 对外暴露的端口,可以指定, Nodeport端口号范围为: 30000-32767
---
apiVersion: apps/v1          
kind: StatefulSet               
metadata:                     name: sts-springboot-dockernamespace: rpp-nslabels:                     app: sts-springboot-docker 
spec:                             replicas: 3                      # Pod的副本数serviceName: springboot-docker2-sts-svc # 必填参数selector:                      matchLabels:                     # 标签选择器app: sts-springboot-docker   # 选择器,用于匹配Pod的标签,确保Pod属于该ststemplate:                 # Pod的模板信息,根据模板信息来创建Pod   metadata:               # Pod的元数据    labels:               # Pod的标签,与Selector中的标签匹配以确保Pod属于该sts   app: sts-springboot-dockerspec:                      containers:                - name: sts-springboot-rpp-longhorn-iscsi  # 容器名image: harbor.echo01.tzncloud.com/my-project/spring-boot-docker2:0.0.1-SNAPSHOTports:                 # 端口- containerPort: 8600  # 容器暴露的端口name: business-port    - containerPort: 8800name: actuator-portvolumeMounts:- name: pvc-sts-longhorn-iscsimountPath: /data_loghorn#volumes:#- name: loghorn-volume#  persistentVolumeClaim:#    claimName: pvc-sts-longhorn-iscsivolumeClaimTemplates:- metadata:name: pvc-sts-longhorn-iscsispec:accessModes: [ "ReadWriteOnce" ]resources:requests:storage: 1GistorageClassName: sts-manual   # 这里并没有名为sts-manual的sc, 这里只是表示 PV 是手动配置的,而不是通过 StorageClass 动态配置的

LongHorn的使用(参考)

创建LongHorn存储类(SC):

接下来,您需要创建一个LongHorn存储类,以便为Kubernetes应用程序提供块存储。您可以将以下内容保存为 longhorn-storageclass.yaml 文件:

sc-longhorn.yaml(use)

# vi sc-longhorn.yaml
# kubectl apply -f sc-longhorn.yaml
# kubectl delete -f sc-longhorn.yaml
# kubectl get sc
# vi sc-longhorn.yaml
# kubectl apply -f sc-longhorn.yaml
# kubectl describe sc longhorn-sc
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: longhorn-sc
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
parameters:numberOfReplicas: "1"staleReplicaTimeout: "2880"
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: longhorn-sc# namespace: rpp-ns # sc 没有 namespace 属性
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
#parameters:
#  numberOfReplicas: "1"
#  staleReplicaTimeout: "2880"
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:name: longhorn-test
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
# reclaimPolicy: Retain # 删除pvc时保留pv
volumeBindingMode: Immediate
parameters:numberOfReplicas: "3"staleReplicaTimeout: "2880"fromBackup: ""fsType: "ext4"

官方Storage Class:

storage-class-parameters

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:name: longhorn-test
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
# reclaimPolicy: Retain # 删除pvc时保留pv
volumeBindingMode: Immediate
parameters:numberOfReplicas: "3"staleReplicaTimeout: "2880"fromBackup: ""fsType: "ext4"
#  mkfsParams: ""
#  migratable: false
#  encrypted: false
#  dataLocality: "disabled"
#  replicaAutoBalance: "ignored"
#  diskSelector: "ssd,fast"
#  nodeSelector: "storage,fast"
#  recurringJobSelector: '[{"name":"snap-group", "isGroup":true},
#                          {"name":"backup", "isGroup":false}]'
#  backingImageName: ""
#  backingImageChecksum: ""
#  backingImageDataSourceType: ""
#  backingImageDataSourceParameters: ""
#  unmapMarkSnapChainRemoved: "ignored"
#  disableRevisionCounter: false
#  replicaSoftAntiAffinity: "ignored"
#  replicaZoneSoftAntiAffinity: "ignored"
#  replicaDiskSoftAntiAffinity: "ignored"
#  nfsOptions: "soft,timeo=150,retrans=3"
#  v1DataEngine: true
#  v2DataEngine: false
#  freezeFSForSnapshot: "ignored"

创建PVC(PersistentVolumeClaim):

pvc-longhorn.yaml (use)

现在,您可以为应用程序创建一个PersistentVolumeClaim,以便使用LongHorn提供的块存储。您可以将以下内容保存为 longhorn-pvc.yaml 文件:

# vi pvc-longhorn.yaml
# kubectl apply -f pvc-longhorn.yaml --dry-run=client
# kubectl apply -f pvc-longhorn.yaml
# kubectl delete -f pvc-longhorn.yaml
# kubectl get pvc -n rpp-ns
# kubectl delete pvc longhorn-pvc -n rpp-ns
# kubectl describe pvc longhorn-pvc -n rpp-ns
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: longhorn-pvc # 该pvc只能被同一个node上的pod使用namespace: rpp-ns
spec:storageClassName: longhorn-scaccessModes:#- ReadWriteOnce- ReadWriteManyresources:requests:storage: 10Gi

pvc-longhorn2.yaml(use)

# vi pvc-longhorn2.yaml
# kubectl apply -f pvc-longhorn2.yaml
# kubectl delete -f pvc-longhorn2.yaml
# kubectl get pvc -n rpp-ns
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: longhorn-pvc2namespace: rpp-ns
spec:storageClassName: longhorn-scaccessModes:- ReadWriteOnceresources:requests:storage: 10Gi

Longhorn PVC with Block Volume Mode - 官方

对于具有块卷模式的 PVC,Kubelet 在容器内提供块设备时,绝不会尝试更改其权限和所有权。您必须在 pod.spec.securityContext 中设置正确的组 ID,以便 pod 能够读取和写入块设备或以 root 身份运行容器。

默认情况下,Longhorn 将块设备放入组 ID 6,该组通常与“磁盘”组相关联。因此,使用具有块卷模式的 Longhorn PVC 的 pod 必须在 pod.spec.securityContext 中设置组 ID 6,或以 root 身份运行。例如:

在 pod.spec.securityContext 中设置组 ID 为 6 的 Pod:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: longhorn-block-vol
spec:accessModes:- ReadWriteOncevolumeMode: Block  # or FilesystemstorageClassName: longhornresources:requests:storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:name: block-volume-testnamespace: default
spec:securityContext:runAsGroup: 1000runAsNonRoot: truerunAsUser: 1000supplementalGroups:- 6 # sets the group id 6containers:- name: block-volume-testimage: ubuntu:20.04command: ["sleep", "360000"]imagePullPolicy: IfNotPresentvolumeDevices:- devicePath: /dev/longhorn/testblkname: block-volvolumes:- name: block-volpersistentVolumeClaim:claimName: longhorn-block-vol
以 root 身份运行的 Pod
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: longhorn-block-vol
spec:accessModes:- ReadWriteOncevolumeMode: BlockstorageClassName: longhornresources:requests:storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:name: block-volume-testnamespace: default
spec:containers:- name: block-volume-testimage: ubuntu:20.04command: ["sleep", "360000"]imagePullPolicy: IfNotPresentvolumeDevices:- devicePath: /dev/longhorn/testblkname: block-volvolumes:- name: block-volpersistentVolumeClaim:claimName: longhorn-block-vol

创建POD

一旦PVC创建成功,您可以将其绑定到您的应用程序中。您可以添加一个示例应用程序Pod,并将挂载PVC作为卷。例如,您可以将以下内容保存为 app-pod.yaml 文件:

pod-rpp-longhorn.yaml(use)

# vi pod-rpp-longhorn.yaml
# kubectl apply -f pod-rpp-longhorn.yaml --dry-run=client
# kubectl apply -f pod-rpp-longhorn.yaml
# kubectl get pod -n rpp-ns# kubectl describe pod rpp-longhorn-pod -n rpp-ns
# kubectl exec -it -n rpp-ns rpp-longhorn-pod -- sh
# kubectl delete -f rpp-longhorn-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: rpp-longhorn-podnamespace: rpp-ns
spec:nodeSelector:kubernetes.io/hostname: k8s-infra01  # 必须与 longhorn 存储在同一个node上containers:- name: springboot-docker-longhorn  # 容器名image: harbor.echo01.tzncloud.com/my-project/spring-boot-docker2:0.0.1-SNAPSHOTvolumeMounts:- name: loghorn-volumemountPath: /data_loghornports:                 # 端口- containerPort: 8600  # 容器暴露的端口name: business-port- containerPort: 8800name: actuator-portvolumes:- name: loghorn-volumepersistentVolumeClaim:claimName: longhorn-pvc#claimName: test-volume3-pvc
---
# 参考
# vi app-pod.yaml
# kubectl apply -f app-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: app-pod
spec:containers:- name: app-containerimage: your-app-imagevolumeMounts:- name: longhorn-volumemountPath: /datavolumes:- name: longhorn-volumepersistentVolumeClaim:claimName: longhorn-volume

pod-rpp-longhorn2.yaml(use)

# 再创建一个pod, 查看pod中挂载的longhorn目录下是否有第一个pod创建的文件
# vi pod-rpp-longhorn2.yaml
# kubectl apply -f pod-rpp-longhorn2.yaml --dry-run=client
# kubectl apply -f pod-rpp-longhorn2.yaml
# kubectl get pod -n rpp-ns -o wide# kubectl describe pod rpp-longhorn-pod2 -n rpp-ns
# kubectl exec -it -n rpp-ns rpp-longhorn-pod2 -- sh
# kubectl delete -f pod-rpp-longhorn2.yaml
apiVersion: v1
kind: Pod
metadata:name: rpp-longhorn-pod2namespace: rpp-ns
spec:nodeSelector:#kubernetes.io/hostname: k8s-worker2kubernetes.io/hostname: k8s-infra01containers:- name: springboot-docker-longhorn2  # 容器名image: harbor.echo01.tzncloud.com/my-project/spring-boot-docker2:0.0.1-SNAPSHOTvolumeMounts:- name: loghorn-volumemountPath: /data_longhornports:                 # 端口- containerPort: 8600  # 容器暴露的端口name: business-port- containerPort: 8800name: actuator-portvolumes:- name: loghorn-volumepersistentVolumeClaim:#claimName: longhorn-pvc2claimName: longhorn-pvc # 如果使用longhorn-pvc, 则与rpp-longhorn-pod共享存储

PVC 扩容

查看 StorageClass 是否支持动态扩容:

如果有参数 allowVolumeExpansion: true 则表示支持。

在 Longhorn 界面上直接就能进行扩容:

关于Volume的说明

删除 Longhorn Volumes

Deleting Volumes Through Kubernetes

通过删除使用已配置 Longhorn 卷的 PersistentVolumeClaim 来通过 Kubernetes 删除卷。这将导致 Kubernetes 清理 PersistentVolume,然后删除 Longhorn 中的卷。

注意:仅当卷由 StorageClass 配置并且 Longhorn 卷的 PersistentVolume 的回收策略设置为删除时,此方法才有效。

Deleting Volumes Through Longhorn

  • 所有 Longhorn 卷(无论它们是如何创建的)都可以通过 Longhorn UI删除。
  • 要删除单个卷,请转到 UI 中的“卷”页面。在“操作”下拉菜单下,选择“删除”。在删除卷之前,系统会提示您确认。
  • 要同时删除多个卷,您可以在“卷”页面上检查多个卷,然后选择顶部的“删除”。
  • 注意
    • 如果 Longhorn 检测到卷与 PersistentVolume 或 PersistentVolumeClaim 绑定,则删除卷后这些资源也将被删除。
    • 在继续删除之前,您会在 UI 中收到有关此情况的警告。
    • Longhorn 还会在删除附加卷时向您发出警告,因为它可能正在使用中。

分离 Longhorn 卷(Detach Longhorn Volumes)

使用 Longhorn 卷关闭所有 Kubernetes Pod,以便分离卷。
实现此目的的最简单方法是删除所有工作负载,然后在升级后重新创建它们。
如果不希望这样做,则可能会暂停某些工作负载。

在本节中,您将了解如何修改每个工作负载以关闭其 Pod。

Deployment

Edit the deployment with kubectl edit deploy/<name>.

Set .spec.replicas to 0.

StatefulSet

使用 kubectl edit statefulset/<name> 编辑 statefulset。

.spec.replicas 设置为 0

DaemonSet

无法暂停此工作负载。
使用 kubectl delete ds/<name> 删除守护程序集。

Pod

使用 kubectl delete pod/<name> 删除 Pod。

无法暂停未由工作负载控制器管理的 Pod。

CronJob

使用 kubectl edit cronjob/<name> 编辑 cronjob
.spec.suspend 设置为 true

等待当前正在执行的任何作业完成,或通过删除相关 pod 来终止它们。

Job

考虑允许单次运行作业完成。

否则,使用 kubectl delete job/<name> 删除作业。

ReplicaSet副本集

使用 kubectl edit replicaset/<name> 编辑副本集。
.spec.replicas 设置为 0

ReplicationController复制控制器

使用 kubectl edit rc/<name> 编辑复制控制器。
.spec.replicas设置为 0
等待 Kubernetes 使用的卷完成分离。

然后从 Longhorn UI 分离所有剩余卷。这些卷很可能是通过 Longhorn UI 或 REST API 在 Kubernetes 之外创建和附加的。

ReadWriteMany (RWX) Volume

Longhorn 通过位于share-manager pods中的 NFSv4 服务器公开常规 Longhorn 卷,从而支持 ReadWriteMany (RWX) 卷。

RWX 卷仅可通过 NFS 挂载访问。默认情况下, Longhorn 使用 NFS 版本 4.1, 并带有 softerr 挂载选项、timeo 值为"600"、retrans 值为"5"。

使用 Longhorn Volume 作为 iSCSI Target

Longhorn 支持 iSCSI 目标前端模式(frontend mode)。可以通过任何 iSCSI 客户端(包括 open-iscsi)和虚拟机管理程序(如 KVM)连接到它,只要它与 Longhorn 系统位于同一网络中即可。

Longhorn CSI 驱动程序不支持 iSCSI 模式。

即:iscsi类型的volume不支持使用longhorn类型的sc的pvc挂载

要使用 iSCSI 目标前端模式启动卷,请在创建卷时选择 iSCSI 作为前端。

连接卷后,您将在端点字段中看到类似以下内容:

# use 
# 查看登录状态
iscsiadm -m session –R# use
iscsi://192.168.1.181:3260/iqn.2014-09.com.rancher:test-volume/1
# 验证
$. iscsiadm --versioniscsiadm --mode discoverydb \
--type sendtargets \
--portal 192.168.1.181:3260 --discover# ==================== 参考 =========================
iscsi://10.42.0.21:3260/iqn.2014-09.com.rancher:testvolume/1kubectl get lhe -n longhorn-system
  • IP 和端口为 10.42.0.21:3260。
  • 目标名称为 iqn.2014-09.com.rancher:testvolume。
  • 卷名称为 testvolume。
  • LUN 编号为 1。Longhorn 始终使用 LUN 1。

上述信息可用于使用 iSCSI 客户端连接到 Longhorn 提供的 iSCSI 目标。

相关文章:

K8S上安装LongHorn(分布式块存储) --use

要在 Kubernetes上安装 LongHorn&#xff0c;您可以按照以下步骤进行操作&#xff1a; 准备工作 参考 官网教程将LongHorn只部署在k8s-worker5节点上。https://github.com/longhorn/longhorn 安装要求 Each node in the Kubernetes cluster where Longhorn is installed must f…...

2024年前端技术发展趋势分析

2024年的前端技术发展趋势继续受到快速变化的技术环境和不断增长的用户期望的影响。以下是2024年前端技术发展的几个关键趋势&#xff1a; 1. Web 组件和自定义元素 Web 组件技术&#xff08;包括 Shadow DOM、HTML Templates 和 Custom Elements&#xff09;正在成为构建可重…...

spring boot 笔记大杂烩

一&#xff0c;springboot项目创建 springboot创建时idea会打开start.spring.io失败报错 可以手动打开这个页面&#xff0c;然后选择maven项目&#xff0c;然后修改group和name名然后添加依赖web&#xff0c;然后生成项目包&#xff0c;解压缩后用idea打开就能用了 运行后报错…...

如何在香港云服务器上优化网站性能?

在香港云服务器上优化网站性能可以通过以下几种方式进行&#xff0c;确保用户从全球各地访问时获得快速、稳定的体验&#xff1a; 1. 使用内容分发网络 (CDN) 优势&#xff1a;CDN可以将静态内容&#xff08;如图像、视频、CSS、JavaScript文件&#xff09;缓存到全球多个节点…...

STM32低功耗与备用备份区域

STM的备份备用区域其实就是两个区块&#xff1a;BKP和RTC。低功耗则其实是STM32四种模式中的三种耗能很低的模式。 目录 一&#xff1a;备用区域 1.BKP 2.RTC 二&#xff1a;低功耗模式 1.睡眠模式&#xff1a; 2.停机模式&#xff1a; 3.待机模式&#xff1a; 一&…...

武汉某汽配公司携手三品软件 共绘PLM项目新蓝图

近日&#xff0c;三品软件与武汉某汽配公司达成战略合作&#xff0c;双方将共同启动PLM项目&#xff0c;以助力该公司在汽车制造业的研发管理领域实现全面升级。 客户简介 该公司自2008年成立以来&#xff0c;一直专注于为汽车制造业提供自动化输送系统、车辆装配的合装技术和…...

uniapp多图上传uni.chooseImage上传照片uni.uploadFile,默认上传9张图

uniapp多图上传uni.chooseImage上传照片uni.uploadFile 代码示例&#xff1a; /**上传照片 多图*/getImage() {uni.chooseImage({count: 9, //默认9sizeType: [original, compressed], //可以指定是原图还是压缩图&#xff0c;默认二者都有sourceType: [album], //从相册选择/…...

MySQL——内置函数

时间函数 select * from msg where date_add(sendtime, interval 2 minute) > now(); 理解&#xff1a; ------------------------------|-----------|-------------|------------------ 初始时间 now() 初始时间2min 字符串 length函数返回字符串长度&#xff0c;以字节为…...

2024年最新版小程序云开发数据模型的开通步骤,支持可视化数据库管理,支持Mysql和NoSql数据库,可以在vue3前端web里调用操作

小程序官方又改版了&#xff0c;搞得石头哥不得不紧急的再新出一版&#xff0c;教大家开通最新版的数据模型。官方既然主推数据模型&#xff0c;那我们就先看看看新版的数据模型到底是什么。 一&#xff0c;什么是数据模型 数据模型是什么 数据模型是一个用于组织和管理数据的…...

智慧水库大坝安全监测预警系统解决方案

前言 水库大坝作为重要的水利设施&#xff0c;承载着防洪涝、灌溉、发电等功能&#xff0c;关系着无数人的生命财产安全&#xff0c;一旦发生意外事故&#xff0c;后果将不堪设想&#xff0c;因此需要建立一套水库大坝安全监测预警系统解决方案。 系统概述 水库大坝安全监测…...

基于SpringBoot+VUE的社区团购系统(源码+文档+部署)

主要内容&#xff1a;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能与大数据、单片机开发、物联网设计与开发设计、简历模板、学习资料、面试题库、技术互助、就业指导等 业务范围&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写…...

LeetCode 3151. 特殊数组 I【数组】简单【Py3,C++,Java,GO,Rust】

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

超级字符串技能:提升你的编码游戏

嘿嘿,uu们,今天咱们来详解字符函数与字符串函数,好啦,废话不多讲,开干&#xff01; 1.:字符分类函数 C语言中又一系列的函数是专门做字符分类的,也就是一个字符属于什么类型的字符的,这些函数的使用需要包含头文件ctype.h 这些函数的使用方法都十分类似,博主在这里就举两到三个…...

米联客-FPGA程序设计Verilog语法入门篇连载-16 Verilog语法_时钟分频设计

软件版本&#xff1a;无 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用所有系列FPGA 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑&#xff01; 1概述 本小节讲解Verilog语法的时钟…...

【Echarts】custom自定义图表实现甘特图

效果图 主要注意点&#xff1a; 1、右上角图例visualMap实现 2、visualMap增加formatter 3、series使用custom自定义图表&#xff0c;encode解析四维数组。核心是renderItem方法&#xff0c;必填项&#xff0c;且需要注意要全部定义在options里面&#xff01;&#xff01;&…...

【高等代数笔记】003线性方程组的解法(一)

1. 线性方程组的解法 1.1 解线性方程组的矩阵消元法 【例1】解线性方程组 { x 1 3 x 2 x 3 2 3 x 1 4 x 2 2 x 3 9 − x 1 − 5 x 2 4 x 3 10 2 x 1 7 x 2 x 3 1 \left\{\begin{array}{ll} x_{1}3x_{2}x_{3}2 \\ 3x_{1}4x_{2}2x_{3}9 \\ -x_{1}-5x_{2}4x_{3}10 \\…...

Scrapy入门教程

Scrapy入门教程&#xff1a;打造高效爬虫的第一步 1. 引言 在当今的网络世界中&#xff0c;信息是无价的资源。而爬虫工具则是获取这些资源的有力武器。Scrapy 是 Python 生态系统中最强大的爬虫框架之一&#xff0c;它不仅功能强大&#xff0c;而且易于扩展&#xff0c;适用…...

Microsoft VBA Excel VBA学习笔记——双重筛选+复制数值1.0

问题场景 CountryProductCLASS 1CLASS 2CLASS 3CLASS 4CLASS 5CLASS 6…USApple0.3641416030.8918210610.0591451990.7320110290.0509636560.222464259…USBanana0.2300833330.4027262180.1548836670.2988904860.7802326210.028592635…CNApple0.7762370470.5075548320.481978…...

谷歌反垄断官司败诉后,或又面临被拆分风险?

KlipC报道&#xff1a;上周8月5日&#xff0c;美国法院裁定谷歌的搜索业务违反了美国反垄断法&#xff0c;非法垄断在线搜索和搜索文本广告市场。据悉&#xff0c;胜诉的美国司法部正在考虑拆分谷歌。其他选项包括强制谷歌与竞争对手分享更多数据&#xff0c;以及防止其在人工智…...

数据结构入门——06树

1.树 树&#xff08;Tree&#xff09;非线性数据结构&#xff0c;它是n&#xff08;n≥0&#xff09;个节点的有限集合&#xff0c;它满足两个条件 &#xff1a; 有且仅有一个特定的称为根&#xff08;Root&#xff09;的节点&#xff1b; 其余的节点可以分为m&#xff08;m…...

FFmpeg源码:av_packet_move_ref、av_packet_make_refcounted函数分析

一、av_packet_move_ref函数 &#xff08;一&#xff09;av_packet_move_ref函数的声明 av_packet_move_ref函数声明在FFmpeg源码&#xff08;本文演示用的FFmpeg源码版本为7.0.1&#xff09;的头文件libavcodec/packet.h中&#xff1a; /*** Move every field in src to ds…...

12 中断

12 中断 1、内核中断编程2、顶半部和底半部机制2.1 任务的相关概念2.1.1 分类2.1.2 优先级2.1.3 进程调度2.1.4 休眠sleep 2.2 顶半部和底半部实现机制2.2.1 顶半部特点2.2.2 底半部特点2.2.3 底半部实现方法之:tasklet2.2.4 底半部实现机制之工作队列2.2.5 底半部实现机制之软…...

经典算法题总结:十大排序算法,外部排序和Google排序简介

十大排序算法 就地性&#xff1a;顾名思义&#xff0c;原地排序通过在原数组上直接操作实现排序&#xff0c;无须借助额外的辅助数组&#xff0c;从而节省内存。通常情况下&#xff0c;原地排序的数据搬运操作较少&#xff0c;运行速度也更快。 稳定性&#xff1a;稳定排序在完…...

服务器是什么?怎么选择适合自己的服务器?

在这个数字化的世界中&#xff0c;我们每天都在与各种网站打交道&#xff0c;浏览新闻、购物、看视频等。你是否曾经好奇过&#xff0c;这些网站是如何运行的&#xff1f;它们又是如何实现随时随地可访问的呢&#xff1f; 在这背后&#xff0c;有一个神秘的角色在默默地支撑着…...

区块链技术的应用场景

区块链技术是一种分布式数据库或公共分类账的形式&#xff0c;它保证了数据的完整性和透明性。它最初是为了支持比特币这种加密货币而被发明的&#xff0c;但现在已经被广泛应用于多种领域&#xff0c;包括供应链管理、投票系统、数字身份验证等。 基本概念 区块 (Block) 区块…...

凤凰端子音频矩阵应用领域

凤凰端子音频矩阵&#xff0c;作为一种集成了凤凰端子接口的音频矩阵设备&#xff0c;具有广泛的应用领域。以下是其主要应用领域&#xff1a; 一、专业音响系统 会议系统&#xff1a;在会议室中&#xff0c;凤凰端子音频矩阵能够处理多个话筒和音频源的信号&#xff0c;实现…...

LeetCode-字母异位词分组

题目描述 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "na…...

《Linux运维总结:基于x86_64架构CPU使用docker-compose一键离线部署etcd 3.5.15容器版分布式集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面对不同的客户部署业务系统&#xff0…...

WPF动画

补间动画&#xff1a;动画本质就是在一个时间段内对象尺寸、位移、旋转角度、缩放、颜色、透明度等属性值的连续变化。也包括图形变形的属性。时间、变化的对象、变化的值 工业应用场景&#xff1a;蚂蚁线、旋转、高度变化、指针偏移、小车 WPF动画与分类 特定对象处理动画过…...

大数据系列之:统计hive表的详细信息,生成csv统计表

大数据系列之:统计hive表的详细信息,生成csv统计表 一、获取源数据库、源数据库类型、hive数据库名称二、获取hive数据库名、hive表名、数仓层级、空间、维护者信息三、统计hive表信息四、统计源库信息五、合并hive表信息六、生成csv统计表七、完整代码一、获取源数据库、源数…...

广州优化网站关键词/seo项目培训

总括 MATLAB和pyplot有当前的图形&#xff08;figure&#xff09;和当前的轴&#xff08;axes&#xff09;的概念&#xff0c;所有的作图命令都是对当前的对象作用。可以通过gca()获得当前的axes&#xff08;轴&#xff09;&#xff0c;通过gcf()获得当前的图形&#xff08;fig…...

政府网站群应该如何建设/百度app登录

【导语】课件中对每个课题或每个课时的教学内容&#xff0c;教学步骤的安排&#xff0c;教学方法的选择&#xff0c;板书设计&#xff0c;教具或现代化教学手段的应用&#xff0c;各个教学步骤教学环节的时间分配等等&#xff0c;下面是无忧考网整理的初中七年级信息技术下册课…...

经济型网站建设/百度收录技巧

在 android 的API中有提供 SystemClock.setCurrentTimeMillis()函数来修改系统时间&#xff0c;可惜无论你怎么调用这个函数都是没用的&#xff0c;无论模拟器还是真机&#xff0c;在logcat中总会得到"Unable to open alarm driver: Permission denied ".这个函数需要…...

网站闭站保护/seo关键词排名网络公司

1. 马哈鱼数据血缘分析工具简介 马哈鱼数据血缘分析工具&#xff08;英文名称为 Gudu SQLFlow &#xff09;是一款用于分析 SQL 语句&#xff0c;并发现其中数据血缘关系的分析软件&#xff0c;经常和元数据管理工具一起使用&#xff0c;是企业数据治理的基础工具。 如果你对 …...

网站优化月总结/就业seo好还是sem

一 PON基础知识 1.1 PON技术概念 PON(Passive Optical Network)即无源光网络&#xff0c;一种基于点到多点(P2MP)拓朴的技术。“无源”指ODN(光分配网络)不含有任何电子器件及电子电源&#xff0c;ODN全部由光分路器Splitter等无源器件组成&#xff0c;不需要贵重的有源电子设…...

导航栏宽度wordpress/做网站要多少钱

来源&#xff1a;Modis数据简介 - zerobyzero - 博客园 (cnblogs.com) 【ENVI精讲】处理专题十二&#xff1a;基于MODIS数据的气溶胶遥感监测 - 知乎 (zhihu.com) MODIS 二级气溶胶产品指北&#xff08;with Python&#xff09; - 炸鸡人博客 (zhajiman.github.io) 美国于19…...