【云原生 | Kubernetes 实战】14、K8s 控制器 Statefulset 入门到企业实战应用

news2024/9/22 11:29:16

目录

一、Statefulset 控制器:概念、原理解读

1.1 什么是有状态服务?

1.2 什么是无状态服务?

二、 Statefulset 资源清单文件编写技巧

三、Statefulset 使用案例:部署 web 站点

3.1 StatefulSet 由以下几个部分组成:

3.2 什么是 Headless service ?

3.3 为什么要用 volumeClaimTemplate ?

3.4 举例说明 service 和 headless service 区别

3.5 Statefulset 小结

四、Statefulset 管理 pod:动态扩容、缩容、更新 

4.1 Statefulset 实现 pod 的动态扩容 

4.2 Statefulset 实现 pod 的动态缩容

4.3 Statefulset 实现 pod 的更新 

更新策略

分区滚动更新 

对 partition 和 maxUnavailable 字段的官方解释:


 

一、Statefulset 控制器:概念、原理解读

StatefulSet 是用来管理有状态应用的工作负载 API 对象。

StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。

        和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

        如果希望使用存储卷为工作负载提供持久存储,可以使用 StatefulSet 作为解决方案的一部分。 尽管 StatefulSet 中的单个 Pod 仍可能出现故障, 但持久的 Pod 标识符使得将现有卷与替换已失败 Pod 的新 Pod 相匹配变得更加容易。

1.1 什么是有状态服务?

        StatefulSet 是有状态的集合,管理有状态的服务,它所管理的 Pod 的名称不能随意变化。数据持久化的目录也是不一样,每一个 Pod 都有自己独有的数据持久化存储目录。比如 MySQL 主从、redis集群等。

1.2 什么是无状态服务?

        RC、Deployment、DaemonSet 都是管理无状态的服务,它们所管理的 Pod 的 IP、名字,启停顺序等都是随机的。个体对整体无影响,所有 pod 都是共用一个数据卷的,部署的 tomcat 就是无状态的服务,tomcat 被删除,在启动一个新的 tomcat,加入到集群即可,跟 tomcat 的名字无关。

官方参考文档:StatefulSet | Kubernetes 

二、 Statefulset 资源清单文件编写技巧

# 用来存放这次的实验文件
[root@k8s-master01 ~]# mkdir statefulset
[root@k8s-master01 ~]# cd statefulset/
 
# 查看定义 Statefulset 资源需要的字段
[root@k8s-master01 ~]# kubectl explain statefulset
[root@k8s-master01 ~]# kubectl explain statefulset.metadata
[root@k8s-master01 ~]# kubectl explain statefulset.spec
[root@k8s-master01 ~]# kubectl explain statefulset.spec.template
[root@k8s-master01 ~]# kubectl explain statefulset.spec.template.metadata
[root@k8s-master01 ~]# kubectl explain statefulset.spec.template.spec
[root@k8s-master01 ~]# kubectl explain statefulset.spec.template.spec.containers

        通过上面可以看到,statefulset 资源中有两个 spec 字段。第一个 spec 声明的是 statefulset定义多少个 Pod 副本(默认将仅部署1个Pod)、匹配 Pod 标签的选择器、创建 pod 的模板、存储卷申请模板;第二个 spec是 spec.template.spec,主要用于 Pod 里的容器属性等配置。

        .spec.template 里的内容是声明 Pod 对象时要定义的各种属性,所以这部分也叫做PodTemplate(Pod模板)。还有一个值得注意的地方是:在 .spec.selector 中定义的标签选择器必须能够匹配到 spec.template.metadata.labels 里定义的 Pod 标签,否则 Kubernetes 将不允许创建 statefulset。

三、Statefulset 使用案例:部署 web 站点

# 编写一个 Statefulset 资源清单文件
[root@k8s-master01 statefulset]# vim statefulset.yaml
apiVersion: v1                 # 定义api版本
kind: Service                  # 定义要创建的资源:service
metadata:
  name: nginx                  # 定义 service 的名字
  labels:
    app: nginx                 # service 的标签
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None              # 创建一个没有 ip 的 service
  selector:
    app: nginx                 # 关联拥有 app=nginx 标签的 pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata: 
  name: web
