最近在帮团队搭建新的微服务环境,发现很多刚接触容器化和云原生的同学,对 Docker 和 Kubernetes (K8S) 的理解还停留在“听说过”的阶段。从安装配置到实际部署应用,中间踩的坑一个接一个,网上资料要么太旧,要么太散,不成体系。

如果你也正面临类似困境——想系统学习容器技术却不知从何下手,或者项目急需落地但被复杂的配置和网络问题卡住——那么这篇文章就是为你准备的。本文将带你从零开始,手把手搭建一套完整的 Docker + K8S 学习与实践环境。内容涵盖从 Linux 基础操作、Docker 核心概念与实战,到 K8S 集群搭建、应用部署与管理,最后还会探讨其在云计算运维中的核心价值。文末提供了完整的实战项目配置文件和常见问题排查清单,无论是学生练手还是企业开发,都能直接复用。

1. 背景与核心概念:为什么是 Docker 和 K8S?

在深入动手之前,我们需要先理解这两个技术解决了什么问题,以及它们之间的关系。

Docker 的核心是 容器化 。你可以把它想象成一个超级轻量级的“虚拟机”。但与虚拟机需要模拟完整的操作系统(Guest OS)不同,容器直接共享宿主机的操作系统内核,只打包应用及其运行所需的库和依赖。这使得容器具有启动快、资源消耗小、部署一致性好等巨大优势。Docker 提供了构建、分发和运行容器的完整工具链。

Kubernetes (K8S) 的核心是 容器编排 。当你的应用从单体服务拆分成数十甚至上百个微服务,每个服务都用容器封装后,如何管理这些容器的生命周期?如何实现自动扩缩容、负载均衡、服务发现、滚动更新和故障自愈?手动操作 Docker 命令会变得极其困难。K8S 就是一个生产级的容器编排平台,它负责自动化管理成百上千的容器,让开发者可以专注于应用本身。

它们的关系 :Docker 是“集装箱”,负责把货物(应用)标准化打包;Kubernetes 是“超级货轮和港口调度系统”,负责管理成千上万个集装箱的运输、存放和调度。通常,我们使用 Docker 来创建容器镜像,然后在 K8S 集群中运行这些镜像。

应用场景

  • 开发环境一致性 :用 Docker 镜像固化环境,“一次构建,处处运行”,彻底解决“在我机器上是好的”问题。
  • CI/CD 流水线 :容器作为构建和测试的标准单元,实现快速、可靠的持续集成与部署。
  • 微服务架构 :K8S 是微服务架构的理想运行平台,提供服务治理、弹性伸缩等能力。
  • 混合云与多云部署 :K8S 提供了抽象层,让应用可以无缝运行在不同的云平台或数据中心。

2. 环境准备与版本说明

本文将在一个纯净的 Linux 环境下进行所有操作。为了保证教程的通用性和可复现性,我们选择 Ubuntu 22.04 LTS 作为演示系统。其他 Linux 发行版(如 CentOS、Debian)的命令会有细微差别,文中会适当说明。

核心软件版本

  • 操作系统 :Ubuntu 22.04.4 LTS (Jammy Jellyfish)
  • Docker Engine :24.0.7
  • Kubernetes (kubeadm, kubelet, kubectl) :1.28.2
  • 容器运行时 :containerd 1.7.6 (由 Docker 安装时默认集成,K8S 也使用它)

硬件与网络要求

  • 至少 2核 CPU 4GB 内存 (运行 K8S 单节点集群的最低要求,生产环境需更高)。
  • 稳定的网络连接,用于下载软件包和容器镜像。
  • 禁用交换分区(Swap),K8S 默认要求。 sudo swapoff -a 并编辑 /etc/fstab 注释掉 swap 行。

重要提示 :容器和云原生生态迭代迅速,版本兼容性至关重要。本文提供的安装命令和配置基于上述版本验证。如果你的环境是其他版本(尤其是较新的版本),部分命令或参数可能需要调整。建议先通读全文理解原理,再根据官方文档进行微调。

3. Linux 基础与 Docker 核心实战

在搭建 K8S 之前,我们必须先掌握 Docker,而 Docker 又运行在 Linux 之上。因此,我们从必要的 Linux 操作开始。

