VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#网络编程之容器化部署(Docker、Kubernetes)

第74章 容器化部署(Docker、Kubernetes)
一、我踩过的容器化坑:从“镜像1.2GB部署10分钟”到“K8s Pod重启找不到配置文件”
第一次做Docker镜像时,直接用了.NET SDK镜像,打包出来1.2GB,部署到服务器要10分钟——后来用多阶段构建,把SDK镜像用来构建,Runtime镜像用来运行,镜像体积直接降到200MB,部署1分钟搞定!还有一次部署K8s Pod,把配置文件直接打包到镜像里,Pod重启后配置改了但镜像没更新,导致服务用旧配置运行——后来用ConfigMap挂载配置文件,修改ConfigMap后Pod自动更新配置,问题解决!这节我把这些血泪经验揉进去,用大白话vb.net教程C#教程python教程SQL教程access 2010教程讲透Docker和Kubernetes的核心用法,结合代码逐行拆解,拓展底层原理和生产级技巧,让你一次搞定容器化部署!
二、Docker:跨平台容器引擎,把服务和依赖打包成“移动硬盘”

  1. 核心概念大白话
    镜像:像一个只读的移动硬盘,里面装着服务和所有依赖(比如.NET Runtime、配置文件);
    容器:像从镜像启动的虚拟机,是镜像的运行实例,可读写,停止后可以删除;
    镜像分层:像叠积木,每个层是一个文件,修改只改上层,节省空间(比如SDK镜像有10层,Runtime镜像有5层,多阶段构建可以复用Runtime的层)。
  2. Dockerfile逐行讲解:多阶段构建.NET服务
    我踩过的坑:用SDK镜像做基础镜像,体积太大
    dockerfile
	# 错误写法:用SDK镜像做基础镜像,体积1.2GB
	# FROM mcr.microsoft.com/dotnet/sdk:8.0
	# WORKDIR /app
	# COPY . .
	# RUN dotnet publish -c Release -o out
	# CMD ["dotnet", "out/MyService.dll"]

正确写法:多阶段构建,体积200MB左右
dockerfile

	# 第一阶段:构建阶段,用SDK镜像(包含编译器、NuGet等)
	FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
	WORKDIR /src # 设置工作目录,后续命令都在这个目录下执行
	COPY ["MyService.csproj", "."] # 先复制csproj文件,利用Docker缓存(如果csproj没改,就不用重新restore)
	RUN dotnet restore "MyService.csproj" # 还原NuGet依赖
	COPY . . # 复制所有代码文件
	RUN dotnet build "MyService.csproj" -c Release -o /app/build # 构建项目,输出到/app/build目录
	
	# 第二阶段:运行阶段,用Runtime镜像(只有.NET Runtime,体积小)
	FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
	WORKDIR /app # 设置工作目录
	COPY --from=build /app/build . # 从构建阶段复制构建好的文件到当前镜像
	ENTRYPOINT ["dotnet", "MyService.dll"] # 容器启动时执行的命令,跨平台兼容

代码逐行拆解(结合底层原理)

  1. 多阶段构建的核心优势
    dockerfile
	FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
	...
	FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
	COPY --from=build /app/build .

底层原理:第一阶段用SDK镜像构建项目,第二阶段用Runtime镜像运行项目,只把构建好的文件复制到Runtime镜像里,去掉了SDK的编译器、NuGet等无用内容,体积从1.2GB降到200MB;
拓展知识:Runtime镜像分两种,aspnet镜像包含ASP.NET Core Runtime,runtime镜像包含.NET Runtime(适合控制台应用)。
2. 利用Docker缓存加速构建
dockerfile

	COPY ["MyService.csproj", "."]
	RUN dotnet restore "MyService.csproj"
	COPY . .

底层原理:Docker会缓存每个指令的结果,如果csproj文件没改,dotnet restore就会用缓存,不用重新下载NuGet依赖,构建时间从5分钟降到30秒;
生产级技巧:先复制csproj文件,再restore,最后复制所有代码,这样csproj没改时,restore的结果会被缓存。
3. ENTRYPOINT vs CMD

dockerfile 
ENTRYPOINT ["dotnet", "MyService.dll"]
ENTRYPOINT:容器启动时必须执行的命令,不能被覆盖(除非用docker run --entrypoint);

CMD:容器启动时的默认命令,可以被docker run的命令覆盖;
推荐用法:用ENTRYPOINT设置固定命令,用CMD设置参数,比如ENTRYPOINT ["dotnet"],CMD ["MyService.dll"],这样可以用docker run myservice MyOtherService.dll运行其他服务。
3. Docker核心命令逐行讲解

  1. 构建镜像
    bash
	# -t:给镜像打标签(名称:版本),比如myservice:v1
	# .:指定Dockerfile所在的目录(当前目录)
	docker build -t myservice:v1 .