spec:
  selector:
    matchLabels:
      app: nginx                # 必须匹配 .spec.template.metadata.labels
  serviceName: "nginx"          # headless service 的名字
  replicas: 2                   # 副本数
  template:                     # 定义 pod 的模板
    metadata: 
     labels:
       app: nginx               # 必须匹配 .spec.selector.matchLabels
    spec: 
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:          # 卷申领模板 
  - metadata:
      name: www
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "nfs"    # 指定从哪个存储类申请 pv
      resources:
        requests:
          storage: 1Gi           # 需要 1G 的 pvc,会自动跟符合条件的 pv 绑定

# 前提是已经启动了 nfs 外部驱动和存储类 storageclasses。上一篇文章讲过,下面贴链接
[root@k8s-master01 statefulset]# kubectl get pods 
NAME                               READY   STATUS    RESTARTS   AGE
nfs-provisioner-6fc44b8b68-r8r8d   1/1     Running   0          5s
[root@k8s-master01 statefulset]# kubectl get storageclasses
NAME   PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs    example.com/nfs   Delete          Immediate           false                  44m

# 更新资源清单文件
[root@k8s-master01 statefulset]# kubectl apply -f statefulset.yaml 

# 查看 statefulset 是否创建成功
[root@k8s-master01 statefulset]# kubectl get statefulsets
NAME   READY   AGE
web    2/2     9m20s

[root@k8s-master01 statefulset]# kubectl get pods -o wide -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          8m28s   10.244.169.176   k8s-node2   <none>           <none>
web-1   1/1     Running   0          5m4s    10.244.36.81     k8s-node1   <none>           <none>

        通过上面可以看到创建的 pod 名称是有序的。对于具有 N 个副本的 StatefulSet,该 StatefulSet 中的每个 Pod 将被分配一个从 0 到 N-1 的整数序号,该序号在此 StatefulSet 上是唯一的。

# 查看 pv
[root@k8s-master01 statefulset]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-37663ba6-dbd4-4fa4-af35-30137a1c993d   1Gi        RWO            Delete           Bound    default/www-web-1   nfs                     9m6s
pvc-e988891f-0dba-4ad4-ac7f-848cc667efba   1Gi        RWO            Delete           Bound    default/www-web-0   nfs                     9m13s

# 查看 pvc
[root@k8s-master01 statefulset]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-e988891f-0dba-4ad4-ac7f-848cc667efba   1Gi        RWO            nfs            12m
www-web-1   Bound    pvc-37663ba6-dbd4-4fa4-af35-30137a1c993d   1Gi        RWO            nfs            9m4s

# 查看 headless service
[root@k8s-master01 statefulset]# kubectl get svc -l app=nginx
NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   None         <none>        80/TCP    12m

# 删除其中一个 pod
[root@k8s-master01 statefulset]# kubectl delete pods web-1
pod "web-1" deleted

# 会自动生成一个名字相同 pod
[root@k8s-master01 statefulset]# kubectl get pods -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          70m
web-1   1/1     Running   0          27s

3.1 StatefulSet 由以下几个部分组成:

  1. Headless Service:用来定义 pod 网路标识,生成可解析的 DNS 记录。
  2. volumeClaimTemplates:存储卷申请模板,创建 pvc,指定 pvc 名称大小,自动创建 pvc,且 pvc由存储类供应。
  3. StatefulSet:管理 pod 。

官方参考文档:StatefulSet | Kubernetes 

3.2 什么是 Headless service ?

        Headless service 不分配 clusterIP,headless service 可以通过解析 service 的 DNS,返回所有 Pod 的 dns 和 ip 地址 (statefulSet 部署的 Pod 才有 DNS),普通的 service,只能通过解析service 的 DNS 返回 service 的 ClusterIP。

        headless service 会为 service 分配一个域名,管理域的这个服务的格式为:<service name>.$<namespace name>.svc.cluster.local

K8s 中资源的全局 FQDN 格式:

  • Service_NAME.NameSpace_NAME.Domain.LTD.
    • Domain.LTD.=svc.cluster.local.                     # 这是默认 k8s 集群的域名。

        FQDN 全称 Fully Qualified Domain Name,即全限定域名:同时带有主机名和域名的名称。FQDN = Hostname + DomainName。如主机名是 master,域名是 baidu.com,FQDN= master.baidu.com

        StatefulSet 会为关联的 Pod 保持一个不变的 Pod Name。statefulset 中 Pod 的名字格式为$(StatefulSet 名称)-$(序号),如上面创建的两个名称分别为 web-0、web-1的 Pod。

        一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为:$(pod 名称).$(所属服务的 DNS 域名),其中所属服务由 StatefulSet 的 serviceName 域来设定。

