Linux环境下部署Kubernetes集群的全过程
在当今云原生时代,Kubernetes 已成为容器编排的事实标准。无论你是 DevOps 工程师、后端开发者,还是系统架构师,掌握 Kubernetes 的部署与运维能力都已成为必备技能。本文将带你从零开始,在 Linux 环境中完整部署一个高可用的 Kubernetes 集群,并通过 Java 应用演示其部署、伸缩与服务发现能力。
提示:本文内容基于 Ubuntu 22.04 LTS 操作系统,但大部分命令适用于主流 Linux 发行版如 CentOS、Debian、RHEL 等。
为什么选择 Kubernetes?
在深入部署之前,我们先理解一下为什么 Kubernetes 如此重要:
- 自动化部署与回滚:一键部署应用,失败自动回滚。
- 弹性伸缩:根据 CPU、内存或自定义指标自动扩缩容。
- 服务发现与负载均衡:内置 Service 机制实现内部通信与外部暴露。
- 自我修复:节点宕机自动迁移 Pod,保证服务高可用。
- 配置与密钥管理:安全地注入环境变量和敏感数据。
- 存储编排:支持本地、云盘、NFS、Ceph 等多种存储方案。
基础环境准备
系统要求
我们将部署一个包含 1 个 Master 节点 + 2 个 Worker 节点的小型集群。建议每台机器满足以下最低配置:
| 角色 | CPU 核心数 | 内存 | 存储空间 |
|---|---|---|---|
| Master | 2 | 4GB | 20GB |
| Worker | 2 | 4GB | 20GB |
操作系统推荐使用 Ubuntu 22.04 LTS 或 CentOS Stream 9。
关闭防火墙与 SELinux(可选)
# Ubuntu / Debian sudo ufw disable # CentOS / RHEL sudo systemctl stop firewalld sudo systemctl disable firewalld # 关闭 SELinux(仅限 CentOS/RHEL) sudo setenforce 0 sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
同步时间(重要!)
Kubernetes 对时间同步非常敏感,推荐使用 chrony 或 ntp:
sudo apt update && sudo apt install chrony -y sudo systemctl enable chronyd && sudo systemctl start chronyd chronyc sources -v
安装 Docker 或 containerd
Kubernetes 1.24+ 不再默认支持 Docker,推荐使用 containerd 作为 CRI 运行时。
安装 containerd:
# 更新包索引 sudo apt update # 安装依赖 sudo apt install -y ca-certificates curl gnupg lsb-release # 添加 Docker GPG 密钥(用于 containerd) curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 添加源 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 containerd sudo apt update && sudo apt install -y containerd.io # 配置 containerd 使用 systemd cgroup sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml # 重启并启用 sudo systemctl restart containerd sudo systemctl enable containerd
安装 kubeadm、kubelet 和 kubectl
这是部署 Kubernetes 集群的核心工具链:
kubeadm:用于初始化集群。kubelet:运行在所有节点上,负责 Pod 生命周期。kubectl:命令行控制工具。
# 添加 Kubernetes APT 源 sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list # 安装指定版本(推荐 v1.28.x) sudo apt update sudo apt install -y kubelet=1.28.0-00 kubeadm=1.28.0-00 kubectl=1.28.0-00 # 锁定版本防止自动升级 sudo apt-mark hold kubelet kubeadm kubectl
小贴士:生产环境中建议锁定版本,避免因自动升级导致兼容性问题。
配置网络与主机名
确保各节点之间可以通过主机名互相解析:
# 设置主机名(分别在 master、worker1、worker2 上执行) sudo hostnamectl set-hostname k8s-master sudo hostnamectl set-hostname k8s-worker1 sudo hostnamectl set-hostname k8s-worker2 # 编辑 /etc/hosts,添加如下内容(IP 替换为实际值) 192.168.1.100 k8s-master 192.168.1.101 k8s-worker1 192.168.1.102 k8s-worker2
初始化 Master 节点
现在我们正式初始化 Kubernetes 控制平面:
sudo kubeadm init \ --pod-network-cidr=10.244.0.0/16 \ --apiserver-advertise-address=192.168.1.100 \ --control-plane-endpoint=k8s-master:6443 \ --upload-certs
参数说明:
--pod-network-cidr:Pod 网络 CIDR,Flannel 默认使用10.244.0.0/16--apiserver-advertise-address:API Server 绑定的 IP 地址--control-plane-endpoint:控制平面访问端点(便于未来扩展 HA)--upload-certs:上传证书,便于后续加入其他控制节点
配置 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
验证是否成功:
kubectl get nodes # 此时应看到 master 节点状态为 NotReady(因为还未安装网络插件)
安装 Pod 网络插件 —— Flannel
Kubernetes 需要 CNI 插件来实现 Pod 间通信。我们选择轻量级的 Flannel:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
等待几分钟,再次检查节点状态:
kubectl get nodes # STATUS 应变为 Ready
加入 Worker 节点
回到 Master 初始化输出的最后一段,复制 kubeadm join 命令,在每个 Worker 节点上执行:
sudo kubeadm join k8s-master:6443 \ --token <your-token> \ --discovery-token-ca-cert-hash sha256:<your-hash>
如果你丢失了 join 命令,可以在 Master 上重新生成:
kubeadm token create --print-join-command
等待几分钟,再次在 Master 上执行:
kubectl get nodes # 应看到所有节点状态为 Ready
集群拓扑结构图
下面是一个典型的三节点 Kubernetes 集群架构图:

