• 操作系统:Ubuntu 24.04.1 LTS
  • 容器运行时:containerd://1.7.12
# 此内容为部署完的k8s集群信息

root@ubuntu-k8s:~# kubectl get node -owide
NAME         STATUS   ROLES           AGE    VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
ubuntu-k8s   Ready    control-plane   105s   v1.31.1   172.8.8.16    <none>        Ubuntu 24.04.1 LTS   6.8.0-47-generic   containerd://1.7.12

1. 安装容器运行时

1. 安装containerd,并配置开机自启动

apt install containerd #默认同时安装runc
apt install ipvsadm # 安装ipvs

2. 生成containerd配置文件

mkdir /etc/containerd
containerd config default > /etc/containerd/config.toml

1. 配置 systemd cgroup 驱动

结合 runc 使用 systemd cgroup 驱动,在 /etc/containerd/config.toml 中设置:

sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true

2. 修改sandbox_image镜像地址

sandbox_image = "k8s.lixx.cn/pause:3.10"

重启containerd

systemctl restart containerd
systemctl enable containerd

2. 安装前配置

1. 编辑hosts文件,添加本机host地址

root@ubuntu-k8s:~# cat /etc/hosts
127.0.0.1 localhost

172.8.8.16 ubuntu-k8s

2. 手动启用 IPv4 数据包转发

# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# 应用 sysctl 参数而不重新启动
sudo sysctl --system

# 验证
sysctl net.ipv4.ip_forward

3. 关闭防火墙

ufw disable

sudo systemctl stop apparmor
sudo systemctl disable apparmor

4. 关闭swap

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

修改/etc/fstab配置文件,注释最后一行(和swap有关的一行)并重启操作系统。

3. 安装 k8s

1. 配置apt源,下载 kubelet kubeadm kubectl

如果下载慢可以更换阿里云镜像源或清华镜像源,修改地址即可。

参考官网:安装 kubeadm | Kubernetes

以下指令适用于 Kubernetes 1.31.

  1. 更新 apt 包索引并安装使用 Kubernetes apt 仓库所需要的包:
    sudo apt-get update
    # apt-transport-https 可能是一个虚拟包(dummy package);如果是的话,你可以跳过安装这个包
    sudo apt-get install -y apt-transport-https ca-certificates curl gpg
    
  2. 下载用于 Kubernetes 软件包仓库的公共签名密钥。所有仓库都使用相同的签名密钥,因此你可以忽略URL中的版本:
    # 如果 `/etc/apt/keyrings` 目录不存在,则应在 curl 命令之前创建它,请阅读下面的注释。
    # sudo mkdir -p -m 755 /etc/apt/keyrings
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    

说明:

在低于 Debian 12 和 Ubuntu 22.04 的发行版本中,/etc/apt/keyrings 默认不存在。 应在 curl 命令之前创建它。

  1. 添加 Kubernetes apt 仓库。 请注意,此仓库仅包含适用于 Kubernetes 1.31 的软件包; 对于其他 Kubernetes 次要版本,则需要更改 URL 中的 Kubernetes 次要版本以匹配你所需的次要版本 (你还应该检查正在阅读的安装文档是否为你计划安装的 Kubernetes 版本的文档)。
    # 此操作会覆盖 /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.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    
  2. 更新 apt 包索引,安装 kubelet、kubeadm 和 kubectl,并锁定其版本:
    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl
    # 查看各个组件版本
    kubectl version --client
    kubelet --version
    kubeadm version
    
    systemctl restart kubelet
    systemctl enable kubelet
    

2. 配置crictl

  1. 创建 /etc/crictl.yaml 文件
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
EOF
  1. 验证
root@ubuntu-k8s:~# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID              POD

3. kubeadm初始化

  1. 使用本人自建的镜像仓库,或者使用阿里云的 registry.aliyuncs.com/google_containers
# 查看要下载哪些镜像
kubeadm config images list 
# 执行
kubeadm init  --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address 172.8.8.16 --image-repository k8s.lixx.cn
  • apiserver-advertise-address: 服务器地址
  • image-repository:用阿里云镜像快速下载
  1. 执行成功结果如下
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 172.8.8.16:6443 --token 8on0q5.vhcyalu0mognziwd \
        --discovery-token-ca-cert-hash sha256:3360d57313f4a51f2ce3896a2af503f41fdcd2342a2d8fd74e07522945db922b