即:$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local

# 使用 kubectl run 运行一个提供 nslookup 命令的容器的,这个命令来自于 dnsutils 包,通过对 pod 主机名执行 nslookup,可以检查它们在集群内部的 DNS 地址: 
[root@k8s-master01 ~]# kubectl run busybox --image docker.io/library/busybox:1.28  --image-pull-policy=IfNotPresent --restart=Never --rm -it busybox -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup web-0.nginx.default.svc.cluster.local
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx.default.svc.cluster.local
Address 1: 10.244.169.176 web-0.nginx.default.svc.cluster.local    # statefulset 创建的 pod 也是有 dns 记录的。解析的是 pod 的 ip 地址。

/ # nslookup nginx.default.svc.cluster.local                       # 查询 service dns,会把对应的 pod ip 解析出来
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local    

Name:      nginx.default.svc.cluster.local        
Address 1: 10.244.36.81 web-1.nginx.default.svc.cluster.local
Address 2: 10.244.169.176 web-0.nginx.default.svc.cluster.local

无头服务(Headless Services)官方说明文档:服务(Service) | Kubernetes

稳定的网络 ID 官网说明文档:StatefulSet | Kubernetes

3.3 为什么要用 volumeClaimTemplate ?

        对于有状态应用都会用到持久化存储,比如 mysql 主从,由于主从数据库的数据是不能存放在一个目录下的,每个 mysq 节点都需要有自己独立的存储空间。而在 deployment 中创建的存储卷是一个共享的存储卷,多个 pod 使用同一个存储卷,它们数据是同步的,而 statefulset 定义中的每一个 pod 都不能使用同一个存储卷,这就需要使用 volumeClainTemplate,当在使用statefulset 创建 pod 时,volumeClainTemplate 会自动生成一个 PVC,从而请求绑定一个 PV,每一个 pod 都有自己专用的存储卷。Pod、PVC 和 PV 对应的关系图如下:

# 进入宿主机挂载目录
[root@k8s-master01 ~]# cd /data/nfs_pro/

# 新生成两个 pod 共享目录
[root@k8s-master01 nfs_pro]# ls
archived-pvc-a7571e3f-7017-40fa-8e3f-7d96a106450a           default-www-web-1-pvc-37663ba6-dbd4-4fa4-af35-30137a1c993d
default-www-web-0-pvc-e988891f-0dba-4ad4-ac7f-848cc667efba

# 分别在两个新目录下创建文件
[root@k8s-master01 nfs_pro]# cd default-www-web-0-pvc-e988891f-0dba-4ad4-ac7f-848cc667efba/
[root@k8s-master01 default-www-web-0-pvc-e988891f-0dba-4ad4-ac7f-848cc667efba]# touch web-o.txt

[root@k8s-master01 default-www-web-0-pvc-e988891f-0dba-4ad4-ac7f-848cc667efba]# cd ../default-www-web-1-pvc-37663ba6-dbd4-4fa4-af35-30137a1c993d/
[root@k8s-master01 default-www-web-1-pvc-37663ba6-dbd4-4fa4-af35-30137a1c993d]# touch web-1.txt

# 进入容器内部查询是否独立同步到对应的 pod 里
[root@k8s-master01 statefulset]# kubectl exec -it web-0 -- bash
root@web-0:/# ls /usr/share/nginx/html/
web-o.txt

[root@k8s-master01 statefulset]# kubectl exec -it web-1 -- bash
root@web-1:/# ls /usr/share/nginx/html/
web-1.txt

3.4 举例说明 service 和 headless service 区别

# 通过 deployment 创建 pod,pod 前端创建一个 service
[root@k8s-master01 statefulset]# vim deploy-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: ClusterIP
  ports:
  - port: 80           # service 的端口,暴露给 k8s 集群内部服务访问
    protocol: TCP
    targetPort: 80     # pod 容器中定义的端口
  selector:
    run: my-nginx      # 选择拥有 run=my-nginx 标签的 pod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: busybox
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        command:
          - sleep
          - "3600"

