Skip to main content

Command Palette

Search for a command to run...

Kubernetes集群搭建

Updated
Kubernetes集群搭建

Prerequisites

硬件资源

目前登录使用的是机房内的一台机器(192.168.40.50) 连接已经配好的虚拟机地址 虚拟机硬件资源如下: os版本:Ubuntu 24.04 LTS (GNU/Linux 6.8.0-31-generic x86_64) k8s版本:Kubernetes v1.30.6

将会使用kubeadm进行安装

安装前要求检测

  • 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令。

  • 每台机器 2 GB 或更多的 RAM(如果少于这个数字将会影响你应用的运行内存)。

  • 控制平面机器需要 CPU 2 核心或更多。

  • 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以)。

  • 节点之中不可以有重复的主机名、MAC 地址或 product_uuid。请参见这里了解更多详细信息。

  • 开启机器上的某些端口。请参见这里了解更多详细信息。

  • 交换分区的配置。kubelet 的默认行为是在节点上检测到交换内存时无法启动。更多细节参阅交换内存管理

  • 如果 kubelet 未被正确配置使用交换分区,则你必须禁用交换分区。例如,sudo swapoff -a 将暂时禁用交换分区。要使此更改在重启后保持不变,请确保在如 /etc/fstabsystemd.swap 等配置文件中禁用交换分区,具体取决于你的系统如何配置。

Install Steps

配置必要插件以及网络参数

k8s 需要通过ipv4来进行不同pod之间的通信

# 安装两个必要内核插件,overlay 和 br_netfilter
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
​
# 动态加载这两个模块
sudo modprobe overlay
sudo modprobe br_netfilter
​
# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF
​
# 应用 sysctl 参数而不重新启动
sudo sysctl --system
​
# 使用以下命令验证 net.ipv4.ip_forward 是否设置为 1
sudo sysctl net.ipv4.ip_forward

下载containerd service 选择 container runtime

这里选择containerd而不是docker(kubernetes新版本已将默认容器编排切换为containerd)

## 1、containerd
# 下载包
wget https://github.com/containerd/containerd/releases/download/v1.7.22/containerd-1.7.22-linux-amd64.tar.gz
​
# 将下载的包解压到/usr/local下
tar Cxzvf /usr/local containerd-1.7.22-linux-amd64.tar.gz

# 下载服务启动文件
wget -O /etc/systemd/system/containerd.service https://raw.githubusercontent.com/containerd/containerd/main/containerd.service

# 文件内容如下,下载不下来直接复制
cat /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
# 启动containerd
systemctl daemon-reload
systemctl enable --now containerd
​
## 2、Installing runc
wget https://github.com/opencontainers/runc/releases/download/v1.2.0-rc.3/runc.amd64
TODO:worker1
sudo install -m 755 runc.amd64 /usr/local/sbin/runc

containerd也可以通过apt来下载:

`sudo apt-get install containerd.io`

修改containerd配置文件 (!important)

containerd 相关配置

# 创建containerd目录
sudo mkdir /etc/containerd
​
# 恢复默认配置文件
sudo containerd config default | sudo tee /etc/containerd/config.toml > /dev/null

​
# 切换为国内源
sed -i 's/registry.k8s.io/registry.aliyuncs.com\/google_containers/' /etc/containerd/config.toml
​
# 修改SystemCgroup为true
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true
​
# 重启服务
sudo systemctl daemon-reload
sudo systemctl restart containerd

设置cgroup

sudo sed -i 's/SystemdCgroup = true/SystemdCgroup = false/' /etc/containerd/config.toml

为什么还需要在config中设置镜像源

使用kubeadm init 并指定image-repository 后仍需要在 containerdconfig.toml 文件中指定镜像源的原因,主要是由于这两个配置的生命周期不同:

  • kubeadm init 配置镜像源仅用于初始化过程加速必要的相关组件:如 kube-apiserverkube-controller-managerkube-scheduler 等)

  • containerd 自身的配置不受 kubeadm 影响 。Kubernetes 组件启动后,由 containerd 负责持续管理容器和镜像的生命周期。当 containerd 需要重新拉取镜像(例如镜像更新或节点重启后),它将遵循自己的 config.toml 配置文件,而不是 kubeadm 的参数。未在 containerd 中配置镜像源时,它会默认访问官方的 k8s.gcr.io 源,而这一源在中国大陆访问通常较慢或受限。

设置完成后保存、重新加载containerd配置、重启containerd服务、验证配置是否生效

sudo systemctl daemon-reload
sudo systemctl restart containerd
sudo systemctl status containerd

下载kubeadm以及相关组件

sudo apt-get update
# apt-transport-https may be a dummy package; if so, you can skip that package
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

# If the directory `/etc/apt/keyrings` does not exist, it should be created before the curl command, read the note below.
# sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# This overwrites any existing configuration in /etc/apt/sources.list.d/kubernetes.list
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update

sudo apt-get install -y kubelet kubeadm kubectl

sudo apt-mark hold kubelet kubeadm kubectl

初始化master节点

命令行部署

