Docker与Docker Compose实战:从零搭建MySQL、Redis及Nginx容器化部署
2026/9/16 22:54:08 网站建设 项目流程

1. 部署前的核心概念与整体思路

1.1 Docker与Docker Compose到底是什么

先把概念理清楚。你平时在服务器上装软件,最头疼的是什么?环境依赖、版本冲突、迁移麻烦。今天在这台机器上编译通过了,换台机器又起不来。Docker就是冲着这个问题来的,它把应用和它依赖的运行环境一起打包成一个镜像,走到哪跑到哪。

可以这样理解:Docker就是一个标准化的“集装箱码头”。每个容器就是一个装好货物(应用+环境)的箱子,不管底层是Linux、macOS还是Windows,只要装了Docker这个“起重机”,就能把箱子吊起来跑。关键是箱子之间相互隔离,里面的版本再乱也不影响别的箱子。

那Docker Compose呢?它是Docker官方的容器编排工具,解决的是“多个容器如何一起管理”的问题。一个完整的应用往往不止一个服务,比如一个网站项目可能需要Nginx、MySQL、Redis三个服务,按传统做法得分别启动三个容器,还要自己配置网络让它们能通信。Compose允许你写一个docker-compose.yml文件,把三个服务的镜像、端口、挂载目录、环境变量全声明好,一条docker compose up -d命令全部拉起来。

我见过不少人用了很久Docker,但部署还是靠手工一个个docker run,遇到服务多的时候非常痛苦。这篇文章就是把我在实际部署中反复验证过的完整流程写出来,从零开始装Docker,到用Compose把一整套环境跑起来,全程亲测有效,跟着操作就能复现。

1.2 为什么现在部署应用首选Docker方案

聊一下技术选型的问题。有人会问:我直接在服务器上装MySQL、装Redis不行吗?非得套一层容器?说实话,在没被环境问题折磨过之前,我也觉得直接装更省事。但经历了几个真实项目之后,我彻底倒向了Docker方案,原因很实际:

第一是交付一致性。开发在自己电脑上用的MySQL 8.0,生产环境如果装的MySQL 5.7,有些SQL语法就有差异,线上出问题排查半天结果发现是版本不一致。用Docker的话,镜像里锁死了版本,开发和生产跑的是同一个容器镜像,这个坑直接抹平。

第二是集成环境快速搭建。新入职一台工作电脑,要装Node.js、Java、Redis、MySQL、Nginx,手工装一遍没一两个小时下不来,装完还要配环境变量。用Docker Compose写一个配置文件,拉到任何一台机器上,几分钟一套环境就绪。这个体验用过一次就回不去了。

第三是隔离和清理方便。哪个服务出问题了,直接把容器删了重建一个,只要数据目录挂载在外面,数据不会丢。相比在宿主机上装一堆服务,把系统弄得乱七八糟,容器方案干净利落。

当然也有不适合的场景,比如性能极致敏感、需要直接操作宿主硬件的地方,容器会有些损耗。但对绝大多数Web应用、中间件、开发环境来说,Docker的收益远大于那点性能开销。

2. 环境准备与Docker安装实操

2.1 Windows平台安装Docker Desktop

Windows是最容易出问题的平台,我见过很多人在虚拟机未开启的情况下卡在安装那一步。先确认两件事:系统版本和虚拟化设置。Windows 11的64位专业版、企业版、教育版(Windows 10也类似)都行,但家庭版可能有些限制。另外必须保证BIOS里开启了虚拟化。

打开任务管理器,切到“性能”标签页,看右下角“虚拟化”是不是显示“已启用”。如果显示“已禁用”,需要重启进BIOS,找到Intel VT-x或AMD-V的选项,改成Enabled,保存重启。不做这步,Docker Desktop会启动失败,报错信息里常见的就是“Virtualization support not detected”或“Docker Desktop failed to start because virtualization support wasn't detected”。