# 更新资源清单文件
[root@k8s-master01 statefulset]# kubectl apply -f deploy-service.yaml
service/my-nginx created
deployment.apps/my-nginx created

# 查看 service
[root@k8s-master01 statefulset]# kubectl get svc -l run=my-nginx
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.103.6.151   <none>        80/TCP    17s

# 查看 pod。可以看到 deployment 创建的 pod 名称是随机生成的:
[root@k8s-master01 statefulset]# kubectl get pods -l run=my-nginx -o wide 
NAME                        READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
my-nginx-676b95659c-lvttl   1/1     Running   0          42s   10.244.169.178   k8s-node2   <none>           <none>
my-nginx-676b95659c-lzfgk   1/1     Running   0          42s   10.244.36.82     k8s-node1   <none>           <none>

# 解析域名
[root@k8s-master01 ~]# kubectl run busybox --image docker.io/library/busybox:1.28  --image-pull-policy=IfNotPresent --restart=Never --rm -it busybox -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup my-nginx.default.svc.cluster.local
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      my-nginx.default.svc.cluster.local
Address 1: 10.103.6.151 my-nginx.default.svc.cluster.local    # 解析的是 service 的 ip 地址,而不是关联的 pod ip。

3.5 Statefulset 小结

  1. Statefulset 管理的 pod,pod 名字是有序的,由 statefulset 的名字-0、1、2这种格式组成。
  2. 创建 statefulset 资源的时候,必须事先创建好一个 service,如果创建的 service 没有 ip,那对这个 service 做 dns 解析,会找到它所关联的 pod ip,如果创建的 service 有 ip,那对这个service 做 dns 解析,会解析到 service 本身 ip。
  3. statefulset 管理的 pod,删除 pod,自动恢复创建的 pod 名字跟删除的 pod 名字是一样的。
  4. statefulset 具有 volumeclaimtemplate 这个字段,这个是卷申请模板,会自动创建 pv,pvc 也会自动生成,跟 pv 进行绑定,那如果创建的 statefulset 使用了 volumeclaimtemplate 这个字段,那创建 pod,数据目录是独享的。
  5. ststefulset 创建的 pod,是有域名的(域名组成:pod-name.svc-name.svc-namespace.svc.cluster.local)

四、Statefulset 管理 pod:动态扩容、缩容、更新 

4.1 Statefulset 实现 pod 的动态扩容 

        如果我们觉得两个副本太少了,想要增加,只需要修改配置文件 statefulset.yaml 里的replicas 的值即可,原来 replicas: 2,现在变成 replicaset: 3,修改之后,执行如下命令更新实现动态扩容:

[root@k8s-master01 statefulset]# vim statefulset.yaml 
······
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 3
······

[root@k8s-master01 statefulset]# kubectl apply -f statefulset.yaml 

[root@k8s-master01 statefulset]# kubectl get pods -l app=nginx -o wide 
NAME    READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          118m   10.244.169.176   k8s-node2   <none>           <none>
web-1   1/1     Running   0          48m    10.244.36.80     k8s-node1   <none>           <none>
web-2   1/1     Running   0          20s    10.244.169.179   k8s-node2   <none>           <none>

也可以直接编辑控制器实现扩容

# 使用 kubectl edit 编辑副本字段:把 spec 下的 replicas 后面的值改成 4,保存退出
[root@k8s-master01 statefulset]# kubectl edit sts web 
······
spec:
  podManagementPolicy: OrderedReady
  replicas: 4
  revisionHistoryLimit: 10
······

[root@k8s-master01 statefulset]# kubectl get pods -l app=nginx -o wide 
NAME    READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          122m    10.244.169.176   k8s-node2   <none>           <none>
web-1   1/1     Running   0          52m     10.244.36.80     k8s-node1   <none>           <none>
web-2   1/1     Running   0          4m12s   10.244.169.179   k8s-node2   <none>           <none>
web-3   1/1     Running   0          28s     10.244.36.86     k8s-node1   <none>           <none>

4.2 Statefulset 实现 pod 的动态缩容

        如果我们觉得 4 个 Pod 副本太多了,想要减少,只需要修改配置文件 statefulset.yaml 里的replicas 的值即可,把 replicaset:3 变成 replicas: 2,修改之后,执行如下命令更新:

[root@k8s-master01 statefulset]# vim statefulset.yaml 
······
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 2
······

[root@k8s-master01 statefulset]# kubectl apply -f statefulset.yaml 
service/nginx unchanged
statefulset.apps/web configured

[root@k8s-master01 statefulset]# kubectl get pods -l app=nginx -o wide 
NAME    READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          126m   10.244.169.176   k8s-node2   <none>           <none>
web-1   1/1     Running   0          56m    10.244.36.80     k8s-node1   <none>           <none>

也可以直接编辑控制器实现扩容

# 使用 kubectl edit 编辑副本字段:把 spec 下的 replicas 后面的值改成 1,保存退出
[root@k8s-master01 statefulset]# kubectl edit sts web
······
spec:
  podManagementPolicy: OrderedReady
  replicas: 1
  revisionHistoryLimit: 10
······

[root@k8s-master01 statefulset]# kubectl get pods -l app=nginx -o wide 
NAME    READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          127m   10.244.169.176   k8s-node2   <none>           <none>

小结:

  • 对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为 0..N-1
  • 当删除 Pod 时,它们是逆序终止的,顺序为 N-1..0

扩缩 StatefulSet 官方参考文档:扩缩 StatefulSet | Kubernetes

4.3 Statefulset 实现 pod 的更新 

  • 更新策略

        StatefulSet 的 .spec.updateStrategy 字段让你可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求或限制、以及注解。有两个允许的值:

  • OnDelete

        当 StatefulSet 的 .spec.updateStrategy.type 设置为 OnDelete 时, 它的控制器将不会自动更新 StatefulSet 中的 Pod。 用户必须手动删除 Pod 以便让控制器创建新的 Pod,以此来对 StatefulSet 的 .spec.template 的变动作出反应。

  • RollingUpdate

   RollingUpdate 更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。这是默认的更新策略。

  • 分区滚动更新 

[root@k8s-master01 statefulset]# vim statefulset.yaml 
······
spec:                    # 新增内容
  updateStrategy:
    rollingUpdate:
      partition: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: nginx
······
    spec:
      containers:
      - name: nginx
        image: tomcat    # 修改镜像
        imagePullPolicy: IfNotPresent
······

[root@k8s-master01 statefulset]# kubectl apply -f statefulset.yaml

# 在另一个终端动态查看 pod
[root@k8s-master01 ~]# kubectl get pods -l app=nginx -w
web-0                              1/1     Running   0          138m
web-1                              0/1     Pending   0          0s
web-1                              0/1     Pending   0          0s
web-1                              0/1     ContainerCreating   0          0s
web-1                              0/1     ContainerCreating   0          1s
web-1                              1/1     Running             0          2s

        从上面结果可以看出来,pod 在更新的时候,只是更新了 web-1 这个 pod, 因为 partition: 1 表示更新的时候会把 pod 序号大于等于 1 的进行更新。

  • 对 partition 和 maxUnavailable 字段的官方解释:

        如果更新策略是 OnDelete,那不会自动更新 pod,需要手动删除旧的 pod,重新创建 pod 才会实现更新:

[root@k8s-master01 statefulset]# vim statefulset.yaml 
······
spec:
  updateStrategy:
    type: OnDelete             # 更新策略为 OnDelete    
  selector:
    matchLabels:
      app: nginx
······
    spec:
      containers:
      - name: nginx
        image: nginx            # 修改镜像
        imagePullPolicy: IfNotPresent
······

# 在另一个终端动态查看信息
[root@k8s-master01 ~]# kubectl get pods -w -l app=nginx

[root@k8s-master01 statefulset]# kubectl apply -f statefulset.yaml 

发现没有 pod 没有任何变化:

 

只有手动删除 pod 才会实现更新: 

[root@k8s-master01 statefulset]# kubectl delete pods web-1
pod "web-1" deleted

[root@k8s-master01 statefulset]# kubectl delete pods web-0
pod "web-0" deleted

statefulset 更新策略官方参考文档:StatefulSet | Kubernetes

 上一篇文章:【云原生 | Kubernetes 实战】13、K8s 常见的存储方案及具体应用场景分析(下)_Stars.Sky的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/99027.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VMware克隆虚拟机