3.1 必备 Linux 命令速查

即使你是 Windows 或 macOS 用户,在服务器领域,Linux 是绝对的主流。以下是容器运维中最常用的命令:

# 1. 系统与权限
sudo -i # 切换到 root 用户(谨慎使用)
whoami  # 查看当前用户
cat /etc/os-release # 查看系统版本
df -h   # 查看磁盘使用情况
free -h # 查看内存使用情况

# 2. 文件操作
ls -la /path/      # 详细列出目录内容
cp -r source dest  # 递归复制
mv old new         # 移动或重命名
rm -rf dir         # 强制递归删除(危险!)
chmod +x script.sh # 给脚本添加执行权限
chown user:group file # 修改文件属主和属组

# 3. 网络与进程
ip addr show       # 查看 IP 地址(替代老旧的 ifconfig)
netstat -tulnp    # 查看端口监听情况(需安装 net-tools)
ss -tulnp         # 查看端口监听情况(更现代的 ss 命令)
ps aux | grep nginx # 查找 nginx 进程
systemctl status docker # 查看 Docker 服务状态
journalctl -u docker -f # 实时查看 Docker 服务日志

# 4. 包管理 (Ubuntu/Debian)
sudo apt update    # 更新软件包列表
sudo apt upgrade -y # 升级所有已安装的包
sudo apt install -y vim curl wget git # 安装常用工具

3.2 Docker 安装与配置

在 Ubuntu 上安装 Docker 官方版本是最佳实践。

# 1. 卸载旧版本(如果是全新系统可跳过)
sudo apt remove docker docker-engine docker.io containerd runc

# 2. 安装依赖工具
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. 设置稳定版仓库
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 Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

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

# 7. 验证安装
sudo docker run hello-world

如果看到 “Hello from Docker!” 的输出,说明安装成功。

配置镜像加速器 :从 Docker Hub 拉取镜像在国内可能很慢。我们需要配置国内镜像源。

# 编辑 Docker 守护进程配置文件
sudo vim /etc/docker/daemon.json

将以下内容写入(如果文件不存在则创建),这里使用阿里云和网易的镜像加速器。

{
  "registry-mirrors": [
    "https://<你的ID>.mirror.aliyuncs.com",
    "https://hub-mirror.c.163.com"
  ],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}

保存后,重启 Docker 使配置生效:

sudo systemctl daemon-reload
sudo systemctl restart docker

3.3 Docker 核心概念与实战

理解三个核心概念: 镜像(Image) 容器(Container) 仓库(Registry)

1. 镜像操作 镜像是容器的模板,是一个只读的文件层集合。

# 搜索镜像
docker search nginx

# 拉取镜像(从 Docker Hub)
docker pull nginx:alpine # 拉取轻量版 nginx 镜像
docker pull mysql:8.0

# 查看本地镜像
docker images
# 或使用更强大的格式
docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}"

# 删除镜像
docker rmi <镜像ID或名称>
docker image prune -a # 删除所有未被容器使用的镜像(悬空镜像)

2. 容器操作 容器是镜像的运行实例。

# 运行一个容器
# -d: 后台运行
# -p 80:80: 将宿主机的80端口映射到容器的80端口
# --name mynginx: 给容器命名
docker run -d -p 80:80 --name mynginx nginx:alpine

# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a

# 进入容器内部(就像 SSH 到一台服务器)
docker exec -it mynginx /bin/sh # alpine 镜像用 /bin/sh
# 对于 Ubuntu/CentOS 镜像,通常用 /bin/bash
# docker exec -it myubuntu /bin/bash

# 查看容器日志
docker logs mynginx
docker logs -f mynginx # 实时跟踪日志

# 停止、启动、重启容器
docker stop mynginx
docker start mynginx
docker restart mynginx

# 删除容器(必须先停止)
docker rm mynginx
docker rm -f mynginx # 强制删除运行中的容器(危险!)

# 拷贝文件
docker cp /host/path/file.txt mynginx:/container/path/ # 宿主机 -> 容器
docker cp mynginx:/container/path/log.txt /host/path/ # 容器 -> 宿主机

3. 使用 Dockerfile 构建自定义镜像 这是 Docker 的核心技能。假设我们有一个简单的 Python Web 应用。

