实验与工具:部署多副本应用测试负载均衡、常用命令、工具集、国内外区别、常见坑(K8S下篇)

下面用简单的示例应用,演示包含自定义镜像、多副本部署、内部服务和对外访问入口这四个部分。我们准备一个Java项目,然后将这个SSM项目上传到Master的节点/Root目录下。

Kubernetes 应用部署:

上传文件:将 Hrm_SSM.tar.gz 上传到 Master 节点的 /root 目录。

image.png

# 解压文件
tar -xzvf /root/Hrm_SSM.tar.gz
# 进入目录:
cd /root/Hrm_SSM
ls -l

# 如果看到 Hrm_SSM.war 文件,说明已经打包好。

# 如果你没有 war 包,只有散文件,执行:
# 安装 zip 工具
apt install zip -y

# 将当前目录下的所有文件打包成 war ,注意后面有一个.
zip -r Hrm_SSM.war .

# 验证是否打包成功
ls -lh /root/Hrm_SSM/*.war

准备 Dockerfile:进入解压目录(假设 war 包在 target/ 下),创建一个 Dockerfile:

# 回到 /root/Hrm_SSM 目录
cd /root/Hrm_SSM
# 新建一个文件 Dockerfile
cat > Dockerfile <<EOFFROM tomcat:9.0-jdk11-openjdk
RUN rm -rf /usr/local/tomcat/webapps/*
COPY Hrm_SSM.war /usr/local/tomcat/webapps/ROOT.war
EXPOSE 8080
CMD ["catalina.sh", "run"]
EOF

构建镜像:

先确保 Docker 已安装(在Master 节点如果没有 docker,安装一下):

# 不使用这个安装,docker.io 是 Ubuntu 官方源里的 Docker 包,它会安装 containerd 作为依赖;
# 之前已经从 Docker 官方源安装了 containerd.io,两者冲突,会报错
apt update && apt install docker.io -y

使用docker-ce安装,在 Master 节点 执行以下命令:

# 如果之前没有添加 Docker 官方仓库,先添加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

# 更新并安装 docker-ce(与 containerd.io 兼容)
apt update
apt install -y docker-ce docker-ce-cli

# 启动 Docker 并设置开机自启
systemctl start docker
systemctl enable docker

# 然后构建镜像
docker build -t hrm-ssm:latest .

# 构建成功后查看:
docker images | grep hrm-ssm

image.png

部署到 Kubernetes

创建 Deployment

cat > deployment.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hrm-ssm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hrm-ssm
  template:
    metadata:
      labels:
        app: hrm-ssm
    spec:
      containers:
      - name: hrm-ssm
        image: hrm-ssm:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
EOF

应用Deployment

kubectl apply -f deployment.yaml

创建 Service(NodePort 方式)

新建 service.yaml:

cat > service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: hrm-ssm-service
spec:
  type: NodePort
  selector:
    app: hrm-ssm
  ports:
    - port: 8080
      targetPort: 8080
      nodePort: 30080
EOF

应用service.yaml:

kubectl apply -f service.yaml

查看 Pod 状态:

kubectl get pods
kubectl get svc

等待 Pod 状态变成 Running(可能需要拉取镜像,耐心等一两分钟)。

这里遇到一个问题Pod 状态是 ErrImagePull,因为 Kubernetes(使用 containerd)找不到hrm-ssm:latest 镜像。虽然在 Deployment 中设置了 imagePullPolicy: IfNotPresent,但 containerd 的本地存储中确实没有这个镜像(Docker 构建的镜像存在 Docker 的存储里,两者是隔离的)

将 Docker 镜像导入到 containerd

# 1. 保存 Docker 镜像为 tar 文件
docker save hrm-ssm:latest -o /tmp/hrm-ssm.tar

# 2. 导入到 containerd 的 k8s 命名空间
ctr -n k8s.io image import /tmp/hrm-ssm.tar

# 3. 验证导入成功
ctr -n k8s.io image ls | grep hrm-ssm

导入成功后,删除旧的 Pod 让它重建:

kubectl delete pod hrm-ssm-75c75d4dc7-c4nmn
# 查看新 Pod 状态:
kubectl get pods -w
# 等待状态变为 Running

这里遇到坑了:因为没有将pod调度到其他两个节点,当 Pod 被调度到 Worker 节点,节点上没有这个镜像,就会尝试从 Docker Hub 拉取 → 拉取失败(因为您的镜像没有上传到 Docker Hub),目前是镜像只存在于 Master 节点上,所以 Pod 无法调度到 Worker。除非你有自己的私有镜像仓库,这里选择在master节点搭建Kubernetes (K8s) 私有镜像仓库

方案特点
适用场景
Harbor企业级,有Web UI、RBAC、漏洞扫描等生产环境、大型团队、有合规和安全要求的场景
Docker Registry轻量级,简单高效开发测试、个人项目、或对功能要求不高的场景

在 Master 节点上运行 Registry

# 拉取 registry 镜像
docker pull registry:2

# 运行 registry 容器(监听 5000 端口,并将数据持久化到 /var/lib/registry)
docker run -d \
 --name registry \
 --restart=always \
 -p 5000:5000 \
 -v /data/registry:/var/lib/registry \
 registry:2

验证:curl http://localhost:5000/v2/_catalog 应返回 {"repositories":[]}

配置所有节点(Master + Worker)信任该私有仓库(因为使用 HTTP,不是 HTTPS)

在每个节点上(包括 Master)编辑 containerd 配置文件:

vi /etc/containerd/config.toml

在 /etc/containerd/config.toml 中,找到 [plugins."io.containerd.grpc.v1.cri".registry],添加:

[plugins."io.containerd.grpc.v1.cri".registry]
 config_path = "/etc/containerd/certs.d"

然后创建目录和配置文件:

mkdir -p /etc/containerd/certs.d/162.211.180.112:5000

cat > /etc/containerd/certs.d/162.211.180.112:5000/hosts.toml <<EOF
server = "http://162.211.180.113:5000"

[host."http://162.211.180.112:5000"]
 capabilities = ["pull", "resolve", "push"]
 skip_verify = true
EOF


# 重启 containerd:
systemctl restart containerd

重新标记并推送镜像到本地仓库,在 Master 节点上:

# Master 内网 IP 为 162.211.180.112
docker tag hrm-ssm:latest 162.211.180.112:5000/hrm-ssm:latest
docker push 162.211.180.112:5000/hrm-ssm:latest

# 这一步可能会遇到报错,Docker 默认要求 registry 使用 HTTPS,但我们的私有 registry 是 HTTP 的。
# 配置 Docker 客户端信任 HTTP 仓库
cat > /etc/docker/daemon.json <<EOF
{
 "insecure-registries": ["162.211.180.112:5000"]
}
EOF

# 重启docker
systemctl restart docker

再次执行docker push 162.211.180.112:5000/hrm-ssm:latest

# 验证:curl http://162.211.180.112:5000/v2/hrm-ssm/tags/list

方法二:
# 给本地镜像打上仓库标签
docker tag hrm-ssm:final 162.211.180.113:5000/hrm-ssm:latest
# 推送到私有仓库
docker push 162.211.180.113:5000/hrm-ssm:latest

修改 Deployment 使用私有仓库镜像,并移除 nodeSelector

kubectl set image deployment/hrm-ssm hrm-ssm=10.0.0.2:5000/hrm-ssm:latest
kubectl patch deployment hrm-ssm -p '{"spec":{"template":{"spec":{"imagePullPolicy":"Always"}}}}'
kubectl patch deployment hrm-ssm --type json -p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector"}]'

删除旧 Pod 并观察新 Pod 分布

kubectl delete pods -l app=hrm-ssm
kubectl get pods -o wide

现在 Pod 应该会分布在不同的节点上

image.png

修改表结构并导入数据库

# 1. 修改 SQL 文件中的字段定义
cp /root/employee_manage.sql /root/employee_manage.sql.bak
sed -i 's/`education` varchar(2) NOT NULL/`education` varchar(20) NOT NULL/g' /root/employee_manage.sql

# 2. 删除旧数据库并重新创建
MYSQL_POD=$(kubectl get pods -l app=mysql -o jsonpath='{.items[0].metadata.name}')
kubectl exec -i $MYSQL_POD -- mysql -uroot -proot123 -e "DROP DATABASE IF EXISTS employee_manage; CREATE DATABASE employee_manage;"

# 3. 导入修改后的 SQL
kubectl exec -i $MYSQL_POD -- mysql -uroot -proot123 employee_manage < /root/employee_manage.sql

# 4. 验证
kubectl exec -i $MYSQL_POD -- mysql -uroot -proot123 -e "USE employee_manage; SELECT COUNT(*) FROM user_info;"

让外部访问

外部访开放云防火墙端口,在服务商控制台,找到 Master 节点的防火墙/安全组,添加入站规则:

协议:TCP

端口:30080

来源:0.0.0.0/0

获取 Master 公网 IP,打开浏览器,访问:http://162.211.180.112:30080

image.png

如果看到 Tomcat 默认页面或者你的项目页面,说明部署成功!

配置数据库

在 K8s 内部署 MySQL ,一键部署

cat > mysql.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  MYSQL_ROOT_PASSWORD: cm9vdDEyMw==   # 密码是 root123
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: MYSQL_ROOT_PASSWORD
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: mysql
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
EOF

kubectl apply -f mysql.yaml

等待 MySQL Pod 变成 Running

kubectl get pods -l app=mysql -w

修改项目的数据库连接配置

vi WebContent/WEB-INF/classes/jdbc.properties

在SSM 项目中,数据库配置文件 WebContent/WEB-INF/classes/ 下, jdbc.properties 或 applicationContext.xml。

修改数据库地址、用户名、密码。



K8s实用工具箱:命令、工具与排错

必知必会的kubectl命令 (kubectl Cheat Sheet)

基础操作:kubectl get nodes/pods/deployments/svc/ingress 是查看各类资源的最常用命令;

kubectl describe pod <pod-name> 和 kubectl logs <pod-name> 是排查Pod问题的首选。

创建与更新:kubectl apply -f <配置文件.yaml> 是声明式创建/更新资源的推荐方式;

kubectl delete -f <配置文件.yaml> 用于删除资源。

调试与交互:kubectl exec -it <pod-name> -- /bin/sh 可进入容器内部执行命令;

kubectl port-forward pod/<pod-name> 8080:80 可将本地端口映射到Pod端口。

集群管理:kubectl taint nodes <node-name> <key>=<value>:<effect> 用于管理节点污点;

kubectl top node/pod 可查看资源使用情况。

K8s生态常用工具

包管理工具:Helm 是K8s的包管理器,用于打包和分发应用。

可视化与监控:Portainer 提供轻量级可视化管理界面;Prometheus + Grafana 则是监控领域的黄金组合。

开发与调试:Skaffold 可实现持续开发;Netshoot 一个强大的网络排查工具。

集群排错方法:

Pod启动失败 (ImagePullBackOff, CrashLoopBackOff等):

查看状态:kubectl get pods。

描述详情:kubectl describe pod <pod-name>。

查看日志:kubectl logs <pod-name>。

Pod卡在Pending状态:通常是资源不足。用kubectl describe pod看Events部分,或用kubectl top nodes检查资源。

网络不通:确保Service和Ingress配置正确,以及网络插件(如Calico)已安装且正常运行。

国内外服务器部署差异全解析

镜像拉取加速(首要问题):国内服务器拉取k8s.gcr.io和docker.io镜像极慢甚至失败。

解决方法:配置镜像加速器,改用国内镜像仓库(如registry.aliyuncs.com/google_containers),建立私有镜像仓库同步海外镜像。

容器运行时配置:如前文上篇所述,需在/etc/containerd/config.toml中配置多个镜像加速器。

网络策略与防火墙:某些云厂商默认安全组较严格,需确保节点间所需端口(6443, 2379-2380, 10250等)已开放。

DNS和时区:在Pod里设置国内上游DNS(如114.114.114.114),并通过PodPreset等方式设置时区为Asia/Shanghai。

kubeadm初始化配置:初始化Master时,务必使用内网IP,并在所有节点正确配置/etc/hosts。初始化命令中加入--control-plane-endpoint可实现高可用。

新手避坑指南

一:忘记关闭Swap分区。free -h确认Swap行值为0。

二:网络插件安装时机错误。Worker节点应在Master节点网络插件就绪后加入。

三:忘记配置内核参数。sysctl net.bridge.bridge-nf-call-iptables返回值应为1。

四:service-cidr与pod-cidr冲突。默认值通常无问题,但如果修改,两个网段绝对不能重叠。

五:直接使用Loopback地址通信。必须通过服务名访问,推荐使用Service的DNS名称(如<service-name>.<namespace>.svc.cluster.local)。

六:生产环境使用Latest标签。这可能导致意外更新和版本混乱。始终为镜像指定明确的版本。

七:资源限制设置不当。务必在Deployment中设置resources.requests和resources.limits。

八:Secret数据未加密。对于敏感数据,应启用静态加密(Encryption at Rest) 并集成KMS插件。


本文最后更新时间 2026-06-04
文章链接地址:
https://yrajsh.cn/index.php/archives/86/
本站文章除注明[转载|引用|原文]出处外,均为本站原生内容,转载前请注明出处

文章附件
  • 暂无附件
希望可以帮助到你

留言