一、克隆虚拟机 1. 在WMware中&#xff0c;右键虚拟机模板&#xff08;需要克隆的虚拟机原型&#xff09;&#xff0c;选择&#xff1a;管理 ----> 克隆&#xff0c;如下图所示&#xff1a; 2. 然后&#xff0c;如下图进行操作&#xff1a; 二、扩展&#xff1a;移除、删除…

【Python】 14-CVS文件操作

1.CVS文件 值没有类型&#xff0c;所有东西都是字符串&#xff1b; • 没有字体大小或颜色的设置&#xff1b; • 没有多个工作表&#xff1b; • 不能指定单元格的宽度和高度&#xff1b; • 不能合并单元格&#xff1b; • 不能嵌入图像或图表。 CSV 文件中的每个单元格 有逗…

【JavaSE基础:数据类型和变量】

数据类型一、数据类型1.八大基本数据类型二、变量0.字面常量1.变量1&#xff09;数值类型a.整型b.浮点型2&#xff09;字符类型&#xff08;char&#xff09;3&#xff09;布尔类型&#xff08;boolean&#xff09;2.类型转换3.类型提升一、数据类型 Java是一种强类型编程语言…

[思维模式-6]:《如何系统思考》-2- 认识篇 - 为什么要系统思考?系统思考是系统架构师、系统设计师的基本技能

目录 前言&#xff1a;系统思考的关键字 第1章 系统思考的作用 1.1 系统思考能够化繁为简 1.2 系统思考是敏捷成长和解决问题的系统方法 第2章 常见缺乏系统思考的表现 2.1 分解思维盛行的不足 2.2 面积上&#xff1a;只见树木&#xff0c;不见深林 2.3 时间上&#xf…

Tippecanoe安装使用

Tippecanoe安装使用 介绍 tippecanoe是mapbox官方提供的一个开源矢量切片工具&#xff0c;用C语言编写的。 Tippecanoe 的目标是为您的数据制作一个与比例无关的视图&#xff0c;以便在从整个世界到单个建筑物的任何级别上&#xff0c;您都可以看到数据的密度和纹理&#xf…

02---前端框架搭建

1、创建项目 1.该有的nodejs 、vue都要安装上&#xff0c;我用的是vuecli3&#xff0c;所以可以使用可视化界面 来创建项目&#xff08;更加直观&#xff09;&#xff0c;当然你也可以采用命令行的方式创建项目。 2.cmd命令行输入&#xff1a; vue ui 3.在打开的可视化页面中…

基于asp.net193酒店客房预订网站系统-计算机毕业设计

项目介绍 本酒店系统使用asp.net技术制作,在前台为普通用户提供预定和查询等系统使用功能&#xff0c;在后台为酒店管理员提供对系统平台的管理功能。在前台为用户提供的操作功能包括以下内容&#xff1a;站内新闻、用户注册、酒店查看&#xff0c;留言板等功能。此系统为管理…

AMAIZINGIC晶焱科技:Wi-Fi 6E 路由器产品的ESD/EOS防护方案

AMAIZINGIC晶焱科技&#xff1a;Wi-Fi 6E 路由器产品的ESD/EOS防护方案 随着无线网路的发展&#xff0c;IEEE协会于2020年提出了最新的Wi-Fi 6E&#xff0c;此版本为Wi-Fi 6的延伸版本&#xff0c;除了Wi-Fi 6原先支援的2.4GHz及5GHz的频段外&#xff0c;新增了6GHz的频段&…

功能超级强大,Python 命令行解析工具 argparse很好用

在工作中&#xff0c;我们经常需要从命令行当中解析出指定的参数&#xff0c;而 Python 也提供了相应的标准库来做这件事情&#xff0c;比如 sys, optparse, getopt, argparse。这里面功能最强大的莫过于 argparse&#xff0c;下面就来看看它用法。 import argparse # 使用 a…

Java+SSM在线商城系统电商购物系统(含源码+论文+答辩PPT等)

项目功能简介: 该项目采用的技术实现如下 后台框架&#xff1a;Spring、SpringMVC、MyBatis UI界面&#xff1a;BootStrap、jQuery 、JSP 数据库&#xff1a;MySQL 系统分为前台订票和后台管理&#xff1a; 1.前台商城 商品分类展示、商品详情、商品推荐、购物车、下单、支付 客…