该图展示了客户端请求如何通过负载均衡器进入 API Server,再由调度器分发到各个工作节点上的 Pod 中。每个 Pod 可以运行不同的服务,例如 Java 应用、数据库、缓存等。
验证集群功能
创建测试命名空间
kubectl create namespace test-app kubectl config set-context --current --namespace=test-app
部署第一个 Pod —— nginx
kubectl create deployment nginx --image=nginx:latest kubectl expose deployment nginx --port=80 --type=NodePort kubectl get svc nginx
访问任一节点 IP + NodePort 即可看到欢迎页。
编写 Java Spring Boot 应用
下面我们编写一个简单的 Java 应用,用于部署到 Kubernetes 集群中。
Maven 项目结构
src/ ├── main/ │ ├── java/ │ │ └── com/example/demo/ │ │ ├── DemoApplication.java │ │ └── HelloController.java │ └── resources/ │ └── application.properties pom.xml Dockerfile
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>k8s-demo-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/>
</parent>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}HelloController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.InetAddress;
import java.net.UnknownHostException;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() throws UnknownHostException {
String hostname = InetAddress.getLocalHost().getHostName();
return "Hello from Java Spring Boot! Host: " + hostname + " 🎉";
}
@GetMapping("/health")
public String health() {
return "UP";
}
}application.properties
server.port=8080 management.endpoints.web.exposure.include=* management.endpoint.health.show-details=always
Dockerfile
FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY target/k8s-demo-app-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
构建并推送镜像
在项目根目录执行:
mvn clean package docker build -t your-dockerhub-username/k8s-java-app:v1 . docker login docker push your-dockerhub-username/k8s-java-app:v1
替换 your-dockerhub-username 为你自己的 Docker Hub 用户名。
部署 Java 应用到 Kubernetes
创建 Deployment
# java-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
namespace: test-app
spec:
replicas: 3
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
containers:
- name: java-app
image: your-dockerhub-username/k8s-java-app:v1
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"部署:
kubectl apply -f java-app-deployment.yaml
创建 Service
# java-app-service.yaml
apiVersion: v1
kind: Service
metadata:
name: java-app-service
namespace: test-app
spec:
selector:
app: java-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: NodePort部署:
kubectl apply -f java-app-service.yaml kubectl get svc java-app-service -n test-app
访问 http://<NODE_IP>:<NODE_PORT>/hello,你会看到类似:
Hello from Java Spring Boot! Host: java-app-5d7c8f9b4d-xyz12 🎉
刷新页面,你会发现 Host 名称变化,说明请求被负载均衡到了不同 Pod!
自动扩缩容演示
Kubernetes 支持根据 CPU 使用率自动扩缩容:
# 创建 HPA(Horizontal Pod Autoscaler) kubectl autoscale deployment java-app --cpu-percent=50 --min=2 --max=10 -n test-app # 查看 HPA 状态 kubectl get hpa -n test-app # 模拟压力测试(新开终端) kubectl run load-test --image=busybox --rm -it --restart=Never -- sh -c "while true; do wget -q -O- http://java-app-service/hello; echo; sleep 0.5; done"
观察 HPA 是否触发扩容:
watch kubectl get pods -n test-app
当 CPU 超过阈值,副本数会自动增加;压力解除后,又会自动缩减。
服务发现与 ConfigMap
Kubernetes 内部服务可通过 DNS 自动发现。例如,我们的 Java 应用想连接 Redis,只需知道 Service 名称即可:
// 在 Java 代码中
String redisHost = System.getenv().getOrDefault("REDIS_HOST", "redis-service.test-app.svc.cluster.local");
int redisPort = Integer.parseInt(System.getenv().getOrDefault("REDIS_PORT", "6379"));
同时,我们可以使用 ConfigMap 注入配置:
# app-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: test-app data: APP_NAME: "MyK8sApp" LOG_LEVEL: "INFO" REDIS_HOST: "redis-service" REDIS_PORT: "6379"
在 Deployment 中引用:
envFrom:
- configMapRef:
name: app-config这样,无需修改代码或重建镜像,即可动态调整配置!
使用 Secret 管理敏感信息
比如数据库密码:
kubectl create secret generic db-secret \ --from-literal=username=admin \ --from-literal=password=SuperSecret123! \ -n test-app
在 Deployment 中挂载:
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: passwordSecret 数据在 etcd 中是 Base64 编码存储,建议生产环境启用加密或使用外部密钥管理服务(如 HashiCorp Vault)。
监控与日志收集
虽然不是本文重点,但生产环境不可或缺:
- Prometheus + Grafana:监控集群资源与应用指标。
- EFK Stack(Elasticsearch + Fluentd + Kibana):集中式日志收集与分析。
- Loki + Promtail + Grafana:轻量级日志方案。
高可用架构进阶(简述)
上述部署为单 Master,生产环境建议:
- 多 Master + 负载均衡器:使用 HAProxy 或云厂商 LB。
- 外部 etcd 集群:独立部署 etcd,提高稳定性。
- 存储持久化:使用 CSI 插件对接云存储或 Ceph。
- Ingress Controller:如 Nginx Ingress、Traefik,统一管理外部访问。

