Linux环境下部署Kubernetes集群的全过程

 更新时间:2026年04月22日 09:16:53   作者:知远漫谈  
在当今云原生时代,Kubernetes 已成为容器编排的事实标准,掌握 Kubernetes 的部署与运维能力都已成为必备技能,本文将带你从零开始,在 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 核心数内存存储空间
Master24GB20GB
Worker24GB20GB

操作系统推荐使用 Ubuntu 22.04 LTSCentOS 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 对时间同步非常敏感,推荐使用 chronyntp

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: password

Secret 数据在 etcd 中是 Base64 编码存储,建议生产环境启用加密或使用外部密钥管理服务(如 HashiCorp Vault)。

监控与日志收集

虽然不是本文重点,但生产环境不可或缺:

  • Prometheus + Grafana:监控集群资源与应用指标。
  • EFK Stack(Elasticsearch + Fluentd + Kibana):集中式日志收集与分析。
  • Loki + Promtail + Grafana:轻量级日志方案。

高可用架构进阶(简述)

上述部署为单 Master,生产环境建议:

  1. 多 Master + 负载均衡器:使用 HAProxy 或云厂商 LB。
  2. 外部 etcd 集群:独立部署 etcd,提高稳定性。
  3. 存储持久化:使用 CSI 插件对接云存储或 Ceph。
  4. 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.nodeName

Java 代码中读取:

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  ProFTPd安装与卸载详细介绍

    Linux ProFTPd安装与卸载详细介绍

    这篇文章主要介绍了Linux ProFTPd安装与卸载详细介绍的相关资料,需要的朋友可以参考下
    2016-10-10
  • 对send(),recv()函数的全面理解

    对send(),recv()函数的全面理解

    下面小编就为大家带来一篇对send(),recv()函数的全面理解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Linux配置VSFTP服务器的方法

    Linux配置VSFTP服务器的方法

    下面小编就为大家带来一篇Linux配置VSFTP服务器的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Linux内存泄漏检测实现原理与过程分析

    Linux内存泄漏检测实现原理与过程分析

    这篇文章主要介绍了Linux内存泄漏检测实现原理与过程分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • shell脚本批量执行ping和telnet测试网络方式

    shell脚本批量执行ping和telnet测试网络方式

    文章介绍了如何通过创建shell脚本来简化本地网络测试任务,包括ping和telnet测试,文章详细描述了脚本的创建、编辑、赋予执行权限以及执行的步骤,并提供了具体的脚本示例
    2024-12-12
  • 阿里云ECS实例设置用户root密码和远程连接的方法

    阿里云ECS实例设置用户root密码和远程连接的方法

    这篇文章主要介绍了阿里云ECS实例设置用户root密码和远程连接的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Linux drm_syncobj机制原理与应用方式

    Linux drm_syncobj机制原理与应用方式

    DRM_syncobj是Linux内核中用于GPU同步的抽象,支持二元与时间线语义,提供高效用户接口,实现跨进程/驱动同步,满足现代图形API如Vulkan的复杂需求
    2025-09-09
  • Linux 通过Rsync+Inotify实现本、异地远程数据实时同步功能

    Linux 通过Rsync+Inotify实现本、异地远程数据实时同步功能

    这篇文章主要介绍了Linux 通过Rsync+Inotify实现本、异地远程数据实时同步功能,需要的朋友可以参考下
    2020-04-04
  • 浅析Linux resolv.conf

    浅析Linux resolv.conf

    这篇文章主要介绍了Linux resolv.conf的相关资料,帮助大家更好的理解和学习Linux,感兴趣的朋友可以了解下
    2020-08-08
  • .htaccess设置指南经典说明

    .htaccess设置指南经典说明

    .htaccess 会降低APACHE的性能,除非你对目录权限要求很高或需要做UrlRewrite,否则不推荐你使用.
    2008-04-04

最新评论