CentOS7单机环境安装k8s集群

news2024/9/21 21:47:21

目录

1、环境准备

2、安装依赖工具

3、配置 Kubernetes 的国内 Yum 源

4. 安装 Kubernetes 组件

5、初始化 Kubernetes 集群

1. 容器运行时没有正常运行

1.1. 可能的原因

1.2. 解决办法

2. 初始化拉取镜像卡住

2.1. 使用国内的镜像源(无法解决问题)

2.2. 手动拉取镜像后重命名

3. 重置集群再次初始化

6、配置kubernetes集群

1. 配置 kubectl 命令行工具

2. 部署 Pod 网络

7、验证k8s集群部署情况

1. 检查集群节点状态

2. 检查集群网络

3. 部署测试应用

a、编辑 Deployment 配置

b、使用 YAML 文件进行修改

c、验证修改

4. Pod映射到宿主机端口

a、创建 Service 配置文件

b、应用及验证

c、访问 Nginx 服务

一些kubernetes常用命令

集群信息

Pod 诊断

Service诊断

Deployment诊断

资源使用情况


1、环境准备

我只有一台CentOS 7.9.2009虚拟机,希望搭建一个完整的k8s集群用来学习测试,这里我的配置是 2C 2G 的腾讯云服务器,其实仅仅是搭建一个k8s集群并不需要多少资源。

确保系统已经更新,并且禁用 Swap(Kubernetes 不支持 Swap,必须禁用)

sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab
sudo yum update -y

2、安装依赖工具

安装 Docker 和其他必要的工具

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce
sudo systemctl start docker
sudo systemctl enable docker

3、配置 Kubernetes 的国内 Yum 源

这个配置方法我们可以参考阿里镜像站的最新配置方式,因为它的地址可能会发生变化。kubernetes镜像_kubernetes下载地址_kubernetes安装教程-阿里巴巴开源镜像站

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/repodata/repomd.xml.key
EOF

4. 安装 Kubernetes 组件

安装 kubeadm、kubelet 和 kubectl

sudo yum install -y kubelet kubeadm kubectl
sudo systemctl enable kubelet

5、初始化 Kubernetes 集群

使用 kubeadm 初始化 Kubernetes 集群:

sudo kubeadm init --pod-network-cidr=192.168.0.0/16

如果不出意外的话到这里k8s就基本安装成功了,但是不出意外是不可能的。

下面分享一下我遇到的意外以及对应的解决方法。

1. 容器运行时没有正常运行
[root@VM-12-2-centos yum.repos.d]# kubeadm init --pod-network-cidr=192.168.0.0/16
I0827 14:44:43.282383   30245 version.go:256] remote version is much newer: v1.31.0; falling back to: stable-1.28
[init] Using Kubernetes version: v1.28.13
[preflight] Running pre-flight checks
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR CRI]: container runtime is not running: output: time="2024-08-27T14:44:45+08:00" level=fatal msg="validate service connection: validate CRI v1 runtime API for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"
, error: exit status 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

这个错误是由于 Kubernetes 初始化过程中的 CRI (Container Runtime Interface) 相关的问题导致的。错误提示的是容器运行时(container runtime)没有正常运行,导致 kubeadm 无法与之通信。

1.1. 可能的原因
  1. Docker 和 Containerd 之间的兼容性问题:Kubernetes 1.24 版本及以后,默认不再使用 Docker 作为容器运行时,而是使用 Containerd 或者其他兼容的容器运行时,如果系统上 Docker 和 Containerd 之间配置不当,可能会引发这个错误。
  2. Containerd 没有正确配置或运行:Kubernetes 依赖的容器运行时(如 Containerd)没有正确配置或启动,导致 kubeadm 无法正常初始化集群。

查看自己的k8s版本,可以在kubeadm init 时通过终端打印的日志确认版本,也可以通过下面的命令查看,但是集群没有初始化完成则无法通过kubectl version 查看。

[root@mymaster ~]# kubectl version 
Client Version: v1.28.13
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.13
1.2. 解决办法

由于我安装的k8s版本是v1.28.13,也就是说默认不再使用 Docker 作为容器运行时,我们可以重点排查Containerd服务和k8s的连通性问题。

1.检查Containerd服务是否正常运行:

[root@mymaster ~]# systemctl status containerd.service 
● containerd.service - containerd container runtime
   Loaded: loaded (/usr/lib/systemd/system/containerd.service; disabled; vendor preset: disabled)
   Active: active (running) since Wed 2024-08-28 15:29:26 CST; 5 days ago

2.检查 CRI 配置

确保 Kubernetes 使用的是正确的 CRI 配置文件。检查 /etc/crictl.yaml 是否存在并正确配置:

如果文件不存在,可以创建一个:

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

3.手动重启containerd

sudo systemctl restart containerd
crictl version
crictl info

如果 crictl 无法连接到 Containerd,可能是因为 CRI socket 没有正确配置。

4.检查 Containerd 配置文件

如果上述方法无法解决问题,可以进一步检查containerd配置文件,确保配置正确无误。

查看 /etc/containerd/config.toml 文件,确保配置正确。如果没有此文件,可以生成默认配置并编辑:

sudo containerd config default | sudo tee /etc/containerd/config.toml

确保 systemd 是 cgroup 驱动程序。在配置文件中找到 SystemdCgroup 选项,并将其设置为 true:

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

#如果有下面这行,请注释掉
#disabled_plugins = ["cri"]

下面是我的配置文件:

#   Copyright 2018-2022 Docker Inc.

#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at

#       http://www.apache.org/licenses/LICENSE-2.0

#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

#启用cri插件
#disabled_plugins = ["cri"]

#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0

#[grpc]
#  address = "/run/containerd/containerd.sock"
#  uid = 0
#  gid = 0

#[debug]
#  address = "/run/containerd/debug.sock"
#  uid = 0
#  gid = 0
#  level = "info"

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

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://registry.aliyuncs.com"]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
    endpoint = ["https://registry.aliyuncs.com/google_containers"]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
    endpoint = ["https://quay-mirror.qiniu.com"]

在编辑完配置文件后,重启 Containerd 和 Docker:

sudo systemctl restart containerd
sudo systemctl restart docker
#使用 crictl 工具验证 Kubernetes 与容器运行时的连接
sudo crictl info

这应该显示容器运行时的详细信息,如果有任何错误,则说明 CRI 和 Kubernetes 之间的通信仍然有问题。

2. 初始化拉取镜像卡住
[root@VM-12-2-centos yum.repos.d]# kubeadm init --pod-network-cidr=192.168.0.0/16
W0827 15:06:07.983250    9556 version.go:104] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.txt": Get "https://cdn.dl.k8s.io/release/stable-1.txt": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
W0827 15:06:07.983313    9556 version.go:105] falling back to the local client version: v1.28.13
[init] Using Kubernetes version: v1.28.13
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'

一般来说这一步会卡非常久,因为我们国内的网络无法访问和下载k8s官方的镜像。

2.1. 使用国内的镜像源(无法解决问题)

这个时候如果去网上搜索通常会建议在执行init操作的时候加上参数 --image-repository registry.aliyuncs.com/google_containers 来指定使用阿里镜像源。但这种方法亲测无效,因为阿里镜像源拉下来的镜像命名和k8s初始化所需要的默认镜像名不对应,无法直接使用。

[root@VM-12-2-centos yum.repos.d]# sudo kubeadm init \
>   --pod-network-cidr=192.168.0.0/16 \
>   --image-repository registry.aliyuncs.com/google_containers
I0827 15:13:14.000174   13371 version.go:256] remote version is much newer: v1.31.0; falling back to: stable-1.28
W0827 15:13:24.000473   13371 version.go:104] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.28.txt": Get "https://cdn.dl.k8s.io/release/stable-1.28.txt": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
W0827 15:13:24.000501   13371 version.go:105] falling back to the local client version: v1.28.13
[init] Using Kubernetes version: v1.28.13
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W0827 15:13:38.997537   13371 checks.go:835] detected that the sandbox image "registry.k8s.io/pause:3.6" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.aliyuncs.com/google_containers/pause:3.9" as the CRI sandbox image.
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local vm-12-2-centos] and IPs [10.96.0.1 10.0.12.2]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost vm-12-2-centos] and IPs [10.0.12.2 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost vm-12-2-centos] and IPs [10.0.12.2 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[kubelet-check] Initial timeout of 40s passed. 
Unfortunately, an error has occurred:
        timed out waiting for the condition

This error is likely caused by:
        - The kubelet is not running
        - The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)