# 创建项目目录
mkdir mypythonapp && cd mypythonapp

# 创建应用文件 app.py
cat > app.py << 'EOF'
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, Docker & K8S from Python Flask!\n"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
EOF

# 创建依赖文件 requirements.txt
cat > requirements.txt << 'EOF'
Flask==2.3.3
EOF

# 创建 Dockerfile
cat > Dockerfile << 'EOF'
# 使用官方 Python 轻量级镜像作为基础
FROM python:3.11-alpine

# 设置工作目录
WORKDIR /app

# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 声明容器运行时暴露的端口
EXPOSE 5000

# 定义容器启动命令
CMD ["python", "app.py"]
EOF

# 构建镜像
docker build -t my-python-app:1.0 .

# 运行自定义镜像的容器
docker run -d -p 5000:5000 --name myapp my-python-app:1.0

# 访问应用
curl http://localhost:5000
# 应输出:Hello, Docker & K8S from Python Flask!

4. 使用 docker-compose 编排多容器应用 对于需要多个容器协作的应用(如 Web + 数据库),使用 docker-compose 更方便。

# docker-compose.yml
version: '3.8'
services:
  web:
    build: . # 使用当前目录的 Dockerfile 构建
    ports:
      - "5000:5000"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
    networks:
      - app-network

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-network

volumes:
  postgres-data:

networks:
  app-network:
    driver: bridge

运行: docker-compose up -d ;停止: docker-compose down

4. Kubernetes (K8S) 单节点集群搭建与核心概念

掌握了 Docker,我们就可以进军 K8S 了。生产环境通常是多节点集群,但对于学习和开发测试,一个单节点集群(All-in-One)完全足够。我们将使用 kubeadm 这个官方工具来搭建。

4.1 安装前系统配置

这些步骤至关重要,很多安装失败都源于此。

# 1. 关闭交换分区(K8S 1.8+ 要求)
sudo swapoff -a
# 永久关闭:编辑 /etc/fstab,注释掉所有包含 swap 的行,然后重启。

# 2. 设置主机名(可选,但有助于识别)
sudo hostnamectl set-hostname k8s-master
# 修改 /etc/hosts,确保主机名能解析到本机IP
# 例如:192.168.1.100 k8s-master

# 3. 允许 iptables 检查桥接流量
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

4.2 安装容器运行时和 K8S 组件

K8S 本身不直接运行容器,它通过 CRI (Container Runtime Interface) 调用容器运行时。我们将使用 Docker 安装时已经集成的 containerd

# 1. 安装 containerd 的配置工具(如果尚未安装)
sudo apt install -y containerd

# 2. 生成 containerd 的默认配置文件
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# 3. 修改配置文件,使用 systemd 作为 cgroup 驱动(与 K8S 保持一致)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# 4. 重启 containerd
sudo systemctl restart containerd
sudo systemctl enable containerd

# 5. 安装 kubeadm, kubelet, kubectl
# 添加 Kubernetes 阿里云镜像源
sudo apt install -y apt-transport-https ca-certificates curl
curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

# 安装指定版本(避免使用最新版可能带来的兼容性问题)
sudo apt update
sudo apt install -y kubelet=1.28.2-00 kubeadm=1.28.2-00 kubectl=1.28.2-00
sudo apt-mark hold kubelet kubeadm kubectl # 阻止自动更新

# 6. 初始化 Master 节点(单节点集群)
# 注意:将 <MASTER_IP> 替换为你本机的实际 IP 地址
sudo kubeadm init \
  --apiserver-advertise-address=<MASTER_IP> \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.28.2 \
  --service-cidr=10.96.0.0/12 \
  --pod-network-cidr=10.244.0.0/16

# 初始化成功后会输出类似以下信息,请务必保存好最后的 kubeadm join 命令(虽然单节点用不上):
# kubeadm join 192.168.1.100:6443 --token xxxxxx.xxxxxxxxxxxxxx \
#         --discovery-token-ca-cert-hash sha256:xxxxxxxx...

# 7. 配置 kubectl(普通用户)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 8. 安装 Pod 网络插件(CNI)
# 这是 K8S 集群的“神经系统”,负责 Pod 间的通信。这里安装最常用的 Flannel。
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# 等待所有 Pod 变为 Running 状态
kubectl get pods --all-namespaces -w
# 看到 kube-flannel-* 和 coredns-* 都 Running 即可。

