简介
Kubernetes 简称 k8s。是用于自动部署,扩展和管理容器化应用程序的开源系统。
中文官网:https://kubernetes.io/zh/
中文社区:https://www.kubernetes.org.cn/
官方文档:https://kubernetes.io/zh/docs/home/
社区文档:http://docs.kubernetes.org.cn/
Kubernetes核心组件
分类 | 组件名称 | 核心作用 | 关键功能/备注 |
|---|---|---|---|
控制平面 |
| 集群网关 | 所有内外通信的唯一入口,负责认证、鉴权、API 注册与发现。 |
| 数据存储 | 分布式数据库,存储集群的所有状态数据(Pod、Service、配置等) | |
| 调度器 | 监控新创建的 Pod,根据资源需求、亲和性规则等算法,决策将其调度到哪个具体的 Node 节点上运行。 | |
| 状态维护 | 运行多种控制器(如Deployment、Node控制器),通过循环监控确保集群当前状态与期望状态一致(例如维持Pod副本数)。 | |
网络组件 |
| 节点网络 | 负责为每个Pod分配IP,维护节点间的路由规则,实现跨节点Pod通信。 |
| 网络策略控制 | 监听K8s API,根据NetworkPolicy资源动态配置Calico底层的防火墙规则(ACL)。 | |
| DNS服务 | 集群内部的DNS服务器,为Service和Pod提供域名解析服务(服务发现),允许通过服务名互相访问。 | |
| 流量转发 | 运行在每个节点上,维护网络规则(iptables/IPVS),负责将Service的虚拟IP流量转发到后端Pod,实现负载均衡。 | |
节点代理 |
| 节点管家 | 节点必备,负责Pod生命周期管理,接收API Server指令,通过CRI接口管理容器运行时(如Containerd),上报节点状态。 |
系统资源要求
节点类型
数量
最低配置
备注
系统 控制平面(Master)
1
2 vCPU / 2GB(生产建议 4 vCPU / 8GB)
运行 API Server、etcd、Scheduler、Controller Manager
Kylin v10 sp3 工作节点(Worker)
1
2 vCPU / 2GB
运行业务 Pod
Centos 7.6
系统初始化配置
加载内核模块和网络参数
所有主机均执行:
# 为了让底层支持流量转发 cat > /etc/sysctl.d/k8s.conf << EOF net.ipv4.ip_forward = 1 net.ipv4.tcp_tw_recycle = 0 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF cat > /etc/modules-load.d/k8s.conf << EOF overlay br_netfilter EOF modprobe overlay modprobe br_netfilter sysctl --system关闭防火墙及swap分区
systemctl stop firewalld && systemctl disable firewalld setenforce 0 sed -i s/SELINUX=enforcing/SELINUX=disabled/ /etc/selinux/config swapoff -a sed -ri 's/.*swap.*/#&/' /etc/fstab配置hosts解析
cat >> /etc/hosts << EOF 192.168.1.128 k8s-master 192.168.1.100 k8s-worker EOF安装containerd
containerd版本建议1.6以上,版本太低初始化会报错:相关插件加载失败
curl -LO https://mirrors.huaweicloud.com/docker-ce/linux/centos/7/x86_64/stable/Packages/containerd.io-1.6.21-3.1.el7.x86_64.rpm rpm -ivh containerd.io-1.6.21-3.1.el7.x86_64.rpm --nodeps cp /usr/bin/containerd /usr/local/bin/ 或者yum -y install containerd systemctl restart containerd systemctl enable --now containerd # 如果containerd启动失败是因为配置的插件或者是格式等等问题,可以先清空然后重置在修改 systemctl stop containerd rm -rf /etc/containerd/config.toml # 删除旧配置 rm -rf /var/lib/containerd/* # 清空数据目录 containerd config default | sudo tee /etc/containerd/config.toml #初始化生成文件 systemctl restart containerd# 版本1.60以上就行 containerd --version修改containerd配置文件,添加国内镜像源和开启systemd cgroup
/etc/containerd/config.toml
version = 2 root = "/var/lib/containerd" state = "/run/containerd" [grpc] address = "/run/containerd/containerd.sock" max_recv_message_size = 16777216 max_send_message_size = 16777216 [debug] level = "" [metrics] address = "" [cgroup] path = "" [plugins] [plugins."io.containerd.grpc.v1.cri"] # 配置国内源pause镜像,避免拉取失败 sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9" stream_server_address = "127.0.0.1" stream_server_port = "0" stream_idle_timeout = "4h0m0s" [plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" max_conf_num = 1 [plugins."io.containerd.grpc.v1.cri".containerd] default_runtime_name = "runc" snapshotter = "overlayfs" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] # 关键:开启systemd cgroup,和K8s kubelet保持一致 SystemdCgroup = true # 国内镜像加速配置(避免Calico拉取失败) [plugins."io.containerd.grpc.v1.cri".registry] [plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = [ "https://docker.mirrors.ustc.edu.cn", "https://registry.cn-hangzhou.aliyuncs.com", "https://hub-mirror.c.163.com", "https://docker.m.daocloud.io", "https://huecker.io", "https://dockerhub.timeweb.cloud" ] # K8s官方镜像加速(CoreDNS等组件用) [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"] endpoint = [ "https://registry.cn-hangzhou.aliyuncs.com/google_containers" ] [plugins."io.containerd.internal.v1.opt"] path = "/opt/containerd" [plugins."io.containerd.metadata.v1.bolt"] content_shard_size = 2097152 [plugins."io.containerd.snapshotter.v1.overlayfs"] slow_chattr = true [timeouts] "io.containerd.timeout.shim.cleanup" = "5s" "io.containerd.timeout.shim.load" = "5s" "io.containerd.timeout.task.state" = "2s"container服务正常启动,info输出无报错基本就没问题
crictl pull docker.io/calico/node:v3.29.4下载镜像返回Image is up to date for。。。就说明镜像下载也没问题
安装kubelet
cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key EOF yum install -y kubelet-1.30.0 kubeadm-1.30.0 kubectl-1.30.0 systemctl enable --now kubelet初始化k8s
master执行
Kubeadm init --apiserver-advertise-address=192.168.1.128 --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.30.0 # --pod-network-cidr=10.244.0.0/16 指定pod网络 # --image-repository=registry.aliyuncs.com/google_containers 指定阿里云镜像 # 如果初始化失败,可以在修复后执行以下命令清空数据重新执行init初始化 kubeadm reset -f rm -rf /etc/kubernetes/manifests/* rm -rf /etc/cni/net.d/* iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X初始化成功会提示如下
提示创建配置文件并使用命令加入到集群
mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/configworker节点
按照提示加入集群
kubeadm join 192.168.1.128:6443 --token ug4jqv.u7h3xj0k1cn4it2a --discovery-token-ca-cert-hash sha256:7dc37aad305c03516c0d322789f685ccc90e765583faae1c9b4cb3462fbd918d 986 systemctl status kublet部署网络插件calico
企业一般都选择的是calico
Calico | Flannel | |
|---|---|---|
核心定位 | 企业级网络 + 安全方案 | 轻量级 Pod 网络连通方案 |
默认转发模式 | BGP(无封装,最优)/ IPIP / VXLAN / eBPF | VXLAN(Overlay 封装)/ host-gw |
网络性能 | BGP 模式无封装,接近物理网络性能 | VXLAN 有约 50 字节包头开销,延迟增加 10-30% |
NetworkPolicy 支持 | 原生完整支持,还可扩展 GlobalNetworkPolicy、HostEndpoint | 不支持,写了策略也不生效,需搭配其他组件 |
跨子网/跨网段 | BGP/IPIP/VXLAN 多模式适应 | host-gw 要求同子网;跨子网只能用 VXLAN |
大规模集群扩展性 | 设计支持万级节点,BGP 路由收敛高效;eBPF 模式消除 iptables O(n) 瓶颈 | 节点 > 100、Service > 2000 时 iptables 规则线性增长成为瓶颈 |
资源占用 | 较高,单节点约 50-100MB 内存 | 极低,单节点约 10-20MB 内存 |
创建命名空间安装calico
kubectl create namespace calico-system kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.4/manifests/calico.yaml查看节点全部是Ready状态
核心组件全部是Running'状态
部署集群的时候除了Running以外,会常见以下几种pod状态:
ImagePullBackOff:下载镜像失败,检查网络以及containerd的镜像源、服务等,执行以下命令确保镜像可以正常下载
crictl pull docker.io/calico/node:v3.29.4
ContainerCreating:Pod 已调度到节点,正在创建容器(拉镜像、挂载卷等),如果时间太长了就得看下详情的Events
kubectl describe pod -nkube-system <pod_name>
init:0/1:初始化过程,可能是在等pasue容器,也可能是初始化数据,时间长了也得看
kubectl logs -f pod -nkube-system <pod_name>
部署应用
mysql-pv.yaml
mysql的存储定义,企业存储是NFS、glusterfs等,这里为了方便用的是本地磁盘
apiVersion: v1 kind: PersistentVolume metadata: name: mysql-local-pv # PV 的名称 spec: capacity: storage: 5Gi # 申请的磁盘大小 accessModes: - ReadWriteOnce # MySQL 只能单节点读写 persistentVolumeReclaimPolicy: Retain # 删除 PVC 后保留数据 storageClassName: local-storage-mysql # 定义一个StorageClass名称,供 PVC 引用 local: path: /data/mysql-pv # 宿主机本地目录 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - k8s-worker # 节点名称,kubectl get nodes 查看kubectl apply -f mysql-pv.yaml kubectl get pvmysql-secret.yaml
存储敏感信息
apiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque data: # 可选:创建一个普通用户 mysql-user: root # echo -n "123456"|base64 mysql-password: MTIzNDU2kubectl apply -f mysql-secret.yaml kubectl get secretmysql-service.yaml
服务发现映射
映射NodePort端口默认范围是30000-32767,如需修改,需要修改api-server的启动参数
apiVersion: v1 kind: Service metadata: name: mysql-service labels: app: mysql spec: type: NodePort #定义nodeport类型 selector: app: mysql ports: - name: mysql port: 3306 targetPort: 3306 # 容器端口 nodePort: 30036 # 宿主机端口kubectl apply -f mysql-service.yaml kubectl get svc -A | grep mysqlmysql-configmap
配置文件资源
apiVersion: v1 kind: ConfigMap metadata: name: mysql-config data: my.cnf: | [mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci max_connections=500 slow_query_log=1 slow_query_log_file=/var/lib/mysql/slow.log long_query_time=2 innodb_buffer_pool_size=1G skip-name-resolvekubectl apply -f mysql-configmap.yaml kubectl get configmap | grep mysqlmysql-statefulset.yaml
控制器
apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: "mysql" replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: terminationGracePeriodSeconds: 60 # 等待MySQL关机时间 containers: - name: mysql image: mysql:5.7.44 imagePullPolicy: IfNotPresent args: - "--default-authentication-plugin=mysql_native_password" - "--lower_case_table_names=1" # 忽略表名大小写 ports: - containerPort: 3306 name: mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: mysql-password # 可选:初始化数据库 # - name: MYSQL_DATABASE # value: appdb resources: requests: cpu: 100m memory: 512Mi limits: cpu: "1" memory: 1Gi # 存货和就绪探针 livenessProbe: exec: command: ["mysqladmin", "ping", "-h", "localhost", "-uroot", "-p"] initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 readinessProbe: exec: command: ["mysqladmin", "ping", "-h", "localhost", "-uroot", "-p"] initialDelaySeconds: 5 periodSeconds: 10 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql # MySQL 数据目录 - name: mysql-conf mountPath: /etc/mysql/conf.d # 配置文件目录 volumes: - name: mysql-conf configMap: name: mysql-config # 引用创建的 ConfigMap名字 volumeClaimTemplates: # 自动创建 PVC 的模板 - metadata: name: mysql-data spec: accessModes: ["ReadWriteOnce"] storageClassName: local-storage-mysql # 必须与PV定义的storageClassName一致 resources: requests: storage: 5Gikubectl apply -f mysql-statefulset.yaml
查看deceribe发现报错:
绑定的worker节点没有这个目录,忘了创建了,手动去对应机器创建
mkdir -p /data/mysql-pv chmod -R 755 /data/mysql-pv删除pod重启,因为控制器副本的原因(replicas)所以删除后会自动拉起新的服务,相当于重启
kubectl delete pod -ndefault mysql-0
再次查看正在下载镜像
查看pod已完成
进入mysql查看
查看配置文件,确认configmap挂载成功
测试nodeport不通
排查思路:
那说明问题出现在网络这层,主要看service,endpoints,kube-proxy
查看svc正常
查看endpoints不正常,没有显示IP,说明没找到后端服务
查看svc的标签和pod的标签,标签不匹配直接导致了 Service 无法将流量转发至 Pod
kubectl describe svc mysql-service kubectl get pod mysql-0 -o yaml | grep -A 5 "labels"解决:
编辑service.yaml,修改Selector为app: mysql
然后重建svc
kubectl delete svc mysql-service kubectl apply -f mysql-service.yaml kubectl get endpoints显示了后端IP
再次访问nodeport测试成功
创建数据测试
外部连接数据库可以查看到数据
------------------------至此,整个流程从创建到编写yaml部署就基本完成了-----------------------------
追加
pod的各种状态
kubectl get pods 时可以看到Pod 整体生命周期阶段,状态如下:
状态 | 含义 | 典型原因 | 处理方向 |
|---|---|---|---|
Pending | Pod 已被 API Server 接收,但还未调度到节点或容器镜像未拉取完 | 资源不足、节点有污点、PVC 未绑定、镜像拉取中 |
|
ContainerCreating | Pod 已调度到节点,正在创建容器(拉镜像、挂载卷等) | 正在拉镜像、等待 PV 挂载、CNI 分配 IP 中 | 一般短暂出现,长时间停留则 |
Running | Pod 已绑定到节点,所有容器已创建,至少一个容器在运行 | 正常工作状态 | 配合 READY 列看是否就绪 |
Succeeded | 所有容器正常退出(exit 0)且不再重启 | Job/CronJob 执行完成 | 正常状态,无需处理 |
Failed | 所有容器终止,且至少一个容器以非 0 状态退出 | 应用错误、OOM、配置错误 | 看日志和退出码 |
Unknown | API Server 无法获取 Pod 状态,通常是节点 kubelet 失联 | 节点 NotReady、kubelet 挂掉、网络分区 | 检查节点状态 |
Terminating | Pod 正在被删除,处于终止过程中 | 执行了 delete、滚动更新、驱逐 | 一般 30 秒内消失,长时间停留说明优雅停机卡住 |
| CrashLoopBackOff | 容器反复启动后崩溃,kubelet 退避重试 | 应用配置错误、依赖服务不可用、exit code 非 0 | 看日志 |
| ImagePullBackOff | 拉取镜像失败,按指数退避重试 | 镜像名/tag 错误、私有仓库无权限、网络不通 | 检查镜像标签,检测网络 |
三大控制器的区别
为啥mysql要用statefulset,因为它需要固定的网络标识和独立的持久化存储。
Deployment | 无状态应用 | Web 服务、API、前端 | 滚动更新、回滚、声明式配置、扩缩容 |
StatefulSet | 有状态应用 | MySQL、Redis、Kafka、Zookeeper | 稳定的网络标识(固定 Pod 名)、独立 PVC、有序扩缩容 |
DaemonSet | 节点级守护进程 | 日志采集、监控 Agent、CNI 网络插件 | 每个节点(或匹配节点)运行且只运行一个 Pod |
安装helm
wget https://get.helm.sh/helm-v3.15.3-linux-amd64.tar.gz
tar -zxvf helm-v3.15.3-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm
helm list -A #查看列表 helm install <业务名> <资源名/目录名> #以当前目录资源安装 helm uninstall <业务名> # 卸载 helm template <业务名> # 模板渲染,检查语法 helm create <资源名/目录名> # 创建资源创建nginx资源
helm create nginxvalues.yaml:环境变量定义
templates:存放各种资源模板
修改values.yaml,配置nodeport
编辑templates/service.yaml
添加这一行,走向values里定义的nodeport
helm install my-nginx nginx测试nodeport正常