ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Docker零基础实战:从安装配置到MySQL与Redis部署全攻略

Docker零基础实战:从安装配置到MySQL与Redis部署全攻略 想学Docker的零基础用户最常卡住的地方不是“不知道Docker是什么”而是“看完一堆概念依然不知道第一行命令该敲什么”。这篇博客就是给你一条可以直接照着走的通关路线从安装、配对镜像源到第一个容器跑起来再到完成MySQL部署和Redis主从实战最后把新手最容易踩的报错整理成自查手册。概念我只会讲够用的部分重点放在实操你在自己电脑上跟着敲一遍就能完成一次完整的Docker入门闭环。如果你能拿出一台Windows电脑或者Linux服务器按照下面的顺序把每一步都走一遍我基本可以保证你会比大多数只看了几篇教程的人更理解Docker到底在解决什么问题。1. 开场先搞明白Docker到底是什么1.1 镜像、容器、仓库三个词就能建立核心认知很多教程一上来就讲虚拟化、命名空间、CGroup、联合文件系统零基础的人当场就被劝退了。其实对初学者来说你只需要先牢牢记住这三个词镜像、容器、仓库。镜像可以理解成“一份只读的打包模板”它把软件运行所需的一切——操作系统底层库、运行时环境、配置文件、代码——全部打进一个包里。容器则是这个模板运行起来之后的一个实例你可以同时从同一个镜像启动多个容器它们之间互不影响。仓库就是存放镜像的地方最出名的就是Docker Hub相当于一个“应用市场”你需要什么软件直接从这里下载对应镜像。我见过一个很适合零基础的类比镜像是一张菜谱容器是按照菜谱做出来的一盘菜仓库是摆满菜谱的书架。同一张菜谱你可以反复做出一模一样的菜不管换哪个厨房做出来口味都相同。这就是Docker最核心的价值——让软件在任意环境里都表现得一模一样。1.2 Docker到底解决了什么问题在没有Docker之前最折磨人的问题是什么是环境不一致。你在自己电脑上开发得好好的代码推到服务器上就报错你用的是CentOS同事用的是Ubuntu同一个安装步骤在两边结果完全不一样你想测试两个版本的MySQL光卸载重装就能折腾一个下午。Docker把这些复杂的安装、配置过程全部封装进镜像里。别人已经做好了一个带MySQL的镜像你拉下来就能直接跑起来不需要关心它底层依赖了什么库、安装路径在哪、配置文件该怎么改。这就是容器化最大的价值让“能跑”变成一种默认状态。1.3 零基础最容易混淆的几个概念先把一些容易绕晕的对比讲清楚这会让你少走很多弯路。容器不是虚拟机。虚拟机是在一台物理机上模拟出多台完整电脑每一台都有独立操作系统资源占用非常重启动要论分钟算。容器则共享宿主机内核没有独立操作系统只打包了应用程序和它需要的依赖启动速度是秒级的资源开销小得多。你可以把虚拟机理解成租了一个独立的单间把容器理解成合租房里隔出来的工位共用水电、共用厨房但彼此生活习惯互不影响。Docker Compose也不是Kubernetes。Compose是用来管理单台机器上多个容器的编排工具适用于本地开发或中小规模部署文件写好后一条命令就能把数据库、后端、前端全部拉起来。Kubernetes是用于跨多台服务器大规模管理容器的系统零基础阶段可以完全不用碰本指南也不涉及。2. 安装DockerWindows和Linux两条主流路线2.1 Windows安装Docker DesktopWindows上最推荐的方式就是装Docker Desktop它自带图形界面安装完以后点开就能用对新人非常友好。安装之前你要先确认两件事。第一电脑的虚拟化功能必须在BIOS里开启。打开任务管理器切到“性能”标签看右下角有没有“虚拟化已启用”。如果显示“已禁用”需要重启电脑进BIOS在CPU相关设置里找到Intel VT-x或AMD-V把它设为Enabled。很多Windows用户卡在Docker Desktop起不来十有八九就是这一步没做好。第二Docker Desktop推荐使用WSL2作为后端这是Windows上运行Docker引擎的核心组件。如果系统是Win 10 2004以上版本或者Win 11在管理员PowerShell里执行wsl --install装完以后重启系统即可。然后去Docker官网下载Docker Desktop安装包双击安装一路Next。安装过程中会提示是否启用WSL2集成保持默认勾选就行。安装完成后启动Docker Desktop托盘区域会出现小鲸鱼图标第一次启动会比较慢因为它要初始化Linux子系统耐心等一两分钟。等图标上不再转圈打开命令行执行docker version如果能看到Client和Server两部分信息说明Docker引擎已经正常工作了。需要特别提醒一点装完之后第一次拉镜像非常容易超时这不是软件坏掉了而是因为默认镜像仓库在境外网络不稳是正常的。你先不用急着解决这个下一章我会专门讲镜像加速。2.2 Linux安装DockerLinux下安装方式比Windows简单得多。以Ubuntu为例直接用系统自带的包管理器就能安装sudo apt update sudo apt install docker.io sudo systemctl enable --now dockerCentOS系统则对应执行sudo yum install -y docker sudo systemctl enable --now docker如果你想要官方维护的最新版本Docker Engine可以让包管理器去官方源安装但国内执行起来网络状况不确定零基础阶段直接用发行版自带的docker.io包完全够用它和官方版本在基本的容器运行上没有区别。有一点值得说一说在国产化环境里比如龙芯这类自主指令集平台yum或apt仓库里往往已经有适配好的Docker版本直接用系统源安装是最省事也最稳妥的方式不建议自己去下载通用版装因为架构不匹配很容易装上了也跑不起来。装完之后同样先验证一下sudo systemctl status docker docker -vLinux上还有一个经典坑普通用户执行docker ps会报permission denied。这是因为Docker的socket文件只对root用户和docker组开放。解决办法是把当前用户加入docker组sudo usermod -aG docker $USER然后重新登录一次普通用户就能直接使用docker命令了。这里多说一句如果你是在公司内网或离线环境安装Docker最稳妥的方式是下载对应发行版的deb或rpm包用dpkg -i或rpm -ivh手动安装安装包依赖不全时再用apt --fix-broken install或者yum install -y补齐。Docker本身对硬件要求不高但依赖的iptables、bridge-utils这些内核相关组件不能缺。2.3 安装后第一件事跑通hello-world不管你用哪种方式装好了Docker都建议先敲下面这条命令docker run hello-world这条命令会做三件事检查本地有没有hello-world镜像没有就去仓库下载然后启动一个容器执行镜像里的输出逻辑。如果你看到一大段“Hello from Docker!”的提示说明整个链条已经通了。我特别建议零基础的人认真读一下hello-world容器打印的这段英文说明它实际上是官方写给你的一次完整流程演示本地没找到镜像就自动去拉取然后创建容器、启动容器、运行任务、容器退出。你只需要运行一条命令Docker就把这些步骤全部自动处理了这就是这个工具的魅力所在。3. 镜像下载太慢五步搞定镜像加速源3.1 为什么拉镜像总是卡住拉镜像慢是绝大多数中国Docker新手碰到的第一个真正的痛点。原因很简单Docker镜像默认从Docker Hub拉取而Docker Hub的服务节点主要在境外公共网络下跨海传输速度非常不稳定尤其是一些体积动辄几百MB甚至几个GB的基础镜像拉一半超时然后重来体验极其糟糕。解决方案就是配置镜像加速器也叫镜像源。它本质上是一个在境内缓存了大量Docker Hub镜像的代理服务你拉镜像时从加速器上拿路径短了速度自然就上去了。3.2 Docker Desktop中配置镜像源Windows上配置镜像源很简单打开Docker Desktop点击右上角设置齿轮左侧选“Docker Engine”你会看到一个JSON格式的配置文件把镜像加速地址加进去{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] }填好以后点“Apply Restart”Docker Desktop会用新配置自动重启。等你重启完成执行docker info在输出里找到“Registry Mirrors”这一行能看到刚刚填的地址就说明配置生效了。这里要提醒一句公共镜像加速地址会不定期变动今天能用不代表三个月以后还能用。这也是我建议大家多配置几个地址的原因一个失效了还有备用的。配置完如果拉镜像依然超时可以先试试ping一下加速地址通不通或者换一组新的地址。3.3 Linux系统配置daemon.jsonLinux下配置方法也很直接。Docker引擎启动时读的是/etc/docker/daemon.json这个文件如果它不存在你手动创建一个就行sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker配置文件写错一个标点符号Docker服务都起不来。改完文件之后如果执行systemctl restart docker报错先执行sudo dockerd --validate验证一下配置格式或者用journalctl -u docker -n 100看日志。这是新手最容易忽略的一个细节。注意一点镜像加速只对拉取公共镜像有加速效果。如果你后续在公司内网部署需要拉取私有仓库里的镜像那就不是配置registry-mirrors的问题了而是要在daemon.json里配置insecure-registries或者带有证书认证的仓库地址。4. 常用命令通关从拉镜像到管理容器4.1 镜像管理命令镜像相关的命令零基础先掌握这几条就够了。docker pull用来拉取镜像。写完整格式是docker pull 仓库地址/命名空间/镜像名:标签默认会从Docker Hub拉取默认标签是latest。比如拉一个MySQL 8.0docker pull mysql:8.0docker images列出本机所有镜像你能看到镜像名、标签、镜像ID、创建时间和大小。docker rmi用来删除镜像删的时候注意要先停掉正在使用这个镜像的容器。docker tag给镜像打标签比如你后面想自己构建镜像、上传到自己的仓库这一步就会用到docker tag nginx:latest my-registry.com/ops/nginx:v14.2 容器生命周期命令容器的命令要区分“创建时”和“运行后”两个阶段。启动容器的核心命令是docker run最常用的参数要记熟-d表示后台运行--name给容器起名字-p做端口映射-v做数据目录挂载-e注入环境变量--restart always设置容器意外退出或机器重启后自动拉起。当时我教别人看-p 80:8080这个参数时很多人分不清前后关系这里统一说明一下冒号左边是宿主机端口冒号右边是容器内部端口。外部访问走80端口数据进到容器后被转发到8080端口。你可以把容器理解成一间公寓你住在808房间楼下门卫是80号窗口外人只需要跟80号窗口沟通就行。查看正在运行的容器用docker ps想连已经退出的容器也一起看用docker ps -a。容器的启停管理对应三条命令docker stop 容器名 docker start 容器名 docker restart 容器名删除容器用docker rm 容器名删除一个正在运行的容器需要先停掉它或者直接docker rm -f强制删除。批量删除所有已退出的容器可以执行docker rm $(docker ps -aq)这条命令在清理环境时非常实用。4.3 日常运维三件套日志、进容器、拷文件容器跑起来之后你一定会遇到的三个场景是看日志、进容器内部、拷文件。日志查看用docker logs 容器名最常用的是-f参数表示持续跟踪输出效果类似Linux下的tail -f排查问题的时候会一直开着。加上--tail 100可以只看最近100行docker logs -f --tail 100 容器名进入运行中的容器内部用docker exec -it 容器名 bash。有些容器里没有bash比如很多基于Alpine的镜像就改成docker exec -it 容器名 sh。进入容器后你就是在一个精简版Linux环境里可以检查进程、看配置、执行命令。退出时输入exit即可。宿主机和容器之间拷贝文件的命令是docker cp语法很简单docker cp 宿主机文件路径 容器名:/容器内路径 docker cp 容器名:/容器内路径 宿主机文件路径4.4 常用命令速查表我整理了一个零基础阶段高频使用的命令表你贴在手边边练边查比死记硬背效率高得多命令作用常见参数docker pull 镜像名拉取镜像默认从Docker Hub拉取可指定标签docker images查看本地镜像列表无特别常用参数docker rmi 镜像名删除镜像删除前需保证没有容器在用docker run 镜像名创建并启动容器-d后台、-p端口、-v挂载、-e环境变量、--name命名docker ps查看运行中的容器-a查看全部、-q只显示IDdocker stop/start/restart停止/启动/重启容器后面跟容器名或IDdocker rm 容器名删除容器-f强制删除运行中的容器docker logs 容器名查看容器日志-f跟踪、--tail指定行数docker exec -it 容器名 bash进入容器内部没有bash时改用shdocker cp宿主机与容器之间拷贝文件路径在前的是源在后的是目标docker build用Dockerfile构建镜像-t指定镜像名和标签docker login登录镜像仓库默认登录Docker Hub命令这东西光看没有用一定要在终端里敲几遍形成肌肉记忆。后面几章我会结合实战项目来用这些命令零基础学完这一轮这些命令基本就不会忘了。5. 实战用Docker快速部署MySQL和Redis5.1 部署MySQL 8.0并完成数据目录挂载理论知识说了一堆不如直接上一个实战。零基础的第一站我推荐部署MySQL 8.0。先拉取镜像docker pull mysql:8.0然后创建容器。这里我先给一个完整命令再逐行拆讲docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ -e TZAsia/Shanghai \ -v /opt/mysql-data:/var/lib/mysql \ mysql:8.0-d让容器后台运行。--name mysql8给它起名之后管理这个容器只需要用mysql8这个名称不用记一长串容器ID。-p 3306:3306把宿主机3306端口映射到容器3306端口。-e MYSQL_ROOT_PASSWORD123456设置root账号的密码这是MySQL官方镜像要求必须提供的环境变量。-v /opt/mysql-data:/var/lib/mysql是这次部署里最关键的一步它把宿主机上的/opt/mysql-data目录挂载到容器内的MySQL数据存储目录。为什么挂载这么重要默认情况下容器内产生的数据会存在容器可写层里一旦你执行了docker rm -f mysql8把容器删掉这个容器里所有数据会跟着一起消失。挂载数据卷以后数据真正存放在宿主机目录中容器只是一个临时运行环境哪怕你删掉容器重新创建只要挂载的还是同一个宿主机目录数据就在那里。部署完成后先验证容器状态docker ps看到STATUS为Up就可以尝试连接MySQL了。进入容器内部连一下docker exec -it mysql8 mysql -uroot -p123456能进入mysql命令行就说明部署成功了。同时可以确认一下时区是否生效SELECT NOW();我看到很多人都曾在时区问题上栽过跟头因为官方镜像默认时区是UTC和你本地差8个小时所以我在创建容器时直接用-e TZAsia/Shanghai把时区提前设置好这是实战中一次搞定问题的方式。从宿主机外部连接时MySQL 8.0默认的认证插件是caching_sha2_password如果连接工具版本太老可能会报认证失败。这时候进到容器里改一下远程账号认证插件即可ALTER USER root% IDENTIFIED WITH mysql_native_password BY 123456; FLUSH PRIVILEGES;5.2 用Docker搭建Redis主从结构拉完关系型数据库接下来再来一个更轻量的分布式缓存Redis。这段实战会用到前面学的容器命名和端口映射同时你会第一次接触到容器之间怎么通信的问题。先拉取Redis镜像docker pull redis:7启动主节点。主节点上我额外开启了AOF持久化防止容器重启后内存中数据丢失docker run -d --name redis-master -p 6379:6379 redis:7 redis-server --appendonly yes启动从节点docker run -d --name redis-slave -p 6380:6379 redis:7 redis-server --slaveof 192.168.1.100 6379注意从节点的--slaveof参数后面跟的是主节点的宿主机IP不是localhost也不是127.0.0.1。因为容器有自己独立的网络命名空间你在从节点容器内部写localhost指向的是从节点容器自己而不是运行在宿主机6400端口上的主节点。验证主从同步是否正常执行docker exec -it redis-slave redis-cli info replication重点看这行role:slave如果是slave角色就说明配置生效了。同时master_link_status:up表示目前和主节点的连接是正常的。如果你想避免直接用宿主机IP这种不够优雅的方式还可以创建一个自定义网络让容器之间通过容器名直接通信docker network create redis-net docker run -d --name redis-master --network redis-net -p 6379:6379 redis:7 redis-server --appendonly yes docker run -d --name redis-slave --network redis-net -p 6380:6379 redis:7 redis-server --slaveof redis-master 6379这种方式的原理是自定义网络内置DNS解析容器之间可以直接通过容器名寻址。以后你部署多个互相依赖的服务用自定义网络都是比手工填IP更推荐的做法。这里补充一个我在实际生产环境里踩过的坑不要把Redis的--requirepass密码设置写在命令行里面用-e环境变量传官方镜像不支持这个环境变量Redis会直接忽略。正确做法是通过redis-cli CONFIG SET requirepass设置或者挂载自定义的redis.conf文件进去。这也是为什么使用官方镜像时最好先去它的文档页面看一眼支持哪些环境变量省得绕弯路。5.3 用Docker Compose编排多容器如果你已经跟着上面把MySQL和Redis都部署出来了你会发现每次创建容器都要敲一长串命令而且这些配置很容易忘记。当你的项目有多个服务时Docker Compose就该上场了。Compose的核心就是用一个YAML文件描述你要启动的所有服务之后执行一条命令全部搞定。我写一个最典型的组合一个MySQL加一个Nginx。创建一个目录并进入mkdir -p /opt/app cd /opt/app创建docker-compose.ymlversion: 3.8 services: mysql: image: mysql:8.0 container_name: app-mysql environment: MYSQL_ROOT_PASSWORD: 123456 TZ: Asia/Shanghai ports: - 3306:3306 volumes: - ./mysql-data:/var/lib/mysql restart: always web: image: nginx:1.25 container_name: app-web ports: - 8080:80 restart: always启动命令docker compose up -d第一次执行会先拉取两个镜像然后按顺序创建和启动容器。-d是后台运行。查看当前Compose管理的服务状态docker compose ps查看所有服务的实时日志docker compose logs -f停止并清理所有由Compose管理的容器docker compose down这里需要注意执行docker compose down不会删除Volume卷中的数据如果你在Compose文件里定义了volumes数据目录依然保留着这种设计是为了防止误删数据。想连数据一起清理的话使用docker compose down -v。经历过一次Compose之后你应该能直观感受到它的价值以前要写一长串命令去分别管理多个容器现在只需要一个YAML文件就能把整个应用栈编排起来。这也是后面你学Kubernetes时最舒服的知识铺垫因为两者使用的配置思想是一脉相承的。6. 零基础高频报错自查手册6.1 Windows虚拟化相关的两座大山对于Windows用户新手期最容易卡住的是Docker Desktop启动时报docker desktop failed to start because virtualisation support wasnt detected。这句话翻译过来是Docker Desktop要求系统开启虚拟化但系统说没开。第一步去任务管理器的“性能”页面看虚拟化状态是不是“已启用”。如果是“已禁用”重启进BIOS找到Intel Virtualization Technology或AMD-V改为Enabled保存退出。第二步确认WSL2已经安装执行wsl --status看内核版本是否为2。有时候你之前装过WSL的旧版本内核还是1.x需要执行wsl --update升级内核。第三步检查Windows功能里“虚拟机平台”和“适用于Linux的Windows子系统”这两个选项是否都已经打勾打开“启用或关闭Windows功能”找到它们勾选后重启系统。6.2 服务启动失败和API连接失败Linux下执行systemctl start docker之后过两秒服务又自己退出了这种情况十有八九是配置文件出了问题。检查顺序是先看daemon.json的JSON格式是否合法再看日志sudo journalctl -u docker -n 100日志会直接告诉你是配置解析失败还是网络冲突还是SELinux拦截。处理完问题后执行sudo systemctl daemon-reload sudo systemctl restart docker让配置生效。Windows下执行任何docker命令时报failed to connect to the docker api at npipe:////./pipe/docker_desktop_linux这类报错的直接原因是Docker Desktop引擎没有跑起来大部分时候你打开系统托盘Docker引擎图标是停止状态或者正在初始化。等它变为运行状态再重新执行命令即可。如果一直起不来就需要回到上一步检查虚拟化和WSL2。6.3 权限问题与端口冲突Linux下普通用户执行docker命令报permission denied while trying to connect to the Docker daemon socket解决办法就是我前面提到过的把用户加入docker组sudo usermod -aG docker $USER重新登录系统后生效。还有一个原因可能是socket文件权限被改过正常情况下/var/run/docker.sock的属主是root:docker权限是660。端口冲突是另外一个高频问题。启动容器时报bind: address already in use说明宿主机上这个端口已经被其他进程占用了。排查命令lsof -i:3306找到占用端口的进程PID关掉它或者创建容器时换一个宿主机端口映射比如把3306改成3307再试一次。生产环境中端口被占用的几率很高所以设计端口映射时最好养成分段规划的习惯例如数据库用3306、缓存用6379、Web用8080并在团队里维护一份端口分配表避免互相打架。6.4 镜像拉取失败与容器秒退拉镜像时报dial tcp: i/o timeout或者一直卡在等待下载就是典型的网络问题。先检查镜像加速是否配置成功执行docker info看Registry Mirrors列表。如果加速配置正确但依然超时可以试着把配置里的加速地址换一组或者检查是否处于内网环境内网一般是需要配置代理才能访问外网的。容器启动以后马上就退出这种问题需要用日志定位。比如MySQL容器秒退执行docker logs mysql8日志里会写明具体退出原因。我看到最多的情况是两种一种是数据目录权限不对容器内的mysql用户无法写挂载卷另一种是环境变量缺失。官方镜像一般会检查必需的环境变量缺少就直接退出并给出提示。所以遇到容器退出不要急着换镜像或者重装容器第一件事永远都是看日志。我把这些高频问题整理成一张速查表供你排查时对照抱错现象可能原因解决思路Docker Desktop提示虚拟化未启用BIOS未开启VT-x/AMD-V进BIOS开启虚拟化重启系统Docker Desktop启动后引擎一直不运行WSL2未安装或内核版本旧执行wsl --install更新WSL内核无法连接到docker daemon apiDocker引擎未启动检查托盘图标状态确保引擎正常运行普通用户看不到容器列表当前用户不在docker组sudo usermod -aG docker $USER后重新登录启动容器端口被占用宿主端口被别的进程占用lsof -i:端口定位占用进程换端口或释放占用拉镜像一直超时没有配置镜像加速或加速地址失效配置registry-mirrors替换新的加速地址容器启动后立即退出启动报错、环境变量缺失、挂载目录权限错误用docker logs 容器名查看具体错误信息修改daemon.json后Docker起不来配置文件JSON格式错误用dockerd --validate检查格式7. 接下来该怎么练到这里你已经走完了一条从零到能独立部署服务的完整路线。按顺序回顾一遍掌握镜像和容器的核心概念装好Docker环境配置镜像加速熟悉常用命令完成了MySQL部署和Redis主从搭建还接触了Compose编排方式最后掌握了常见报错的排查思路。我一直觉得学Docker最重要的是建立“用容器思考”的直觉。当你以后拿到一个软件要部署时第一反应不再是去查安装教程、解决依赖冲突而是想“这个软件有没有现成的镜像拉下来跑起来需要配哪些参数”有这种直觉之后Docker就算真正入门了。还有一个零基础非常实用的练习建议把创建好的MySQL容器删掉再用同样的挂载参数重新创建一个。第一次删掉容器时你会担心数据没了第二次创建后发现数据还在你对数据卷的理解会产生质变比单纯看十篇文章都管用。这是我在带新人时最常布置的练习效果非常稳定。下一步如果你想继续深入建议从自己写Dockerfile开始尝试把你写的项目打成镜像。这一步会真正串起所有基础知识基础镜像选择、依赖安装、启动命令编写、优化构建缓存。等到你能独立写出一份像样的Dockerfile时你已经从一个Docker用户变成了一个可以给团队交付Docker化服务的人。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进