底层原理:Docker从当前目录读取Dockerfile,执行每个指令,生成镜像的每个层,最后把层合并成一个镜像;
生产级技巧:用--no-cache参数强制不使用缓存,比如docker build -t myservice:v1 --no-cache .,适合依赖更新后重新构建。
2. 运行容器
bash

	# -d:后台运行容器(守护进程模式)
	# -p:映射端口,格式是“主机端口:容器端口”,比如把主机的5000端口映射到容器的5000端口
	# -v:挂载目录,格式是“主机目录:容器目录”,比如把主机的/config目录挂载到容器的/app/config目录,实现配置文件持久化
	# --name:给容器起名字,方便管理
	# myservice:v1:用哪个镜像启动容器
	docker run -d -p 5000:5000 -v /host/config:/app/config --name myservice myservice:v1

底层原理:Docker从镜像创建容器,给容器分配网络、存储,映射端口和目录,然后执行ENTRYPOINT命令;
生产级技巧:用--rm参数,容器停止后自动删除,比如docker run --rm -p 5000:5000 myservice:v1,适合临时测试。
3. 查看容器状态
bash

	# 查看所有运行中的容器
	docker ps
	# 查看所有容器(包括停止的)
	docker ps -a
	# 查看容器日志,-f表示实时查看
	docker logs -f myservice
	# 进入容器的命令行,/bin/bash是Linux的Shell,Windows用cmd
	docker exec -it myservice /bin/bash
  1. 推送镜像到仓库
    bash
	# 给镜像打标签,格式是“仓库地址/用户名/镜像名:版本”,比如Docker Hub的标签是username/myservice:v1
	docker tag myservice:v1 username/myservice:v1
	# 登录Docker Hub,输入用户名和密码
	docker login
	# 推送镜像到仓库
	docker push username/myservice:v1

底层原理:Docker把镜像分成多个层,只推送本地没有的层,节省带宽;
生产级技巧:用私有仓库(比如Harbor)存储镜像,避免敏感代码泄露到公共仓库。
4. Docker Compose:多容器部署神器,一键启动服务和依赖
我踩过的坑:手动启动Web服务+Redis,每次都要输两个命令,容易忘参数
docker-compose.yml逐行讲解:Web服务+Redis
yaml

	# 指定Docker Compose的版本,推荐用3.8以上
	version: '3.8'
	
	# 定义所有服务
	services:
	# Web服务
	myservice:
	# 用哪个镜像启动,或者用build指定Dockerfile目录
	image: myservice:v1
	# build: . # 如果要构建镜像,用这个参数,指定Dockerfile所在目录
	ports:
	- "5000:5000" # 映射端口
	volumes:
	- /host/config:/app/config # 挂载配置目录
	environment:
	- ASPNETCORE_ENVIRONMENT=Production # 设置环境变量
	- Redis__ConnectionString=redis:6379 # Redis的连接字符串,用服务名redis(因为Docker Compose会给每个服务分配DNS)
	depends_on:
	- redis # 依赖Redis服务,启动myservice前先启动redis
	restart: always # 容器崩溃或重启后自动重启
	
	# Redis服务
	redis:
	image: redis:7.0 # 用官方Redis镜像
	ports:
	- "6379:6379" # 映射Redis端口
	volumes:
	- redis-data:/data # 挂载Redis数据目录,实现数据持久化
	restart: always
	
	# 定义卷(持久化存储)
	volumes:
	redis-data: # Redis的数据会存在这个卷里,容器删除后数据不会丢失

代码逐行拆解(结合底层原理)

  1. 服务之间的通信
    yaml
	environment:
	- Redis__ConnectionString=redis:6379

底层原理:Docker Compose会创建一个默认的桥接网络,所有服务都在这个网络里,用服务名(比如redis)作为DNS名称,直接访问服务的端口,不用输IP地址;
拓展知识:用docker network ls查看Docker网络,用docker network inspect myservice_default查看服务的IP地址。
2. 卷(Volumes)持久化存储
yaml

	volumes:
	redis-data:

底层原理:卷是Docker管理的存储目录,比挂载主机目录更安全,跨平台兼容(Windows、Linux、macOS都支持);
生产级技巧:用命名卷存储数据,不用挂载主机目录,避免主机目录权限问题。
核心命令
bash

	# 启动所有服务,-d表示后台运行
	docker-compose up -d
	# 停止所有服务
	docker-compose down
	# 查看服务日志
	docker-compose logs -f myservice
	# 重新构建服务(如果Dockerfile改了)
	docker-compose build myservice