If you are on a systemd-powered system, you can try to troubleshoot the error with the following commands:
        - 'systemctl status kubelet'
        - 'journalctl -xeu kubelet'

Additionally, a control plane component may have crashed or exited when started by the container runtime.
To troubleshoot, list all containers using your preferred container runtimes CLI.
Here is one example how you may list all running Kubernetes containers by using crictl:
        - 'crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock ps -a | grep kube | grep -v pause'
        Once you have found the failing container, you can inspect its logs with:
        - 'crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock logs CONTAINERID'
error execution phase wait-control-plane: couldn't initialize a Kubernetes cluster
To see the stack trace of this error execute with --v=5 or higher

上面的日志表明在 kubeadm init 过程中,Kubernetes 控制平面的组件未能成功启动,导致初始化失败。具体来说,kubelet 可能没有正常运行,或者由于某种原因无法启动控制平面的容器。

2.2. 手动拉取镜像后重命名

先确认一下初始化k8s集群所需要的镜像有哪些:

[root@mymaster ~]# kubeadm config images list
I0902 16:38:11.190130   24023 version.go:256] remote version is much newer: v1.31.0; falling back to: stable-1.28
registry.k8s.io/kube-apiserver:v1.28.13
registry.k8s.io/kube-controller-manager:v1.28.13
registry.k8s.io/kube-scheduler:v1.28.13
registry.k8s.io/kube-proxy:v1.28.13
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.12-0
registry.k8s.io/coredns/coredns:v1.10.1

拉取阿里镜像源的官方镜像:

# 拉取镜像
ctr image pull registry.aliyuncs.com/google_containers/pause:3.6
ctr image pull registry.aliyuncs.com/google_containers/pause:3.9
ctr image pull registry.aliyuncs.com/google_containers/coredns:v1.10.1
ctr image pull registry.aliyuncs.com/google_containers/etcd:3.5.12-0
ctr image pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.13
ctr image pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.28.13
ctr image pull registry.aliyuncs.com/google_containers/kube-proxy:v1.28.13
ctr image pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.28.13

修改镜像标签:

sudo ctr -n k8s.io  image tag  registry.aliyuncs.com/google_containers/pause:3.6 registry.k8s.io/pause:3.6
sudo ctr -n k8s.io  image tag registry.aliyuncs.com/google_containers/pause:3.9 registry.k8s.io/pause:3.9
sudo ctr -n k8s.io  image tag registry.aliyuncs.com/google_containers/coredns:v1.10.1 registry.k8s.io/coredns/coredns:v1.10.1
sudo ctr -n k8s.io  image tag registry.aliyuncs.com/google_containers/etcd:3.5.12-0 registry.k8s.io/etcd:3.5.12-0
sudo ctr -n k8s.io  image tag  registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.13 registry.k8s.io/kube-apiserver:v1.28.13
sudo ctr -n k8s.io  image tag  registry.aliyuncs.com/google_containers/kube-controller-manager:v1.28.13 registry.k8s.io/kube-controller-manager:v1.28.13
sudo ctr -n k8s.io  image tag    registry.aliyuncs.com/google_containers/kube-proxy:v1.28.13 registry.k8s.io/kube-proxy:v1.28.13
sudo ctr -n k8s.io  image tag  registry.aliyuncs.com/google_containers/kube-scheduler:v1.28.13 registry.k8s.io/kube-scheduler:v1.28.13

改完名后可以使用 crictl images 命令查看相关的镜像信息。

[root@mymaster ~]# crictl images ls |grep k8s.io
registry.k8s.io/pause                                             3.6                 6270bb605e12e       302kB
registry.k8s.io/pause                                             3.9                 e6f1816883972       322kB
registry.k8s.io/coredns/coredns                                   v1.10.1             ead0a4a53df89       16.2MB
registry.k8s.io/etcd                                              3.5.12-0            3861cfcd7c04c       57.2MB
registry.k8s.io/kube-apiserver                                    v1.28.13            5447bb21fa283       34.5MB
registry.k8s.io/kube-controller-manager                           v1.28.13            f1a0a396058d4       33.4MB
registry.k8s.io/kube-proxy                                        v1.28.13            31fde28e72a31       28.3MB
registry.k8s.io/kube-scheduler                                    v1.28.13            a60f64c0f37d0       18.6MB