国内如果不指定image源,在拉取sandbox的时候会出现异常 sudo kubeadm init --image-repository registry.aliyuncs.com/google_containers --pod-network-cidr=10.128.0.0/16

yaml部署(推荐)

首先执行kubeadm config print init-defaults 输出kubeadm默认配置

之后需要在kubeadm-config.yaml这个文件中修改以下几个地方:

  1. hostname 修改name为自己的主机名称,上下文: nodeRegistration: criSocket: unix:///run/containerd/containerd.sock imagePullPolicy: IfNotPresent imagePullSerial: true name: k8s-master taints: null

  2. podSubnet 追加podSubnet podSubnet: 10.244.0.0/16 上下文: networking: dnsDomain: cluster.local serviceSubnet: 10.96.0.0/12 podSubnet: 10.244.0.0/16

  3. KubeletConfiguration 文件最后追加 KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: systemd

之后,可以根据yaml文件初始化master节点:kubeadm init --config=kubeadm-config.yaml

master初始化完成

初始化完成后显示示例:

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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.40.140:6443 --token wssf4y.fikow8fj6w1f2oar \
        --discovery-token-ca-cert-hash sha256:f942ac3be4f63eff7ff780145bf2937bd10656e7a361daf2da002fe2ece6a76e

注意:export KUBECONFIG=$HOME/.kube/config 这里需要设置环境变量,当使用普通用户非root的时候,如果没有上述操作,可能会默认读取/etc下的config文件

初始化flannel网络插件

下载配置文件

wget https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml

如果连接失败可参考文件:

apiVersion: v1
kind: Namespace
metadata:
  labels:
    k8s-app: flannel
    pod-security.kubernetes.io/enforce: privileged
  name: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: flannel
  name: flannel
  namespace: kube-flannel
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: flannel
  name: flannel
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: flannel
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-flannel
---
apiVersion: v1
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "EnableNFTables": false,
      "Backend": {
        "Type": "vxlan"
      }
    }
kind: ConfigMap
metadata:
  labels:
    app: flannel
    k8s-app: flannel
    tier: node
  name: kube-flannel-cfg
  namespace: kube-flannel
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: flannel
    k8s-app: flannel
    tier: node
  name: kube-flannel-ds
  namespace: kube-flannel
spec:
  selector:
    matchLabels:
      app: flannel
      k8s-app: flannel
  template:
    metadata:
      labels:
        app: flannel
        k8s-app: flannel
        tier: node
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - linux
      containers:
      - args:
        - --ip-masq
        - --kube-subnet-mgr
        command:
        - /opt/bin/flanneld
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: EVENT_QUEUE_DEPTH
          value: "5000"
        image: docker.io/flannel/flannel:v0.26.0
        name: kube-flannel
        resources:
          requests:
            cpu: 100m
            memory: 50Mi
        securityContext:
          capabilities:
            add:
            - NET_ADMIN
            - NET_RAW
          privileged: false
        volumeMounts:
        - mountPath: /run/flannel
          name: run
        - mountPath: /etc/kube-flannel/
          name: flannel-cfg
        - mountPath: /run/xtables.lock
          name: xtables-lock
      hostNetwork: true
      initContainers:
      - args:
        - -f
        - /flannel
        - /opt/cni/bin/flannel
        command:
        - cp
        image: docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel2
        name: install-cni-plugin
        volumeMounts:
        - mountPath: /opt/cni/bin
          name: cni-plugin
      - args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        command:
        - cp
        image: docker.io/flannel/flannel:v0.26.0
        name: install-cni
        volumeMounts:
        - mountPath: /etc/cni/net.d
          name: cni
        - mountPath: /etc/kube-flannel/
          name: flannel-cfg
      priorityClassName: system-node-critical
      serviceAccountName: flannel
      tolerations:
      - effect: NoSchedule
        operator: Exists
      volumes:
      - hostPath:
          path: /run/flannel
        name: run
      - hostPath:
          path: /opt/cni/bin
        name: cni-plugin
      - hostPath:
          path: /etc/cni/net.d
        name: cni
      - configMap:
          name: kube-flannel-cfg
        name: flannel-cfg
      - hostPath:
          path: /run/xtables.lock
          type: FileOrCreate
        name: xtables-lock

设置镜像源

[plugins."io.containerd.grpc.v1.cri".registry.mirrors] 
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."[docker.io](http://docker.io)"] 
endpoint = ["[https://docker.1panel.live(https://docker.1panel.live)","[https://docker.agsv.top](https://docker.agsv.top)","[https://docker.agsvpt.work](https://docker.agsvpt.work)"] 
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."[k8s.gcr.io](http://k8s.gcr.io)"]
endpoint = ["[registry.aliyuncs.com/google_containers](http://registry.aliyuncs.com/google_containers)"]

目前境内一些好用的镜像源:

https://docker.1panel.live ✅网友自建
地址 https://docker.agsv.top  ✅网友自建
备用 https://docker.agsvpt.work  ✅网友自建
地址①:https://dockerpull.com ✅网友自建
地址②:https://dockerproxy.cn ✅网友自建

配置完成后进行应用 kubectl apply -f kube-flannel.yml