4.3 K8S 核心概念与对象

在 K8S 中,一切皆对象。通过 YAML 文件定义对象的期望状态,K8S 会努力让实际状态与之匹配。

  1. Pod :K8S 的最小调度单元。一个 Pod 可以包含一个或多个紧密关联的容器(如主容器和 Sidecar 容器),它们共享网络和存储空间。
  2. Deployment :用于部署无状态应用。它管理一组相同的 Pod(称为 ReplicaSet),并提供滚动更新、回滚等功能。
  3. Service :定义一组 Pod 的访问策略。为 Pod 提供一个稳定的 IP 地址和 DNS 名称,并实现负载均衡。
  4. Namespace :虚拟集群,用于在物理集群中划分多个虚拟环境,实现资源隔离(如 dev, test, prod)。
  5. ConfigMap & Secret :用于将配置信息和敏感数据(如密码)与容器镜像解耦。

4.4 第一个 K8S 应用:部署 Nginx

让我们用 kubectl 命令和 YAML 文件两种方式部署一个 Nginx。

方式一:使用 kubectl run 命令(快速测试)

# 创建一个名为 my-nginx 的 Deployment,使用 nginx 镜像
kubectl create deployment my-nginx --image=nginx:alpine

# 将 Deployment 暴露为一个 Service(NodePort 类型,便于从集群外访问)
kubectl expose deployment my-nginx --type=NodePort --port=80

# 查看资源状态
kubectl get deployments
kubectl get pods
kubectl get services

# 获取 NodePort 端口号
kubectl get svc my-nginx -o jsonpath='{.spec.ports[0].nodePort}'
# 假设输出是 31876,则在浏览器访问 http://<你的服务器IP>:31876

方式二:使用 YAML 文件(推荐,可版本控制)

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2 # 运行 2 个 Pod 副本
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
---
# nginx-service.yaml (也可以和上面写在一个文件里,用 --- 分隔)
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx # 选择标签为 app: nginx 的 Pod
  ports:
    - protocol: TCP
      port: 80 # Service 对内的端口
      targetPort: 80 # Pod 容器的端口
      nodePort: 30080 # 集群外访问的端口 (范围 30000-32767)
  type: NodePort

应用配置:

kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml
# 或合并执行:kubectl apply -f .

5. 深入实战:在 K8S 中部署有状态应用(MySQL)

无状态应用(如 Nginx)的 Pod 可以随意创建和销毁。有状态应用(如数据库)则需要持久化存储和稳定的网络标识。我们使用 StatefulSet PersistentVolume (PV) / PersistentVolumeClaim (PVC) 来部署 MySQL。

5.1 创建持久化存储

首先,我们创建一个本地目录作为存储(生产环境请使用网络存储如 NFS、Ceph、云盘等)。

# 在宿主机上创建存储目录
sudo mkdir -p /data/mysql
sudo chmod 777 /data/mysql # 简化权限,生产环境需严格设置

然后,创建 PV 和 PVC 的 YAML 文件。

# mysql-pv-pvc.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce # 单节点读写
  hostPath:
    path: /data/mysql
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

应用: kubectl apply -f mysql-pv-pvc.yaml

5.2 创建 ConfigMap 存储配置

将 MySQL 的配置文件从镜像中分离。

# mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  my.cnf: |
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    default-authentication-plugin=mysql_native_password
    max_connections=1000

5.3 创建 Secret 存储密码

敏感信息必须用 Secret。

# 使用 kubectl 命令创建 Secret(密码会经过 base64 编码)
kubectl create secret generic mysql-secret \
  --from-literal=root-password=MyStrongPassword123!

5.4 创建 MySQL StatefulSet 和 Service

# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-service # 必须有,用于提供稳定的 DNS
  replicas: 1 # 单实例 MySQL,生产环境可考虑主从
  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: root-password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
        - name: mysql-config
          mountPath: /etc/mysql/conf.d
      volumes:
      - name: mysql-config
        configMap:
          name: mysql-config
  volumeClaimTemplates: # StatefulSet 特有的,为每个 Pod 动态创建 PVC
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: mysql
  ports:
    - port: 3306
      targetPort: 3306
  clusterIP: None # Headless Service,用于 StatefulSet 的 DNS 解析