这里有个特殊的地方就是虽然使用 kubeadm config images list 没有列出 registry.k8s.io/pause:3.6 的镜像,但是我在查看 containerd 日志的时候却看到了对应的报错,所以顺便也加上了这个镜像。

如果不清楚具体缺失的镜像,可以在执行 kubeadm init 命令时另外开两个窗口监控 containerd 和 kubelet 服务的日志信息,我就是通过这种方法把全部所需的镜像下载下来并命名的。

sudo journalctl -u containerd -f
sudo journalctl -u kubelet -f
3. 重置集群再次初始化

如果之前尝试过初始化集群,可能会留下部分配置文件,这些文件可能会干扰新的初始化过程。可以尝试重置 Kubernetes 配置:

#终端确认信息输入 y 后按回车
kubeadm reset
rm -rf /etc/kubernetes/manifests
rm -rf /var/lib/etcd

重新执行 kubeadm init

最后,重新执行 kubeadm init 命令,这里并不需要指定使用阿里镜像源,因为我前面已经手动下载和修改 tag 为 k8s 初始化所需的。

[root@VM-12-2-centos yum.repos.d]# sudo kubeadm init --pod-network-cidr=192.168.0.0/16
......
......
......
[kubelet-check] Initial timeout of 40s passed.
[apiclient] All control plane components are healthy after 185.502361 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node mymaster as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node mymaster as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: cr5apt.fk1mx89qc0r9b3e6
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

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 10.0.12.2:6443 --token cr5apt.fk1mx89qc0r9b3e6 \
        --discovery-token-ca-cert-hash sha256:d1cb1bda5109cc9d6d9bdfa34e47fb33167485481b39e56b017d6edbcce3a25d 

看到类似上面的输出就说明已经成功初始化了 Kubernetes ,接下来,我们可以根据提示进行后续操作,比如配置 kubectl 命令行工具并部署一个 Pod 网络,以便让集群能够正常运行 Pod。如果后续有其他节点需要加入集群,可以使用最后的 kubeadm join 命令。

6、配置kubernetes集群

1. 配置 kubectl 命令行工具

如果是普通用户,执行以下命令来配置 kubectl:

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

如果是 root 用户,可以直接执行以下命令:

export KUBECONFIG=/etc/kubernetes/admin.conf
2. 部署 Pod 网络

为了让集群能够运行 Pod,我们需要部署一个 Pod 网络。这里我使用的是flannel插件。

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

执行上述命令时,Kubernetes 将从指定的 URL 中获取 Flannel 网络插件的配置文件,并在你的集群中应用这些配置。但是这个命令中的URL我们的本机网络不一定可以直接访问,下面是文件对应的文件内容,可以直接新建一个文件写入下面的内容。

---
kind: Namespace
apiVersion: v1
metadata:
  name: kube-flannel
  labels:
    k8s-app: flannel
    pod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
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
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
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
kind: ServiceAccount
metadata:
  labels:
    k8s-app: flannel
  name: flannel
  namespace: kube-flannel
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-flannel
  labels:
    tier: node
    k8s-app: flannel
    app: flannel
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"
      }
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds
  namespace: kube-flannel
  labels:
    tier: node
    app: flannel
    k8s-app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - linux
      hostNetwork: true
      priorityClassName: system-node-critical
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni-plugin
        image: docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel2
        command:
        - cp
        args:
        - -f
        - /flannel
        - /opt/cni/bin/flannel
        volumeMounts:
        - name: cni-plugin
          mountPath: /opt/cni/bin
      - name: install-cni
        image: docker.io/flannel/flannel:v0.25.6
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: docker.io/flannel/flannel:v0.25.6
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: EVENT_QUEUE_DEPTH
          value: "5000"
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
        - name: xtables-lock
          mountPath: /run/xtables.lock
      volumes:
      - name: run
        hostPath:
          path: /run/flannel
      - name: cni-plugin
        hostPath:
          path: /opt/cni/bin
      - name: cni
        hostPath:
          path: /etc/cni/net.d
      - name: flannel-cfg
        configMap:
          name: kube-flannel-cfg
      - name: xtables-lock
        hostPath:
          path: /run/xtables.lock
          type: FileOrCreate

