从零实战Docker与Kubernetes:构建云原生应用部署与运维核心技能
在云计算和运维领域,容器化与编排技术已成为现代应用部署的基石。无论是个人开发者快速搭建环境,还是企业构建微服务架构,Docker与Kubernetes(K8S)都是绕不开的核心技能。然而,面对海量零散的教程,很多朋友反馈从入门到实战的路径漫长且充满“坑点”,环境配置、概念理解、集群搭建每一步都可能卡住。
本文旨在整合一套从零开始的系统性实战教程,以 Docker 和 K8S 为核心,串联 Linux 基础与 云计算运维 的关键操作。我们将从最基础的环境安装讲起,逐步深入到镜像构建、容器管理、集群部署和服务发布,并提供完整的可复现代码与配置。无论你是刚接触运维的初学者,还是希望系统梳理容器技术的开发者,都能通过本文构建清晰的知识脉络和实操能力。
1. 背景与核心概念:为什么是 Docker 和 K8S?
在深入动手之前,理解技术解决的问题至关重要。这能帮助你在后续遇到复杂配置时,明白其设计初衷,而非机械记忆命令。
1.1 容器化技术:Docker 解决了什么?
传统软件部署面临“环境一致性”的经典难题:开发环境运行正常,测试环境报错,生产环境直接崩溃。根源在于操作系统、库依赖、配置文件的不一致。
Docker 的出现,提供了一种轻量级的标准化打包方案。它将应用及其所有依赖(库、环境变量、配置文件)打包成一个独立的“镜像”。这个镜像可以在任何安装了 Docker 引擎的机器上运行,并生成一个隔离的“容器”进程。简单理解:
-
镜像 (Image)
:类似于软件安装包(如
.exe或.dmg),是一个只读的模板。 - 容器 (Container) :类似于运行起来的软件进程,是基于镜像创建的可读写实例。
Docker 的核心价值 :一次构建,处处运行。它实现了开发、测试、生产环境的绝对一致,极大地简化了持续集成和交付(CI/CD)的流程。
1.2 容器编排:为什么需要 Kubernetes (K8S)?
当你的应用从单体架构演进为数十上百个微服务时,每个服务都可能由多个容器实例组成。这时,手动管理容器的生命周期(创建、销毁、扩缩容)、网络连接、存储挂载和负载均衡将变得极其复杂且容易出错。
Kubernetes (K8S) 就是一个生产级的容器编排系统。它像一个集群的“大脑”,自动化的管理着成百上千的容器。主要能力包括:
- 服务发现与负载均衡 :自动为容器组分配 IP 和 DNS 名称,并实现流量分发。
- 存储编排 :自动挂载你选择的存储系统(本地、云存储等)。
- 自动部署和回滚 :可以声明应用的期望状态(如运行3个实例),K8S 会自动调整当前状态至目标状态。如果更新出错,可以一键回滚。
- 自动扩缩容 :根据 CPU 使用率或自定义指标,自动增加或减少容器实例数量。
- 自我修复 :重启失败的容器、替换不可用节点、杀死不健康的容器。
简单比喻 :Docker 是“集装箱”,标准化了货物的打包方式;Kubernetes 是“超级货轮和自动化港口系统”,管理着成千上万个集装箱的运输、调度和存放。
1.3 Linux、云计算与运维的关系
- Linux :是 Docker 和 K8S 最主要的宿主操作系统。绝大多数容器化应用都运行在 Linux 内核之上。掌握 Linux 基础命令(文件操作、权限管理、进程查看、网络配置)是运维容器的基础。
- 云计算 :提供了弹性的基础设施(虚拟机、网络、存储)。公有云(如阿里云、腾讯云、AWS)是快速搭建 K8S 集群的常见平台。云原生(Cloud Native)理念与容器、微服务、DevOps 紧密结合。
- 运维 :在上述技术栈中,运维工程师的职责从传统的“保稳定”向“促交付”演进,需要掌握容器化部署、监控、日志收集、自动化脚本等技能,即 云计算运维 或 云原生运维 。
2. 环境准备与版本说明
我们将在一个 Linux 环境中完成所有实践。如果你使用 Windows 或 macOS,强烈建议通过虚拟机(如 VirtualBox + Ubuntu)或云服务器进行操作,以获得最接近生产环境的体验。
本文环境说明:
- 操作系统 :Ubuntu 22.04 LTS (Jammy Jellyfish)。其他发行版(如 CentOS)命令略有不同,会附带说明。
- Docker 版本 :24.0.5 (社区版)。安装方法适用于较新版本。
-
Kubernetes 版本
:1.28.0。使用
kubeadm工具搭建单控制平面集群。 -
硬件要求
:
- 至少 2 CPU 核心。
- 至少 2 GB 内存(推荐 4 GB+)。
- 至少 20 GB 磁盘空间。
重要提示 :生产环境请务必参考官方文档,并使用经过充分测试的稳定版本。本文示例旨在演示核心流程和原理。
3. Linux 基础与 Docker 安装实战
在安装 Docker 之前,我们需要确保系统环境就绪,并熟悉一些必要的 Linux 操作。
3.1 基础 Linux 命令速查
打开终端,尝试以下命令:
# 1. 查看系统信息
cat /etc/os-release
uname -r # 查看内核版本,Docker要求内核3.10+
# 2. 更新软件包索引(Ubuntu/Debian)
sudo apt update && sudo apt upgrade -y
# 3. 安装常用工具
sudo apt install -y curl wget vim net-tools
# 4. 管理服务
sudo systemctl start <service-name> # 启动服务
sudo systemctl stop <service-name> # 停止服务
sudo systemctl restart <service-name> # 重启服务
sudo systemctl status <service-name> # 查看服务状态
sudo systemctl enable <service-name> # 设置开机自启
3.2 安装 Docker 引擎
我们将使用 Docker 官方提供的便捷脚本进行安装,这也是最推荐的方式。
# 1. 卸载旧版本(如果存在)
sudo apt remove docker docker-engine docker.io containerd runc
# 2. 安装依赖,允许 apt 通过 HTTPS 使用仓库
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
# 3. 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 4. 设置 Docker 稳定版仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 5. 安装 Docker 引擎
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 6. 验证安装
sudo docker run hello-world
如果看到 “Hello from Docker!” 等信息,说明安装成功。这个命令会从 Docker Hub 拉取一个测试镜像并运行。
3.3 配置 Docker(非 root 用户运行 & 镜像加速)
默认情况下,运行
docker
命令需要
sudo
权限。为了方便,我们将当前用户加入
docker
组。
# 1. 将当前用户加入 docker 组
sudo usermod -aG docker $USER
# 2. 退出当前终端并重新登录,使组权限生效
# 或者执行:newgrp docker
# 3. 验证无需 sudo 运行 docker
docker ps
国内访问 Docker Hub 可能较慢,需要配置镜像加速器(以阿里云为例):
# 创建或修改 Docker 守护进程配置文件
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
“registry-mirrors”: [“https://<你的ID>.mirror.aliyuncs.com“]
}
EOF
# 重启 Docker 服务使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker
# 检查配置是否生效
docker info | grep -A 1 “Registry Mirrors”
请将
<你的ID>.mirror.aliyuncs.com
替换为你从阿里云容器镜像服务获取的专属加速地址。
4. Docker 核心操作实战
现在,我们通过一个完整的 Web 应用示例来学习 Docker 的核心工作流:构建镜像、运行容器、管理数据、配置网络。
4.1 构建第一个 Docker 镜像
我们创建一个简单的 Python Flask 应用。
1. 创建项目目录和文件:
mkdir my-flask-app && cd my-flask-app
2. 编写应用代码
app.py
:
# app.py
from flask import Flask
app = Flask(__name__)
@app.route(‘/’)
def hello():
return ‘<h1>Hello, Docker and CSDN!</h1><p>This is my first containerized app.</p>’
if __name__ == ‘__main__’:
app.run(host=‘0.0.0.0’, port=5000)
3. 编写依赖文件
requirements.txt
:
Flask==2.3.2
4. 编写 Dockerfile(构建镜像的蓝图):
# 使用官方 Python 轻量级镜像作为基础
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 将依赖文件复制到容器内
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 将当前目录所有文件复制到容器的 /app 目录
COPY . .
# 声明容器运行时暴露的端口
EXPOSE 5000
# 定义容器启动时执行的命令
CMD [“python”, “app.py”]
5. 构建镜像:
# -t 参数为镜像打标签,格式通常为 名称:版本
docker build -t my-flask-app:1.0 .
构建成功后,使用
docker images
查看本地镜像列表。
4.2 运行与管理容器
1. 运行容器:
# -d 后台运行,-p 将主机端口 8080 映射到容器端口 5000
docker run -d -p 8080:5000 --name my-flask-container my-flask-app:1.0
2. 访问应用:
打开浏览器,访问
http://<你的服务器IP>:8080
,即可看到 Flask 应用页面。
3. 常用容器管理命令:
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 查看容器日志
docker logs my-flask-container
# 实时查看日志
docker logs -f my-flask-container
# 进入容器内部(调试用)
docker exec -it my-flask-container /bin/bash
# 停止容器
docker stop my-flask-container
# 启动已停止的容器
docker start my-flask-container
# 删除容器(必须先停止)
docker rm my-flask-container
# 删除镜像(必须先删除依赖它的容器)
docker rmi my-flask-app:1.0
4.3 数据持久化:使用 Volume
容器内的文件是临时的,容器删除后数据会丢失。Volume(数据卷)是 Docker 推荐的持久化数据方式。
# 1. 创建一个命名卷
docker volume create my-data
# 2. 运行容器并挂载卷
# -v my-data:/app/data 将卷挂载到容器的 /app/data 目录
docker run -d -p 8081:5000 \
--name flask-with-volume \
-v my-data:/app/data \
my-flask-app:1.0
# 3. 进入容器,在 /app/data 下创建文件
docker exec -it flask-with-volume /bin/bash
echo “Persistent Data” > /app/data/test.txt
exit
# 4. 删除容器
docker rm -f flask-with-volume
# 5. 重新运行一个新容器,挂载同一个卷
docker run -d -p 8082:5000 \
--name new-flask-container \
-v my-data:/app/data \
my-flask-app:1.0
# 6. 进入新容器,查看文件是否还在
docker exec -it new-flask-container cat /app/data/test.txt
你会发现
test.txt
文件依然存在,数据实现了持久化。
5. Kubernetes (K8S) 单机集群搭建与核心概念
在生产中,K8S 运行在多台机器组成的集群上。为了学习和测试,我们使用
kubeadm
在单台机器上搭建一个“单节点集群”(All-in-One)。
5.1 安装前置依赖与 K8S 组件
1. 关闭 Swap 分区(K8S 要求):
sudo swapoff -a
# 永久关闭,编辑 /etc/fstab,注释掉 swap 相关行
sudo sed -i ‘/ swap / s/^\(.*\)$/#\1/g’ /etc/fstab
2. 安装容器运行时(containerd): Docker 本身包含 containerd,但 K8S 推荐直接使用 containerd。
# 安装 containerd
sudo apt update
sudo apt install -y containerd
# 生成默认配置
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 修改配置,使用 systemd 作为 cgroup 驱动(关键步骤!)
sudo sed -i ‘s/SystemdCgroup = false/SystemdCgroup = true/’ /etc/containerd/config.toml
# 重启并启用 containerd
sudo systemctl restart containerd
sudo systemctl enable containerd
3. 安装 kubeadm, kubelet, kubectl:
# 添加 Kubernetes 仓库密钥
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
# 添加 Kubernetes 仓库
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
# 安装
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 # 阻止自动更新
5.2 使用 kubeadm 初始化集群
1. 初始化控制平面节点:
# 注意:将 <your-ip> 替换为你的服务器内网IP
sudo kubeadm init \
--apiserver-advertise-address=<your-ip> \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.28.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
初始化成功后会输出类似下面的信息,
请务必保存好最后的
kubeadm join
命令
,用于添加工作节点(单机环境可忽略)。
2. 配置 kubectl(普通用户):
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
3. 安装 Pod 网络插件(CNI): Pod 之间需要网络才能通信。我们安装 Flannel。
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
4. 检查集群状态:
kubectl get nodes
# 稍等片刻,节点状态应为 Ready
kubectl get pods --all-namespaces
# 查看所有命名空间的 Pod,确保 CoreDNS 和 Flannel 的 Pod 都是 Running
5.3 K8S 核心对象实战:Deployment 与 Service
K8S 通过 YAML 文件来声明资源对象的期望状态。我们来部署一个 Nginx 服务。
1. 创建 Deployment (
nginx-deployment.yaml
):
Deployment 管理 Pod 的副本集,确保指定数量的 Pod 副本始终运行。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3 # 期望运行3个副本
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21-alpine # 使用轻量级镜像
ports:
- containerPort: 80
2. 创建 Service (
nginx-service.yaml
):
Service 为一组 Pod 提供稳定的网络访问入口,实现负载均衡。
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # 选择标签为 app: nginx 的 Pod
ports:
- protocol: TCP
port: 80 # Service 对外的端口
targetPort: 80 # Pod 内容器的端口
type: NodePort # 类型为 NodePort,会在每个节点上开放一个端口(30000-32767)映射到该 Service
3. 应用配置并验证:
# 应用 Deployment
kubectl apply -f nginx-deployment.yaml
# 应用 Service
kubectl apply -f nginx-service.yaml
# 查看资源状态
kubectl get deployments
kubectl get pods -l app=nginx
kubectl get svc nginx-service
kubectl get svc
会显示
nginx-service
的
CLUSTER-IP
和一个
PORT(S)
,例如
80:30678/TCP
。其中
30678
就是 NodePort。
4. 访问应用:
在浏览器访问
http://<你的服务器IP>:30678
,即可看到 Nginx 欢迎页面。Service 会将你的请求负载均衡到后端的 3 个 Nginx Pod 之一。
6. 常见问题与排查思路
在学习和实践过程中,你一定会遇到各种问题。以下是高频问题的排查指南。
| 问题现象 | 可能原因 | 排查思路与解决方案 |
|---|---|---|
| Docker 命令报错:权限被拒绝 |
当前用户不在
docker
组。
|
执行
sudo usermod -aG docker $USER
,
注销并重新登录
。或临时使用
sudo
。
|
docker pull
镜像速度极慢
| 默认从 Docker Hub 拉取,网络不佳。 |
配置国内镜像加速器(如阿里云、中科大)。修改
/etc/docker/daemon.json
。
|
| 容器启动后立即退出 | 容器内主进程执行完毕。 |
检查 Dockerfile 中的
CMD
或
ENTRYPOINT
。前台进程需持续运行(如
nginx -g ‘daemon off;‘
)。使用
docker logs <容器ID>
查看日志。
|
kubeadm init
失败
|
1. Swap 未关闭。
2. 防火墙/安全组阻止端口。 3. 镜像拉取失败。 |
1. 确认
swapoff -a
并永久禁用。
2. 开放 6443, 2379-2380, 10250-10252 等端口。 3. 使用
--image-repository
指定国内镜像源。查看
journalctl -xeu kubelet
日志。
|
kubectl get nodes
显示 NotReady
|
1. 网络插件未安装。
2.
kubelet
服务异常。
|
1. 安装 Flannel/Calico 等 CNI 插件。
2. 执行
systemctl status kubelet
查看状态,
journalctl -xeu kubelet
查看详细错误。
|
| Pod 状态一直为 Pending | 资源不足(CPU/内存)或没有合适节点。 |
kubectl describe pod <pod-name>
查看事件详情。检查节点资源
kubectl describe node
。
|
| Pod 状态为 CrashLoopBackOff | 容器内应用启动失败。 |
kubectl logs <pod-name>
查看应用日志。
kubectl describe pod <pod-name>
查看事件。检查镜像、命令、端口配置。
|
| Service 无法通过 NodePort 访问 |
1. 节点防火墙。
2. 云服务商安全组。 3. Pod 就绪检查失败。 |
1. 放行 NodePort 范围(30000-32767)。
2. 在云控制台配置安全组规则。 3.
kubectl get endpoints <service-name>
检查 Endpoints 是否为空。
|
kubectl exec
进入 Pod 失败
|
Pod 内没有
/bin/bash
或
/bin/sh
。
|
尝试
/bin/sh
。或使用
kubectl debug
临时添加调试容器。
|
7. 最佳实践与工程建议
掌握基础操作后,遵循最佳实践能让你在生产环境中走得更稳。
7.1 Docker 最佳实践
-
使用多阶段构建
:对于编译型语言(如 Go, Java),在第一个阶段编译,在第二个仅包含运行环境的阶段复制二进制文件,可以极大减小最终镜像体积。
FROM golang:1.19 AS builder WORKDIR /app COPY . . RUN go build -o myapp . FROM alpine:latest WORKDIR /root/ COPY --from=builder /app/myapp . CMD [“./myapp”] -
优化镜像层
:合并相关的
RUN命令,清理缓存,减少镜像层数。# 不佳 RUN apt update RUN apt install -y package RUN rm -rf /var/lib/apt/lists/* # 更佳 RUN apt update && apt install -y package && rm -rf /var/lib/apt/lists/* -
使用
.dockerignore文件 :避免将本地不必要的文件(如.git,node_modules, 日志)复制到镜像构建上下文,加速构建。 -
指定非 root 用户运行容器
:增强安全性。
RUN groupadd -r appuser && useradd -r -g appuser appuser USER appuser -
为镜像打上明确的标签
:避免使用
latest,而是使用版本号或 Git 提交哈希,如myapp:v1.2.3。
7.2 Kubernetes 最佳实践
-
资源请求与限制
:为 Pod 设置
resources.requests和resources.limits,防止单个 Pod 耗尽节点资源,也便于调度器决策。resources: requests: memory: “64Mi” cpu: “250m” limits: memory: “128Mi” cpu: “500m” - 使用 ConfigMap 和 Secret 管理配置 :将配置与镜像分离。敏感信息(密码、密钥)用 Secret,普通配置用 ConfigMap。
-
就绪探针与存活探针
:配置
livenessProbe和readinessProbe,让 K8S 能自动检查应用健康状态,实现自我修复和流量管理。 - 命名空间隔离 :使用 Namespace 对不同环境(dev, staging, prod)或不同团队的项目进行逻辑隔离。
-
声明式管理
:始终使用
kubectl apply -f <file.yaml>来应用配置变更,而不是kubectl edit或kubectl replace。将 YAML 文件纳入版本控制(如 Git)。
7.3 学习路线与下一步
通过本文,你应该已经完成了从 Linux 基础到 Docker 容器化,再到 Kubernetes 集群部署和应用的完整闭环。要真正掌握云原生运维,建议按以下路径深化:
-
巩固基础
:反复练习 Dockerfile 编写、
kubectl常用命令、YAML 语法。 - 深入核心概念 :学习 Pod 生命周期、Service 类型(ClusterIP, NodePort, LoadBalancer, Ingress)、ConfigMap/Secret、Volume 存储(PV/PVC)。
- 学习高级控制器 :掌握 StatefulSet(有状态应用)、DaemonSet(节点守护进程)、Job/CronJob(批处理任务)。
-
探索生态工具
:
- Helm :K8S 的包管理工具,简化复杂应用的部署。
- Ingress Controller (如 Nginx Ingress):管理集群外部 HTTP/HTTPS 访问。
- 监控告警 :Prometheus + Grafana。
- 日志收集 :EFK Stack(Elasticsearch, Fluentd, Kibana)或 Loki。
- 动手项目 :尝试在云服务器上搭建多节点 K8S 集群,并部署一个包含前端、后端、数据库的完整微服务应用。
技术的核心在于实践。遇到报错时,善用
docker logs
、
kubectl describe
、
kubectl logs
和
journalctl
查看日志,大部分问题都能找到线索。将本文的示例代码和命令亲手敲一遍,理解其背后的原理,你便已经迈入了容器化与云原生运维的大门。
更多推荐


所有评论(0)