Kubernetes资源管理

1.1 资源管理介绍

Kubernetes(通常缩写为 k8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。在 Kubernetes 中,资源管理是核心概念之一,以下是 Kubernetes 资源管理的一些关键组件和概念:

Kubernetes 资源管理对象 描述
Pods Kubernetes 中的最小部署单元,可以包含一个或多个容器(通常是 Docker 容器),为容器提供运行环境,包括网络和存储。
Deployments 负责 Pod 的声明式更新,定义应用的期望状态,确保指定数量的 Pod 副本始终运行。
Services 提供一种访问 Pod 的方式,通过固定的 IP 地址(ClusterIP)或 DNS 名称,为一组 Pod 提供统一的访问接口。
Volumes 存储机制,允许数据持久化,即使 Pod 被删除或重新调度,数据也不会丢失。可以与外部存储系统集成。
Namespaces 将集群资源划分为多个逻辑分区,允许不同用户、团队或项目在同一个物理集群中运行而不互相干扰。
ConfigMaps 和 Secrets 存储配置数据和敏感信息的对象,供 Pods 使用,避免将信息硬编码在应用程序中。
Ingress 管理外部访问到集群内服务的 HTTP 和 HTTPS 路由,提供 URL 路由、负载均衡、SSL 终止和名称基的虚拟托管。
Persistent Volumes (PV) 集群中的一块预先配置好的存储,可以作为 Volume 使用。
Persistent Volume Claims (PVC) 用户对持久存储的请求,允许申请特定大小和访问模式的存储。
Resource Quotas 限制一个 Namespace 中所有 Pods 可以使用的资源总量,如 CPU 和内存。
LimitRanges 为 Namespace 中的资源设置默认和最大资源限制,防止资源过度使用。
Horizontal Pod Autoscaler (HPA) 根据 CPU 使用率或其他度量自动扩展 Pod 的数量。
Network Policies 定义 Pod 之间网络通信的规则,控制哪些 Pod 可以相互通信。

  • PodController:是 Kubernetes 中用于管理一组 Pods 的控制器,确保这些 Pods 的数量符合用户指定的数量。

  • Deployment:一种 Pod 控制器,用于声明式地管理无状态应用的 Pods。它允许定义应用的期望状态,并且可以自动滚动更新应用。

  • CronJob:用于在给定的时间点或周期性地创建 Jobs,通常用于定时任务。

  • DaemonSet:确保所有(或某些)节点上都运行一个 Pod 的副本,通常用于运行集群存储、日志收集等系统守护进程。

  • ReplicaSet:确保指定数量的 Pod 副本始终运行,是 Deployment 的底层实现。

  • Job:用于创建一个或多个 Pods,并确保它们以某种方式完成(例如,成功退出)。Job 负责重启失败的 Pods。

  • StatefulSet:用于管理有状态应用的 Pods,与 Deployment 类似,但提供了额外的功能,如稳定的持久化存储和网络标识。

  • Service:定义了一种访问 Pod 的方式,无论这些 Pod 如何分布,通常通过一个固定的 IP 地址或 DNS 名称。

  • Pod:Kubernetes 中的最小部署单元,可以包含一个或多个容器。

  • Container:Pod 中的容器,通常是 Docker 容器,是运行应用程序的执行环境。

  • Volume:Kubernetes 中的存储机制,允许数据在 Pod 之间共享和持久化。

  • ConfigMap:用于存储配置数据的键值对,可以被 Pods 作为环境变量或文件挂载使用。

  • PVC (Persistent Volume Claim):用户对持久存储的请求,允许用户申请特定大小和访问模式的存储。

  • Secret:用于存储敏感信息,如密码、密钥等,可以被 Pods 作为环境变量或文件挂载使用。

1.2 YAML语法

1.2.1 YAML语法介绍

YAML(YAML Ain't Markup Language)是一种数据序列化格式,它被设计为易于人类阅读和编写,常用于配置文件和数据交换。以下是 YAML 语言的一些核心特性和语法规则:

  • 大小写敏感:YAML 中的键(key)和值(value)的大小写是敏感的,这意味着 Keykey 被视为不同的键。

  • 缩进表示层级:YAML 使用缩进来定义数据结构的层级关系。相同层级的元素需要保持对齐。

  • 空格缩进:YAML 严格使用空格进行缩进,不允许使用制表符(Tab)。不同版本的 YAML 对缩进的空格数有不同的要求,但通常是两个或四个空格。

  • 对齐的灵活性:虽然不同层级的元素可以有不同的缩进空格数,但只要它们左对齐,就被认为是相同层级的。

  • 注释:以 # 开头的行表示注释,直到行尾。

  • 数据类型

    • 纯量(Scalar):表示单个的、不可再分的值,如字符串、数字、布尔值等。

      1、布尔类型 (Boolean):
      c1: true
      ​
      2、整型 (Integer):
      c2: 234
      ​
      3、浮点型 (Float):
      c3: 3.14
      ​
      4、Null类型 (Null):
      c4: ~
      ​
      5、日期类型 (Date):
      c5: 2018-02-17
      日期格式遵循 ISO 8601 标准。
      ​
      6、时间类型 (Time):
      c6: 2018-02-17T15:02:31+08:00
      时间格式同样遵循 ISO 8601 标准,使用 T 连接日期和时间,最后是时区信息。
      ​
      7、字符串类型 (String):
      c7: openlab
      c8: | # 使用管道符号表示字符串可以跨越多行
        line1
        line2
    • 对象(Mapping):由键值对组成,也称为映射或字典。在 YAML 中,键值对通常用冒号(:)分隔。

      对象在 YAML 中由键值对组成,可以使用两种形式表示:
      1、形式一(推荐):使用块格式,每个键值对占据一行,推荐用于清晰性和扩展性。
      openlab:
        age: 15
        address: Beijing
        
      2、形式二(了解):使用紧凑格式,键值对写在一起,用花括号 {} 包围。这种格式在需要节省空间时可以使用,但在复杂的配置中可能导致可读性降低。
      openlab: {age: 15, address: Beijing}
    • 数组(Sequence):表示一组有序的值,也称为序列或列表。在 YAML 中,数组中的元素通常用短划线(-)开头。

      数组在 YAML 中是有序的元素集合,也可以使用两种形式表示:
      1、形式一(推荐):使用块格式,数组中的每个元素都以短划线 - 开头,占据一行。
      address:
        - 顺义
        - 昌平
      ​
      2、形式二(了解):使用紧凑格式,数组中的所有元素放在一个行内,用方括号 [] 包围。
      address: [顺义, 昌平]

1.2.2 YAML 语法的最佳实践

  • 缩进:在块格式中,每个层级的缩进应该是空格,通常是两个或四个空格,但必须保持一致。

  • 简洁性:YAML 旨在简洁,块格式通常更易于阅读和维护,特别是在配置文件较大或包含复杂结构时。

  • 注释:使用 # 添加注释,注释行不会被程序解析。

  • 键值对分隔:键和值之间用冒号 : 分隔,后面通常跟一个空格。

  • 多行字符串:如果字符串跨越多行,可以使用 |> 来表示,| 保留换行,> 折叠换行。

  • 标点:YAML 中的标点符号很重要,确保正确使用短划线 - 来表示数组元素,使用连字符 - 来开始列表项。

  • 一致性:在同一个 YAML 文件中,尽量保持一致的格式,这样有助于提高可读性和减少错误。

小提示:

  • 键值对分隔:在 YAML 中,键和值之间使用冒号 : 分隔。重要的是,冒号后面应该紧跟一个空格(如果键和值之间没有空格,某些 YAML 解析器可能会报错或产生不预期的结果)。

    key: value
  • 多文档分隔:YAML 允许一个文件中存在多个文档,每个文档之间使用 --- 分隔。这在将多个配置块组合在同一个文件中时非常有用,例如,当你想要在同一个文件中定义多个 Kubernetes 资源时。

    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod1
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod2
  • YAML 转 JSON 工具:您提供了一个在线工具的链接 https://www.json2yaml.com/convert-yaml-to-json这个工具可以帮助用户将 YAML 格式的配置转换为 JSON 格式,也可以用于验证 YAML 配置的书写是否正确。如果用户在尝试使用该工具时遇到问题,可能是因为网络连接问题,或者网站本身的问题。建议用户检查网络连接,并在必要时重试。

1.3 Kubernetes资源管理方式

  • 命令式对象管理:通过 kubectl run 等命令直接操作 Kubernetes 资源。

  • 命令式对象配置:通过 kubectl createkubectl patch 命令结合配置文件操作 Kubernetes 资源。

  • 声明式对象配置:通过 kubectl apply 命令结合配置文件操作 Kubernetes 资源,这是推荐的做法,因为它允许跟踪资源的声明式状态。

管理方法 操作对象 适用环境 优点 缺点
命令式对象管理 对象 测试 - 简单,快速执行单个命令 - 适合快速迭代和临时变更 - 无法审计和跟踪历史变更 - 不适合管理复杂的部署和应用状态
命令式对象配置 文件 开发 - 可以审计和跟踪历史变更 - 方便管理和记录资源的期望状态 - 项目规模大时,配置文件数量增多,管理变得复杂
声明式对象配置 目录 开发 - 支持目录操作 - 允许系统跟踪资源的期望状态 - 意外情况下,调试可能比较困难

1.3.1 命令式对象管理

  • kubectl 是 Kubernetes 集群的命令行工具,它允许用户与 Kubernetes 集群交互,执行各种资源管理和应用部署任务。以下是 kubectl 命令的一些基本语法和使用示例:

1.3.1.1 基本语法
kubectl [command] [TYPE] [NAME] [flags]
  • command:要执行的操作,如 get, create, delete, apply 等。

  • TYPE:资源类型,如 pods, services, deployments 等。

  • NAME:资源的名称,可以是名称、标签选择器或资源文件路径。

  • flags:可选的标志或配置项,用于修改命令的行为。

1.3.1.2 使用示例
  • 获取资源信息

    [root@K8s-master ~]# kubectl run nginx --image=nginx:latest
    pod/nginx created
    [root@K8s-master ~]# kubectl get pods
    NAME    READY   STATUS              RESTARTS   AGE
    nginx   0/1     ContainerCreating   0          3s
    [root@K8s-master ~]# kubectl get pod nginx   #显示指定一个pod信息
    NAME    READY   STATUS              RESTARTS   AGE
    nginx   0/1     ContainerCreating   0          28s
    [root@K8s-master ~]# kubectl get pod nginx -o wide  #-o wide选项获取Pod详细信息
    NAME    READY   STATUS    RESTARTS   AGE     IP           NODE          NOMINATED NODE   READINESS GATES
    nginx   1/1     Running   0          2m45s   10.244.2.3   k8s-node-02   <none>           <none>
    [root@K8s-master ~]# kubectl get pod nginx -o yaml   #以yaml格式显示出来
  • 创建资源

    [root@K8s-master ~]# kubectl create -f nginx-deployment.yaml
  • 应用配置

    [root@K8s-master ~]# kubectl apply -f nginx-deployment.yaml
1.3.1.3 资源类型
[root@K8s-master ~]# kubectl api-resources
资源分类 资源名称 缩写 资源作用
集群级别资源 nodes no 集群组成部分
namespaces ns 隔离 Pod
Pod资源 pods po 装载容器
Pod资源控制器 replicationcontrollers rc 控制 Pod 资源
replicasets rs 控制 Pod 资源
deployments deploy 控制 Pod 资源,用于无状态应用
daemonsets ds 控制 Pod 资源,确保所有(或某些)节点上运行 Pod 的副本
jobs 控制 Pod 资源,用于批处理作业
cronjobs cj 控制 Pod 资源,用于定时任务
horizontalpodautoscalers hpa 控制 Pod 资源,根据 CPU 使用率自动扩展 Pod 数量
statefulsets sts 控制 Pod 资源,用于有状态应用
服务发现资源 services svc 统一 Pod 对外接口,提供服务发现
ingress ing 统一 Pod 对外接口,管理外部访问到集群内服务的路由
存储资源 volumeattachments 存储资源
persistentvolumes pv 存储资源,集群中的一块预先配置好的存储
persistentvolumeclaims pvc 存储资源,用户对持久存储的请求
配置资源 configmaps cm 配置资源,存储配置数据的键值对
secrets 配置资源,存储敏感信息,如密码、密钥等
1.3.1.4 kubectl命令参数
[root@K8s-master ~]# kubectl --help
1.3.1.4.1 基本命令
命令 翻译 描述
create 创建 从文件或标准输入创建资源
expose 暴露 将复制控制器、服务、部署或 Pod 暴露为一个新的 Kubernetes 服务
run 运行 在集群上运行特定的镜像
set 设置 对对象设置特定功能
explain 解释 获取资源的文档
get 获取 显示一个或多个资源
edit 编辑 在服务器上编辑资源
delete 删除 通过文件名、标准输入、资源和名称或标签选择器删除资源
[root@K8s-master ~]# kubectl explain --help  #一层一层的查看
1.3.1.4.2 部署命令
命令 翻译 描述
rollout 推出 管理资源的 rollout
scale 扩展 为部署、副本集或复制控制器设置新的尺寸
autoscale 自动扩展 自动扩展部署、副本集、有状态集或复制控制器
1.3.1.4.3 集群管理命令
命令 翻译 描述
certificate 证书 修改证书资源
cluster-info 集群信息 显示集群信息
top 资源使用 显示资源(CPU/内存)使用情况
cordon 隔离 将节点标记为不可调度
uncordon 解除隔离 将节点标记为可调度
drain 排空 为维护准备排空节点
taint 污点 更新一个或多个节点上的污点
1.3.1.4.4 故障排查和调试命令
命令 翻译 描述
describe 描述 显示特定资源或资源组的详细信息
logs 日志 打印 Pod 中容器的日志
attach 连接 连接到正在运行的容器
exec 执行 在容器中执行命令
port-forward 端口转发 将一个或多个本地端口转发到 Pod
proxy 代理 运行到 Kubernetes API 服务器的代理
cp 复制 复制文件和目录到容器中或从容器中复制
auth 授权 检查授权
debug 调试 为故障排查工作负载和节点创建调试会话
1.3.1.4.5 高级命令
命令 翻译 描述
diff 差异 对比实时版本和将要应用的版本
apply 应用 通过文件名或标准输入将配置应用到资源
patch 补丁 更新资源的字段
replace 替换 通过文件名或标准输入替换资源
wait 等待 实验性:等待一个或多个资源上的特定条件
kustomize 自定义 从目录或 URL 构建 kustomization 目标
1.3.1.4.6 设置命令
命令 翻译 描述
label 标签 更新资源上的标签
annotate 注解 更新资源上的注解
completion 补全 输出指定 shell(bash、zsh 或 fish)的 shell 完成代码
1.3.1.4.7 其他命令
命令 翻译 描述
alpha Alpha Alpha 功能中的命令
api-resources API 资源 打印服务器上支持的 API 资源
api-versions API 版本 打印服务器上支持的 API 版本,形式为 "group/version"
config 配置 修改 kubeconfig 文件
plugin 插件 提供与插件交互的实用工具
version 版本 打印客户端和服务器版本信息
1.3.1.5 基本命令使用示例
[root@K8s-master ~]# kubectl get ns  #获取命名空间
NAME              STATUS   AGE
default           Active   2d
kube-node-lease   Active   2d
kube-public       Active   2d
kube-system       Active   2d
[root@K8s-master ~]# kubectl create ns dev  #创建一个名称为dev的名称空间
namespace/dev created
[root@K8s-master ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   2d
dev               Active   4s
kube-node-lease   Active   2d
kube-public       Active   2d
kube-system       Active   2d
[root@K8s-master ~]# kubectl run test --image nginx -n dev #在dev命名空间中创建了一个名test的Pod
pod/test created
[root@K8s-master ~]# kubectl get pod -n dev -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE   READINESS GATES
test    1/1     Running   0          42s   10.244.2.4   k8s-node-02   <none>           <none>
[root@K8s-master ~]# kubectl delete pod test -n dev  #删除pod
pod "test" deleted
[root@K8s-master ~]# kubectl delete ns dev   #删除名称空间
namespace "dev" deleted

1.3.2 命令式对象配置

1.3.2.1 查看apiVersion版本
[root@K8s-master ~]# kubectl explain namespace.apiVersion
KIND:     Namespace
VERSION:  v1
​
FIELD:    apiVersion <string>
​
DESCRIPTION:
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
1.3.2.2 编写TAML文件创建命名空间
[root@K8s-master ~]# vim nginxpod.yml
---
apiVersion: v1
kind: Namespace
metadata:
  name: dev
​
[root@K8s-master ~]# kubectl create -f nginxpod.yml 
namespace/dev created
[root@K8s-master ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   2d1h
dev               Active   7s
kube-node-lease   Active   2d1h
kube-public       Active   2d1h
kube-system       Active   2d1h
1.3.2.3 编写TAML文件创建Pod
[root@K8s-master ~]# kubectl explain Pod    #查帮助
kubectl explain Pod.metadata #一层一层的看
kubectl explain Pod.spec
​
[root@K8s-master ~]# vim pod.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: dev
spec:
  containers:
    - name: nginx-containers
      image: nginx:1.17.1
​
[root@K8s-master ~]# kubectl create -f pod.yml 
pod/nginxpod created
[root@K8s-master ~]# kubectl get pod -n dev -o wide 
NAME       READY   STATUS    RESTARTS   AGE    IP           NODE          NOMINATED NODE   READINESS GATES
nginxpod   1/1     Running   0          2m1s   10.244.2.6   k8s-node-02   <none>           <none>
[root@K8s-master ~]# kubectl describe pod nginxpod -n dev  #查看详细信息
Name:         nginxpod
Namespace:    dev
Priority:     0
Node:         k8s-node-02/192.168.110.23
Start Time:   Mon, 06 May 2024 15:37:42 +0800
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.244.2.6
IPs:
  IP:  10.244.2.6
Containers:
  nginx-containers:
    Container ID:   containerd://289c686267b373fe722c6f6c43a922b5bfae1732cb73208e0d0a4c8fc910daa3
    Image:          nginx:1.17.1
    Image ID:       docker.io/library/nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 06 May 2024 15:38:48 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vnk9w (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-vnk9w:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  2m42s  default-scheduler  Successfully assigned dev/nginxpod to k8s-node-02
  Normal  Pulling    2m41s  kubelet            Pulling image "nginx:1.17.1"
  Normal  Pulled     96s    kubelet            Successfully pulled image "nginx:1.17.1" in 1m4.92839306s
  Normal  Created    96s    kubelet            Created container nginx-containers
  Normal  Started    96s    kubelet            Started container nginx-containers
​
[root@K8s-master ~]# kubectl delete -f nginxpod.yml   #删除
namespace "dev" deleted

总结:命令式对象配置的方式操作资源,可以简单的认为:命令 + yaml配置文件(里面是命令需要的各种参数)

1.3.3 声明式对象配置

声明式对象配置是 Kubernetes 中的一种资源管理方法,它允许用户通过声明资源的期望状态来配置系统。这种方法与命令式对象配置形成对比,其中命令式配置侧重于执行特定的操作来达到某种状态。声明式配置的核心概念如下:

  • 声明资源的期望状态:用户通过 YAML、JSON 或其他格式的配置文件来描述资源的期望状态,而不是指定如何达到该状态的具体步骤。

  • 使用 kubectl apply:使用 kubectl apply -f <filename> 命令来应用配置文件中定义的资源状态。如果资源已经存在,kubectl apply 将更新资源以匹配配置文件中的描述;如果资源不存在,它将创建新的资源。

  • 资源版本控制:声明式配置利用 Kubernetes 的资源版本控制机制(通过 metadata.resourceVersion 字段)来确保一致性和避免冲突。当用户尝试应用一个旧的或过时的配置时,系统会检测到版本不匹配并拒绝应用,从而避免潜在的冲突。

  • 幂等性:声明式配置是幂等的,这意味着多次应用相同的配置文件将保持资源状态不变,不会导致意外的错误或副作用。

  • 自动化处理:Kubernetes 系统会自动处理配置文件中声明的状态,无需用户介入。这包括创建、更新、删除和滚动更新资源。

  • 记录和审计:由于声明式配置通过配置文件记录资源的期望状态,它便于审计和记录资源变更历史。

[root@K8s-master ~]# kubectl apply -f nginxpod.yml 
namespace/dev created
[root@K8s-master ~]# kubectl apply -f  pod.yml 
pod/nginxpod created
​
[root@K8s-master ~]# vim pod.yml   #更改文件
---
apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: dev
spec:
  containers:
    - name: nginx-containers
      image: nginx
​
[root@K8s-master ~]# kubectl apply -f pod.yml   #会重新配置,如果是create必须先删除
pod/nginxpod configured
  • 创建资源:如果资源不存在,kubectl apply 会根据 YAML 文件中的定义来创建资源。这与 kubectl create 命令的功能相似。

  • 更新资源:如果资源已经存在,kubectl apply 会将资源更新为 YAML 文件中定义的状态。这与 kubectl patch 命令的功能相似,但 kubectl apply 会更全面地更新资源,包括所有字段,而不仅仅是指定的字段。

1.3.4 再node节点上运行kubectl

[root@K8s-node-01 ~]# kubectl get pod  #正常是无法运行的
The connection to the server localhost:8080 was refused - did you specify the right host or port?
​
#只需将master点的 ~/.kube/ 目录(Kubernetes 配置目录)复制到node节点上 
[root@K8s-master ~]# scp -r ~/.kube/ K8s-node-02:~
[root@K8s-master ~]# scp -r ~/.kube/ K8s-node-02:~
​
[root@K8s-node-01 ~]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          69m

1.3.5 推荐管理方式

1.3.5.1 创建/更新资源
  • 声明式对象配置:使用 kubectl apply -f XXX.yaml 命令来创建或更新资源。这种方法允许你通过 YAML 文件来定义资源的期望状态,然后 Kubernetes 集群会根据这些定义来创建或更新资源。

1.3.5.2 删除资源
  • 命令式对象配置:使用 kubectl delete -f XXX.yaml 命令来删除资源。这种方法允许你直接在命令行中指定要删除的资源,而无需定义资源的期望状态。

1.3.5.3 查询资源
  • 命令式对象管理:使用 kubectl getkubectl describe 命令来查询资源的状态。这些命令允许你直接在命令行中查看资源的当前状态,而无需定义资源的期望状态。

相关推荐

  1. Kubernetes学习笔记-Part.04 资源规划

    2024-05-09 15:26:08       35 阅读
  2. Kubernetes基础(二十九)-资源预留

    2024-05-09 15:26:08       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-09 15:26:08       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-09 15:26:08       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-09 15:26:08       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-09 15:26:08       20 阅读

热门阅读

  1. redux实现原理

    2024-05-09 15:26:08       13 阅读
  2. 算法精讲:冒泡排序

    2024-05-09 15:26:08       13 阅读
  3. C++类型与声明

    2024-05-09 15:26:08       14 阅读
  4. 每天一个数据分析题(三百一十三)-漏斗模型

    2024-05-09 15:26:08       16 阅读
  5. var, let, const 的区别

    2024-05-09 15:26:08       12 阅读
  6. poker(typescript版)

    2024-05-09 15:26:08       13 阅读
  7. (六)Linux的Shell编程(下)

    2024-05-09 15:26:08       11 阅读
  8. 点击菜单改变svg图标颜色

    2024-05-09 15:26:08       11 阅读
  9. GUIDELINES FOR THE PREPARATION OF FINAL YEAR PROJECT REPORT

    2024-05-09 15:26:08       10 阅读
  10. 头歌python本月天数

    2024-05-09 15:26:08       8 阅读