三、Kubernetes(K8s):容器编排引擎,管理成千上万的容器

  1. 核心概念大白话
    Pod:K8s的最小部署单位,像一个小盒子,里面装着一个或多个容器(比如Web服务+日志收集容器),共享网络和存储;
    Deployment:像Pod的“保姆”,管理Pod的副本数,比如指定3个Pod,挂了一个会自动启动新的;
    Service:像Pod的“域名”,给Pod分配一个固定的虚拟IP,不管Pod怎么重启,Service的IP都不变,外部可以通过Service访问Pod;
    ConfigMap:像Pod的“配置文件仓库”,把配置文件从镜像里抽出来,挂载到Pod里,修改ConfigMap后Pod自动更新配置;
    Secret:像加密的ConfigMap,用来存储敏感数据(比如密码、API密钥),存储时会加密,挂载到Pod里是明文。
  2. K8s YAML逐行讲解:Deployment+Service+ConfigMap
    我踩过的坑:把配置文件打包到镜像里,修改配置要重新构建镜像
  3. ConfigMap:存储配置文件
    yaml
	# 定义ConfigMap
	apiVersion: v1
	kind: ConfigMap
	metadata:
	name: myservice-config # ConfigMap的名字
	data:
	# 配置文件内容,key是文件名,value是文件内容
	appsettings.json: |
	{
	"Logging": {
	"LogLevel": {
	"Default": "Information"
	}
	},
	"Redis": {
	"ConnectionString": "redis:6379"
	}
	}

底层原理:ConfigMap存储在K8s的etcd数据库里,挂载到Pod里时会变成文件,Pod可以直接读取;
生产级技巧:用kubectl create configmap myservice-config --from-file=appsettings.json从本地文件创建ConfigMap,不用手动写YAML。
2. Deployment:管理Pod的副本数

yaml

	# 定义Deployment
	apiVersion: apps/v1
	kind: Deployment
	metadata:
	name: myservice-deployment # Deployment的名字
	labels:
	app: myservice # 标签,用来和Service关联
	spec:
	replicas: 3 # 运行3个Pod副本
	selector:
	matchLabels:
	app: myservice # 选择标签为app=myservice的Pod
	template:
	metadata:
	labels:
	app: myservice # Pod的标签,要和selector的matchLabels一致
	spec:
	containers:
	- name: myservice # 容器的名字
	image: username/myservice:v1 # 用哪个镜像启动容器
	ports:
	- containerPort: 5000 # 容器的端口
	volumeMounts:
	- name: config-volume # 挂载的卷名字,要和volumes的name一致
	mountPath: /app/appsettings.json # 挂载到容器的哪个路径(覆盖原来的appsettings.json)
	subPath: appsettings.json # 用ConfigMap里的哪个文件
	resources:
	requests:
	cpu: "100m" # 每个Pod请求100m CPU(1核=1000m)
	memory: "256Mi" # 每个Pod请求256MB内存
	limits:
	cpu: "500m" # 每个Pod最多用500m CPU
	memory: "512Mi" # 每个Pod最多用512MB内存
	env:
	- name: ASPNETCORE_ENVIRONMENT # 设置环境变量
	value: "Production"
	volumes:
	- name: config-volume # 卷的名字
	configMap:
	name: myservice-config # 用哪个ConfigMap

代码逐行拆解(结合底层原理)

  1. 副本数(Replicas)
    yaml
    replicas: 3
    底层原理:Deployment会创建3个Pod,如果其中一个Pod崩溃,Deployment会自动启动一个新的Pod,保证始终有3个Pod运行;
    生产级技巧:用HPA(Horizontal Pod Autoscaler)自动调整副本数,比如CPU使用率超过70%时自动增加到5个副本,低于30%时减少到2个。
  2. 资源请求和限制(Resources)
    yaml
    resources:
    requests:
    cpu: "100m"
    memory: "256Mi"
    limits:
    cpu: "500m"
    memory: "512Mi"
    底层原理:K8s会根据资源请求调度Pod到有足够资源的节点上,资源限制防止Pod占用过多资源导致其他服务崩溃;
    生产级技巧:不要设置超过节点资源的限制,比如节点只有2核CPU,不要设置每个Pod的CPU限制为3核。
  3. 挂载ConfigMap
    yaml
	volumeMounts:
	- name: config-volume
	mountPath: /app/appsettings.json
	subPath: appsettings.json

底层原理:把ConfigMap里的appsettings.json文件挂载到容器的/app/appsettings.json路径,覆盖原来的文件,修改ConfigMap后,Pod会自动重新读取配置;
拓展知识:用kubectl rollout restart deployment myservice-deployment手动重启Pod,应用新配置。
3. Service:给Pod分配固定IP
yaml

	# 定义Service
	apiVersion: v1
	kind: Service
	metadata:
	name: myservice-service # Service的名字
	spec:
	type: NodePort # Service的类型,NodePort表示把服务暴露到节点的端口上
	selector:
	app: myservice # 选择标签为app=myservice的Pod
	ports:
	- protocol: TCP
	port: 80 # Service的端口
	targetPort: 5000 # 容器的端口
	nodePort: 30007 # 节点的端口,范围是30000-32767(可选,K8s会自动分配)

