博客链接:使用 kubeadm 创建高可用 Kubernetes 及外部 etcd 集群

前言

Kubernetes 的官方中文文档内容全面,表达清晰,有大量示例和解析

无论任何情况下都推荐先花几个小时通读官方文档,来了解配置过程中的可选项,以及可能会遇到哪些问题

本文基于官方文档中 入门 - 生产环境 一章来整理部署流程

Kubernetes 文档 | Kubernetes

架构

  • OS: Debian 12
  • CGroup Driver: systemd
  • Container Runtime: containerd
  • CNI: Calico
  • Kubernetes: v1.32.0

注意

所有节点服务器都需要关闭 swap

  • Other

    • 说明

      • 该服务器运行 K8S 外部应用,包括 Nginx、Nexus 等
      • 该服务器运行的所有业务通过 docker-compose 管理
      • 与 K8S 自身配置相关的步骤说明中的“所有节点”不包括该服务器
    • Server
      • vCPU: 2
      • Memory: 4G
    • Network: 192.168.1.100 2E:7E:86:3A:A5:20
    • Port:
      • 8443/tcp: 向集群提供 Kubernetes APIServer 负载均衡
  • Etcd
    • Server

      • vCPU: 1
      • Memory: 1G
    • Network
      • Etcd-01: 192.168.1.101 2E:7E:86:3A:A5:21
      • Etcd-02: 192.168.1.102 2E:7E:86:3A:A5:22
      • Etcd-03: 192.168.1.103 2E:7E:86:3A:A5:23
    • Port:
      • 2379/tcp: etcd HTTP API
      • 2380/tcp: etcd peer 通信
  • Master
    • Server

      • vCPU: 4
      • Memory: 8G
    • Network
      • Master-01: 192.168.1.104 2E:7E:86:3A:A5:24
      • Master-02: 192.168.1.105 2E:7E:86:3A:A5:25
      • Master-03: 192.168.1.106 2E:7E:86:3A:A5:26
    • Port:
      • 179/tcp: Calico BGP
      • 6443/tcp: Kubernetes APIServer
      • 10250/tcp: kubelet API
  • Node
    • Server

      • vCPU: 4
      • Memory: 8G
    • Network
      • Node-01: 192.168.1.107 2E:7E:86:3A:A5:27
      • Node-02: 192.168.1.108 2E:7E:86:3A:A5:28
      • Node-03: 192.168.1.109 2E:7E:86:3A:A5:29
    • Port:
      • 179/tcp: Calico BGP
      • 10250/tcp: kubelet API

配置基础环境

说明

所有节点

apt update
apt upgrade
apt install curl apt-transport-https ca-certificates gnupg2 software-properties-common vim curl -fsSL https://mirrors.ustc.edu.cn/kubernetes/core:/stable:/v1.32/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.ustc.edu.cn/kubernetes/core:/stable:/v1.32/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.ustc.edu.cn/docker-ce/linux/debian bookworm stable" | tee /etc/apt/sources.list.d/docker.list apt update apt install containerd.io mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml systemctl restart containerd apt install kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

开启 ipv4 转发

编辑 /etc/sysctl.conf,找到下方配置并取消注释

net.ipv4.ip_forward=1

执行 sysctl -p 应用配置

创建 crictl 配置

cat << EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF

如果需要通过代理服务器访问容器仓库,需要为 containerd 配置代理服务

mkdir -p /etc/systemd/system/containerd.service.d
cat << EOF > /etc/systemd/system/containerd.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://username:password@proxy-server-ip:port"
Environment="HTTPS_PROXY=http://username:password@proxy-server-ip:port"
Environment="NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
EOF systemctl daemon-reload
systemctl restart containerd.service

已知问题

使用 systemd 作为 CGroup Driver 且使用 containerd 作为 CRI 运行时

需要修改 /etc/containerd/config.toml,添加如下配置

相关文章:配置 systemd cgroup 驱动 | Kubernetes

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true

执行 systemctl restart containerd

参照另一篇文章的解决方案