确认虚拟化没问题后,去Docker官网下载Docker Desktop for Windows,双击安装包。安装时有个复选框问你要不要用WSL 2,建议勾上。WSL 2比之前的Hyper-V方案更稳定,性能也更好,而且能在Windows里跑Linux子系统,对后端开发的人来说本身就值得装。

装完之后重启电脑,再打开Docker Desktop,等右下角的小鲸鱼图标变成稳定的运行状态。在命令行里输入:

docker --version docker compose version

两个命令都能正常输出版本号,说明安装成功。如果你之前没装WSL 2,Docker Desktop可能会提示你先安装内核更新包,按提示下载安装就行,这个步骤官方文档写得很清楚,照着做就好。

2.2 CentOS与Ubuntu服务器安装Docker

服务器上用Docker一般是CentOS或Ubuntu,安装方式略有差异,我分开说。

CentOS 7的系统,安装命令是:

sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl start docker sudo systemctl enable docker

Ubuntu 22.04的系统,安装命令是:

sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 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 sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

装完之后验证一下:

docker --version sudo systemctl status docker

如果显示active (running),那就没问题。另外顺手把当前用户加到docker组,这样就不用每次敲命令都加sudo:

sudo usermod -aG docker $USER

这里要注意:改完用户组之后,要重新登录或者执行newgrp docker才会生效。我之前在这块吃过亏,执行完usermod直接敲docker命令,还是报权限错误,以为是哪一步搞错了,结果就是没重新登录。

2.3 Docker Compose独立安装方法

在较新版本的Docker中,Compose已经集成到Docker CLI里了,就是docker compose命令(注意是子命令,中间没横杠)。上面Ubuntu安装的时候我已经装好了docker-compose-plugin这个包。但如果你用云主机提供的旧镜像,或者某些发行版的Docker版本比较老,可能需要单独装Compose。

历史版本的做法是下载一个二进制文件:

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose docker-compose --version

注意新版Docker Compose的推荐用法是带空格的docker compose version,而老版本是通过docker-compose(带横杠)调用的。这两个用法目前在市面上都能见到,很多老教程还在用第二种。我不建议你在新环境再单独装docker-compose了,直接用Docker自带的插件就好,少一个二进制文件就少一个维护负担。

3. Docker核心操作与必备命令解析

3.1 镜像与容器的常用命令

安装完成之后,先把最常用的命令走一遍。镜像(Image)是静态的模板,容器(Container)是镜像运行时的实例。可以把镜像理解成程序安装包,容器就是运行起来的进程。

拉取镜像:

docker pull nginx:latest

nginx:latest是“镜像名:标签”,标签相当于版本号。日常我建议尽量用具体版本号,比如nginx:1.25.3,不要图省事用latest。不然哪天镜像仓库里latest更新了,某次pull之后环境就变了,排查问题的时候很难发现是这个原因。

查看本地镜像:

docker images

运行容器:

docker run -d --name my-nginx -p 8080:80 nginx

这条命令的参数逐个解释:-d是后台运行,--name给容器起个名字方便管理,-p 8080:80把宿主机的8080端口映射到容器内的80端口。跑完之后浏览器访问http://服务器IP:8080就能看到Nginx的欢迎页。

查看运行中的容器:

docker ps

想看包括已停止的全部容器,加-a参数。停止和删除容器:

docker stop my-nginx docker rm my-nginx

进到容器里调试:

docker exec -it my-nginx bash

进入之后可以执行命令,就像SSH进了一台机器。-it表示用交互模式打开终端。操作完输入exit退出。

3.2 数据持久化与目录挂载原理

刚接触Docker的人很容易犯一个错误:容器一删,数据全没了。原因很简单,容器默认是临时存储,删除容器之后写入的文件跟着消失。解决的办法是挂载卷。