配置文件中有几个地方是需要特别注意的。

  • kube-flannel.yml 使用到的两个 docker.io 的镜像,我们直接执行的话由于网络原因大概率会下载失败。我这里采用迂回的方法,是先用 docker pull 把镜像拉到本地,用 docker save 导出镜像 tar 包,然后使用 ctr 命令导入镜像,具体的操作步骤如下:
#拉取镜像、导出镜像为tar文件、使用ctr命令导入镜像
sudo docker pull docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel2
sudo docker save -o flannel.tar flannel/flannel-cni-plugin:v1.5.1-flannel2
sudo ctr -n k8s.io images import flannel.tar
sudo crictl images
sudo docker pull docker.io/flannel/flannel:v0.25.6
sudo docker save -o flannelv0.25.6.tar docker.io/flannel/flannel:v0.25.6
sudo ctr -n k8s.io images import flannelv0.25.6.tar
sudo crictl images
  • 网段配置这里不能使用默认的,因为前面执行 kubeadm init 的时候加上了 --pod-network-cidr=192.168.0.0/16 参数,所以这里需要把 "Network" 修改成 192.168.0.0/16 ,否则网络会报错。
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",  #这里需要根据实际情况修改
      "EnableNFTables": false,
      "Backend": {
        "Type": "vxlan"
      }
    }
  • 最后一个就是部署 flannel 的时候可能会报错找不到 /run/flannel/subnet.env 文件,这里可以自己创建一个,内容如下:
[root@mymaster ~]# cat <<EOF | sudo tee /run/flannel/subnet.env
FLANNEL_NETWORK=192.168.0.0/16
FLANNEL_SUBNET=192.168.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
EOF

前面的配置工作全部完成后就可以使用命令 kubectl apply -f kube-flannel.yml 部署 flannel 了。

[root@mymaster ~]# kubectl apply -f kube-flannel.yml
[root@mymaster ~]# kubectl get pods -n kube-flannel
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-dzg9r   1/1     Running   0          1m

#查看所有命名空间的pod状态
[root@mymaster ~]# kubectl get pods --all-namespaces
NAMESPACE      NAME                               READY   STATUS              RESTARTS   AGE
kube-flannel   kube-flannel-ds-tvm8x              1/1     Running             0          28m
kube-system    coredns-5dd5756b68-6tp4l           1/1     Running             0          88m
kube-system    coredns-5dd5756b68-vgc2r           1/1     Running             0          88m
kube-system    etcd-mymaster                      1/1     Running             0          89m
kube-system    kube-apiserver-mymaster            1/1     Running             0          89m
kube-system    kube-controller-manager-mymaster   1/1     Running             0          89m
kube-system    kube-proxy-ps2d4                   1/1     Running             0          88m
kube-system    kube-scheduler-mymaster            1/1     Running             0          89m

从上面的终端输出可以看到 coredns 的 POD 也正常运行了,至此单机版的k8s集群就算搭建完成了。

7、验证k8s集群部署情况

1. 检查集群节点状态
[root@mymaster ~]# kubectl get nodes
NAME       STATUS   ROLES           AGE   VERSION
mymaster   Ready    control-plane   7d    v1.28.13
2. 检查集群网络

使用以下命令查看 Pod 和 Service 的状态:

kubectl get pods --all-namespaces
kubectl get svc --all-namespaces

确保这些资源都处于 Running 状态,并且没有异常。

3. 部署测试应用

为了确保集群的功能正常,这里我们部署一个 Nginx 应用并检查其状态:

docker pull nginx
docker save -o nginx.tar nginx
ctr -n k8s.io images import nginx.tar
#确认Nginx镜像是否导入成功
crictl images ls |grep nginx

此时我们直接使用kubectl create deployment nginx --image=nginx创建一个 Nginx Pod,会发现新创建的 Pod 状态一直无法变成 Running,使用kubectl describe pod nginx-7854ff8877-xqkfv查看 Pod 的详细信息:

[root@mymaster ~]# kubectl describe pod nginx-7854ff8877-xqkfv 
Name:             nginx-7854ff8877-xqkfv
Namespace:        default
Priority:         0
Service Account:  default
Node:             <none>
Labels:           app=nginx
                  pod-template-hash=7854ff8877
Annotations:      <none>
Status:           Pending
IP:               
IPs:              <none>
Controlled By:    ReplicaSet/nginx-7854ff8877
Containers:
  nginx:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-97xsr (ro)
Conditions:
  Type           Status
  PodScheduled   False 
Volumes:
  kube-api-access-97xsr:
    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
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  3m50s  default-scheduler  0/1 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..

这个错误信息表明 Pod 无法调度到任何可用节点上,原因是节点上有一个未容忍的污点(taint),日志显示节点上的污点是:{node-role.kubernetes.io/control-plane: },这是 Kubernetes 用来标记控制平面节点的污点。默认情况下,标记为 node-role.kubernetes.io/control-plane 的节点才允许调度控制平面 Pod,不允许调度普通的工作负载 Pod。

因为我的集群是单机版部署的,所以我只有一个节点,那么解决方法有两种:

  1. 修改或移出这个节点的污点;
  2. 使用 Node Selector 或 Tolerations,为 Pod 添加适当的 tolerations,以允许它们调度到具有特定污点的节点上。
a、编辑 Deployment 配置

可以使用 kubectl edit 命令直接编辑 Deployment 的配置:

kubectl edit deployment nginx

这会打开一个编辑器,在其中直接修改 Deployment 的 YAML 配置。找到 spec.template.spec 部分,并在其中添加 tolerations 配置。例如:

spec:
  template:
    spec:
      tolerations:
      - key: "node-role.kubernetes.io/control-plane"
        operator: "Exists"
        effect: "NoSchedule"

编辑完成后,保存并退出编辑器,Kubernetes 会自动更新 Deployment 配置,并重新调度 Pod。

b、使用 YAML 文件进行修改

也可以通过 YAML 文件更新 Deployment 配置。首先,使用以下命令导出现有的 Deployment 配置到 YAML 文件:

kubectl get deployment nginx -o yaml > nginx-deployment.yaml

编辑 nginx-deployment.yaml 文件,找到 spec.template.spec 部分,并添加 tolerations 配置:

spec:
  template:
    spec:
      tolerations:
      - key: "node-role.kubernetes.io/control-plane"
        operator: "Exists"
        effect: "NoSchedule"

然后,使用以下命令应用修改后的 YAML 文件:

kubectl apply -f nginx-deployment.yaml
c、验证修改

修改完成后,可以使用以下命令检查 Pod 是否被正确调度:

kubectl get pods -o wide

通过这些步骤,我们可以将 tolerations 添加到 Nginx Deployment 中,以便让它能够调度到有特定 taint 的节点上。

4. Pod映射到宿主机端口

通过前面的操作,已经成功在 k8s 集群中运行了 Nginx Pod,但是我们现在还无法通过浏览器的方式访问到这个 Pod。

要将 Nginx Pod 的端口映射到服务器的 80 端口,我们可以创建一个 Service 资源来实现。Service 是 Kubernetes 中用于定义如何访问 Pod 的方式,它可以在集群内部提供一个稳定的 IP 地址和 DNS 名称,并将流量负载均衡到匹配的 Pods。

a、创建 Service 配置文件

创建一个 YAML 文件nginx-service.yaml 用于定义 Service。以下是一个示例配置文件,它会将 Nginx Pod 的 80 端口暴露到集群外部的 80 端口(NodePort 类型):

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30000
  selector:
    app: nginx

在这个配置中:

  • port: 80 是在 Service 上暴露的端口。
  • targetPort: 80 是 Nginx Pod 上的端口。
  • nodePort: 30000 是 Kubernetes 将服务暴露到所有节点上的端口。可以选择 30000-32767 之间的任何端口号。
b、应用及验证

使用 kubectl 命令应用这个配置文件,并且验证 Service 是否已成功创建并运行

kubectl apply -f nginx-service.yaml
kubectl get services

接下来应该能看到 nginx-service 列在输出中。确认 PORT(S) 列包含 80:30000/TCP,说明服务正在将 80 端口映射到节点的 30000 端口。

c、访问 Nginx 服务

