1. 引言:容器技术的前世今生
在软件开发的世界里,一直存在一个难题:“在我的机器上能运行,怎么到你那就报错了?”环境不一致、依赖冲突、配置复杂……这些问题常常让开发者和运维人员头疼不已。
为了解决这个问题,虚拟化技术应运而生。传统的虚拟机(如VMware、VirtualBox)通过模拟整个硬件,再在上面运行完整的操作系统,从而实现了环境的隔离。但虚拟机太重了:每个虚拟机都需要占用大量磁盘空间、内存和CPU资源,启动也需要几分钟。
这时,容器技术登场了。容器不像虚拟机那样模拟硬件和运行完整操作系统,而是共享宿主机的操作系统内核,只将应用程序及其依赖(库、配置文件等)打包在一起,形成一个独立的运行环境。容器轻量、快速、资源利用率高,启动只需秒级。
容器的概念其实很早就有(如Linux的chroot、LXC),但真正让容器技术火起来的是Docker。Docker在2013年发布,提供了简单易用的命令行工具和镜像格式,大大降低了容器技术的使用门槛,让“构建一次,到处运行”成为现实。
随着容器越来越多,如何管理成百上千个容器又成了新问题。于是,Kubernetes(简称K8s)应运而生。Kubernetes是Google开源的容器编排平台,能够自动化地部署、伸缩、管理容器化应用。如今,Kubernetes已成为云原生时代的事实标准。
本指南将带小白读者一步步走进容器技术的世界,从Docker的基础操作到Kubernetes的核心概念,并通过实战案例巩固理解。全文约2万字,力求通俗易懂,希望你能轻松上手!
2. Docker基础篇
2.1 什么是Docker?
Docker是一个开源的容器化平台,它可以让开发者将应用程序及其依赖打包成一个可移植的容器镜像,然后在任何安装了Docker的机器上运行这个容器。Docker的口号是“Build, Ship, and Run Any App, Anywhere”。
简单来说,Docker提供了三个核心功能:
打包(Build):通过Dockerfile定义应用的运行环境,构建出镜像。
分发(Ship):将镜像推送到镜像仓库(如Docker Hub),其他人可以拉取使用。
运行(Run):在任意主机上运行容器,保证环境一致。
2.2 安装Docker
Docker支持主流操作系统:Linux、macOS、Windows。下面分别介绍安装方法。
Linux(以Ubuntu为例)
bash
# 更新软件包索引 sudo apt update # 安装依赖包 sudo apt install apt-transport-https ca-certificates curl software-properties-common # 添加Docker官方GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # 添加稳定版仓库 sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" # 再次更新并安装Docker CE sudo apt update sudo apt install docker-ce # 启动Docker并设置开机自启 sudo systemctl start docker sudo systemctl enable docker # 验证安装 sudo docker run hello-world
macOS
下载Docker Desktop for Mac安装包(需注册Docker Hub账号),双击安装即可。安装后会在菜单栏出现Docker图标。
Windows
下载Docker Desktop for Windows,同样双击安装。Windows 10/11专业版或企业版支持Hyper-V,家庭版需使用WSL 2后端。
安装完成后,打开终端(或PowerShell),执行docker version查看信息。如果希望普通用户也能运行docker命令,可以将用户加入docker组(Linux下):sudo usermod -aG docker $USER,然后注销重新登录。
2.3 Docker核心概念:镜像、容器、仓库
镜像(Image):一个只读的模板,包含运行应用程序所需的所有内容:操作系统基础层、代码、运行时、库、环境变量、配置文件等。可以类比为虚拟机镜像或Java中的类。
容器(Container):镜像的一个运行实例,可以启动、停止、删除、暂停。容器是轻量级的,相互隔离。可以类比为虚拟机实例或Java中类的对象。
仓库(Repository):存放镜像的地方,类似Git仓库。Docker Hub是官方公共仓库,也可以搭建私有仓库。
2.4 第一个Docker容器:Hello World
安装好Docker后,执行:
bash
docker run hello-world
如果本地没有hello-world镜像,Docker会自动从Docker Hub拉取,然后运行一个容器输出欢迎信息。这验证了Docker能正常工作。
2.5 操作容器:启动、停止、删除
运行一个交互式容器(Ubuntu)
bash
docker run -it ubuntu bash
-it:分配交互式终端,这样就可以在容器里执行命令。ubuntu:镜像名,默认从Docker Hub拉取。bash:容器启动后执行的命令。
在容器内可以执行ls、apt update等操作。输入exit退出,容器停止。
常用容器命令
bash
# 查看运行中的容器 docker ps # 查看所有容器(包括已停止) docker ps -a # 启动一个已存在的容器 docker start <容器ID或名称> # 停止一个运行中的容器 docker stop <容器ID> # 删除一个已停止的容器 docker rm <容器ID> # 强制删除运行中的容器 docker rm -f <容器ID> # 查看容器日志 docker logs <容器ID> # 在运行中的容器中执行命令 docker exec -it <容器ID> bash
2.6 Docker镜像的获取与管理
拉取镜像
bash
docker pull nginx:latest # 拉取最新版Nginx镜像 docker pull ubuntu:20.04 # 拉取指定版本的Ubuntu
查看本地镜像
bash
docker images
删除镜像
bash
docker rmi nginx:latest
镜像标签
可以为镜像打标签(tag):
bash
docker tag ubuntu:20.04 myubuntu:v1
2.7 使用Dockerfile构建自定义镜像
Dockerfile是一个文本文件,包含一系列指令,用于自动化构建镜像。下面是一个简单的Dockerfile示例(基于Ubuntu安装Nginx):
dockerfile
# 基础镜像 FROM ubuntu:20.04 # 维护者信息 LABEL maintainer="yourname@example.com" # 设置环境变量,避免交互式安装时卡住 ENV DEBIAN_FRONTEND=noninteractive # 更新软件源并安装Nginx RUN apt update && apt install -y nginx # 暴露端口 EXPOSE 80 # 启动Nginx(前台运行) CMD ["nginx", "-g", "daemon off;"]
在Dockerfile所在目录执行构建:
bash
docker build -t mynginx:v1 .
-t:指定镜像名和标签。.:构建上下文路径(即当前目录)。
构建完成后,可用docker run -d -p 8080:80 mynginx:v1启动容器,访问http://localhost:8080即可看到Nginx欢迎页。
常用Dockerfile指令
FROM:指定基础镜像,必须位于第一行。RUN:在构建镜像时执行的命令(每一条RUN都会创建一层镜像层)。COPY/ADD:将文件从构建上下文复制到镜像中。ADD支持自动解压tar包和远程URL。WORKDIR:设置工作目录。ENV:设置环境变量。EXPOSE:声明容器内应用监听的端口(仅是声明,实际映射需用-p)。CMD:容器启动时执行的默认命令(可以被覆盖)。ENTRYPOINT:配置容器启动时运行的命令(不可被覆盖,但可传参)。
2.8 数据持久化:数据卷(Volume)
默认情况下,容器内创建的文件在容器删除后会丢失。为了实现数据持久化,Docker提供了数据卷(Volume)。
使用数据卷
bash
# 创建一个数据卷 docker volume create mydata # 启动容器并挂载数据卷 docker run -d -v mydata:/data --name myapp ubuntu sleep 3600 # 查看数据卷信息 docker volume inspect mydata
数据卷由Docker管理,存在于宿主机特定目录。另一种方式是绑定挂载,将宿主机目录映射到容器内:
bash
docker run -d -v /host/path:/container/path ubuntu ...
这种方式更灵活,但依赖宿主机目录结构。
2.9 网络基础:容器间的通信
Docker默认创建三种网络:bridge、host、none。默认情况下,容器连接到bridge网络,可以互相通过IP通信,但无法通过容器名直接访问。要让容器通过名字通信,可以创建自定义网络。
创建自定义网络
bash
docker network create mynet
启动容器并连接到网络
bash
docker run -d --name app1 --network mynet nginx docker run -d --name app2 --network mynet nginx
现在app2可以ping app1(需容器内有ping命令)。自定义网络提供了自动DNS解析。
2.10 Docker Compose:多容器应用
实际应用中,一个项目往往包含多个服务(如Web应用+数据库+缓存)。手动管理多个容器的启动顺序、网络连接、数据卷等会很麻烦。Docker Compose通过一个YAML文件定义多容器应用,用一条命令即可启动整个应用。
安装Docker Compose
Docker Desktop for Mac/Windows已自带Compose。Linux下需单独安装:
bash
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
docker-compose.yml示例
创建一个docker-compose.yml文件:
yaml
version: '3' services: web: image: nginx:latest ports: - "8080:80" volumes: - ./html:/usr/share/nginx/html networks: - appnet db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: rootpass volumes: - dbdata:/var/lib/mysql networks: - appnet volumes: dbdata: networks: appnet:
启动所有服务:
bash
docker-compose up -d
停止并删除容器和网络:
bash
docker-compose down
查看日志:
bash
docker-compose logs -f
Docker Compose非常适合开发环境和简单的部署。但在生产环境中,容器数量多、分布在不同主机上时,就需要容器编排工具如Kubernetes。
3. Docker实战:容器化一个Web应用
为了更直观地理解Docker的使用,我们从一个简单的Node.js应用开始,将其容器化,并用Docker Compose集成数据库。
3.1 准备一个简单的Node.js应用
首先,创建一个项目目录,比如node-app。在目录下创建app.js:
javascript
const express = require('express'); const mysql = require('mysql'); const app = express(); const port = 3000; // MySQL连接配置(环境变量或硬编码,待会儿会用环境变量) const db = mysql.createConnection({ host: process.env.DB_HOST || 'localhost', user: process.env.DB_USER || 'root', password: process.env.DB_PASSWORD || 'password', database: process.env.DB_NAME || 'testdb' }); db.connect(err => { if (err) { console.error('数据库连接失败:', err); } else { console.log('数据库连接成功'); } }); app.get('/', (req, res) => { res.send('Hello World!'); }); app.get('/users', (req, res) => { db.query('SELECT * FROM users', (err, results) => { if (err) { res.status(500).send(err); } else { res.json(results); } }); }); app.listen(port, () => { console.log(`应用监听端口 ${port}`); });创建package.json:
json
{ "name": "node-app", "version": "1.0.0", "dependencies": { "express": "^4.18.2", "mysql": "^2.18.1" } }3.2 编写Dockerfile
在项目根目录创建Dockerfile:
dockerfile
# 使用官方Node.js镜像作为基础 FROM node:18-alpine # 设置工作目录 WORKDIR /app # 复制package.json和package-lock.json(如果有) COPY package*.json ./ # 安装依赖 RUN npm install # 复制应用程序代码 COPY . . # 暴露应用端口 EXPOSE 3000 # 启动命令 CMD ["node", "app.js"]
3.3 构建镜像并运行容器
构建镜像:
bash
docker build -t node-app:v1 .
运行容器(假设本地没有MySQL,暂时先不连接数据库):
bash
docker run -d -p 3000:3000 --name myapp node-app:v1
访问http://localhost:3000,应该看到“Hello World!”。但访问/users会报错,因为没有数据库。下面我们用Docker Compose启动应用+MySQL。
3.4 使用Docker Compose管理应用+数据库
创建docker-compose.yml:
yaml
version: '3.8' services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: testdb MYSQL_USER: appuser MYSQL_PASSWORD: apppass volumes: - dbdata:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化脚本 ports: - "3306:3306" # 仅开发时暴露,生产不建议 networks: - appnet app: build: . depends_on: - db environment: DB_HOST: db DB_USER: appuser DB_PASSWORD: apppass DB_NAME: testdb ports: - "3000:3000" networks: - appnet volumes: dbdata: networks: appnet:
创建初始化SQL脚本init.sql:
sql
CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL ); INSERT INTO users (name) VALUES ('Alice'), ('Bob');现在启动:
bash
docker-compose up -d
等待数据库初始化完成,访问http://localhost:3000/users,应能看到JSON数据。至此,我们成功容器化了一个Node.js应用并整合了数据库。
4. 为什么需要容器编排?
上面的Docker Compose可以在单机上很好地管理多个容器。但在生产环境中,我们面临更多挑战:
容器分布在多台服务器:如何跨主机通信、调度?
高可用:某个容器挂了,如何自动恢复?
负载均衡:流量大时,如何动态增加容器数量?
滚动更新:如何在不中断服务的情况下升级应用?
服务发现:容器IP变化,如何让其他服务找到它?
存储、配置、密钥管理:如何统一管理?
这些问题正是容器编排工具要解决的。目前最流行的容器编排平台就是Kubernetes。
5. Kubernetes基础篇
5.1 什么是Kubernetes?
Kubernetes(简称K8s)是一个开源的容器编排引擎,用于自动化部署、扩展和管理容器化应用。它最初由Google设计,现在由云原生计算基金会(CNCF)维护。
Kubernetes提供了一个“集群”的概念:一组机器(节点)组成一个计算资源池,Kubernetes负责将容器调度到合适的节点上,并保证它们按照用户期望的状态运行。
5.2 Kubernetes核心概念
集群(Cluster):一组节点(物理机或虚拟机),包括一个主节点(Master)和多个工作节点(Node)。
节点(Node):集群中的一台机器,可以是物理机或虚拟机。每个节点上运行着容器运行时(如Docker)和Kubelet(与Master通信的代理)。
Pod:Kubernetes最小的部署单元,一个Pod可以包含一个或多个紧密相关的容器(共享网络和存储)。通常一个Pod只运行一个主容器。
控制器(Controller):负责管理Pod的控制器,例如Deployment、StatefulSet、DaemonSet等。
Service:定义一组Pod的访问策略,通常为一组Pod提供稳定的IP和DNS名,实现负载均衡。
命名空间(Namespace):将集群资源划分为多个虚拟集群,用于隔离不同团队或项目。
ConfigMap / Secret:将配置信息与容器镜像解耦,方便管理。
Ingress:管理外部访问集群服务的入口,通常提供HTTP路由。
5.3 安装Kubernetes环境(Minikube)
对于学习,推荐使用Minikube,它可以在本地启动一个单节点Kubernetes集群。
安装Minikube(以Linux为例)
bash
# 下载Minikube二进制文件 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube # 启动集群(自动安装kubectl) minikube start --driver=docker # 如果已有Docker,用docker驱动
macOS和Windows用户可以用Docker Desktop自带的Kubernetes,或者用Minikube。
安装完成后,验证:
bash
kubectl cluster-info kubectl get nodes
5.4 kubectl基本命令
kubectl是Kubernetes的命令行工具,用于与集群交互。
常用命令:
bash
# 查看所有资源 kubectl get all # 查看Pod kubectl get pods # 查看详细信息 kubectl describe pod <pod-name> # 创建资源(通过YAML文件) kubectl apply -f my-deployment.yaml # 删除资源 kubectl delete -f my-deployment.yaml # 查看日志 kubectl logs <pod-name> # 进入Pod执行命令 kubectl exec -it <pod-name> -- /bin/sh # 端口转发(临时访问Pod) kubectl port-forward <pod-name> 8080:80
5.5 第一个应用:在Kubernetes中部署Nginx
创建nginx-deployment.yaml:
yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80
部署:
bash
kubectl apply -f nginx-deployment.yaml
查看Pod:
bash
kubectl get pods
创建Service暴露它们:
yaml
apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancer # 在Minikube下需要运行 minikube tunnel 才能获取外部IP
应用Service:
bash
kubectl apply -f nginx-service.yaml
在Minikube中,可以使用minikube service nginx-service打开浏览器访问。
5.6 Pod详解
Pod是Kubernetes中最小的调度单元。一个Pod可以包含多个容器,它们共享:
网络命名空间(同一个IP和端口空间)
存储卷(Volume)
进程间通信(IPC)
常见场景:一个主容器+一个辅助容器(sidecar),例如日志收集器、代理等。
Pod的生命周期
Pending:Pod已被接受,但有一个或多个容器尚未创建。
Running:Pod已经绑定到节点,所有容器已创建,至少有一个在运行。
Succeeded:所有容器成功终止。
Failed:所有容器终止,至少一个容器失败。
CrashLoopBackOff:容器启动后崩溃,Kubelet正在重启。
5.7 控制器:Deployment与ReplicaSet
Deployment是最常用的控制器,它管理ReplicaSet(副本集),进而管理Pod。Deployment支持声明式更新、回滚、滚动升级。
ReplicaSet:确保指定数量的Pod副本始终运行。
Deployment:在ReplicaSet基础上提供更高级的功能,如版本更新。
创建Deployment时,可以指定strategy来控制更新策略:
yaml
strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: 1
其他控制器:
StatefulSet:用于有状态应用,提供稳定的网络标识和持久化存储。
DaemonSet:在每个节点上运行一个Pod,用于监控、日志收集等。
Job / CronJob:运行一次性任务或定时任务。
5.8 服务发现:Service
由于Pod会动态创建和销毁,IP会变化,因此需要Service为一组Pod提供稳定的访问入口。Service通过标签选择器(selector)关联Pod。
Service类型:
ClusterIP(默认):仅在集群内部可访问,分配一个虚拟IP。
NodePort:在每个节点上开放一个静态端口,外部可通过
<NodeIP>:<NodePort>访问。LoadBalancer:在云提供商上自动创建外部负载均衡器,将流量转发到NodePort。
ExternalName:将服务映射到外部DNS名。
示例:ClusterIP Service
yaml
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: myapp ports: - protocol: TCP port: 80 targetPort: 8080
5.9 配置管理:ConfigMap与Secret
ConfigMap用于存储非机密性的配置数据(如环境变量、配置文件)。Secret用于存储敏感数据(如密码、密钥),以Base64编码存储,并且支持加密。
ConfigMap示例
yaml
apiVersion: v1 kind: ConfigMap metadata: name: app-config data: DB_HOST: mysql-service DB_NAME: testdb APP_COLOR: blue
在Pod中引用ConfigMap作为环境变量:
yaml
env: - name: DB_HOST valueFrom: configMapKeyRef: name: app-config key: DB_HOST
也可以将ConfigMap挂载为文件。
Secret示例
创建Secret(命令行):
bash
kubectl create secret generic db-secret --from-literal=password=rootpass
Secret的YAML:
yaml
apiVersion: v1 kind: Secret metadata: name: db-secret type: Opaque data: password: cm9vdHBhc3M= # base64编码的 "rootpass"
在Pod中引用Secret作为环境变量(注意:Secret需先解码)。
5.10 数据持久化:PersistentVolume与PersistentVolumeClaim
Kubernetes通过PersistentVolume(PV)和PersistentVolumeClaim(PVC)来管理持久化存储。
PV:集群管理员预先配置的存储资源(如NFS、云盘)。
PVC:用户对存储的请求,像“我要5GB的快速存储”。Pod通过PVC使用PV。
流程:
管理员创建PV。
用户创建PVC。
Pod的volumes中引用PVC。
示例PV(本地hostPath,仅用于测试):
yaml
apiVersion: v1 kind: PersistentVolume metadata: name: pv-local spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce hostPath: path: /data/pv
示例PVC:
yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-demo spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi
Pod中使用:
yaml
volumes: - name: data persistentVolumeClaim: claimName: pvc-demo
5.11 命名空间(Namespace)
命名空间提供资源隔离。默认有default、kube-system(系统组件)、kube-public等。可以创建自己的命名空间。
bash
kubectl create namespace myapp
在YAML中指定metadata.namespace。查看某命名空间的资源:
bash
kubectl get pods -n myapp
5.12 Ingress:外部访问
Service的NodePort和LoadBalancer方式通常用于暴露服务。但更常见的做法是使用Ingress,它提供基于HTTP/HTTPS的路由规则,将外部请求转发到不同的Service。
Ingress需要安装Ingress控制器(如nginx-ingress、traefik)。Minikube自带Ingress插件:
bash
minikube addons enable ingress
创建Ingress示例:
yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress spec: rules: - host: myapp.local http: paths: - path: / pathType: Prefix backend: service: name: nginx-service port: number: 80
修改本地hosts文件,将myapp.local指向Minikube IP(minikube ip),然后访问即可。
6. Kubernetes实战:部署完整应用
现在,我们将之前Docker Compose中的Node.js应用+MySQL部署到Kubernetes中。
6.1 将之前的Node.js应用部署到Kubernetes
首先,我们需要将应用的Docker镜像推送到一个仓库(如Docker Hub),以便Kubernetes节点拉取。或者使用Minikube的内置镜像缓存,如果镜像已在本地。
这里假设我们将镜像推送到Docker Hub(需注册):
bash
docker tag node-app:v1 yourusername/node-app:v1 docker push yourusername/node-app:v1
如果不想推送,也可以在Minikube环境中直接使用本地镜像:执行eval $(minikube docker-env),然后在当前终端构建镜像,就可以在Minikube内使用。
6.2 使用Deployment管理应用
创建app-deployment.yaml:
yaml
apiVersion: apps/v1 kind: Deployment metadata: name: node-app spec: replicas: 2 selector: matchLabels: app: node-app template: metadata: labels: app: node-app spec: containers: - name: node-app image: yourusername/node-app:v1 # 替换为你的镜像 ports: - containerPort: 3000 env: - name: DB_HOST value: mysql-service # 稍后创建的Service名 - name: DB_USER value: appuser - name: DB_PASSWORD value: apppass - name: DB_NAME value: testdb
6.3 创建Service暴露应用
创建app-service.yaml:
yaml
apiVersion: v1 kind: Service metadata: name: node-app-service spec: selector: app: node-app ports: - protocol: TCP port: 80 targetPort: 3000 type: LoadBalancer # 在Minikube下用minikube tunnel或NodePort
6.4 使用ConfigMap配置应用
将环境变量提取到ConfigMap中,更灵活。
创建app-config.yaml:
yaml
apiVersion: v1 kind: ConfigMap metadata: name: app-config data: DB_HOST: mysql-service DB_USER: appuser DB_NAME: testdb
然后修改Deployment的env部分:
yaml
env: - name: DB_HOST valueFrom: configMapKeyRef: name: app-config key: DB_HOST - name: DB_USER valueFrom: configMapKeyRef: name: app-config key: DB_USER - name: DB_NAME valueFrom: configMapKeyRef: name: app-config key: DB_NAME - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password
密码存入Secret(见后)。
6.5 添加MySQL数据库
MySQL是有状态应用,可以使用StatefulSet或者简单的Deployment+PersistentVolume。
创建mysql-deployment.yaml:
yaml
apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: db-secret key: rootpassword - name: MYSQL_DATABASE value: testdb - name: MYSQL_USER value: appuser - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password ports: - containerPort: 3306 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql - name: init-sql mountPath: /docker-entrypoint-initdb.d volumes: - name: mysql-data persistentVolumeClaim: claimName: mysql-pvc - name: init-sql configMap: name: mysql-init-sql
创建PVCmysql-pvc.yaml:
yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi
创建ConfigMapmysql-init-sql.yaml:
yaml
apiVersion: v1 kind: ConfigMap metadata: name: mysql-init-sql data: init.sql: | CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL ); INSERT INTO users (name) VALUES ('Alice'), ('Bob');创建Secretdb-secret.yaml:
yaml
apiVersion: v1 kind: Secret metadata: name: db-secret type: Opaque data: rootpassword: cm9vdHBhc3M= # rootpass的base64 password: YXBwcGFzcw== # apppass的base64
创建Servicemysql-service.yaml(供app访问):
yaml
apiVersion: v1 kind: Service metadata: name: mysql-service spec: selector: app: mysql ports: - protocol: TCP port: 3306 targetPort: 3306
6.6 应用扩容与滚动更新
现在所有资源都已定义,执行:
bash
kubectl apply -f db-secret.yaml kubectl apply -f mysql-init-sql.yaml kubectl apply -f mysql-pvc.yaml kubectl apply -f mysql-deployment.yaml kubectl apply -f mysql-service.yaml kubectl apply -f app-config.yaml kubectl apply -f app-deployment.yaml kubectl apply -f app-service.yaml
检查状态:
bash
kubectl get pods kubectl get svc
如果一切正常,可以使用minikube service node-app-service访问应用。
扩容
将Node.js应用副本数扩展到3:
bash
kubectl scale deployment node-app --replicas=3
滚动更新
修改代码后,构建新镜像yourusername/node-app:v2,然后更新Deployment:
bash
kubectl set image deployment/node-app node-app=yourusername/node-app:v2
或者直接修改YAML后apply。Kubernetes会执行滚动更新,逐个替换Pod,确保服务不中断。
查看更新状态:
bash
kubectl rollout status deployment/node-app
如有问题,可回滚:
bash
kubectl rollout undo deployment/node-app
至此,我们完成了一个完整的Kubernetes应用部署。
7. 进阶概念与生态
7.1 Helm:Kubernetes包管理器
Helm是Kubernetes的包管理工具,类似yum或apt。它将一组Kubernetes资源打包成Chart,方便分发、安装、升级、回滚。
安装Helm(客户端):
bash
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
查找Chart(如WordPress):
bash
helm search hub wordpress
添加仓库并安装:
bash
helm repo add bitnami https://charts.bitnami.com/bitnami helm install my-wordpress bitnami/wordpress
Helm通过模板化生成YAML,可以自定义参数。对于复杂应用,推荐使用Helm管理。
7.2 存储类(StorageClass)
在云环境中,StorageClass定义了动态创建PV的存储类型(如SSD、HDD)。PVC可以通过指定StorageClassName来请求特定类型的存储。
示例StorageClass(AWS EBS):
yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/aws-ebs parameters: type: gp2
PVC引用:
yaml
spec: storageClassName: fast resources: requests: storage: 10Gi
7.3 网络策略(NetworkPolicy)
默认情况下,Kubernetes允许所有Pod之间的通信。为了安全,可以使用NetworkPolicy限制流量。这需要CNI网络插件支持(如Calico、Cilium)。
示例:禁止来自其他命名空间的访问,只允许某标签的Pod访问。
yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-from-other-namespaces spec: podSelector: {} policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: project: myapp7.4 水平自动伸缩(HPA)
HorizontalPodAutoscaler根据CPU、内存使用率或自定义指标自动调整Deployment的副本数。
示例:基于CPU使用率,保持平均50%,副本范围1-10。
yaml
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: node-app-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: node-app minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50
7.5 服务网格(Service Mesh)简介
服务网格如Istio、Linkerd,在Kubernetes基础上提供了更细粒度的流量管理、安全、可观测性功能。它们通过在每个Pod中注入sidecar代理,拦截所有进出流量,实现:
金丝雀发布、蓝绿部署
服务间mTLS加密
流量镜像、故障注入
分布式追踪、监控
7.6 CI/CD集成
将Docker和Kubernetes集成到CI/CD流水线,可以实现代码提交后自动构建镜像、推送仓库、更新Kubernetes中的应用。常用工具有:
Jenkins
GitLab CI
GitHub Actions
ArgoCD(GitOps)
例如,GitHub Actions的流程:
代码push触发workflow
构建Docker镜像并推送到Docker Hub
更新Kubernetes Deployment的镜像版本
可选:等待滚动更新完成