Kubernetes学习指北之单节点集群(Master)
Kubernetes学习指北之单节点集群(Master)
一、 单节点集群(Single Node Cluster)说明
学习和开发利器,操作简单
特点
- Master 节点和 Worker 节点在同一台机器上
- kube-apiserver、kube-scheduler、kube-controller-manager、kubelet 都在同一台机器
- Pod 也在同一台机器上运行
- 资源有限:所有容器共享同一台机器的 CPU、内存和存储
- 高可用性低:Master 节点宕机,整个集群不可用
- 网络简单:只需一个节点,Pod 网络配置相对简单
适用场景
- 学习和测试 Kubernetes 核心概念
- 开发环境部署微服务
- 练习 kubectl 命令、Deployment、Service 等
优点
配置简单,一条命令就能搭建
资源占用低,不需要多台虚拟机
部署快速,便于练手
缺点
不适合生产环境
没有高可用性
无法模拟真实多节点调度
二、 准备环境和工具
- 这里我使用的CentOS7
- 做一些初始化
1# 切换 root 2sudo -i 3 4# 关闭防火墙(实验环境) 5systemctl stop firewalld 6systemctl disable firewalld 7 8# 关闭 selinux 9setenforce 0 10sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config 11 12# 关闭 swap 13swapoff -a 14sed -i '/swap/d' /etc/fstab 15 16# 调整内核参数(K8s 网络需要) 17cat <<EOF > /etc/sysctl.d/k8s.conf 18net.bridge.bridge-nf-call-ip6tables = 1 19net.bridge.bridge-nf-call-iptables = 1 20EOF 21sysctl --system
三 、 安装 Docker 或 Containerd
Kubernetes 需要一个容器运行时,这里推荐 containerd(更接近 K8s 原生)。
1# 安装 containerd
2yum install -y yum-utils device-mapper-persistent-data lvm2
3
4# 添加 Docker CE 源(阿里云加速)
5yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
6
7# 更新缓存
8yum makecache fast
9
10# 安装 containerd
11yum install -y containerd.io
12
13# 生成默认配置
14mkdir -p /etc/containerd
15containerd config default > /etc/containerd/config.toml
16
17# 修改 SystemdCgroup = true(K8s 要求)
18sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
19
20# 启动并开机自启
21systemctl enable --now containerd
22systemctl status containerd
如果 yum install -y yum-utils device-mapper-persistent-data lvm2出现Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock error was 14: curl#6 - “Could not resolve host: mirrorlist.centos.org; Unknown error” 这类问题需要切换到可用镜像源
- 替换 CentOS 镜像源
# 备份旧的 repo 文件 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak # 使用 vault 源(CentOS 官方归档) cat <<EOF | sudo tee /etc/yum.repos.d/CentOS-Base.repo [base] name=CentOS-7 - Base baseurl=http://vault.centos.org/7.9.2009/os/\$basearch/ gpgcheck=0 enabled=1 [updates] name=CentOS-7 - Updates baseurl=http://vault.centos.org/7.9.2009/updates/\$basearch/ gpgcheck=0 enabled=1 [extras] name=CentOS-7 - Extras baseurl=http://vault.centos.org/7.9.2009/extras/\$basearch/ gpgcheck=0 enabled=1 EOF # 清理缓存并更新 yum clean all yum makecache - 使用阿里云镜像(更快,推荐国内用户)
1# 下载阿里云 repo 文件 2sudo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 3 4# 清理缓存并更新 5yum clean all 6yum makecache - 检查 DNS(如果还报 Could not resolve host)
- 说明虚拟机网络没配置好,先检查 DNS:
cat /etc/resolv.conf - 如果里面没有:
nameserver 8.8.8.8 nameserver 114.114.114.114 - 就加上:
1echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf 2echo "nameserver 114.114.114.114" | sudo tee -a /etc/resolv.conf
- 说明虚拟机网络没配置好,先检查 DNS:
四、安装 Kubernetes 工具
安装 kubeadm、kubelet、kubectl。
1# 添加 Kubernetes 仓库
2cat <<EOF > /etc/yum.repos.d/kubernetes.repo
3[kubernetes]
4name=Kubernetes
5baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
6enabled=1
7gpgcheck=0
8repo_gpgcheck=0
9EOF
10
11# 安装
12yum install -y kubelet kubeadm kubectl
13
14# 开机自启
15systemctl enable kubelet
五、初始化单节点集群
1# 使用 kubeadm 初始化(--pod-network-cidr 根据网络插件而定)
2kubeadm init --apiserver-advertise-address=192.168.56.10 --pod-network-cidr=10.244.0.0/16
3
4# 如果出现 /proc/sys/net/bridge/bridge-nf-call-iptables does not exist 和 /proc/sys/net/ipv4/ip_forward contents are not set to 1 执行下面的命令解决然后重新初始化:
5modprobe br_netfilter
6echo "br_netfilter" >> /etc/modules-load.d/k8s.conf
7#配置内核参数
8cat <<EOF > /etc/sysctl.d/k8s.conf
9net.bridge.bridge-nf-call-iptables = 1
10net.bridge.bridge-nf-call-ip6tables = 1
11net.ipv4.ip_forward = 1
12EOF
13# 应用配置
14sysctl --system
15#验证
16lsmod | grep br_netfilter
17cat /proc/sys/net/bridge/bridge-nf-call-iptables
18cat /proc/sys/net/ipv4/ip_forward
19# 期望输出:
20# br_netfilter 模块存在
21# bridge-nf-call-iptables = 1
22# ip_forward = 1
23
24
25# 清理上一次初始化的残留
26kubeadm reset -f # 清理上次失败的初始化
27rm -rf /etc/cni/net.d # 清理 CNI 网络配置
28# 清理 iptables(避免残留规则)
29iptables -F
30iptables -t nat -F
31iptables -t mangle -F
32iptables -X
33# 清理 kubeconfig
34rm -rf $HOME/.kube
35
36# 重新初始化
37kubeadm init --apiserver-advertise-address=192.168.56.10 --pod-network-cidr=10.244.0.0/16
38
39# 如果出现拉取镜像失败问题,核心原因就是 虚拟机里根本访问不到 Google 的镜像仓库(k8s.gcr.io / registry.k8s.io),给 kubeadm 用国内的镜像源,指定 image-repository 重新初始化
40# 阿里云: registry.aliyuncs.com/google_containers
41# Azure China: gcr.azk8s.cn/google_containers
42# : quay-mirror.qiniu.com
43kubeadm init --apiserver-advertise-address=192.168.56.10 --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers
44
45# 如果出现 The kubelet is not running
46# - The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)
47# 这是 CentOS7 + kubelet 常见问题,主要原因是 cgroup 驱动没配置好 或 containerd 默认配置不对。
48# 1. 检查 kubelet 状态
49systemctl status kubelet -l
50journalctl -xeu kubelet
51# 大概率会看到类似:
52# failed to run Kubelet: failed to run Kubelet: misconfiguration: kubelet cgroup driver
53# 2. 修改 containerd 配置, 生成 containerd 默认配置:
54containerd config default > /etc/containerd/config.toml
55# 3. 编辑/etc/containerd/config.toml, 把 sandbox 镜像 改成阿里云 pause 镜像:
56[plugins."io.containerd.grpc.v1.cri"]
57 sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
58# 4. 找到 SystemdCgroup 配置(默认是 false),改成:
59[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
60 SystemdCgroup = true
61# 5. 重启 containerd & kubelet
62systemctl daemon-reexec
63systemctl restart containerd
64systemctl restart kubelet
65# 6. 清理并再次执行 kubeadm init
66sudo kubeadm reset -f
67sudo rm -rf /etc/cni/net.d
68sudo rm -rf /var/lib/etcd
69sudo rm -rf /etc/kubernetes/manifests/*
70sudo lsof -i :6443,10250,10259,10257,2379,2380
71# 如果有进程占用,可以 kill
72sudo systemctl restart kubelet
73
74kubeadm init --apiserver-advertise-address=192.168.56.10 --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers
执行成功后,会输出一段提示,包括:
- Your Kubernetes control-plane has initialized successfully!
- To start using your cluster, you need to run the following as a regular user: 配置 kubectl 的命令
kubeadm join ...(多节点才用到)
按照提示执行如:
1mkdir -p $HOME/.kube
2sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
3sudo chown $(id -u):$(id -g) $HOME/.kube/config
4Alternatively, if you are the root user, you can run:
5
6 export KUBECONFIG=/etc/kubernetes/admin.conf
六、安装网络插件(CNI)
最简单用 Flannel:
1kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
2
3# 如果访问不了,可以改成使用 阿里云加速的镜像
4# 先下载原始 yaml:
5curl -O https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
6
7# 替换国内镜像
8sed -i 's#ghcr.io/flannel-io/flannel#registry.aliyuncs.com/google_containers/flannel#g' kube-flannel.yml
9
10# 应用 Flannel
11kubectl apply -f kube-flannel.yml
12
13# 检查 Flannel Pod 状态
14kubectl get pods -n kube-system -l app=flannel -w
15# 等待 Pod 变为 Running
16# 如果一直 Pending,可能是:
17 #节点有 NoSchedule 污点(需要移除)
18 #镜像拉取失败(网络或镜像源问题)
19
20# 移除单节点控制平面的污点。 单节点控制平面默认不调度 Pod,需要允许调度:
21kubectl taint nodes k8s-single node-role.kubernetes.io/control-plane-
22
23# 再次查看节点状态
24kubectl get nodes
25# 节点 STATUS 应该从 NotReady 变为 Ready
26# 网络插件就绪后,CoreDNS Pod 也会从 Pending 变为 Running
27
28# 检查 CoreDNS
29kubectl get pods -n kube-system -l k8s-app=kube-dns
30# 一旦网络就绪,CoreDNS 应该变为 Running
31# 这是集群 DNS 功能是否正常的关键
七、允许单节点调度 Pod
默认 Master 节点不调度 Pod(但我们单机需要)。
1kubectl taint nodes --all node-role.kubernetes.io/control-plane-
八、验证集群
1# 查看节点状态
2kubectl get nodes -w
3
4# 查看 Pod 状态
5kubectl get pods -A
6kubectl get pods -n kube-system
如果节点是 Ready,Pods 都是 Running,就说明单节点集群搭建完成
1#如果节点是NotReady,说明 控制平面节点已经初始化,但网络插件(CNI)还没完全就绪。
2#查看 kube-system Pod 状态
3kubectl get pods -n kube-system
4# 重点看 kube-flannel Pod 是否 Running。
5#如果 Pod Pending 或 CrashLoopBackOff,节点就会 NotReady。
单节点 Kubernetes 就绪操作顺序
1# 1️⃣ 移除控制平面污点,允许单节点调度 Pod
2kubectl taint nodes k8s-single node-role.kubernetes.io/control-plane-
3
4# 2️⃣ 删除旧的 Flannel 配置(可选,保证干净环境)
5kubectl delete -f kube-flannel.yml
6
7# 3️⃣ 重新应用 Flannel CNI
8kubectl apply -f kube-flannel.yml
9
10# 4️⃣ 等待 Flannel Pod 启动
11kubectl get pods -n kube-system -l app=flannel -w
12# 等 Pod 全部状态变为 Running 后,Ctrl+C 退出
13
14# 5️⃣ 检查节点状态
15kubectl get nodes -o wide
16# 节点 STATUS 应该变为 Ready
17
18# 6️⃣ 检查 CoreDNS 状态
19kubectl get pods -n kube-system -l k8s-app=kube-dns
20# CoreDNS Pod 应变为 Running
21
22# 7️⃣ 测试 Pod 调度
23kubectl run nginx --image=nginx
24kubectl get pods
25# Pod 应成功调度到单节点
其他问题:
systemctl status kubelet -l
- Flannel 的 CNI 插件 Pod 拉取镜像失败
- 手动拉取镜像到节点
ctr image pull registry.aliyuncs.com/google_containers/flannel:v0.27.3ctr image pull registry.aliyuncs.com/google_containers/flannel-cni-plugin:v1.7.1-flannel1
- 标记(Tag)镜像,让 Kubernetes 能找到。Kubelet/Flannel 期望的镜像名必须和 kube-flannel.yml 中一致:
ctr images tag registry.aliyuncs.com/google_containers/flannel:v0.27.3 ghcr.io/flannel-io/flannel:v0.27.3ctr images tag registry.aliyuncs.com/google_containers/flannel-cni-plugin:v1.7.1-flannel1 registry.aliyuncs.com/google_containers/flannel-cni-plugin:v1.7.1-flannel1
- 然后重新应用 Flannel:
1kubectl delete -f kube-flannel.yml 2kubectl apply -f kube-flannel.yml
- 手动拉取镜像到节点
- 本地下载docker镜像,虚拟机导入
1# 本机下载导出
2docker save ghcr.io/flannel-io/flannel:v0.27.3 -o ./data/flannel.tar
3docker save ghcr.io/flannel-io/flannel-cni-plugin:v1.7.1-flannel1 -o ./data/flannel-cni-plugin.tar
4
5# 修改Vagrantfile共享目录
6config.vm.synced_folder "./images", "/home/vagrant/flannel-images"
7#重新挂载(虚拟机已经启动,可以直接 vagrant reload
8vagrant reload
9
10#重新ssh,切换root
11vagrant ssh k8s-single -- -F NUL
12sudo -i
13# 虚拟机里访问共享目录:
14ls /home/vagrant/flannel-images
15sudo ctr -n k8s.io images import /home/vagrant/flannel-images/flannel.tar
16sudo ctr -n k8s.io images import /home/vagrant/flannel-images/flannel-cni-plugin.tar
17
18#验证
19sudo ctr -n k8s.io images import /home/vagrant/flannel-images/flannel-cni-plugin.tar
20
21# 修改 kube-flannel 主镜像
22sed -i 's|image: registry.aliyuncs.com/google_containers/flannel:v0.*|image: ghcr.io/flannel-io/flannel:v0.27.3|' kube-flannel.yml
23
24# 修改 cni 插件镜像
25sed -i 's|image: registry.aliyuncs.com/google_containers/flannel-cni-plugin:v1.*|image: ghcr.io/flannel-io/flannel-cni-plugin:v1.7.1-flannel1|' kube-flannel.yml
26
27# 然后重新应用 Flannel:
28kubectl delete -f kube-flannel.yml
29kubectl apply -f kube-flannel.yml
30# 等待 Flannel Pod 启动
31kubectl get pods -n kube-system -l app=flannel -
32
33kubectl get nodes
34# 单节点应该从 NotReady 变成 Ready。
35
36# 如果 Flannel 容器 Running,但节点仍 NotReady,说明 kubelet 还没认到 CNI,可能需要重启 kubelet:
37sudo systemctl restart kubelet
38
39# 然后再观察状态:
40kubectl get nodes -w
九、 测试 Pod 调度
1# 查看系统命名空间的 Pod 状态
2kubectl get pods -n kube-system
3
4# 部署一个测试 Pod 验证网络:
5kubectl run nginx-test --image=nginx --restart=Never
6kubectl get pod nginx-test -o wide
7kubectl get pods
8
9# Pod IP 和节点 IP 是否在 Flannel 网段内(默认 10.244.0.0/
10kubectl get pod nginx-test -o wide
- 确认 Pod 能调度到单节点
- 如果能运行,说明单节点 Kubernetes 已完全可用
十、Laravel on Kubernetes 单节点示例
准备 Laravel 项目镜像,
- Laravel 项目目录写一个 Dockerfile,示例如下:
1FROM php:8.3-fpm 2 3# 安装 SQLite 和 Laravel 需要的扩展 4RUN apt-get update && apt-get install -y libsqlite3-dev \ 5 && docker-php-ext-install pdo pdo_sqlite bcmath 6 7# 安装 Composer 8COPY --from=composer:2 /usr/bin/composer /usr/bin/composer 9 10WORKDIR /var/www/html 11 12# 拷贝代码 13COPY . . 14 15# 安装依赖(忽略 dev) 16RUN composer install --no-dev --optimize-autoloader \ 17&& chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache - 构建镜像(假设名字叫 laravel-app:demo)
docker build -t laravel-app:demo . - 加载到 containerd(因为 kubelet 默认用 containerd 而不是 docker):
1# 保存镜像 2docker save laravel-app:demo -o laravel-app.tar 3 4# 导入到 containerd 5sudo ctr -n k8s.io images import laravel-app.tar
- Laravel 项目目录写一个 Dockerfile,示例如下:
Kubernetes YAML(最小示例)
创建一个 laravel-demo.yaml:
Secret 管理 MySQL 如:
1# 会生成一个 Secret(存储在 etcd,K8s 内部是 base64 编码的,不是明文,但还是要注意权限管理) 2kubectl create secret generic mysql-secret \ 3--from-literal=username=laravel \ 4--from-literal=password=SuperSecret123 \ 5--from-literal=database=laravel_db \ 6--from-literal=host=mysql-servicelaravel-demo.yaml示例
# ========================== # Namespace,所有资源都放在 laravel-demo 命名空间 apiVersion: v1 kind: Namespace metadata: name: laravel-demo --- # ========================== # MySQL Secret # 用来存储数据库连接信息 # 假设之前已经用 kubectl create secret 创建了,也可以在 YAML 中声明 # ========================== apiVersion: v1 kind: Secret metadata: name: mysql-secret namespace: laravel-demo type: Opaque # 数据可以省略,已经创建过 secret --- # ========================== # PHP-FPM Deployment # 运行 Laravel 的 PHP 后端 # ========================== apiVersion: apps/v1 kind: Deployment metadata: name: laravel-php namespace: laravel-demo spec: replicas: 1 # 单节点只需一个副本 selector: matchLabels: app: laravel-php template: metadata: labels: app: laravel-php spec: containers: - name: php-fpm image: php:8.3-fpm ports: - containerPort: 9000 # PHP-FPM 默认端口 env: # 从 Secret 中读取数据库信息 - name: DB_USERNAME valueFrom: secretKeyRef: name: mysql-secret key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password - name: DB_DATABASE valueFrom: secretKeyRef: name: mysql-secret key: database - name: DB_HOST valueFrom: secretKeyRef: name: mysql-secret key: host volumeMounts: - name: laravel-code mountPath: /var/www/html # Laravel 项目挂载路径 volumes: - name: laravel-code hostPath: # 挂载宿主机代码目录 path: /home/vagrant/laravel-demo type: Directory --- # ========================== # Nginx Deployment # 处理 HTTP 请求,反向代理到 PHP-FPM # ========================== apiVersion: apps/v1 kind: Deployment metadata: name: laravel-nginx namespace: laravel-demo spec: replicas: 1 selector: matchLabels: app: laravel-nginx template: metadata: labels: app: laravel-nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 # HTTP 默认端口 volumeMounts: - name: laravel-code mountPath: /var/www/html # Laravel 项目代码挂载 - name: nginx-conf mountPath: /etc/nginx/conf.d # Nginx 配置挂载 volumes: - name: laravel-code hostPath: path: /home/vagrant/laravel-demo type: Directory - name: nginx-conf configMap: name: nginx-config # 配置来自 ConfigMap --- # ========================== # Nginx 配置 ConfigMap # 配置 Nginx 反向代理到 PHP-FPM # ========================== apiVersion: v1 kind: ConfigMap metadata: name: nginx-config namespace: laravel-demo data: default.conf: | server { listen 80; server_name localhost; root /var/www/html/public; # Laravel 公共目录 index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass laravel-php:9000; # PHP-FPM 服务名和端口 fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } --- # ========================== # Nginx Service # 暴露 HTTP 端口,NodePort 用于单节点测试 # ========================== apiVersion: v1 kind: Service metadata: name: laravel-nginx-service namespace: laravel-demo spec: selector: app: laravel-nginx # 关联 Nginx Pod ports: - protocol: TCP port: 80 targetPort: 80 type: NodePort # 可以通过节点 IP:NodePort 访问部署 & 使用
# 部署
kubectl apply -f laravel-demo.yaml
# 查看 Pod 状态:
kubectl get pods
等待 laravel-app 和 laravel-nginx 都是 Running。
然后在浏览器访问:
http://<你的宿主机IP>:30080
就能打开 Laravel 的首页
- 管理
应用生命周期管理
1# 查看运行状态 2kubectl get pods 3 4# 查看详细日志(Laravel PHP-FPM Pod) 5kubectl logs -f <laravel-app-pod> -c laravel 6 7# 查看 Nginx 的日志 8kubectl logs -f <laravel-nginx-pod> -c nginx 9 10# 重启 Deployment(相当于重新部署) 11kubectl rollout restart deployment laravel-app 12kubectl rollout restart deployment laravel-nginx扩展和升级
Kubernetes 会 滚动更新,保证不中断服务。
1# 扩容(增加副本数): 2kubectl scale deployment laravel-app --replicas=3 3kubectl scale deployment laravel-nginx --replicas=2 4 5# 升级镜像(比如新版本 Laravel 代码): 6kubectl set image deployment/laravel-app laravel=laravel-app:v2监控与调试
1# 实时监控 Pod: 2kubectl get pods -w 3 4# 进入容器调试: 5kubectl exec -it <laravel-app-pod> -- bash
使用虚拟机说明
Vagrantfile 单机示例
1Vagrant.configure("2") do |config|
2 config.vm.box = "generic/centos7"
3
4 config.vm.define "k8s-single" do |vm|
5 vm.vm.hostname = "k8s-single"
6 vm.vm.network "private_network", ip: "192.168.56.10"
7
8 vm.vm.provider "virtualbox" do |vb|
9 vb.memory = 2048
10 vb.cpus = 2
11 vb.name = "vagrant-k8s-single"
12 end
13 end
14end
vagrant 命令:
1vagrant up
2
3vagrant status k8s-single
4
5vagrant ssh k8s-single -- -F NUL
6
7vagrant halt k8s-single
8# 删除虚拟机
9vagrant destroy k8s-single
发表评论