现在我们可以通过访问集群中任何节点(这里是单节点)的 IP 地址和 nodePort(在这个例子中是 30000)来访问 Nginx 服务。

注意:如果你希望将服务直接暴露在节点的 80 端口,可以修改 Service 配置文件中的 nodePort 为 80(80 端口通常需要管理员权限),一般生产环境中不会这么做。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2107044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习之监督学习(二)二元逻辑回归

机器学习之监督学习&#xff08;二&#xff09;逻辑回归(二元分类问题&#xff09; 1. 分类 classification2.二元分类逻辑回归 binary-classified logistic regression模块1: sigmoid 激活函数 sigmoid function模型公式模块2: 决策边界 decision boundary代价函数梯度下降欠拟…

【Redis】Redis 主从复制原理与配置详解:解决单点故障与性能瓶颈的最佳方案

目录 主从复制配置建立复制断开复制安全性只读传输延迟 拓扑⼀主⼀从结构一主多从结构树形主从结构 原理复制过程数据同步 psync全量复制部分复制实时复制 小结 主从复制 这部分相关操作不需要记忆!!! 后续⼯作中如果⽤到了能查到即可. 重点理解流程和原理. 单点问题&#xff1…

onvif应用--IPC鉴权(认证)

一、鉴权原理 1&#xff09;onvif的用户验证&#xff0c;是基于WS_UsernameToken&#xff0c;所谓的WS_UsernameToken加密&#xff0c;就是将用户名、密码、Nonce、Created都包含在了header里面 参数 意义 username待认证的用户名Nonce客户端随机产生的字符串Created请求认证…

arXiv风评被害?

arXiv “风评被害”&#xff1f; arXiv是一个在学术界具有重要影响力的开放预印本论文网站&#xff0c;自三十多年前创立以来&#xff0c;它已经成为了物理学、计算机科学、统计学等科学论文最重要的发布平台之一&#xff0c;同时也是众多科研人员分享和交流研究成果的重要渠道…

单片机工程师:创新与挑战之路

摘要&#xff1a;本文全面深入地探讨了单片机工程师这一职业角色。详细阐述了单片机工程师的职责范围、所需技能&#xff0c;包括硬件设计、软件编程、调试与测试等方面。分析了单片机在不同领域的应用&#xff0c;如工业控制、消费电子、智能家居等。同时&#xff0c;探讨了单…

【计算机组成原理】计算机系统的基本组成

文章目录 计算机硬件的基本组成早期的冯诺依曼机冯诺依曼结构冯诺依曼机的特点 现代计算机现代计算机的结构 各硬件的工作原理主存储器主存储器的基本组成 运算器运算器的基本组成 控制器控制器的基本组成 计算机软件 计算机硬件的基本组成 早期的冯诺依曼机 冯诺依曼在研究 …

图纸文件怎么加密?2024六款图纸加密软件推荐,个个好用不踩雷!

想象一下&#xff0c;公司的设计图纸被无意间泄露&#xff0c;结果对手提前推出了相似的产品。为了避免这种令人头疼的情况发生&#xff0c;图纸加密就显得尤为重要。 别担心&#xff0c;今天我们就带你了解2024年六款超好用的图纸加密软件&#xff0c;让你的图纸“安全感”爆…

业务复杂度治理方法论--十年系统设计经验总结

一、复杂度综述 1、什么是复杂度 软件设计的核心在于降低复杂性。 --《软件设计的哲学》 业界对于复杂度并没有统一的定义&#xff0c;斯坦福教授John Ousterhout从认知负担和工作量方面给出了一个复杂度量公式 &#xfeff; &#xfeff;&#xfeff; 子模块的复杂度cp乘…

快充协议方案的工作原理及场景应用

快充协议芯片是支持各种快充快充协议的芯片&#xff0c;它们能智能识别插入的设备类型&#xff0c;并根据设备的需求调整充电电压和电流&#xff0c;从而实现快速充电。 XSP08Q芯片是内置快充功能的协议芯片&#xff0c;它基于先进的充电技术&#xff0c;通过协商电压和电流&a…

【数据结构】二叉树顺序存储结构堆的应用以及解决TOP-K问题

