容器化与Kubernetes实战:从Docker到K8s全栈指南(建议收藏)
前言
前面的系列文章中,我们先后学习了Java基础、Spring全家桶、MySQL优化、Redis实战以及消息中间件。今天,我们进入云原生时代最核心的技术——容器化与Kubernetes。从Docker的基本操作,到编写Dockerfile、多阶段构建,再到Kubernetes集群的搭建、Pod、Service、Ingress、ConfigMap、存储卷、自动伸缩、Helm包管理,本文将带你全面掌握容器化部署与编排的必备技能。全文配有大量命令行示例和YAML配置,助你快速上手生产级容器化实践。
一、为什么需要容器化?
-
环境一致:开发、测试、生产环境保持一致,避免“在我机器上能运行”。
-
资源隔离:容器共享宿主机内核,但拥有独立的文件系统、网络、进程空间。
-
快速启动:容器启动是毫秒级,远快于虚拟机。
-
弹性伸缩:结合K8s,可根据负载自动增减实例。
-
交付效率:将应用及其依赖打包成镜像,通过镜像仓库分发,实现一键部署。
二、Docker核心概念与安装
1. 核心概念
-
镜像(Image):只读模板,包含应用及运行环境。
-
容器(Container):镜像的可运行实例,拥有独立的文件系统和网络。
-
仓库(Repository):存储镜像的地方(Docker Hub、私有Harbor)。
-
Dockerfile:定义镜像构建步骤的脚本。
2. 安装Docker(CentOS 7+)
# 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common
# 安装依赖
sudo yum install -y yum-utils
# 添加官方源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装Docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 验证
docker version
三、Docker常用命令与实战
1. 镜像管理
docker pull nginx:1.24 # 拉取镜像
docker images # 列出镜像
docker rmi <image_id> # 删除镜像
docker tag nginx:1.24 mynginx:v1 # 打标签
docker push myregistry/mynginx:v1 # 推送镜像
2. 容器管理
docker run -d --name mynginx -p 80:80 nginx:1.24 # 后台运行并映射端口
docker ps # 查看运行中容器
docker ps -a # 查看所有容器
docker stop <container_id> # 停止容器
docker start <container_id> # 启动已停止容器
docker rm <container_id> # 删除容器(需先停止)
docker exec -it <container_id> bash # 进入容器内部
docker logs -f <container_id> # 查看日志
3. 数据卷(Volume)
docker volume create mydata # 创建卷
docker run -v mydata:/app/data myapp # 挂载卷
# 宿主机目录挂载(推荐)
docker run -v /host/path:/container/path myapp
4. 网络模式
-
bridge(默认):容器间通过NAT通信。 -
host:使用宿主机网络栈。 -
none:无网络。 -
container:共享其他容器的网络。
docker network create mynet
docker run --network mynet --name app1 myapp
docker run --network mynet --name app2 myapp # app2可通过容器名访问app1
四、编写Dockerfile的最佳实践
1. 示例:Spring Boot应用
dockerfile
# 基础镜像(使用openjdk官方)
FROM openjdk:11-jre-slim
# 作者信息
LABEL maintainer="yourname@example.com"
# 设置工作目录
WORKDIR /app
# 复制jar包(利用docker缓存,将变动频率低的放前面)
COPY target/*.jar app.jar
# 创建非root用户
RUN groupadd -r spring && useradd -r -g spring spring
USER spring
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
2. 多阶段构建(减小镜像体积)
dockerfile
# 第一阶段:编译
FROM maven:3.8-openjdk-11 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 第二阶段:运行
FROM openjdk:11-jre-slim
COPY --from=builder /build/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
3. 构建与运行
docker build -t myapp:1.0 .
docker run -d -p 8080:8080 --name myapp myapp:1.0
4. 镜像优化建议
-
选择轻量级基础镜像(
alpine、slim版本)。 -
合并
RUN命令,减少层数。 -
清理临时文件(
apt-get clean、rm -rf /var/lib/apt/lists/*)。 -
使用
.dockerignore排除无用文件。
五、Docker Compose:多容器编排
1. 安装Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
2. 编写docker-compose.yml
yml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: mydb
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- appnet
redis:
image: redis:7-alpine
container_name: redis
ports:
- "6379:6379"
networks:
- appnet
app:
build: .
container_name: spring-app
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mydb?useSSL=false
SPRING_REDIS_HOST: redis
networks:
- appnet
volumes:
mysql_data:
networks:
appnet:
driver: bridge
3. 启动与停止
docker-compose up -d # 后台启动
docker-compose logs -f app # 查看app日志
docker-compose down # 停止并删除容器、网络(保留数据卷)
docker-compose down -v # 同时删除数据卷
六、Kubernetes核心概念
Kubernetes是一个开源的容器编排平台,用于自动部署、扩展和管理容器化应用。
1. 架构组件
-
Master节点:
-
kube-apiserver:集群统一入口,REST API。 -
etcd:分布式键值存储,保存集群状态。 -
kube-scheduler:调度Pod到合适的Node。 -
kube-controller-manager:运行各种控制器(Node、Deployment等)。
-
-
Worker节点:
-
kubelet:与Master通信,管理Pod和容器。 -
kube-proxy:维护网络规则,实现Service负载均衡。 -
容器运行时(Docker/containerd)。
-
2. 资源对象
-
Pod:最小部署单元,一个Pod包含一个或多个容器(共享网络和存储)。
-
Service:为一组Pod提供稳定的访问入口(ClusterIP、NodePort、LoadBalancer)。
-
Deployment:无状态应用的管理器,支持滚动更新、回滚、副本扩缩容。
-
StatefulSet:有状态应用(如数据库),提供稳定的网络标识和持久化存储。
-
ConfigMap / Secret:管理配置和敏感信息。
-
Ingress:七层路由,将外部请求转发到Service。
-
Namespace:资源隔离(类似虚拟集群)。
七、搭建K8s集群(使用Minikube或kubeadm)
1. 本地开发:Minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
minikube start --driver=docker --cpus=2 --memory=4096
2. 生产级:kubeadm(Ubuntu 20.04示例)
# 所有节点:安装容器运行时和kubeadm
sudo apt update && sudo apt install -y docker.io
sudo systemctl enable --now docker
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update && sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# 初始化Master(仅主节点)
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 安装网络插件(Flannel)
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
# Worker节点加入集群(主节点输出token)
kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash <hash>
八、Kubernetes核心资源操作
1. Pod
yaml
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
bash
kubectl apply -f pod.yaml
kubectl get pods -o wide
kubectl exec -it nginx-pod -- /bin/bash
kubectl delete pod nginx-pod
2. Deployment + Service
yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
ports:
- containerPort: 8080
env:
- name: ENV
value: "prod"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
type: NodePort
selector:
app: myapp
ports:
- port: 8080
targetPort: 8080
nodePort: 30080
kubectl apply -f deployment.yaml -f service.yaml
kubectl get deploy,svc,po
3. 滚动更新与回滚
# 更新镜像
kubectl set image deployment/myapp-deploy myapp=myapp:2.0
# 查看更新状态
kubectl rollout status deployment/myapp-deploy
# 回滚到上一个版本
kubectl rollout undo deployment/myapp-deploy
# 查看历史版本
kubectl rollout history deployment/myapp-deploy
4. Ingress(七层路由)
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-svc
port:
number: 8080
需要安装Ingress Controller(如Nginx Ingress):
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
5. ConfigMap 和 Secret
yaml
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
application.yml: |
server:
port: 8080
database:
url: jdbc:mysql://mysql-svc:3306/mydb
---
# secret.yaml(密码base64编码)
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
password: cm9vdDEyMw== # echo -n 'root123' | base64
在Pod中使用:
yaml
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
6. 持久化存储(PV/PVC)
yaml
# 静态PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /mnt/data
---
# PVC申请
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Pod挂载PVC:
yaml
volumes:
- name: mydata
persistentVolumeClaim:
claimName: mypvc
containers:
- volumeMounts:
- name: mydata
mountPath: /data
7. 自动伸缩(HPA)
# 安装metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 创建HPA(基于CPU)
kubectl autoscale deployment myapp-deploy --cpu-percent=50 --min=2 --max=10
# 查看HPA状态
kubectl get hpa
九、Helm:K8s应用包管理器
1. 安装Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
2. 创建Chart
helm create mychart
# 目录结构
# mychart/
# Chart.yaml # 元数据
# values.yaml # 默认配置
# templates/ # 模板文件
# charts/ # 依赖子Chart
3. 模板示例(templates/deployment.yaml)
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.appName }}
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
4. 安装与升级
helm install my-release ./mychart --set image.tag=1.0
helm upgrade my-release ./mychart --set replicaCount=3
helm list
helm uninstall my-release
十、生产环境最佳实践
1. 资源限制
-
为每个容器设置
requests和limits,避免资源争抢和节点不稳定。 -
命名空间设置
ResourceQuota限制总资源消耗。
2. 健康检查
-
livenessProbe:探测容器是否存活,失败则重启。
-
readinessProbe:探测容器是否准备好接收流量,失败则从Service端点移除。
yaml
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
3. 优雅终止
-
Pod删除时,K8s发送
SIGTERM,应用需在terminationGracePeriodSeconds(默认30s)内处理完现有请求并关闭。
yaml
spec:
terminationGracePeriodSeconds: 60
containers:
- lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
4. 使用PodDisruptionBudget保证可用性
yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: myapp
5. 镜像拉取策略
-
IfNotPresent(默认):节点上没有才拉取。 -
Always:每次启动都拉取(适合latest标签)。 -
生产环境推荐使用固定版本标签,避免意外拉取失败。
6. 日志与监控
-
日志:容器标准输出由kubelet收集,推荐使用Fluentd/Filebeat发送到ES或Loki。
-
监控:Prometheus + Grafana(kube-prometheus-stack一键部署)。
-
事件:
kubectl get events --watch,或使用开源工具(如KubeSphere)。
7. 安全加固
-
使用RBAC限制权限(不创建cluster-admin角色给普通用户)。
-
启用PodSecurityPolicy(或K8s 1.25+的Pod Security Admission)。
-
运行容器时使用非root用户(如前面Dockerfile中创建的
spring用户)。 -
扫描镜像漏洞(Trivy、Clair)。
十一、CI/CD集成示例(GitLab + K8s)
1. .gitlab-ci.yml
stages:
- build
- deploy
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
build:
stage: build
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
deploy:
stage: deploy
script:
- kubectl set image deployment/myapp-deploy myapp=$IMAGE_TAG -n prod
- kubectl rollout status deployment/myapp-deploy -n prod
only:
- main
十二、常见问题与排查
1. Pod一直处于Pending状态
-
原因:资源不足(CPU/内存),节点没有满足
nodeSelector或affinity。 -
解决:
kubectl describe pod <pod-name>查看事件,添加节点或降低资源请求。
2. CrashLoopBackOff
-
原因:容器启动后立即退出(如命令错误、依赖缺失、健康检查失败)。
-
解决:
kubectl logs <pod-name> --previous查看上次日志,检查启动命令和环境。
3. Service无法访问
-
检查
kubectl get endpoints是否有Pod IP(如果为空,检查selector是否匹配)。 -
确认网络插件(Calico/Flannel)正常工作。
-
测试ClusterIP:
kubectl run test --rm -it --image=busybox -- wget -O- http://<service-ip>:<port>
4. 证书过期
-
kubeadm集群:
sudo kubeadm certs renew all并重启kubelet。 -
设置证书自动轮换:
kubelet --rotate-certificates
结语
容器化和Kubernetes已经彻底改变了软件交付和运维的方式。从单个Docker容器到大规模K8s集群,掌握这些技术将极大提升你的工程效率和架构能力。
学习建议:
-
本地用Minikube或Kind搭建实验环境,动手部署自己的应用。
-
学习常用kubectl命令和YAML配置,熟练使用
kubectl explain。 -
尝试部署一个完整微服务(前端、后端、数据库、缓存),并配置Ingress和HPA。
-
阅读K8s官方文档,理解Controller、Scheduler、Operator等高级概念。
-
考取CKA(Certified Kubernetes Administrator)认证,系统化验证能力。
下期预告:服务网格与云原生架构实战(Istio + Envoy)。
如果本文对你有帮助,欢迎点赞、收藏、转发!
更多推荐



所有评论(0)