kubectl get pods --all-namespaces 可以检查看dns和flannel相关pod有没有正常启动,

初始化工作节点

工作节点前置任务完成后(安装containerd&安装kubeadm)

kubeadm join <master-ip>:<port> --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:<discovery-token-ca-cert-hash>

主节点的 IP 和端口

主节点的 IP 地址可以通过在主节点上运行 ip addr showifconfig 命令来获取。

端口通常是 6443,这是 Kubernetes API 服务器默认使用的端口。

加入令牌(Token)

当你使用 kubeadm init 初始化主节点时,命令会输出一个加入令牌。这个令牌用于工作节点加入集群时的身份验证。

如果你丢失了这个令牌,可以通过以下命令在主节点上重新获取:

kubeadm token list

这将列出所有可用的令牌及其过期时间。你可以选择一个合适的令牌用于 kubeadm join 命令。

发现令牌的 CA 证书哈希

发现令牌的 CA 证书哈希是用于验证集群信息的证书的哈希值。这个哈希值也可以在主节点上通过以下命令获取:

kubeadm token create --print-join-command

这个命令会输出一个完整的 kubeadm join 命令,包括所需的 CA 证书哈希。你可以直接复制这个命令中的哈希值。

# 可以在master节点生成新的加入令牌
kubeadm token create --print-join-command

初始化完成后可以跳到主节点,kubectl get nodes 查看是否加入成功

工作节点不需要进行flannel配置,工作节点加入集群后会自动进行同步

初始化节点失败后回退方法

重置 Kubernetes 节点,使其恢复到初始化前的状态 sudo kubeadm reset -f

手动清除配置文件: sudo rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes

查看是否有端口占用,如果有kill一下 sudo lsof -i :10250

More from this blog

Go 隐式接口与模板方法

前言 今天在使用testify框架写单元测试的时候有这样一个需求: 对于一个方法来说,可能会有很长的上下文链路数据。 按照正常的单元测试流程,这个时候我们需要按照接口的逻辑来事先mock好原始未处理的数据,并且定义最终想要的数据结果。定义好不同的test case 尽可能的覆盖到每一个if else,才可以通过后续的ci 流程。 对于一些特殊的case,我们需要一些特殊的操作: 测试前置处理-> 运行测试代码 -> 测试后处理 需要在测试前后对数据进行预处理,如:事先存入一些数据,测试后再删除...

Nov 13, 2025
Go 隐式接口与模板方法

一次Nginx 403 的问题排查

前言&问题复现 参与了一个内部效率提升项目(边角料项目)后要发到内部的测试机器上。内部的测试机器上并没有配置集群,没有一个专门的ingress或者说是网关来处理请求分发。 并且这个测试机器属于多个部门,导致机器环境很复杂,一台物理机安装有多个nginx,有直接host安装的,也有在容器上运行的。 由于这是一个内部项目,没有必要专门部署一个minio,but 项目需要上传文件,所以就直接保存在server的目录下,简单配置了一下nginx的配置,配置如下: location /static...

Oct 18, 2025
一次Nginx 403 的问题排查

[Learn With Agent] JSX & React Components

前言 这是Learn With Agent 的第一篇博客,这个系列(不知道有没有后续了)是想通过agent辅助进行快速的学习(过概念)掌握一些相关的知识。之后再通过agent辅助开发,应该也能做出来个7788。对于AI还有很多思考,另起一个博客再说吧就。 因为网络和经费原因,这里使用的是CC+GLM 4.6 & Gemini 系列。🈚️广,文字为百分百人类手敲&传统CV大法。 JSX JSX是React生态中占据很重要的部分,JSX是一种语法拓展,它可以允许用户在js中写类似html的标签结构...

Oct 9, 2025
[Learn With Agent] JSX & React Components

提示词以及常见优化技巧

prompt 种类 system : 系统提示词用于统一设定当前会话下ai的行为,例如设定ai的行为、语气、风格或限制。用户不会显式观察到系统提示词,但是会影响到用户和ai的后续对话。 user : 这是用户实际向ai提出的问题,这是对话的起点。 assistant: 这是ai对于用户问题的回答,通常也会被添加到上下文中,供下一次对话进行参考,所以也属于prompt的范畴。 prompt 格式 标准格式: <Instruction> 问答格式: <Question>? 零样本提示 ...

Aug 14, 2025
提示词以及常见优化技巧

Http 长连接 & 短连接详解

网络连接基础 TCP/IP TCP/IP,是几乎所有互联网通信的基石。HTTP、WebSocket 和 常见的RPC框架尽管功能各异,但都运行在应用层,并从根本上依赖传输层的 TCP(传输控制协议)来实现可靠的、面向连接的数据传输 。 TCP 的核心职责是确保数据包从发送端到接收端可靠、按序且无损地传输 。这包括序列号、确认、流量控制和拥塞控制等机制。在网络层,IP(互联网协议)负责网络路由和寻址,使数据能够跨越不同网络到达其目的地 。现代操作系统普遍内置并管理 TCP/IP 协议栈,从而为应用...

Jun 13, 2025
E

Ekreke's Blog

11 posts