看一个实际的例子。假设你跑的是MySQL,数据库文件存在容器里,哪天容器崩溃或者你误删了容器,数据就全丢了。所以必须把数据目录挂载到宿主机上。运行MySQL 8.0的命令通常长这样:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=your_password \ -v /data/mysql:/var/lib/mysql \ mysql:8.0

-v /data/mysql:/var/lib/mysql的意思是把宿主机的/data/mysql目录映射到容器内的/var/lib/mysql目录。MySQL写数据的时候实际上写到宿主机上了,以后即使容器删掉,数据还在。

这里补一个常见坑:挂载目录的权限问题。MySQL容器内部是以mysql用户运行的,如果你宿主机上/data/mysql目录的属主和权限不对,容器会启动失败,日志里报权限不足。遇到这种情况,把目录权限放宽一点:

sudo chown -R 999:999 /data/mysql

或者干脆赋予当前用户权限。这个问题的本质是容器内用户的UID和宿主机目录属主不匹配,我在部署多个数据库项目时都踩过同样的坑,所以先写出来帮你绕开。

3.3 Dockerfile是自定义镜像的入口

官方仓库里有现成的镜像模板能覆盖80%的场景。但有时你需要定制化:比如拉一个Python镜像,再装几个pip依赖包进去。这就需要自己写镜像。

我举个最常用的例子。用Docker部署一个Python Flask应用,项目目录下有app.pyrequirements.txt,写一个Dockerfile:

FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . EXPOSE 5000 CMD ["python", "app.py"]

然后构建并运行:

docker build -t my-flask-app . docker run -d -p 5000:5000 my-flask-app

Dockerfile的每条指令都有讲究。FROM指定基础镜像,WORKDIR设定工作目录,COPY把本机文件复制到镜像里,RUN在构建时执行命令,CMD指定容器启动时执行的命令。注意CMD只能有一个,如果写了多个只有最后一个生效。

实际生产中我建议多利用镜像的缓存机制。Docker构建时的缓存逻辑是:如果某一行指令没变化,这一层就会复用缓存。所以要把不常变的指令放前面,比如COPY requirements.txtRUN pip install放在代码之前,这样改代码重新构建时不会每次重新装一遍依赖,速度能快不少。

4. Docker Compose实战部署完整流程

4.1 编写docker-compose.yml文件的规范

现在进入重头戏:Compose部署。前面说过,多容器服务用docker run逐个启动太低效了,Compose用一个YAML文件搞定所有服务定义。

先看一个典型场景:部署一个完整的Web应用,包含Nginx反向代理、MySQL数据库、Redis缓存。项目目录下新建docker-compose.yml

version: '3.8' services: nginx: image: nginx:1.25.3 ports: - "80:80" - "443:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./nginx/logs:/var/log/nginx networks: - app-network depends_on: - web web: image: nginx:1.25.3 expose: - "8080" volumes: - ./html:/usr/share/nginx/html networks: - app-network mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: app_db MYSQL_USER: app_user MYSQL_PASSWORD: app_password ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql networks: - app-network redis: image: redis:7.2-alpine ports: - "6379:6379" volumes: - redis_data:/data networks: - app-network volumes: mysql_data: redis_data: networks: app-network:

这个配置文件看着长,拆开理解并不复杂:

  • services下面定义了4个服务,每个服务的配置项有镜像、端口、挂载卷、环境变量、网络。
  • ports把宿主机端口映射到容器端口,expose只声明容器内的端口给同一网络的其他容器访问,不暴露到宿主机。
  • volumes分为两种:短语法./html:/usr/share/nginx/html是绑定挂载(bind mount),把宿主机当前目录下的目录直接映射到容器里;命名卷mysql_data:/var/lib/mysql是把数据存到Docker管理的卷中,执行docker volume ls可以看到。
  • networks定义了所有服务共用的网络。Compose会自动为同一个文件中的服务创建一个默认网络,所有服务默认都在这个网络里。我在配置中显式声明了网络,是为了更清晰地区分和后续扩展。