课题设计基于nodejs购票系统的设计与实现.zip(论文+源码+ppt文档+视频录制)

第 1 章 绪 论 3 1.1研究现状及存在问题 3 1.2主要工作 4 第 2 章 系统开发技术概述 5 2.1 B/S 架构模式与C/S 架构模式 5 2.2 nodejs框架模式 6 第 3 章 需求分析 7 3.1 系统情况概述 7 3.2 系统功能性需求分析 9 3.3 系统非功能性需求分析 9 3.4 系统用例图 10 第 4 章 系统设…

【JavaSE】文件读写

目录 一、文件 1、文件的概念 1.广义 2.狭义 二、路径 1、绝对路径 2、相对路径 1.进入下一级./ 2.回退上一级../ 三、Java里的文件基本操作----File类 1、说明 2、File类的基本操作 1.基本方法 ​2.创建与删除文件 3.创建目录 4.文件的重命名 四、文件的读写操…

信息安全技术

安全分析模型自动化调优 MLOps&#xff08;Machine Learning Operations&#xff09;是一种人工智能 的工程实践&#xff0c;是面向机器学习项目的研发运营管理体系 。旨在实现 ML 管道的操作、ML 模型的部署和管理标准化&#xff0c;支持ML 模型的发布、激活、监控、性能跟踪…

【Spring Cloud】Nacos命名空间Namespace的介绍与使用

本期目录1. Namespace介绍2. 创建Namespace3. 配置Namespace专栏精选文章1. Namespace介绍 Namespace 通常用来做环境隔离。例如开发环境 dev 、测试环境 test 和生产环境 pro 之间的服务/数据相互隔离&#xff0c;无法相互访问。 Nacos 中服务和数据存储的最外层都是 Namespa…

常用性能测试工具的比较

目录性能测试的重要性针对接口的性能测试性能测试基准接口性能测试的主要指标abenchjMeterKelude性能脚本各种监控工具参考总结性能测试的重要性 众所周知性能测试在软件测试中占有举足轻重的作用&#xff0c;尤其是对于互联网产品这种具有大用户量&#xff0c;大数据量&#…

Spring Boot学习篇(一)

Spring Boot学习篇(一) 1 Spring、SpringBoot、SpringCloud有什么区别&#xff1f; spring一般指Spring框架&#xff08;SpringFramework&#xff09;&#xff0c;它是一个开源、轻量级的Java应用开发框架。其核心是控制反转IOC和面向切面编程AOP。Spring提供了很多包括ORM、…

Kaggle 新赛 | GoDaddy 微型企业密度预测

文章目录一、比赛背景和目标1. 背景2. 比赛目标二、提交、时间线和奖项三、代码要求一、比赛背景和目标 1. 背景 美国政策领导人努力发展更具包容性和抗衰退能力的经济体。他们也意识到&#xff0c;随着科技的进步&#xff0c;创业从来没有像今天这样容易。无论是创造一个更合…

【阙值分割】粒子群算法自适应多阈值图像分割【含Matlab源码 1459期】

⛄一、粒子群算法自适应多阈值图像分割简介 理论知识参考&#xff1a;【基础教程】基于matlab图像处理图像分割【含Matlab源码 191期】 粒子群优化的多阈值图像自分割算法 ⛄二、部分源代码 clc;clear;close all; %% 输入图像&#xff1b; Imag imread(‘24063.jpg’);%29…

【算法】常见的排序算法(插入排序、希尔排序、选择排序、冒泡排序、快速排序、归并排序)

目录一.常见排序类型二.排序详解1.冒泡排序2.选择排序3.插入排序4.希尔排序5.快速排序6.归并排序一.常见排序类型 插入排序&#xff1a;插入排序、希尔排序选择排序&#xff1a;简单选择排序、堆排序交换排序&#xff1a;冒泡排序、快速排序归并排序基数排序(又叫桶排序)八万个…

Java项目:新闻推荐管理系统(java+SSM+JavaScript+Ajax+Mysql)

源码获取&#xff1a;俺的博客首页 "资源" 里下载&#xff01; 项目介绍 本项目新闻推荐管理系统&#xff1b; 前台: 登录、首页、全部新闻、系统特色、猜你喜欢、分类、评论 后台&#xff1a; &#xff08;1&#xff09;文件管理&#xff1a;文件列表。 &#x…