应用所有配置:

kubectl apply -f mysql-configmap.yaml
kubectl apply -f mysql-statefulset.yaml

5.5 验证与连接

# 查看 Pod 状态
kubectl get pods -l app=mysql -w
# 等待状态变为 Running

# 查看 PVC 绑定状态
kubectl get pvc

# 进入 MySQL Pod 执行命令
kubectl exec -it mysql-0 -- mysql -uroot -pMyStrongPassword123!

# 或者在集群内其他 Pod 中,通过 Service 名连接
# mysql -h mysql-service -uroot -p

6. 常见问题与排查思路

在学习和使用 Docker 与 K8S 的过程中,你一定会遇到各种问题。以下是高频问题排查指南。

问题现象 可能原因 排查思路与解决方案
Docker 命令报错 Got permission denied 当前用户不在 docker 用户组。 1. sudo usermod -aG docker $USER
2. 注销并重新登录 (或执行 newgrp docker )。
docker pull 速度极慢或超时 默认 Docker Hub 镜像源在国内访问慢。 配置国内镜像加速器(见 3.2 节 /etc/docker/daemon.json )。
kubeadm init 卡在 pull image 或失败 无法拉取 k8s.gcr.io 镜像。 1. 使用 --image-repository 参数指定阿里云等国内镜像源。
2. 或提前用 docker pull 拉取镜像并打标签。
kubectl get pods 显示 Pending Pod 无法被调度到节点。 1. kubectl describe pod <pod-name> 查看事件。
2. 常见原因:资源不足、节点有污点(Taint)、未安装网络插件。
kubectl get pods 显示 ImagePullBackOff 无法拉取容器镜像。 1. kubectl describe pod 查看具体错误。
2. 检查镜像名称拼写、镜像仓库权限、网络。
kubectl get pods 显示 CrashLoopBackOff 容器启动后立即退出。 1. kubectl logs <pod-name> 查看容器日志。
2. 检查应用配置、依赖、启动命令、端口冲突。
Pod 间网络不通 Pod 网络插件(CNI)未正常工作。 1. kubectl get pods -n kube-system 检查 kube-flannel-* 等 CNI Pod 状态。
2. 查看 CNI Pod 日志: kubectl logs -n kube-system <cni-pod-name>
Service 无法通过 NodePort 访问 防火墙未放行端口、节点 IP 错误。 1. 检查服务器防火墙(如 ufw )是否允许 NodePort 范围(30000-32767)。
2. curl http://<节点内网IP>:<NodePort> 测试。
kubectl 命令报错 The connection to the server was refused Kubernetes API Server 未运行或配置错误。 1. sudo systemctl status kubelet 检查 kubelet 状态。
2. 检查 $HOME/.kube/config 文件是否存在且内容正确。
3. 确认 kubeadm init 已成功完成。
磁盘空间不足 容器镜像、日志、未清理的停止容器占用空间。 1. docker system df 查看 Docker 磁盘使用。
2. docker system prune -a 清理(谨慎,会删除未使用的镜像)。
3. 清理 K8S 日志: journalctl --vacuum-time=7d

通用排查命令

  • kubectl describe <资源类型> <资源名> :查看资源的详细状态和事件,是排错第一选择。
  • kubectl logs <pod-name> [-c <container-name>] :查看 Pod 或指定容器的日志。
  • kubectl exec -it <pod-name> -- /bin/sh :进入 Pod 内部调试。
  • kubectl get events --sort-by=.metadata.creationTimestamp :查看集群级别的事件。

7. 最佳实践与工程建议

将技术用于生产环境,必须考虑稳定性、安全性和可维护性。