4.2 用Compose启动整套环境的完整步骤

配置文件写好后,部署就很简单了。首次启动:

docker compose up -d

-d参数表示后台运行。第一次执行会拉取所有镜像,时间取决于网络情况,耐心等就行。看到Started的提示说明启动成功。

查看所有服务的状态:

docker compose ps

查看日志(特别是启动失败时排查很有用):

docker compose logs -f

-f表示持续跟踪日志输出,退出时按Ctrl+C即可。

如果修改了配置文件,想让改动生效:

docker compose up -d

等等,这个命令有个细节要说清楚。如果你只是改了镜像版本或者端口映射,第二个up命令会自动重建有变化的容器。这个“检测变化并重建”的机制非常方便,工作流就变成了:改配置文件,重新up,完事。

停止服务但保留容器和卷:

docker compose stop

停止并删除容器和网络(但保留命名卷):

docker compose down

彻底删除所有内容(包括命名卷,数据会丢,慎用):

docker compose down -v

4.3 搭建MySQL 8.0容器的关键配置

热词里有个“docker安装mysql8.0并使用”,这个场景非常典型,我单独拿出来讲详细一点。MySQL容器启动时有几个初始化的选项,这是平时部署中最好利用好、也最容易踩坑的地方。

基础配置:

mysql: image: mysql:8.0 container_name: mysql8 restart: always environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: testdb MYSQL_USER: testuser MYSQL_PASSWORD: testpass ports: - "3306:3306" volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf - ./mysql/init:/docker-entrypoint-initdb.d command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

几个关键点展开说明:

第一,MYSQL_DATABASEMYSQL_USERMYSQL_PASSWORD三个环境变量组合使用,容器首次启动时会自动创建对应的数据库和账号,权限也配好。这比启动后手动建库建用户方便得多。但注意:这个初始化只会在数据目录为空时执行一次。如果你已经挂载过带数据的目录,再改这三个参数是不生效的。

第二,/docker-entrypoint-initdb.d这个目录很特别。目录下的.sh.sql.sql.gz文件,在首次启动构建数据目录时会被按文件名顺序执行。所以要做表结构初始化,把SQL文件丢到sudo创建的这个目录就好。我通常会把热词里的“初始化建表脚本”放在这个目录,容器第一次启动就自动建表,非常省事。

第三,command参数里可以追加MySQL服务端的启动参数。括号里声明字符集为utf8mb4,加上对应的排序规则,是为了避免表里的中文乱码。现在新项目基本都建议用utf8mb4,可以完整支持emoji和一些特殊字符。

第四,restart: always表示容器异常退出后会自动重启。生产环境一定要加,否则机器重启后MySQL容器起不来,服务就挂了。这是很多人容易忽略的。

5. 核心服务实战:Redis、Nginx与更多部署场景

5.1 Redis生产环境Compose部署与配置

Redis的场景在系统里也出现了,而且提到了“生产环境部署”和“主从”,这两个都值得展开聊聊。

如果你是单机Redis,Compose配置可以很精简:

redis: image: redis:7.2-alpine container_name: redis restart: always ports: - "6379:6379" volumes: - ./redis/data:/data - ./redis/redis.conf:/usr/local/etc/redis/redis.conf command: redis-server /usr/local/etc/redis/redis.conf environment: - TZ=Asia/Shanghai

这里把自定义的redis.conf挂载进容器,并用command指定以这个配置启动。生产环境里Redis的配置有几个不能省:持久化(RDB或AOF)、密码认证、最大内存限制。配置文件中至少要有:

appendonly yes requirepass your_redis_password maxmemory 512mb maxmemory-policy allkeys-lru

appendonly yes开启AOF持久化,requirepass设置密码,maxmemory限制最大内存防止OOM,maxmemory-policy allkeys-lru指定内存满了之后的淘汰策略。

