每天5分钟玩转K8S (看书笔记)
文章目录
- 第3章 部署k8s集群
- 安装docker
- 安装kubeadm,kubelet,kubectl
- 使用kubeadm创建集群
- 1.kubeadm初始化创建master
- 2.配置kubectl
- 3.安装pod网络
- 4.添加node节点
- 总结
- 第5章 运行应用
- Deployment
- DaemonSet
- Job
- 第6章 通过service访问pod
- 创建service
- 通过dns访问Service
- 访问service
- 第八章 health check
- 默认检测
- liveness探测
- readiness探测
- 三者的区别
- health check在扩容和更新中的作用
- 第九章 数据管理
- Volume
- emptyDir
- hostPath
- 外部Storage Provider
- Pv和Pvc
- 回收pv
- Pv动态供给
- 实例
- 第10章 Secret和Configmap
- Secret
- 创建Secret
- 在pod中使用Secret
- ConfigMap
- 创建ConfigMap
- 使用ConfigMap
- 第11章 Helm K8s的包管理器
- 安装Helm3
- Helm3常用指令
- 创建Chart
- Chart.yaml
- values.yaml
- 搭建本地repo
- 使用chartmuseum镜像搭建repo仓库
- 第12章 网络
- k8s网络模型
- 1. pod内容器之间通信
- 2. pod之间通信
- 3. pod和service之间通信
- 4. 外部访问
- 各种网络方案
第3章 部署k8s集群
安装docker
安装kubeadm,kubelet,kubectl
使用kubeadm创建集群
1.kubeadm初始化创建master
kubeadm init --apiserver-advertise-address 192.168.56.105 --pod-network-cidr=10.244.0.0/16
–apiserver-advertise-address 指明了使用master与其他节点的通信ip
–pod-network-cidr 指定pod网络的范围。
2.配置kubectl
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl 需要通过这个config文件访问K8s的apiserver,来获取集群的信息。
KUBECONFIG=xxx.conf kubectl get pods
所以使用不同的配置文件,就可以访问不同的集群
3.安装pod网络
没有pod网络,集群中的pod就不能相互通信。K8s有多种网络
flannel
创建flannel网络
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Cannal
4.添加node节点
在node节点上执行
kubeadm join --token xxxx 192.168.56.105:6443
token是master节点 kubeadm init时创建。可以通过kubeadm token list获取。
总结
k8s的组件都是由kubeadm控制,从官方库下载的镜像,然后运行的容器。他们都是k8s中的pod,属于集群中的一部分。
kubelet是唯一没有以容器形式运行的k8s组件。以systemd服务运行。
第5章 运行应用
Deployment
k8s支持两种创建资源的方式
- 使用命令创建
kubectl run nginx-deployment --image=nginx:1.9.1 --replicas2
- 使用配置文件
apiVersion: apps/v1 #apiserver版本,每个版本内功能可能不相同
kind: Deployment #资源类型
metadata: #deployment元数据,name是必要元数据项name: bxy-local-nginxnamespace: kube-system #命名空间
spec: #deployment资源清单replicas: 1 #副本数量selector: #(必须项)保证和pod标签一致即可matchLabels:k8s-app: bxy-local-nginx-labeltemplate: #pod模板metadata: #pod元数据,至少有一个labellabels: #pod标签(必需项)k8s-app: bxy-local-nginx-labelspec: #pod规格imagePullSecrets:- name: regcredcontainers: #容器描述,name和image是必须- name: bxy-local-nginximage: mirrors.tencent.com/tcnp_tkestack/busybox:latestimagePullPolicy: IfNotPresent #如果本地没有则拉取镜像库volumeMounts: #挂载卷配置- mountPath: /echo_dir #挂载容器目录name: bxy-local-pv-volume #绑定的pv名称,和volumes.name一致args:- /bin/sh- -c- echo "hello world" > /echo_dir/hello; sleep 3000volumes: #pv描述- name: bxy-local-pv-volume #pv名称 persistentVolumeClaim:claimName: bxy-local-pvc-volume #绑定的pvc名称
kubectl apply -f nginx.yml 应用nginx.yml配置文件
kubectl delete -f nginx.yml 或者 kubectl delete deployment_name 删除deployment
kubectl describe pod -n namespace 查看pod的详细情况
- 将master变成node使用。
kubectl tain node k8s-master node-role.kubernetes.io/master- 将master配置成nodekubectl tain node k8s-master node-role.kubernetes.io/master="":NoSchedule 恢复master only
- 使用label控制pod位置
- 通过label将pod部署到指定node
- 1.给node添加标签
kubectl label node k8s-node1 disktype=ssd 添加标签 kubectl label node k8s-node1 disktype- 删除标签
- 2.修改deployment配置
spec:containers:- name:nginximage: nginx:1.0.9nodeSelector:disktype: ssd
- 直接指定部署的node
spec:nodename: k8s-node1
nodename就是主机名,修改主机名
kubectl --hostname-override=node1
DaemonSet
DaemonSet的不同之处,每个node只能运行一个副本,一般用于监控daemon,日志收集daemon,存储daemon.
Job
容器分为服务型和工作型,服务型需要一直运行,工作型一次性任务,完成后容器退出。
第6章 通过service访问pod
pod内的容器共享同一个ip和端口空间,他们之间可以使用localhost通信。类似于同一个机器上的不同进程。
每一个pod都会分配一个IP,这个ip只能被集群内的容器和节点访问。
Pod可能会频繁地销毁和创建,也就是说Pod的IP不是固定的。为了解决这个问题,Service提供了访问Pod的抽象层。无论后端的Pod如何变化,Service都作为稳定的前端对外提供服务。同时,Service还提供了高可用和负载均衡功能,Service负责将请求转发给正确的Pod。
创建service
apiVersion: apps/v1
kind: Service
metadata:name: nginx-service
spec:type: NodePortselector:app: nginx-test #pod标签ports:- protocol: TCPport: 8080 #将service端口映射到pod的80端口targetPort: 80nodePort: 30326 #将service的8080端口绑定到宿主机的30326端口,这样外网机器就能通过宿主机的30326访问pod
转发pod ip: 集群中的pod通过ip相互访问。现假设pod1通过pod2的ip1来访问服务,现在Pod2重启,分配了一个新的ip2。于是为了访问pod2,就需要修改pod1的访问配置,这显然是不合理的。service可以映射一组pod,k8s会维护service和pod的映射关系。无论pod如何变化,service的ip都不会变,所以客户端只需要通过service就能访问到pod。
通过dns访问Service
集群中的pod除了通过service的ip访问之外,还可以使用dns访问。
kubeadm部署kube-dns组件,每当有新的service创建,就会在dns组件中添加service - dns记录。集群中的pod通过<server_name>.就能访问service。
访问service
k8s提供了多种访问service的方法
- ClusterIP: service通过集群内部的ip对外提供服务,只有集群内的容器和节点可以访问。(内部访问)
- NodePort: 在主机上绑定一个代理端口,通过主机网络访问集群service和pod。 (外部访问)
- LoadBalanceer:通过云服务商提供的load balance对外提供服务。cloud provider负责将流量导向service。该方法主要是部署在云上使用。例如腾讯云,阿里云等。 (外部访问)
第八章 health check
k8s提供了健康检测主要有三种
默认检测
只要容器启动指令返回值不为0就重启
apiVersion: apps/v1
kind: pod
metadata:labels:test: healthcheckname: healthcheck
spec:restartPlicy: OnFailurecontainers:- name: healthcheckimage: busyboxargs:- /bin/bash- -c- sleep 1; exit 1
liveness探测
探测指令执行失败,返回非零,重启容器
spec:restartPlicy: OnFailurecontainers:- name: healthcheckimage: busyboxargs:- /bin/bash- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600livenessProbe:exec:command:- cat- /tmp/healthyinitialDelaySeconds: 10 #10s后开始探测periodSeconds: 5 #探测间隔5s
readiness探测
探测指令执行失败,返回非零,把pod从service负载均衡中剔除。
spec:restartPlicy: OnFailurecontainers:- name: healthcheckimage: busyboxargs:- /bin/bash- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600redinessProbe:exec:command:- cat- /tmp/healthyinitialDelaySeconds: 10 #10s后开始探测periodSeconds: 5 #探测间隔5s
三者的区别
- 默认探测是保证容器成功启动。如果容器启动失败,就会重启。
- liveness探测的情况,用于容器启动成功,但是有故障,无法正常提供服务。通过探测发现故障容器,并重启。
- readiness探测的情况是,容器启动成功,当前可能还没有做好准备(或者故障),则该pod不会被加入到service负载均衡中。
- 1关注的是容器启动指令,2,3关注的是探测指令。
health check在扩容和更新中的作用
spec:containers:- name: webimage: myhttpdports:- containerPort: 8080readlinessProbe:httpGet:scheme: HTTPpath: /healthyport: 8080initialDelaySeconds: 10periodSeconds: 5
httpGet探测判断成功的条件是http请求返回的代码在200~400之间。
在扩容和更新的过程中,新的pod启动需要一段时间准备,通过探测可以知道当前pod服务是否准备好了,如果服务准备好了,就可以加入到负载均衡中。
第九章 数据管理
Volume
emptyDir
emptyDir volume 生命周期和pod一致
pod的所有容器都共享volume,他们可以指定各自的mount路径。
spec:containers:- name: producerimage: busyboxvolumeMouts: #挂载volume- mountPath: /producer_dirname: shared-volumeargs:- /bin/bash- -c- echo "hello world" > /producer_dir/hello; sleep 3000- name: consumerimage: busybox- mountPath: /consumer_dirname: shared-volumeargs:- /bin/bash- -c- cat /consumer_dir/hello; sleep 3000volumes: #创建volume- name: shared-volumeemptyDir: {}
hostPath
把node宿主机上的目录挂载给容器。一般不会用这种,增加了pod和节点的耦合。
volumeMouts: #挂载volume- mountPath: /producer_dirname: k8svolumes: - name: k8shostPath:path: /etc/k8s #宿主机目录
外部Storage Provider
如果k8s部署在公有云上,可以直接使用云硬盘作为volume
Pv和Pvc
在实际生产中,12两种方案都不适用。使用3方案,在编写yml的时候,必须知道volume的信息。而pod通常由开发人员维护,而volume通常由存储系统的管理人员负责。也就是说开发人员要总是去问管理人员新的volume信息。这显然是不合理的,于是k8s给出了pv和pvc的解决方案。
- pv(PersistentVolume)是外部存储系统中的一块存储空间。由管理源创建和维护,生命周期独立于pod。
- pvc(PersistentVolumeClaim) 是对pv的申请。由普通用户创建和维护。
管理人员提前创建pv,然后开发人员创建pvc指明存储资源的容量大小和访问模式等信息。K8s就会查找并提供满足条件的pv。
PV
apiVersion: v1
kind: PersistentVolume
metadata:name: mypv1labels:name: nfs
spec:capacity:storage: 1Gi #PV容量accessModes: - ReadWriteOncepersistentVolumeReclaimPolicy: RecyclestorageClassName: nfs-namenfs:path: /nfsdata/pv1server: 192.168.56.105**** 本地文件作为存储资源volumeMode: FilesystemstorageClassName: local-namelocal:path: /data/home/waynebfhu/k8s/pv1
- accessModes指定访问模式为ReadWriteOnce,支持的访问模式有3种:ReadWriteOnce表示PV能以read-write模式mount到单个节点,ReadOnlyMany表示PV能以read-only模式mount到多个节点,ReadWriteMany表示PV能以read-write模式mount到多个节点
- storageClassName指定PV的class为nfs。相当于为PV设置了一个分类,PVC可以指定class申请相应class的PV。
PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: mypvc1
spec:accessModes:- ReadWriteOncevolumeMode: Filesystemresources:requests:storage: 1GistorageClassName: nfsselector:matchLabels:name: nfs
pvc创建成功后,pv就和pvc绑定在一起了。之后就是在pod中使用存储了
Pod.yml
spec:containers:volumeMounts:- mountPath: "/mydata"name: mydatavolumes:- name: mydatapersistentVolumeClaim:claimName: mypvc1
回收pv
删除pvc,pv就会被回收。
persistentVolumeReclaimPolicy: Recycle pv回收后,数据被删除。 Retain 则数据保留。
Pv动态供给
动态供给是指StorageClass动态创建Pv
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: name: standard
provisioner: kubernetes.io/no-provisioner
parameters:type: gp2
reclaimPolicy: Retain
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: name: slow
provisioner: kubernetes.io/no-provisioner
parameters:type: io1zones: us-east-1diopsPerGB: "10"
reclaimPolicy: Retain
provisioner 指定了生成aws ebs
pvc和pv中的storageClassName 就是指的上述metada中的name,也就是standard和slow
实例
mysql数据库,可以把数据库数据存放到pv中。当pod1故障后,切换新的pod,重新读取pv中的数据。
第10章 Secret和Configmap
在实际生产中,我们应该实现配置文件和容器分离。
例如密码,token等敏感信息,可以使用Secret。其他的不敏感信息,可以使用Configmap保存。
Secret
创建Secret
(1)通过–from-env-file
cat << EOF > secret.txt
username=admin
password=123456
EOF
kubectl create secret generic mysecret --from-env-file=secret.txt
文件中的每行key-value对应一个信息条目
(2)通过YAML配置文件
apiVersion: v1
kind: Secret
metadata:name: mysecret
data:username: YWRtaW4=password: MTIzNDU2
文件中的敏感数据必须通过base64编码后的结果。
echo -n admin | base64
echo -n YWRtaW4=| base64 --decode 反编码
kubectl edit secret mysecret 查看mysecret
在pod中使用Secret
(1)volume形式
spec:volumeMounts:- name: foomountPath: "/etc/foo"readOnly: true
volumes:
- name: foosecret: secretName: mysecret
在pod的/etc/foo目录下会根据key分别生成名为username和password的两个文件,文件内容就是之前设置的value。
也可以自定义文件名
volumes:
- name: foosecret:secretName: mysecretitems:- key: usernamepath: my-username-key: passwordpath: my-password
(2)环境变量形式
env:- name: SECRET_USERNAME # 环境变量名valueFrom:secretKeyRef:name: mysecretkey: username # 变量值 - name: SECRET_PASSWORDvalueFrom:secretKeyRef:name: mysecretkey: password
ConfigMap
创建ConfigMap
(1)通过–from-env-file
cat << EOF > secret.txt
username=admin
password=123456
EOF
kubectl create secret generic myconfig --from-env-file=secret.txt
文件中的每行key-value对应一个信息条目
(2)通过YAML配置文件
apiVersion: v1
kind: Secret
metadata:name: myconfig
data:username: adminpassword: 123456
明文形式
使用ConfigMap
(1) Volume形式使用
spec:volumeMounts:- name: foomountPath: "/etc/foo"readOnly: true
volumes:
- name: fooconfigMap:name: myconfigitems:- key: logging.confpath: myapp/logging.conf
文件会被创建在pod的/etc/foo/myapp/logging.conf
(2)环境变量形式
env:- name: CONF_USERNAME # 环境变量名valueFrom:configMapKeyRef:name: myconfigkey: username # 变量值 - name: CONF_PASSWORDvalueFrom:configMapKeyRef:name: myconfigkey: password
第11章 Helm K8s的包管理器
k8s是用来管理容器的,通过K8S的文件控制容器的部署。
helm是用来管理k8s的容器部署文件的。就是说将所有的k8s容器部署文件打包给helm管理。
也就是说k8s用来管理容器
helm用来管理k8s的
安装Helm3
Helm3和Helm2的区别比较大,且不兼容。所以后续我们都使用Helm3
# 下载helm3,解压并拷贝到/usr/local/bin目录下
wget https://get.helm.sh/helm-v3.5.3-linux-amd64.tar.gz
tar -zxvf helm-v3.5..3-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
或者
sudo curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
已经不再使用helm stable仓库了。而是迁移到artifact hub。artifact hub不是一个仓库,而是所有charts仓库的入口。
命令补全
# 在~/.bashrc 中加入
source <(helm completion bash)
Helm3常用指令
helm repo add bitnami https://charts.bitnami.com/bitnami #添加repo库
helm search repo stable #查找charts
helm install stable/mysql --generate-name #通过helm安装release
helm uninstall stable/mysql #卸载release
helm ls #查看用helm安装的release
helm show all stable/mysql #查看详情
helm pull stable/mysql #下载charts
helm search repo [reponame] #查看库里面的镜像
helm create mychart #创建chart
helm package mychart #打包chart包,生成tgz文件
helm push mychart/mychart.0.1.tgz localrepo #上传chart包到repo仓库
创建Chart
创建一个Chart,分为两个步骤
- 创建docker镜像
- 创建chart
helm create chart.name 创建chart模板,修改该模板就能创建我们自己的chart
Chart.yaml
应用更新就是修改该文件
apiVersion: v2
name: hello-helm
description: A Helm chart for Kubernetes# 分为application 和 library
type: application# chart的版本号,每次修改了chart都要修改当前版本
version: 0.1.0 # 容器tag
appVersion: "1.0.4"
values.yaml
用来描述chart配置的文件,会根据该配置生成对应的 k8s管理文件
replicaCount: 1image:repository: dev.registry.works:30984/hello-hw #镜像pullPolicy: IfNotPresent #拉取镜像的规则# Overrides the image tag whose default is the chart appVersion.tag: ""imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""serviceAccount:# Specifies whether a service account should be createdcreate: true# Annotations to add to the service accountannotations: {}# The name of the service account to use.# If not set and create is true, a name is generated using the fullname templatename: ""podAnnotations: {}podSecurityContext: {}# fsGroup: 2000securityContext: {}# capabilities:# drop:# - ALL# readOnlyRootFilesystem: true# runAsNonRoot: true# runAsUser: 1000service:type: ClusterIPport: 80ingress:enabled: falseannotations: {}# kubernetes.io/ingress.class: nginx# kubernetes.io/tls-acme: "true"hosts:- host: chart-example.localpaths:- path: /backend:serviceName: chart-example.localservicePort: 80tls: []# - secretName: chart-example-tls# hosts:# - chart-example.localresources: {}# We usually recommend not to specify default resources and to leave this as a conscious# choice for the user. This also increases chances charts run on environments with little# resources, such as Minikube. If you do want to specify resources, uncomment the following# lines, adjust them as necessary, and remove the curly braces after 'resources:'.# limits:# cpu: 100m# memory: 128Mi# requests:# cpu: 100m# memory: 128Miautoscaling:enabled: falseminReplicas: 1maxReplicas: 100targetCPUUtilizationPercentage: 80# targetMemoryUtilizationPercentage: 80nodeSelector: {}tolerations: []affinity: {}
搭建本地repo
Helm chart对仓库的要求并不高,需要你对外提供yaml文件和tar文件的web服务即可.
使用chartmuseum镜像搭建repo仓库
chartmuseum镜像给我们提供了repo仓库的功能。
mkdir /opt/charts #创建repo库的文件存放目录docker run -d \-p 4002:8080 \-e DEBUG=1 \-e STORAGE=local \-e STORAGE_LOCAL_ROOTDIR=/charts \-v /opt/charts:/charts \chartmuseum/chartmuseum:latestcurl localhost:4002/api/charts
{} 测试repo是否搭建完成,如果能正确访问,搭建成功helm repo add myrepo http://9.134.35.171:4002 #添加库
第12章 网络
k8s网络模型
Kubernetes采用的是基于扁平地址空间的网络模型,集群中的每个Pod都有自己的IP地址,Pod之间不需要配置NAT就能直接通信。另外,同一个Pod中的容器共享Pod的IP,能够通过localhost通信。应用可以非常方便地从传统网络迁移到Kubernetes。每个Pod可被看作是一个个独立的机器,而Pod中的容器则可被看作同一机器中的不同进程。
K8S的网络模型分为4个部分
1. pod内容器之间通信
pod内的容器共享同一个本地文件系统,IPC和网络空间。他们之间直接使用localhost:port通信
2. pod之间通信
pod之间通过集群给的ip通信
3. pod和service之间通信
在Kubernetes集群中,Pod可能会频繁地销毁和创建,也就是说Pod的IP不是固定的。为了解决这个问题,Service提供了访问Pod的抽象层。无论后端的Pod如何变化,Service都作为稳定的前端对外提供服务。同时,Service还提供了高可用和负载均衡功能,Service负责将请求转发给正确的Pod。
4. 外部访问
k8s提供了两种外界访问pod的方式:
- NodePort Service通过绑定宿主机的端口,对外提供服务。
- LoadBalancer Service利用cloud provider提供的load balancer对外提供服务,cloud provider负责将load balancer的流量导向Service。目前支持的cloudprovider有GCP、AWS、Azur等。
各种网络方案
为了保证网络方案的标准化、扩展性和灵活性,Kubernetes采用了ContainerNetworking Interface(CNI)规范。
目前已有多种支持Kubernetes的网络方案,比如Flannel、Calico、Canal、Weave Net等。因为它们都实现了CNI规范,用户无论选择哪种方案,得到的网络模型都一样。都必须实现网络模型的4种通信情况。
每天5分钟玩转K8S (看书笔记)相关推荐
- 每天五分钟玩转K8S(一)
k8s的安装 总体基于<每天5分钟玩转k8s>这本书,主要是里面有些地方容易有坑,所以想将里面可能有坑的地方记录下来,为其他使用这本书的读者可以避免踩坑.(主要是有些坑坑了我好久T_T)博 ...
- MMU内存管理单元(看书笔记)
http://note.youdao.com/noteshare?id=8e12abd45bba955f73874450e5d62b5b&sub=D09C7B51049D4F88959668B ...
- Javascript权威指南看书笔记
Javascript权威指南看书笔记 第一章 词法结构 javascript区分大小写,而html不区分大小写 unicode转义序列是由/u为前缀加4位16进制数组成 标识符必须以字母,下划线 _, ...
- 读书笔记-每天5分钟玩转k8s
一.K8s基本概念 一.Pod Pod 是容器的集合,通常会将紧密相关的一组容器放到一个 Pod 中,同一个 Pod 中的所有容器共享 IP 地址和 Port 空间,也就是说它们在一个 network ...
- 每天五分钟玩转K8S(十一)
今天我们来了解一下k8s的网络,上网搜了一下,原来k8s的网络水非常深,书上的介绍只是冰山一角.如果有兴趣继续了解的话,需要翻阅其他的资料才行. 可以看看这个,有介绍各种主流的cnihttps://w ...
- 每天五分钟玩转K8S(二)
接着上一篇,在安装完k8s后,就要开始对他进行折腾了!! 今天我们要做的就是对k8s的架构进行简单的学习(超级简单). 一.master节点 k8s cluster由master和node组成,节点上 ...
- vbs学习,书籍,看书笔记(4.2)正则表达式
正则表达式 导航 1.初识正则表达式,语法 2.将搜索的字符串,以及要搜索的关键字,还有要修改的都变为自己输入 3.添加新属性global 4.三个属性三个方法 Execute(要搜索的字符串) 第三 ...
- MYSQL 看书笔记
ACID 原子性(Atomicity).一致性(Consistentcy).隔离性(Isolation).持久性(Durability) 转载于:https://www.cnblogs.com/xwb ...
- 《c语言从入门到精通》看书笔记——第16章 网络套接字编程(下)——套接字
1.套接字概述 套接字是网络通信的基石,是网络通信的基本构件. 所谓套接字,实际上是一个指向传输提供者的句柄.在WinSock中,就是通过操作该句柄来实现网络通信和管理的.根据性质和作用不同,套接字可 ...
最新文章
- python中指定变量为1byte_Python读字节某一位的值,设置某一位的值,二进制位操作...
- 2020了,最流行的密码依旧是123456
- 【Java】Java 集合 可视化 在线演示 环境
- Nginx 是如何实现高并发?常见的优化手段有哪些?
- android 成长日记 3.关于Activity的用户体验提升办法和使用技巧说明
- pku 1276 Cash Machine 多重背包
- 小程序Table样式
- labwindows的学习资料、方法、安装包
- 玩转Redis-8种数据淘汰策略及近似LRU、LFU原理
- iOS控件使用和多样布局
- 如何搜集你想要的信息
- html实现点赞动画效果代码,Twitter“点赞”红心按钮CSS3动画特效
- python转写java踩坑记录
- 【《Multimodal Transformer for Unaligned Multimodal Language Sequences》论文翻译】
- yyyymmddhhmmss时间格式12小时制24小时制区别
- Kafka消费组rebalance原理
- 蔡司镜头的魅力:vivo X60 Pro评测体验
- 教材征订管理系统c语言,基于C语言的图书管理系统的设计与实现范文.doc
- 【DE三维路径规划】基于matlab改进的差分算法多无人机协同三维路径规划【含Matlab源码 169期】
- 浅谈航天磁电企业MES软件系统的运用
热门文章
- python判断字符串是否为大写字母、小写字母
- TCPIP详解Protocol 读书笔记(八) Traceroute程序
- 微信支付分 - 完结支付分订单API
- 计算机网络atm功能,自考计算机网络实用技术考核知识点之ATM原理
- ORACLE 按照指定的ID 顺序排序
- 海外社交媒体平台如何选择
- erlang使用httpc:request报错nxdomain
- Win10、Win11跳过联网注册微软账户激活方法
- 石头、纸、剪刀小游戏(剪刀石头布?)
- python socket清空接收缓冲区_Python网络编程——修改套接字发送和接收的缓冲区大小...