在当今云原生时代,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集群的资料请关注代码网其它相关文章!
发表评论