再说Redis主从复制。三个实例的Compose配置:

services: redis-master: image: redis:7.2-alpine container_name: redis-master ports: - "6379:6379" volumes: - ./redis/master-data:/data command: redis-server --appendonly yes --requirepass masterpass redis-slave1: image: redis:7.2-alpine container_name: redis-slave1 ports: - "6380:6379" volumes: - ./redis/slave1-data:/data command: redis-server --appendonly yes --requirepass slavepass --replicaof redis-master 6379 --masterauth masterpass redis-slave2: image: redis:7.2-alpine container_name: redis-slave2 ports: - "6381:6379" volumes: - ./redis/slave2-data:/data command: redis-server --appendonly yes --requirepass slavepass --replicaof redis-master 6379 --masterauth masterpass

关键参数是--replicaof redis-master 6379,它告诉从库要跟着哪个主库同步。这里直接用了服务名redis-master作为主机名,因为Compose的网络内服务名就是可用的DNS名称,这也是Compose比多个docker run更优雅的原因之一——容器之间可以直接通过服务名互访。

--masterauth masterpass是从库连主库时的认证密码。如果主库配置了requirepass,从库必须配置这一项,否则主从复制会失败,日志里会报MASTER aborted replication with an error

实测下来,这套配置在同一台机器上布三个Redis实例没有任何问题。生产环境建议把从库分布到不同物理机上,不过那就需要把redis-slave拆到别的docker-compose.yml里,再用external网络连接,这个属于进阶玩法了,有兴趣的可以自己去探索。

5.2 用Docker快速搭建本地开发环境

日常开发中最爽的场景,是用Compose一键拉起一堆中间件。比如你要在本地联调一个后端系统,需要MySQL、Redis、RabbitMQ、Nginx,以前是各种下载安装包、起服务、配密码,现在就是一个docker-compose.yml的事。

我自己的开发环境配置文件大概长这样:

version: '3.8' services: mysql: image: mysql:8.0 ports: - "3306:3306" environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: dev_db volumes: - mysql_data:/var/lib/mysql redis: image: redis:7.2-alpine ports: - "6379:6379" command: redis-server --appendonly yes rabbitmq: image: rabbitmq:3.13-management-alpine ports: - "5672:5672" - "15672:15672" environment: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest volumes: - rabbitmq_data:/var/lib/rabbitmq volumes: mysql_data: rabbitmq_data:

RabbitMQ的镜像有两个版本:不带-management的只有服务本身,带-management的会额外开放15672端口提供管理后台。开发环境直接选带管理后台的,浏览器访问http://localhost:15672就能看到消息队列的可视化界面,排查消息堆积、队列绑定关系都很方便。

这个配置文件放在本机任何项目目录里都行,只要保证端口不冲突就可以。每个项目或者每类环境场景建独立的目录,比如~/docker-env/dev~/docker-env/test,用的时候,cd到对应目录下执行docker compose up -d,用完docker compose stop。我目前的工作方式就是这样一个目录一个环境,干净利落,换电脑也不怕。

5.3 在Docker中部署映射数据与端口的管理技巧

实际部署过程中,端口冲突是最常见的问题之一。你启动MySQL容器提示Error starting userland proxy: listen tcp4 0.0.0.0:3306: bind: address already in use,多半是宿主机已经有程序占用3306了。

排查方式:

sudo netstat -tlnp | grep 3306

如果确实是本机装了MySQL占了端口,要么把原来的服务停掉,要么把容器的映射端口改掉,比如-p 3307:3306。我通常建议映射端口改掉,没必要和原来的服务抢。

另一个重要技巧是数据备份。容器跑在生产环境,养成定时备份的习惯很重要。MySQL的容器备份方式跟直接装MySQL不完全一样,需要通过docker exec在容器内执行mysqldump:

docker exec mysql8 sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases' > backup_$(date +%Y%m%d).sql