文章目录 前言1. 堆的应用1.1 堆排序1.2 TOP-K问题 2. 结语 前言 前面我们学习了堆这个数据结构&#xff0c;这种数据结构是一种顺序结构存储的完全二叉树&#xff0c;现在我们来看一看堆的应用。 1. 堆的应用 1.1 堆排序 版本一&#xff1a;基于已有数组建堆、取堆顶元素完…

Linux CentOS 部署Docker

1. yum 配置 &#xff08;1&#xff09;更新yum yum update -y 如果不升级更新yum 可能在后续docker部署后再更新容器会出现oci runtime error等 &#xff08;2&#xff09;安装yum工具类准备 yum install -y yum-utils device-mapper-persistent-data lvm2 &#xff08;3&…

不再为存储‘分家’烦恼,teamOS让你的数据全家桶,一键即达

在数字化浪潮下&#xff0c;数据管理已成为企业运营的核心环节。作为企业管理者&#xff0c;我深知数据的重要性&#xff0c;也明白数据管理所面临的种种挑战。 最近开始使用企业网盘&#xff0c;在体验了一段时间后&#xff0c;目前来说&#xff0c;让我比较满意的就是可道云…

C盘红了怎么办?C盘快满了怎么办?如何提高电脑运行速度?

在电脑的日常使用中&#xff0c;C盘红了&#xff08;也就是C盘满了&#xff09;&#xff0c;那是常有的事&#xff0c;本文将详述一下&#xff0c;C盘红了之后的多种处理方法&#xff0c;只要你看完了&#xff0c;就必有一款适合你。 一、系统自带的磁盘清理 当你的C盘红了&…

vue3 置空a-select数据

置空a-select数据 项目中遇到需求&#xff0c;选择第一个下拉框后&#xff0c;发请求获取数据第二个下拉框数据&#xff08;第二个下拉框已选的情况下需要置空&#xff09;。 解决方法&#xff1a;formData.value.checkUser {value: “” ,label:“”} <a-col :span"…

Win32中的字符串

ANSI字符和Unicode字符 在Visual C中&#xff0c;用CHAR来表示8位ANSI字符&#xff0c;用WCHAR来表示16位Unicode字符&#xff08;宽字符&#xff09; 1 typedef char CHAR 2 typedef wchar_t WCHAR 一般常用的定义如下 TypedefDefinitionCHARcharPSTR or LPSTRchar*PCSTR o…

一个跨平台的换源工具,一键更换操作系统上的软件源或镜像源

大家好&#xff0c;今天给大家分享的是一个全平台通用换源工具chsrc&#xff0c;旨在为各种软件在不同平台上提供从命令行进行换源的功能。 项目介绍 chsrc支持 Linux&#xff08;包括麒麟、openEuler、deepin 等&#xff09;、Windows、macOS、BSD 等多种操作系统&#xff0c…

MySQL数据类型-介绍

MySQL 支持多种数据类型&#xff0c;这些数据类型可以根据它们所存储的数据类型大致分为几类&#xff1a;数值类型、日期和时间类型、字符串&#xff08;字符&#xff09;类型、空间数据类型以及JSON数据类型。 一、数据类型 1.整数类型 TINYINT&#xff1a;非常小的整数。例…

第 2 章:AJAX 的使用

AJAX 的使用 核心对象&#xff1a;XMLHttpRequest&#xff0c;AJAX 的所有操作都是通过该对象进行的。 1. 使用步骤 创建 XMLHttpRequest 对象 var xhr new XMLHttpRequest(); 设置请求信息 xhr.open(method, url);//可以设置请求头&#xff0c;一般不设置 xhr.setReques…

计算机网络八股文之TCP协议

TCP/IP模型 链路层 物理层&#xff1a;主要定义物理设备标准&#xff0c;如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流&#xff08;就是由1、0转化为电流强弱来进行传输&#xff0c;到达目的地后再转化为1、0&#xff0c;也就是我们…

WPS Office for Linux 12 个人版上线deepin 23商店:UI 视觉重构,新增多项 AI 功能

查看原文 全新WPS Office For Linux个人版&#xff08;12.1.0.17881&#xff09;与deepin 23的AI功能深度融合&#xff0c;正式上架在社区商店啦&#xff01; 这是 Linux 版本的一次里程碑式的重大更新。在产品能力层面上&#xff0c;在 deepin 23 上WPS Office 几乎实现了与 …