代码逐行拆解(结合底层原理)

  1. Service类型
    NodePort:把服务暴露到节点的端口上,外部可以用节点IP:节点端口访问;
    ClusterIP:默认类型,只在K8s集群内部访问,适合服务之间的通信;
    LoadBalancer:在云厂商(比如AWS、阿里云)上会自动创建负载均衡器,外部可以用负载均衡器的IP访问;
    Ingress:像K8s的Nginx,用域名访问多个服务,比如api.example.com访问myservice,redis.example.com访问redis。
  2. K8s核心命令逐行讲解
  3. 部署服务
    bash
	# 应用YAML文件,创建或更新资源
	kubectl apply -f configmap.yaml
	kubectl apply -f deployment.yaml
	kubectl apply -f service.yaml
	# 一次性应用所有YAML文件
	kubectl apply -f .
  1. 查看资源状态
    bash
	# 查看Pod状态
	kubectl get pods
	# 查看Deployment状态
	kubectl get deployments
	# 查看Service状态
	kubectl get services
	# 查看Pod日志
	kubectl logs myservice-deployment-7f9d6d8b9c-2xqzk
	# 进入Pod的命令行
	kubectl exec -it myservice-deployment-7f9d6d8b9c-2xqzk -- /bin/bash
	# 查看Pod的详细信息(比如资源使用情况、挂载的卷)
	kubectl describe pod myservice-deployment-7f9d6d8b9c-2xqzk
  1. 升级和回滚服务
    bash
	# 升级镜像版本
	kubectl set image deployment/myservice-deployment myservice=username/myservice:v2
	# 查看升级状态
	kubectl rollout status deployment/myservice-deployment
	# 回滚到上一个版本
	kubectl rollout undo deployment/myservice-deployment
	# 查看升级历史
	kubectl rollout history deployment/myservice-deployment

四、生产级容器化部署技巧

  1. Docker镜像优化
    多阶段构建:用SDK镜像构建,Runtime镜像运行,减少体积;
    清理无用文件:在RUN指令里合并命令,清理临时文件,比如RUN dotnet restore && dotnet build && rm -rf /root/.nuget;
    用Alpine镜像:Alpine是一个轻量级Linux发行版,体积只有5MB,比如mcr.microsoft.com/dotnet/runtime-deps:8.0-alpine,适合控制台应用。
  2. K8s生产级配置
    用Ingress暴露服务:用域名访问服务,比如api.example.com,比NodePort更友好;
    用HPA自动扩缩容:根据CPU或内存使用率自动调整Pod副本数;
    用NodeSelector调度Pod:把Pod调度到指定节点,比如把数据库Pod调度到有SSD的节点;
    用Taints和Tolerances:给节点打污点,只有有容忍度的Pod才能调度到这个节点,比如把GPU节点打污点,只有需要GPU的Pod才能调度到这个节点。
  3. 容器化监控与排查
    Docker监控:用docker stats查看容器的CPU、内存使用率;
    K8s监控:用Prometheus+Grafana监控Pod的CPU、内存、网络使用率;
    日志收集:用ELK(Elasticsearch+Logstash+Kibana)或Loki收集容器日志,统一查看;
    故障排查:用kubectl debug创建调试Pod,比如kubectl debug -it myservice-deployment-7f9d6d8b9c-2xqzk --image=busybox --share-processes,查看Pod的进程和文件。
    五、总结与选型建议
  4. 选型表
场景 推荐工具
本地开发、测试环境 Docker + Docker Compose
生产环境、高并发场景 Kubernetes + Helm
多服务部署、依赖管理 Docker Compose(开发)、Kubernetes(生产)
跨平台部署 Docker(打包镜像)、Kubernetes(管理容器)
  1. 容器化部署流程
    1.本地开发:用Docker Compose启动服务和依赖,测试功能;
    2.构建镜像:用多阶段构建Docker镜像,推送到私有仓库;
    3.测试环境部署:用K8s部署镜像,测试性能和稳定性;
    4.生产环境部署:用K8s+Helm部署,设置自动扩缩容、监控、日志收集;
    5.升级和回滚:用K8s的rollout功能升级镜像,出现问题时回滚到上一个版本。
    现在你已经掌握了Docker和Kubernetes的核心用法,从镜像构建到容器运行,从多服务部署到K8s编排,以后容器化部署不用慌,按照这个流程来,90%的问题都能提前避免!下一节我们会学习“容器化网络与安全”,结合Docker和K8s的网络原理,教你保护容器化服务的安全!

转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49594.html


相关教程