然后配合crontab定时任务,就能实现自动化备份。这个技巧的关键在于理解:容器内运行的程序和宿主机是隔离的,执行命令时如果用到容器的环境变量,用sh -c来展开。如果你需要容器内的工具和宿主机交互,都要沿着这个思路走。

对于运行中的容器,还可以用docker cp把文件复制出来:

docker cp mysql8:/var/lib/mysql/backup.sql ./backup.sql

我个人的习惯是:宿主机上用定时脚本,将每天凌晨的备份文件同步到另一台机器或者对象存储。数据这东西,平时用不上,一旦出问题就是救命稻草,多做几层备份永远不亏。

6. 实操过程中的坑与经验总结

6.1 启动失败排查与权限问题处理

部署过程中,容器启动失败的场景经常遇到。我整理了一套排查方法,按照这个顺序走,大部分问题都能定位到。

第一步,看日志。先docker compose logs 服务名,容器启动时打印的所有错误信息都在这里。比如端口冲突、配置文件语法错误、挂载目录不存在,日志里基本都有明确提示。

第二步,确认镜像是否存在以及标签是否正确。如果是自己构建的镜像,确认docker images能看得到。如果是远程仓库的镜像,确认标签没有拼错。latest标签下可能也有缓存的旧版本,建议先docker pull一下刷新。

第三步,排查权限。日志里看到Permission denied,基本就是挂载目录权限问题。把宿主机目录权限调大,或者让它和容器内用户的UID对应上。前面提到过MySQL需要uid 999,Redis容器内的默认用户uid是999还是别的数字,不同镜像不一样,最快的方式是看日志报什么,或者直接docker exec -it 容器名 id查看容器内用户的uid。

第四步,确认依赖服务就绪顺序。如果一个服务依赖另一个服务的数据库,比如Web应用依赖MySQL,即使配置了depends_on,MySQL容器启动了不代表MySQL已经可以接受连接了。现实情况是:MySQL容器从启动到完全就绪可能有几秒到几十秒的间隔,Web应用在这期间连接数据库会报错。

解决这个等待问题有几种方案:在Web应用里做重试逻辑、用专门的wait-for-it脚本、或者用depends_oncondition: service_healthy加上健康检查。我推荐最后一种,因为最优雅。Compose配置里可以这样写:

services: mysql: image: mysql:8.0 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 web: depends_on: mysql: condition: service_healthy

健康检查通过后,MySQL容器会被标记为healthy,Web服务才启动。这套机制在部署依赖数据库的复杂应用时几乎必备,否则服务起来得碰运气。

6.2 Windows下Docker Desktop启动失败的修复方法

Windows的Docker Desktop新手用户经常遇到“Docker Desktop failed to start because virtualization support wasn't detected”或者“Virtualization support not detected”这类报错。这个问题的主要原因就两个:BIOS里没开虚拟化,或者WSL 2内核版本太旧。

踩过的坑我总结成下面几步,按顺序试:

第一,确认BIOS虚拟化已开启。重启电脑,进入BIOS(一般是开机按Del或F2),找到“Intel Virtualization Technology”或“SVM Mode”(AMD平台),设为Enabled,保存退出。进系统之后到任务管理器里看看虚拟化那一栏是不是“已启用”。

第二,启用来Windows功能里的“虚拟机平台”和“适用于Linux的Windows子系统”。在“控制面板-程序-启用或关闭Windows功能”里勾选这两项,点击确定,重启系统。

第三,更新WSL 2内核。打开PowerShell(管理员模式),执行:

wsl --update wsl --set-default-version 2

第四,重置Docker Desktop。在设置里找到“Troubleshoot”,执行“Reset to factory defaults”。这个操作会清空已有的容器和镜像,慎重执行,但解决启动问题的成功率确实高。