相关文章:Why does etcd fail with Debian/bullseye kernel? - General Discussions - Discuss Kubernetes

cat /etc/default/grub

# Source:
# GRUB_CMDLINE_LINUX_DEFAULT="quiet" # Modify:
GRUB_CMDLINE_LINUX_DEFAULT="quiet systemd.unified_cgroup_hierarchy=0"

执行 update-grub 并重启

配置 etcd 节点

将 kubelet 配置为 etcd 的服务管理器

说明

所有 etcd 节点

apt update
apt install etcd-client mkdir -p /etc/systemd/system/kubelet.service.d cat << EOF > /etc/systemd/system/kubelet.service.d/kubelet.conf
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
anonymous:
enabled: false
webhook:
enabled: false
authorization:
mode: AlwaysAllow
cgroupDriver: systemd
address: 127.0.0.1
containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
staticPodPath: /etc/kubernetes/manifests
EOF cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
[Service]
Environment="KUBELET_CONFIG_ARGS=--config=/etc/systemd/system/kubelet.service.d/kubelet.conf"
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_CONFIG_ARGS
Restart=always
EOF systemctl daemon-reload
systemctl restart kubelet

为 kubeadm 创建配置文件

说明

Etcd-01 节点,由该节点向其他节点分发证书及配置

该节点同时作为 CA

生成 CA

kubeadm init phase certs etcd-ca

生成如下文件

  • /etc/kubernetes/pki/etcd/ca.crt
  • /etc/kubernetes/pki/etcd/ca.key

为方便接下来的步骤操作,先将 etcd 节点信息导出为环境变量

export HOST0=192.168.1.101
export HOST1=192.168.1.102
export HOST2=192.168.1.103 export NAME0="etcd-01"
export NAME1="etcd-02"
export NAME2="etcd-03"

为 etcd 成员生成 kubeadm 配置

HOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=(${NAME0} ${NAME1} ${NAME2}) for i in "${!HOSTS[@]}"; do HOST=${HOSTS[$i]}
NAME=${NAMES[$i]} mkdir -p /tmp/${HOST} cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
---
apiVersion: "kubeadm.k8s.io/v1beta4"
kind: InitConfiguration
nodeRegistration:
name: ${NAME}
localAPIEndpoint:
advertiseAddress: ${HOST}
---
apiVersion: "kubeadm.k8s.io/v1beta4"
kind: ClusterConfiguration
etcd:
local:
serverCertSANs:
- "${HOST}"
peerCertSANs:
- "${HOST}"
extraArgs:
- name: initial-cluster
value: ${NAMES[0]}=https://${HOSTS[0]}:2380,${NAMES[1]}=https://${HOSTS[1]}:2380,${NAMES[2]}=https://${HOSTS[2]}:2380
- name: initial-cluster-state
value: new
- name: name
value: ${NAME}
- name: listen-peer-urls
value: https://${HOST}:2380
- name: listen-client-urls
value: https://${HOST}:2379
- name: advertise-client-urls
value: https://${HOST}:2379
- name: initial-advertise-peer-urls
value: https://${HOST}:2380
EOF
done

为每个成员创建证书

kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST2}/
# Clear useless cert
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST1}/
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml # Clear ca key from member
find /tmp/${HOST2} -name ca.key -type f -delete
find /tmp/${HOST1} -name ca.key -type f -delete

将证书移动到对应的成员服务器

scp -r /tmp/${HOST2}/pki root@${HOST2}:/etc/kubernetes/
scp /tmp/${HOST2}/kubeadmcfg.yaml root@${HOST2}:~/ scp -r /tmp/${HOST1}/pki root@${HOST1}:/etc/kubernetes/
scp /tmp/${HOST1}/kubeadmcfg.yaml root@${HOST1}:~/ mv /tmp/${HOST0}/kubeadmcfg.yaml ~/ rm -rf /tmp/${HOST2}
rm -rf /tmp/${HOST1}
rm -rf /tmp/${HOST0}

此时在三台 etcd 节点中的文件结构均应如下

/root
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── ca.key # 仅 CA 节点既 etcd-01
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key