7.1 Docker 最佳实践

  1. 使用多阶段构建 :对于编译型语言(如 Go, Java),在第一个阶段编译,在第二个仅包含运行环境的阶段拷贝二进制文件,极大减小镜像体积。
    # 以 Go 应用为例
    FROM golang:1.20 AS builder
    WORKDIR /app
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
    
    FROM alpine:latest
    WORKDIR /root/
    COPY --from=builder /app/myapp .
    CMD ["./myapp"]
    
  2. 使用 .dockerignore 文件 :避免将 node_modules , .git , 日志等不必要的文件拷贝进镜像,加速构建并减小体积。
  3. 以非 root 用户运行容器 :在 Dockerfile 中创建并使用非 root 用户,增强安全性。
    RUN addgroup -g 1000 appuser && adduser -u 1000 -G appuser -s /bin/sh -D appuser
    USER appuser
    
  4. 明确指定镜像标签 :避免使用 latest 标签,应指定具体版本号(如 nginx:1.25-alpine ),保证环境一致性。
  5. 限制容器资源 :使用 -m , --cpus 等参数限制容器内存和 CPU 使用,防止单个容器耗尽主机资源。

7.2 Kubernetes 最佳实践

  1. 使用 Namespace 隔离环境 :为开发、测试、生产环境创建不同的命名空间。
    kubectl create namespace dev
    kubectl create namespace prod
    kubectl config set-context --current --namespace=dev # 切换当前上下文命名空间
    
  2. 为 Pod 设置资源请求和限制 :这是 K8S 进行合理调度和防止资源争抢的基础。
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
    
  3. 使用 Readiness 和 Liveness 探针 :确保流量只被发送到已准备好的 Pod,并能自动重启不健康的 Pod。
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
    
  4. 将配置与镜像分离 :永远不要将配置文件、密码等硬编码在镜像中。使用 ConfigMap 和 Secret,并通过环境变量或卷挂载注入容器。
  5. 制定更新策略 :在 Deployment 中配置 strategy ,实现零停机的滚动更新。
    strategy:
      type: RollingUpdate
      rollingUpdate:
        maxSurge: 1        # 更新过程中可以超出期望 Pod 数的最大值
        maxUnavailable: 0   # 更新过程中不可用 Pod 的最大数量
    
  6. 做好日志与监控 :集群层面部署 EFK (Elasticsearch, Fluentd, Kibana) 或 Loki 日志系统,以及 Prometheus + Grafana 监控系统。

7.3 云计算运维视角

从运维角度看,Docker 和 K8S 带来了基础设施即代码 (IaC) 和 GitOps 的实践。

  • 版本化一切 :将 Dockerfile、K8S YAML、Helm Charts 纳入 Git 仓库管理。
  • CI/CD 流水线 :将镜像构建、安全扫描、推送仓库、部署到 K8S 的过程自动化。
  • 不可变基础设施 :一旦部署,不再直接登录容器修改配置。任何变更都应通过更新镜像或 ConfigMap,然后重新部署来实现。
  • 关注安全 :定期扫描镜像漏洞、使用 Pod 安全策略、管理好 RBAC 权限、保护 etcd 数据。

8. 总结与学习路线

通过本文,你应该已经完成了一个从零到一的 Docker 与 Kubernetes 实战旅程:从 Linux 基础、Docker 安装与镜像构建,到 K8S 单节点集群搭建、核心对象操作,再到部署有状态的 MySQL 应用。我们不仅涵盖了操作步骤,更深入探讨了排错方法和生产级的最佳实践。

下一步学习建议

  1. 深入 K8S 核心概念 :学习 Ingress (七层负载均衡)、 ConfigMap/Secret 高级用法、 RBAC (权限控制)、 Helm (包管理)。
  2. 搭建多节点集群 :尝试使用 kubeadm 添加 Worker 节点,理解集群高可用架构。
  3. 体验云厂商托管服务 :在阿里云 ACK、腾讯云 TKE、华为云 CCE 上创建托管集群,体会云原生的便捷。
  4. 学习服务网格 :了解 Istio Linkerd ,这是处理微服务间通信、安全、可观测性的下一代技术。
  5. 参与实际项目 :将你的个人项目或公司的一个非核心服务容器化并部署到 K8S,这是最好的学习方式。

技术的道路很长,但每一步都算数。容器化和云原生不是银弹,但它们确实是构建现代可扩展、高可用应用架构的基石。希望这份教程能成为你探索这个广阔领域的坚实起点。如果在实践中遇到新的问题,欢迎随时回顾文中的排查思路,或查阅官方文档。动手去做,遇到问题解决问题,才是掌握技术的唯一捷径。

更多推荐