最后还不行的话,卸载Docker Desktop重装最新版本。系统都愿意装最新补丁的话,这个问题的概率会低很多。Windows这块,我一直建议有条件的话直接用WSL 2的模式跑Docker,比传统Hyper-V模式稳当,启动速度也快。

6.3 网络与镜像下载加速配置

在国内环境用Docker,一个非常现实的问题是镜像拉取速度慢。官方仓库Docker Hub的访问速度时好时坏,大镜像经常卡到怀疑人生。

解决方式之一是配置镜像加速器。不同的Docker Desktop或Linux的Docker配置方式略有不同。Linux平台,编辑/etc/docker/daemon.json

{ "registry-mirrors": ["https://docker.m.daocloud.io"] }

改完重启Docker服务:

sudo systemctl restart docker

之后docker pull就会优先走这个镜像加速地址。注意:加速器只对Docker Hub的镜像生效,如果你拉的是自建私有仓库的镜像,配置了也不会有影响。

还有一个实用的调试方法:拉镜像太慢时,先用docker pull试试,如果确实不行,检查一下是不是DNS解析问题。可以手动指定DNS:

sudo cat > /etc/docker/daemon.json <<EOF { "dns": ["8.8.8.8", "114.114.114.114"] } EOF sudo systemctl restart docker

这个操作在许多云主机上很有效,因为有些机器的默认DNS解析Docker仓库域名时不够稳定。我用过的方案里,最快的还是找可用的镜像加速地址,这对提升部署效率太关键了。

6.4 常用部署场景速查表

把前面提到的内容整理成一个速查表,方便读者在需要的时候快速找到对应的配置参考。

场景关键配置常见问题
MySQL 8.0environment设置root密码、数据目录挂载首次启动后改密码不生效、中文乱码
Redisappendonly yes、requirepass认证主从认证失败、容器重启丢数据
RabbitMQ选management标签、映射5672和15672端口管理后台打不开
Nginx静态站html目录挂载、容器监听80端口被占用
Python应用写Dockerfile、install依赖镜像缓存利用依赖装太慢
多服务互相调用用服务名而非IP地址、自定义network容器间网络不通

这个表只是最常用的场景,实际生产环境千变万化,核心原理都是通用的:认准镜像标签、配好环境变量、挂载好数据目录、声明好端口和网络、加restart策略。把这五个维度想清楚,任何服务都能顺畅地在Docker里部署起来。

7. 大模型本地部署与Docker扩展应用

7.1 Ollama本地部署大语言模型

热词里出现了不少大模型本地部署的词,比如Ollama本地部署、DeepSeek部署、大模型本地部署。这些场景现在很火,而且跟Docker结合得也非常紧密。这里我特意加一节,因为Ollama+Docker这套方案是我目前实际使用中体验最好的模型管理方式。

Ollama是一个可以本地跑大语言模型的工具,官方直接提供了Docker镜像:

docker run -d \ --name ollama \ -p 11434:11434 \ -v ollama_models:/root/.ollama \ ollama/ollama:latest

装完之后拉取模型:

docker exec ollama ollama pull deepseek-r1:7b docker exec ollama ollama run deepseek-r1:7b

这么做的好处是模型文件全部存在Docker的命名卷里,以后想换机器迁移,直接把卷内容复制走就行,不需要重新下几个G的模型文件。我实测拉取7B规模的对话模型,配合自己的显卡跑,推理速度完全可用,日常文本处理、代码问答都没问题。

给打算部署大模型的读者提个醒:Ollama容器默认只监听本机11434端口,如果你要开放给局域网用,记得在docker run里加--network host或者手工映射0.0.0.0:11434:11434。另外,模型下载非常耗流量,几个G到几十个G不等,建议先确认自己机器的磁盘剩余空间,否则拉到一半磁盘满了会非常尴尬。

7.2 用Compose管理AI相关服务

如果你要在服务器上部署一个完整的AI应用,比如Dify(一个开源的大模型应用平台,热词里也提到了),用Docker Compose部署的效率明显高于手工一步步安装。