创建静态 Pod 清单

说明

所有 etcd 节点

kubeadm init phase etcd local --config=/root/kubeadmcfg.yaml

检查集群运行情况

${HOST0} 替换为想要检查的节点 ip

ETCDCTL_API=3 etcdctl \
--cert /etc/kubernetes/pki/etcd/peer.crt \
--key /etc/kubernetes/pki/etcd/peer.key \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://${HOST0}:2379 endpoint health

使用 kubeadm 创建高可用集群

说明

配置过程中需要完全重置控制平面节点的配置时,需要有至少一台能够访问集群的节点,在该节点上按如下流程操作

kubectl delete pods,nodes,namespaces,deployments,services --all --all-namespaces --force
kubectl delete -f tigera-operator.yaml --force
kubectl delete -f custom-resources.yaml --force
kubeadm reset --cleanup-tmp-dir -f
rm -rf /etc/cni/net.d/*
rm -rf ~/.kube
systemctl restart kubelet containerd

为 kube-apiserver 创建负载均衡

说明

本文中负载均衡使用 Nginx

Nginx 配置

http {
...
} stream {
upstream apiserver {
server 192.168.1.104:6443 weight=5 max_fails=3 fail_timeout=30s; # Master-01
server 192.168.1.105:6443 weight=5 max_fails=3 fail_timeout=30s; # Master-02
server 192.168.1.106:6443 weight=5 max_fails=3 fail_timeout=30s; # Master-03
} server {
listen 8443;
proxy_pass apiserver;
}
}

为控制平面节点配置外部 etcd 节点

说明

任一 etcd 节点与主控制平面节点,本文中为 Etcd-01Master-01

从集群中任一 etcd 节点复制到主控制平面节点

scp /etc/kubernetes/pki/etcd/ca.crt /etc/kubernetes/pki/apiserver-etcd-client.crt /etc/kubernetes/pki/apiserver-etcd-client.key root@192.168.1.104:~

在主控制平面节点中将文件移动到指定位置

mkdir -p /etc/kubernetes/pki/etcd
mv ~/ca.crt /etc/kubernetes/pki/etcd/
mv ~/apiserver-etcd-client.crt /etc/kubernetes/pki/
mv ~/apiserver-etcd-client.key /etc/kubernetes/pki/

创建 kubeadm-config.yaml,内容如下

  • controlPlaneEndpoint: 负载均衡服务器
  • etcd
    • external

      • endpoints: etcd 节点列表
  • networking
    • podSubnet: pod ip cidr
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.32.0
controlPlaneEndpoint: 192.168.1.100:8443
etcd:
external:
endpoints:
- https://192.168.1.101:2379
- https://192.168.1.102:2379
- https://192.168.1.103:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/24
serviceSubnet: 10.96.0.0/16

初始化主控制平面

说明

主控制平面节点,本文中为 Master-01

  • --upload-certs: 将控制平面间的共享证书上传到 kubeadm-certs Secret

    • kubeadm-certs Secret 和解密密钥将在两小时后失效
    • 如果要重新上传证书并生成新的解密密钥,需要在已加入集群的控制平面节点上执行 kubeadm init phase upload-certs --upload-certs
kubeadm init --config kubeadm-config.yaml --upload-certs

等待运行完成后应输出类似如下内容

...

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config Alternatively, if you are the root user, you can run: export KUBECONFIG=/etc/kubernetes/admin.conf You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of control-plane nodes running the following command on each as root: kubeadm join 192.168.1.100:8443 --token 7r34LU.iLiRgu2qHdAeeanS --discovery-token-ca-cert-hash sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 --control-plane --certificate-key 03d66dd08835c1ca3f128cceacd1f31ac94163096b20f445ae84285bc0832d72 Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward. Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.1.100:8443 --token 7r34LU.iLiRgu2qHdAeeanS --discovery-token-ca-cert-hash sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

先将控制台输出的以上内容保存,稍后将使用这些命令来将其他控制平面节点和工作节点加入集群

根据输出的提示,复制 kubeconfig 用于 kubectl

mkdir -p ~/.kube
cp /etc/kubernetes/admin.conf ~/.kube/config

应用 CNI 插件

由于该清单过大,kubectl apply 会产生如下报错,使用 kubectl createkubectl replace

注意

确认 custom-resources.yamlcalicoNetwork 配置的 ip cidr 与集群 podSubnet 配置一致

# kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/refs/heads/release-v3.29/manifests/tigera-operator.yaml
# The CustomResourceDefinition "installations.operator.tigera.io" is invalid: metadata.annotations: Too long: may not be more than 262144 bytes
wget https://raw.githubusercontent.com/projectcalico/calico/refs/heads/release-v3.29/manifests/tigera-operator.yaml
wget https://raw.githubusercontent.com/projectcalico/calico/refs/heads/release-v3.29/manifests/custom-resources.yaml
kubectl create -f tigera-operator.yaml
kubectl create -f custom-resources.yaml

输入以下内容查看控制平面组件 pod 启动状态

kubectl get pod -A

初始化其他控制平面

说明

除主控制平面节点外的其他控制平面节点,本文中为 Master-02 Master-03

使用 kubeadm join 命令加入集群的节点会将 KubeConfig 同步到 /etc/kubernetes/admin.conf

依照上面输出的命令,分别在其他控制平面节点中执行

  • --control-plane: 通知 kubeadm join 创建一个新控制平面
  • --certificate-key xxx: 从集群 kubeadm-certs Secret 下载控制平面证书并使用给定的密钥解密
kubeadm join 192.168.1.100:8443 --token 7r34LU.iLiRgu2qHdAeeanS --discovery-token-ca-cert-hash sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 --control-plane --certificate-key 03d66dd08835c1ca3f128cceacd1f31ac94163096b20f445ae84285bc0832d72

根据输出的提示,复制 kubeconfig 用于 kubectl

mkdir -p ~/.kube
cp /etc/kubernetes/admin.conf ~/.kube/config

初始化负载节点

说明

所有负载节点

使用 kubeadm join 命令加入集群的节点会将 KubeConfig 同步到 /etc/kubernetes/kubelet.conf

依照上面输出的命令,分别在负载节点中执行

kubeadm join 192.168.1.100:8443 --token 7r34LU.iLiRgu2qHdAeeanS --discovery-token-ca-cert-hash sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

使用 kubeadm 创建高可用 Kubernetes 及外部 etcd 集群的更多相关文章

  1. 用kubeadm创建高可用kubernetes集群后,如何重新添加控制平面

    集群信息 集群版本:1.13.1 3个控制平面,2个worker节点 k8s-001:10.0.3.4 k8s-002:10.0.3.5 k8s-003:10.0.3.6 k8s-004:10.0.3 ...

  2. 使用kubeadm搭建高可用k8s v1.16.3集群

    目录 1.部署环境说明 2.集群架构及部署准备工作 2.1.集群架构说明 2.2.修改hosts及hostname 2.3.其他准备 3.部署keepalived 3.1.安装 3.2.配置 3.3. ...

  3. kubeadm 线上集群部署(一) 外部 ETCD 集群搭建

      IP Hostname   192.168.1.23 k8s-etcd-01 etcd集群节点,默认关于ETCD所有操作均在此节点上操作 192.168.1.24 k8s-etcd-02 etcd ...

  4. 高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群

    高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群 libnet软件包<-依赖-heartbeat(包含ldirectord插件(需要perl-MailTools的rpm包)) l ...

  5. 高可用,多路冗余GFS2集群文件系统搭建详解

    高可用,多路冗余GFS2集群文件系统搭建详解 2014.06 标签:GFS2 multipath 集群文件系统 cmirror 实验拓扑图: 实验原理: 实验目的:通过RHCS集群套件搭建GFS2集群 ...

  6. 使用Kubeadm搭建高可用Kubernetes集群

    1.概述 Kubenetes集群的控制平面节点(即Master节点)由数据库服务(Etcd)+其他组件服务(Apiserver.Controller-manager.Scheduler...)组成. ...

  7. K8S 使用Kubeadm搭建高可用Kubernetes(K8S)集群 - 证书有效期100年

    1.概述 Kubenetes集群的控制平面节点(即Master节点)由数据库服务(Etcd)+其他组件服务(Apiserver.Controller-manager.Scheduler...)组成. ...

  8. 附012.Kubeadm部署高可用Kubernetes

    一 kubeadm介绍 1.1 概述 参考<附003.Kubeadm部署Kubernetes>. 1.2 kubeadm功能 参考<附003.Kubeadm部署Kubernetes& ...

  9. 容器云平台No.2~kubeadm创建高可用集群v1.19.1

    通过kubernetes构建容器云平台第二篇,最近刚好官方发布了V1.19.0,本文就以最新版来介绍通过kubeadm安装高可用的kubernetes集群. 市面上安装k8s的工具很多,但是用于学习的 ...

  10. [Kubernetes]CentOS7下Etcd集群搭建

    Etcd简要介绍 Etcd是Kubernetes集群中的一个十分重要的组件,用于保存集群所有的网络配置和对象的状态信息 Etcd构建自身高可用集群主要有三种形式: ①静态发现: 预先已知 Etcd 集 ...

随机推荐

  1. 鸿蒙应用开发从入门到入行 - 篇2:HarmonyOS开发快速基础入门

    鸿蒙应用开发从入门到入行 第二天 - 开发工具与基础组件 导读:在本篇文章里,您将掌握鸿蒙开发工具DevEco的基本使用.ArkUI里的基础组件,并通过制作一个简单界面掌握使用 鸿蒙开发工具 - De ...

  2. 依赖注入在 dotnet core 中实现与使用:5. 使用支持 Unicode 的 HtmlEncoder

    现象 在 ASP.NET Core MVC 中,当在页面中传递了一个包含中文字符串到页面的时候,页面的显示是正常的,但是如果查看页面源码,却看不到中文,变成了一串编码之后的内容. 例如,在页面中直接定 ...

  3. 【MyBatis】学习笔记10:添加功能获取自增的主键

    [Mybatis]学习笔记01:连接数据库,实现增删改 [Mybatis]学习笔记02:实现简单的查 [MyBatis]学习笔记03:配置文件进一步解读(非常重要) [MyBatis]学习笔记04:配 ...

  4. shell内置字符串替换

    shell变量赋值语法: 使用规则 解释单引号 所见即所得,即输出时会将单引号内的所有內容都原样输出,或者描述为单引号里面看到的是什么就会输出什么,这称为强引用双引号 (默认) 输出双引号内的所有内容 ...

  5. shell脚本,主要是对输入参数检验

    usage(){  echo "\nUSAGE:\n"  echo "PmActivityReport.sh\t-type\t<latency|activity&g ...

  6. 【转载】 利用p6spy拦截并查看数据库执行操作

    https://blog.csdn.net/fanxiaobin577328725/article/details/71601760 一.简介 项目首 页:http://p6spy.github.io ...

  7. ERROR: manifest for hyperledger/fabric-orderer:latest not found

    In docker command # pull to local before using itdocker pull hyperledger/fabric-orderer:x86_64-1.0.0 ...

  8. Qt编写项目作品27-多线程文件传输

    一.功能特点 多线程收发文件,支持加密传输. 接收端支持监听端口接收文件和主动连接服务器接收文件两种方式. 按照 文件开始符+文件大小+文件内容+文件结束符 逐个分包接收. 可对接收的加密过的文件包进 ...

  9. An invitation to 3-d vision: from images to geometric models英文pdf下载

    Ma Y, Soatto S, Košecká J, et al. An invitation to 3-d vision: from images to geometric models[M]. N ...

  10. 了解 ASP.NET Core 中的中间件

    在 .NET Core 中,中间件(Middleware) 是处理 HTTP 请求和响应的核心组件.它们被组织成一个请求处理管道,每个中间件都可以在请求到达最终处理程序之前或之后执行操作.中间件可以用 ...