尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Docker容器化实战:从镜像管理到容器编排的完整指南

Docker容器化实战:从镜像管理到容器编排的完整指南 1. 镜像管理先把安装包玩明白1.1 拉取与查看镜像docker pull / docker images用Docker第一步不是急着跑容器而是先把镜像搞明白。镜像这玩意儿你可以直接理解成安装包但它比Windows安装包更狠——它里面不光有程序连运行环境、依赖库、配置文件全给你打包好了。你拿到一个镜像就等于拿到了一套开了就能跑的完整环境。拉镜像的命令就一个docker pull 镜像名:标签比如拉一个MySQL 8.0就是docker pull mysql:8.0标签tag我建议一定要写不写默认拉latest。latest是什么是维护者最新推上去的版本今天拉和三个月后拉可能完全不是一个东西。之前我遇到过同事不写标签docker pull mysql结果拉回来的版本跟代码里用的驱动不兼容服务起不来排查了半天。所以生产环境一定要锁定具体版本。拉完之后看本地有哪些镜像docker images这个命令会列出仓库名、标签、镜像ID、创建时间和大小。镜像ID的前12位就够用了不需要复制整串。如果你不确定有哪些可用版本去Docker Hub搜或者在命令行直接搜docker search mysql搜索结果会显示官方标记OFFICIAL、星级等。除非你有特殊需求否则优先选OFFICIAL标记的镜像官方维护的镜像在安全性和稳定性上都靠谱得多。1.2 构建与清理镜像docker build / docker rmi如果要构建自己的镜像就需要Dockerfile。构建命令是docker build -t 镜像名:标签 .注意最后的点这个代表构建上下文路径很多人第一次用会漏掉。-t是给镜像起名字相当于给安装包贴个标签。构建完之后如果发现旧镜像没用了删掉它docker rmi 镜像ID或镜像名:标签删除镜像有个前置条件如果有容器还在用这个镜像会删不掉提示冲突。这时候要么先把容器停掉删掉要么用-f强制删不建议容易留下孤儿容器。清理时还有个实用命令——一键删掉所有未被使用的镜像docker image prune加上-a参数会连没有标签的悬空镜像一起清掉docker image prune -a这个命令我建议每周执行一次。Docker用久了本地会堆一堆none标签的中间层镜像占十几个G空间都不奇怪。你如果发现磁盘空间越来越小先看看是不是镜像堆太多了。实操心得docker image prune -a会把所有没被容器引用的镜像都删了如果你只是临时用某个镜像不会立刻重建最好先确认再执行。我一般在执行前先看一眼docker images心里有个数。2. 容器生命周期从创建到销毁2.1 一次运行与守护进程docker run 的参数详解镜像搞定之后就是创建容器了。docker run是最常用也最复杂的命令参数极多但核心的就那几个docker run -d --name my-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD123456 mysql:8.0拆开看-d后台运行不加的话终端会卡在前台CtrlC容器就停了。--name给容器起个名字之后操作都靠这个名字比记容器ID方便。-p 3306:3306端口映射宿主机端口:容器端口。外部访问宿主机3306流量转发到容器内的3306。经常有人搞反顺序记住了左边是宿主机右边是容器。-e设置环境变量比如MySQL的root密码就是通过环境变量传进去的。-v数据卷挂载下一节细说。如果只是想临时跑一下测试不想在后台留进程可以用docker run --rm -it ubuntu:22.04 bash--rm表示容器退出后自动删除-it是交互式终端适合进去敲命令。2.2 启动、停止、重启与删除容器创建之后日常管理就是这一套docker start 容器名 # 启动已存在的容器 docker stop 容器名 # 停止容器优雅停止会给进程发送停止信号 docker restart 容器名 # 重启容器 docker rm 容器名 # 删除容器这里有个新手坑docker run是创建并启动docker start只是启动已创建但停止的容器。很多人以为docker start能创建容器结果报了错No such container才反应过来。删除容器也注意停止状态的容器直接删没问题运行中的容器需要先stop再rm或者用docker rm -f强制删除。批量删除所有停止的容器docker container prune这个命令我经常用测试环境里起了一堆容器一个个删太累了一条命令全清。2.3 进入正在运行的容器容器在后台跑着你想进去看看两条路docker exec -it 容器名 bash这个是最常用的-it和前面一样是交互式终端。进容器后可以看日志、查配置、装工具。注意容器里一般没有vim也没有ps、netstat这些常用工具要用的话得先apt update apt install这也是为什么我建议进入容器之前先用docker logs看日志能不进就不进。还有一条老命令docker attach 容器名这条命令会把终端直接挂到容器的输出上CtrlC会直接停掉容器如果你只是想看一眼现在跑出来的输出用attach容易误伤不如用logs。注意docker exec才是进容器执行命令的正道docker attach会让你的终端跟容器的主进程绑定在一起一按CtrlC容器就停了别问我是怎么知道的。3. 信息查看与日志排查3.1 当前状态一览docker ps / docker stats / docker top查运行中的容器docker ps加上-a参数连已停止的容器也显示出来docker ps -a这个命令的结果里关键信息是STATUS状态和PORTS端口映射。如果容器秒退docker ps看不到但docker ps -a会显示Exited (1)之类的状态这是排查崩溃的第一手线索。查看容器资源占用docker stats这个类似Linux的top命令实时显示CPU、内存、网络IO、磁盘IO。如果某个容器内存疯涨跑一下这个命令马上就能发现。我就是靠这个命令抓过一次内存泄漏的Java服务。看容器内进程docker top 容器名相当于在容器外面看容器里面跑了哪些进程排查多进程容器的时候好用。3.2 日志与实时追踪docker logs日志是最重要的排查手段没有之一。我记得刚用Docker那会儿容器起不来就干瞪眼后来才知道Docker会自动收集容器的标准输出和标准错误。docker logs 容器名看最后100行、实时跟踪docker logs --tail 100 -f 容器名--tail 100是只看最后100行-f是follow持续输出新增日志。这个组合基本是我排查问题的固定动作。如果日志太多刷屏可以加上时间戳来看docker logs --since 2026-01-01T00:00:00 容器名--since还可以直接写10m10分钟前、1h1小时前这种相对时间排查最近的问题非常方便。实操心得如果你的容器一直在崩溃用docker logs看到的是启动时的错误但看不到崩溃前一瞬间的日志。这时候把docker run加个--restart unless-stopped让容器崩溃后自动重启再配合docker logs --since 10m -f就能抓到崩溃现场。4. 数据卷与端口让数据不丢、外部可访问4.1 数据卷挂载-v 别乱用方向别搞反容器是用完即弃的设计但数据得活着。比如MySQL的数据文件如果存在容器内部容器一删数据跟着没了。解决办法就是数据卷挂载。docker run -d --name mysql-test \ -v /data/mysql:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0这里-v /data/mysql:/var/lib/mysql的意思是把宿主机的/data/mysql目录映射到容器里的/var/lib/mysql目录。容器写入数据时实际写到宿主机的/data/mysql容器删除后数据还在宿主机上。顺序千万别搞反了左边一直是宿主机路径右边是容器路径。搞反的后果是数据写到容器里删除容器后一无所有而且还会提示权限问题。为什么说权限问题我遇到过好几次宿主机挂载目录的属主和容器内进程的用户不一致导致写入报Permission denied。MySQL镜像默认用mysql用户跑如果你在宿主机上创建的目录属主是root容器内mysql用户写不进去。解决办法是把目录属主改成对应的uid或者运行的时候加--user参数指定用户。4.2 网络模式与端口映射Docker的网络默认是bridge模式相当于容器在一个小内网里外部访问不到。想让外部访问就得做端口映射。docker run -d --name nginx-test -p 8080:80 nginx这条命令把宿主机的8080端口映射到容器的80端口。浏览器访问http://宿主机IP:8080就能看到nginx的欢迎页。除了bridge模式还有两种常用模式--network host容器直接使用宿主机网络没有隔离性能最好适合对网络延迟敏感的服务但端口就不需要映射了直接用宿主机的端口。--network none没有网络一般用来跑一些完全不需要网络的任务比如离线计算。多容器之间如果需要互相通信可以创建自定义网络docker network create my-net docker run -d --name web --network my-net nginx docker run -d --name app --network my-net myapp在同一个自定义网络里的容器可以直接用容器名互相ping通。假设app容器里要访问web容器直接curl http://web:80就行不需要通过宿主机IP和映射端口这个设计比默认的bridge模式舒服太多。5. 三个真实场景从命令到部署5.1 单机跑MySQL 8.0这是Docker最常见的应用场景之一。以前装MySQL要在机器上配源、装依赖、改配置现在一条命令的事docker run -d --name mysql8 \ -p 3306:3306 \ -v /data/mysql8:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD你的密码 \ -e TZAsia/Shanghai \ mysql:8.0这里多了个-e TZAsia/Shanghai把时区设成东八区不然MySQL默认用UTC时间跟你的业务时间差8个小时查询出来的数据看着就懵。外部的应用连接MySQL的地址是宿主机IP:3306用户名root密码是环境变量设置的那个。连接之前先验证一下容器状态docker ps | grep mysql8如果STATUS显示Up基本没问题。连接报错的话先看日志docker logs mysql85.2 快速搭一套Redis主从Redis主从复制这种需求用Docker搭建比手动编译安装方便太多。先创建一个自定义网络让两个Redis容器能互相通信docker network create redis-net启动主节点并把配置目录挂载出来这样改配置不用进容器docker run -d --name redis-master \ --network redis-net \ -p 6379:6379 \ -v /data/redis-master:/data \ redis:7.0 redis-server --appendonly yes启动从节点命令里直接指定主节点的地址和端口docker run -d --name redis-slave \ --network redis-net \ -p 6380:6379 \ redis:7.0 redis-server --slaveof redis-master 6379注意两个容器必须在同一个自定义网络里否则从节点解析不到redis-master这个主机名。验证主从是否正常docker exec -it redis-master redis-cli info replication看到role:master和connected_slaves:1就说明主从配置成功。5.3 用Docker Compose编排多个服务单容器用docker run就够了但一旦涉及多个服务比如应用数据库缓存再一个个run就太累了而且容易漏配置。这时候用Docker Compose。一个典型的docker-compose.yml长这样version: 3.9 services: mysql: image: mysql:8.0 container_name: my-mysql environment: MYSQL_ROOT_PASSWORD: root123 volumes: - /data/mysql:/var/lib/mysql ports: - 3306:3306 redis: image: redis:7.0 container_name: my-redis command: redis-server --appendonly yes volumes: - /data/redis:/data ports: - 6379:6379 app: build: ./app container_name: my-app depends_on: - mysql - redis ports: - 8080:8080启动全部服务docker compose up -d只用这一个命令三个服务全部拉起而且Compose会自动创建默认网络服务之间用服务名互相访问。depends_on指定了启动顺序——mysql和redis先起来app后启动。查看服务状态docker compose ps看日志docker compose logs -f app停止并删除所有服务默认保留数据卷docker compose down如果连数据卷一起删掉docker compose down -v这个-v参数要注意一旦执行数据是彻底没了生产环境千万慎重。Compose文件可以用YAML锚点复用配置也会做变量替换用.env文件但对于小团队、小项目来说上面这个最基本的写法已经覆盖了90%的日常需求。6. 日常问题排查与踩坑实录6.1 Docker Desktop启动失败VT-x和Hyper-V的坑Windows上装Docker Desktop最常见的问题就是启动不了报错信息类似virtualization support not detected或者failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinuxEngine。先说第二个npipe连接不上大概率是Docker引擎根本没起来。原因很多但最常见的是BIOS里没开虚拟化VT-x/AMD-V。重启进BIOS找到Intel Virtualization Technology或者SVM Mode开启它。Windows功能里没启用Hyper-V或者虚拟机平台WSL2依赖它。在控制面板 → 程序 → 启动或关闭Windows功能里勾选上然后重启。装了别的虚拟机软件比如旧版VirtualBox和Hyper-V冲突。现在VirtualBox新版已经支持Hyper-V共存了但老版本会出问题。报错信息里如果带npipe本质是Docker客户端连不上Docker引擎。就像你给服务器发了条消息但服务器没开机自然就报连接失败。先把引擎跑起来问题自然解决。6.2 镜像下载慢配置国内加速源Docker官方仓库的服务器在海外国内拉镜像经常慢得怀疑人生断断续续还容易失败。解决办法是配置镜像加速器镜像registry mirror。Linux版Docker修改/etc/docker/daemon.json{ registry-mirrors: [https://your-mirror.example.com] }然后重启Dockersudo systemctl restart dockerDocker Desktop用户直接在Settings → Docker Engine里改JSON配置也是加registry-mirrors字段。有一点要注意镜像加速只对Docker Hub官方仓库生效如果你拉的是自己私有仓库的镜像或者像gcr.io、quay.io这类第三方仓库加速器是管不着的。6.3 容器时间不对或中文乱码容器默认使用UTC时区跑起来日志时间比本地慢8小时。时间不对会直接影响业务判断。解决办法就是把宿主机的时区文件挂载进容器或者在创建容器时设置TZ环境变量docker run -e TZAsia/Shanghai -v /etc/localtime:/etc/localtime:ro ...涉及中文乱码一般是容器里没有中文字体或者locale没设对。简单的处理是用-e LANGC.UTF-8或者-e LANGen_US.UTF-8大部分场景下能解决。实操心得如果是自己写的应用镜像建议在Dockerfile里把时区和locale问题直接解决掉别等到部署了再一个个容器去改ENV TZAsia/Shanghai ENV LANGC.UTF-8这样任何环境跑起来都是东八区时间中文也不会乱码。6.4 安全与清理两条保命命令日常运维中养成定期清理的习惯很重要docker system df这个命令一键展示当前镜像、容器、数据卷占用了多少空间。看完了再决定要不要清理。docker system prune -a --volumes这条命令会把所有停止的容器、未被使用的网络、悬空镜像、未被引用的数据卷全部清理干净。但注意--volumes会连数据卷一起删你的MySQL数据如果放在数据卷里确认不要了再执行。生产环境我一般只用docker system prune不带 --volumes数据卷留着以防万一。镜像、容器、数据卷这三者你会理清之后Docker的基本功就算扎实了。剩下的像docker cp容器和宿主机之间拷文件、docker export/import导出导入容器文件系统、docker info查看Docker环境详细信息这些用到的时候查一下就能上手核心思路就一句话镜像管安装包容器管进程数据卷管持久化网络管连通日志管排查。这五个维度理通之后Docker在你手里就不是玄学了。我每次带新人都让他们先默写一遍常用命令再手写一个docker run把MySQL和Redis跑起来这两关过了后面接触K8s、云原生那些东西才不至于连基础概念都糊里糊涂。
返回列表