故障模拟与恢复
手动删除一个 Pod
kubectl delete pod <pod-name> -n test-app
观察 Deployment 是否自动重建新 Pod:
kubectl get pods -w -n test-app
Kubernetes 会确保副本数始终符合期望值。
模拟节点宕机
关闭一台 Worker 节点:
sudo shutdown now
在 Master 上查看:
kubectl get nodes # 该节点状态变为 NotReady kubectl get pods -o wide # 原本运行在该节点上的 Pod 会被标记为 Unknown 或 NodeLost
等待约 5 分钟(默认驱逐超时),Pod 会自动迁移到健康节点!
常用调试命令汇总
# 查看所有资源 kubectl get all -A # 查看 Pod 日志 kubectl logs <pod-name> -n test-app # 进入 Pod 内部 kubectl exec -it <pod-name> -n test-app -- sh # 查看事件(排错神器) kubectl get events -n test-app --sort-by='.lastTimestamp' # 查看节点资源使用 kubectl top nodes kubectl top pods -n test-app # 描述资源详情 kubectl describe pod <pod-name> -n test-app
常见问题与解决方案
Pod 一直处于 Pending 状态
可能原因:
- 资源不足(CPU/Memory)
- 节点选择器不匹配
- PVC 未绑定
解决方法:
kubectl describe pod <pod-name> # 查看 Events 部分
ImagePullBackOff
镜像拉取失败:
- 检查镜像名称是否正确
- 私有仓库需配置
imagePullSecrets - 网络策略限制
kubectl get events --field-selector reason=Failed
CrashLoopBackOff
容器反复崩溃:
- 检查启动命令是否正确
- 查看日志:
kubectl logs <pod> --previous - 检查探针配置是否过于严格
Java 开发者专属技巧
在 Java 应用中读取 Pod 信息
Kubernetes 会将 Pod 信息通过 Downward API 注入环境变量或文件:
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeNameJava 代码中读取:
String podName = System.getenv("MY_POD_NAME");
String namespace = System.getenv("MY_POD_NAMESPACE");
System.out.println("Running in Pod: " + podName + ", Namespace: " + namespace);
使用 Actuator 暴露健康检查端点
前面我们已集成 spring-boot-starter-actuator,它提供:
/actuator/health:健康状态/actuator/metrics:性能指标/actuator/env:环境变量
配合 Prometheus 可采集 JVM 指标:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>访问 http://<service>/actuator/prometheus 即可获取指标数据。
使用 Helm 简化部署(进阶)
Helm 是 Kubernetes 的包管理器,类似 Linux 的 apt/yum。
安装 Helm:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
添加仓库 & 部署 Java 应用 Chart:
helm repo add bitnami https://charts.bitnami.com/bitnami helm install my-java-app bitnami/tomcat --set service.type=NodePort
集成 CI/CD 流水线
推荐使用 GitLab CI 或 GitHub Actions 自动构建镜像并部署:
# .gitlab-ci.yml 示例
stages:
- build
- deploy
build_image:
stage: build
script:
- mvn package
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
deploy_to_k8s:
stage: deploy
script:
- kubectl set image deployment/java-app java-app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA -n test-app
only:
- main总结
至此,你已经完成了一个完整的 Kubernetes 集群部署,并成功运行了 Java 应用。回顾整个过程:
✅ 准备 Linux 环境
✅ 安装 containerd + kubeadm 工具链
✅ 初始化 Master 并加入 Worker 节点
✅ 部署 CNI 网络插件
✅ 编写、构建、推送 Java 镜像
✅ 通过 Deployment + Service 部署应用
✅ 配置自动扩缩容、健康检查、服务发现
✅ 学习常用调试与排错技巧
Kubernetes 的世界远不止于此,但你已经打下了坚实的基础。下一步可以探索:
- StatefulSet 管理有状态应用(如 MySQL、ZooKeeper)
- Ingress 实现域名路由
- NetworkPolicy 实现网络安全隔离
- Operator 模式自动化复杂应用管理
记住:Kubernetes 的学习曲线陡峭,但回报巨大。坚持实践,你将成为云原生时代的架构大师!
最后的话
希望这篇长文能帮助你在 Linux 上成功部署 Kubernetes,并愉快地运行 Java 应用。技术世界日新月异,但基础永远是王道。动手实践、不断试错、持续学习 —— 这才是工程师的成长之道。
以上就是Linux环境下部署Kubernetes集群的全过程的详细内容,更多关于Linux部署Kubernetes集群的资料请关注脚本之家其它相关文章!
相关文章
Linux 通过Rsync+Inotify实现本、异地远程数据实时同步功能
这篇文章主要介绍了Linux 通过Rsync+Inotify实现本、异地远程数据实时同步功能,需要的朋友可以参考下2020-04-04


最新评论