#执行
  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

4. 安装cni插件 flannel

  1. 此时coredns pod状态异常,需要安装cni插件。官网:https://github.com/flannel-io/flannel#deploying-flannel-manually
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
  1. 无法访问时,使用以下文件进行配置。自行创建yml文件即可。docker.io已经替换成了hub.lixx.cn

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: hub.lixx.cn/flannel/flannel:v0.25.7
        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: hub.lixx.cn/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: hub.lixx.cn/flannel/flannel:v0.25.7
        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
  1. 执行前:
root@ubuntu-k8s:~# kubectl get po -owide -A
NAMESPACE     NAME                                 READY   STATUS    RESTARTS     AGE   IP           NODE         NOMINATED NODE   READINESS GATES
kube-system   coredns-7d54cd9f-l4m9d               0/1     Pending   0            8s    <none>       <none>       <none>           <none>
kube-system   coredns-7d54cd9f-vv7dl               0/1     Pending   0            8s    <none>       <none>       <none>           <none>
kube-system   etcd-ubuntu-k8s                      0/1     Running   1            14s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system   kube-apiserver-ubuntu-k8s            1/1     Running   1            16s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system   kube-controller-manager-ubuntu-k8s   0/1     Running   0            14s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system   kube-proxy-dvx5g                     1/1     Running   1 (6s ago)   8s    172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system   kube-scheduler-ubuntu-k8s            1/1     Running   1            15s   172.8.8.16   ubuntu-k8s   <none>           <none>
  1. 执行:
root@ubuntu-k8s:~# kubectl apply -f kube-flannel.yml 
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds createdspan
root@ubuntu-k8s:~# kubectl get po -owide -A
NAMESPACE      NAME                                 READY   STATUS    RESTARTS      AGE   IP           NODE         NOMINATED NODE   READINESS GATES
kube-flannel   kube-flannel-ds-bc7jz                1/1     Running   0             22s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system    coredns-7d54cd9f-l4m9d               1/1     Running   0             74s   10.244.0.3   ubuntu-k8s   <none>           <none>
kube-system    coredns-7d54cd9f-vv7dl               1/1     Running   0             74s   10.244.0.2   ubuntu-k8s   <none>           <none>
kube-system    etcd-ubuntu-k8s                      1/1     Running   1             80s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system    kube-apiserver-ubuntu-k8s            1/1     Running   1             82s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system    kube-controller-manager-ubuntu-k8s   1/1     Running   0             80s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system    kube-proxy-dvx5g                     1/1     Running   1 (72s ago)   74s   172.8.8.16   ubuntu-k8s   <none>           <none>
kube-system    kube-scheduler-ubuntu-k8s            1/1     Running   1             81s   172.8.8.16   ubuntu-k8s   <none>           <none>

5. pod service 测试

去除节点上的污点,允许pod调度到该节点

kubectl taint nodes ubuntu-k8s node-role.kubernetes.io/control-plane:NoSchedule-

pod yaml:

root@ubuntu-k8s:~# cat simple-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: MyApp
spec:
  containers:
  - name: nginx
    image: hub.lixx.cn/library/nginx:1.14.2
    ports:
    - containerPort: 80

service yaml:

root@ubuntu-k8s:~# cat my-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80

执行,并查看结果:

kubectl apply -f simple-pod.yaml 
kubectl apply -f my-service.yaml 

root@ubuntu-k8s:~# kubectl get po -owide
NAME    READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          52s   10.244.0.4   ubuntu-k8s   <none>           <none>
root@ubuntu-k8s:~# kubectl get svc -owide
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE     SELECTOR
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP   5m50s   <none>
my-service   ClusterIP   10.98.96.56   <none>        80/TCP    12s     app.kubernetes.io/name=MyApp

# curl pod ip 查看结果:
root@ubuntu-k8s:~# curl  10.244.0.4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</body>
</html>

# curl service ip 查看结果:
root@ubuntu-k8s:~# curl 10.98.96.56
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</body>
</html>

问题排错

systemctl status kubelet
journalctl -xeu kubelet

查看service cidr

kubectl cluster-info dump | grep service-cluster-ip-range