Dify官方提供了docker-compose.yml,包含后端API、前端、PostgreSQL、Redis、向量数据库等七八个服务。部署流程非常简单:

git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d

整个部署过程只需要这几步。等所有服务状态为running之后,浏览器访问http://服务器IP就能看到Dify的界面。这种复杂的多服务应用,用传统方式在服务器上手动部署,一天都未必能搞定,Docker Compose把周期压缩到了几十分钟。

在用Compose部署这类大型应用时,我建议先修改.env文件里的数据库密码、密钥等敏感信息,不要用仓库里默认的值。另外注意服务器配置,Dify包含向量数据库等资源消耗大户,2核4G的配置只能勉强跑起来,体验流畅至少要4核8G起。

7.3 部署过程中Lock资源的表现

实际在多服务部署时,CPU和内存规划也很重要。我一台4核8G的云服务器上同时跑MySQL、Redis、Nginx和一个Java应用,每个容器给多少资源需要有数。Compose配置里也能限制:

services: web: image: myapp:latest deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '0.25' memory: 500M

limits是上限,reservations是预留值。合理的限制能防止某个服务把服务器资源吃光导致其他服务崩掉。有一说一,资源规划这事在原生的单机Compose模式下只能做到限制,做不了跨机器的自动调度。容器数量多了、服务复杂了,还是得上Kubernetes或Docker Swarm,那是另一个话题了。

8. 实际部署的心得与后记

8.1 生产环境使用Docker的建议清单

把这段时间积累的经验归纳成几条建议,每一条都是踩坑换来的。

第一,镜像版本必须锁定。无论是nginx:1.25.3还是mysql:8.0,在Compose文件里写具体的版本号,不要用latest。生产环境最怕的就是“昨天还好好的,今天忽然不行了”,这种情况最常见的元凶就是latest标签对应的镜像偷偷更新了。

第二,数据目录全部挂载。容器本身是临时的,数据必须绑在宿主机或Docker卷上。参数、配置、日志也需要挂载,不然排查问题的时候容器一删日志也没了。

第三,配置restart: always或者合适的重启策略。服务器重启后自动拉起所有服务,这是生产系统的基本要求。不加restart策略,机器一重启服务全部failed,如果有监控报警还好,没有的话客户那边就要炸锅了。

第四,预留健康检查。重要的服务都加上healthcheck配置。有了健康状态,你才能在监控面板里一目了然地知道系统是否健康,也能让Compose正确处理依赖顺序。

第五,网络和端口规划要有全局观念。在同一个Compose文件里用内网互通,对外只暴露必用的端口。数据库、Redis这些内部组件的端口不要映射到宿主机公网IP上,否则等于把门打开给攻击者,安全风险极高。

8.2 这个部署方案后续如何继续扩展

Docker Compose解决的是单机上多容器的编排问题,它做得很出色,但在某些场景下也会有瓶颈。比如一台机器资源不够了,要横向扩容到多台机器,或者要实现自动伸缩,Compose就不够用了。这时候得往两个方向进化:Kubernetes(K8s)和Docker Swarm。

K8s是目前的主流选择,它不仅有Compose类似的编排能力,还有自动扩容、滚动更新、故障自愈等特性。Docker Swarm的优势是轻量,完全兼容Compose文件,学习成本低,如果只是想要简单的多机编排和基本的服务发现,Swarm也够用。

从一个普通的Docker用户走到这一步,路径可以理解为:单机用Docker命令,多服务单机用Docker Compose,多设备集群用K8s或Swarm。每一步都是顺着需求自然演化出来的,不用一开始就上最强的方案。

我自己从装好Docker到成为日常部署首选,大概只花了一周时间;从只会docker run到熟练用Compose管理各种中间件,又花了两周。等哪天部署新服务已经不用再百度和翻文档了,说明这套能力已经真正到你手里了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询