有些问题并不是你不会用 Docker,而是你刚准备开始用,环境就先给你一拳。
写在前面
其实最近一段时间,我并没有频繁折腾 Docker。
本地开发时我基本都挂着网络工具,拉镜像虽然偶尔慢一点,但通常还能忍;真正让我重新把这套东西捡起来,是前几天想把一个项目部署到云服务器上,结果第一步就出了问题:
docker pull xxx
卡住,失败,重试,继续失败。
那一刻就很真实地意识到,之前那种“Docker 挺省心”的印象,很大程度上建立在本地网络还过得去的前提上。一旦到了国内云服务器环境,很多事情立刻就变味了。
如果你也遇到过下面这些情况,这篇大概能对上胃口:
- 本地能拉镜像,服务器就是拉不下来
- Docker 装好了,但一跑项目就开始补配置
- 日志不设限制,磁盘迟早被打满
- 记不住常用命令,每次都得翻之前的笔记
所以这篇文章不打算讲太多“Docker 的伟大原理”,而是更偏向一次真实的整理:
我被环境折腾了一遍之后,最后是怎么把 Docker 重新收拾顺手的。
这次到底踩了什么坑
从 2024 年中开始,国内很多 Docker Hub 镜像加速服务陆续失效,一些原本还能用的高校缓存服务也开始不可用。对平时只在本地开发的人来说,这种变化未必很明显;但只要你开始在国内服务器上部署项目,这个问题几乎绕不过去。
- 之前
本地偶尔用 Docker,挂着网络工具,基本没什么感觉。
- 后来
想把项目部署到云服务器上,结果镜像拉取失败。
- 再后来
开始重新翻资料、找镜像源、改
daemon.json、顺手把日志和 IPv6 也一并收拾了。
更烦的还不只是“拉不下来”本身,而是那种很典型的消耗感:你明明不是在解决业务问题,只是想把环境先跑起来,结果一个 docker pull 就能拖走你半天。
能用非大陆服务器折腾 Docker,就尽量别在大陆服务器上硬扛。
不是说完全不能用,而是同样的事情,在不同网络环境下,体验差距会大得离谱。
很多时候大家不是不会 Docker,而是被外部环境拖住了。再叠加国内云服务器普遍不算大方的带宽,拉镜像这件事就更容易变成耐心测试。
当然,现实是现实。多数时候机器已经买了,项目也得上,那就只能接受条件有限,然后尽量把配置做得稳一点。
如果非要用一句话概括 Docker,我自己更喜欢这种不太严谨但够直观的说法:
Docker 就像一个能搬来搬去的运行盒子。你不需要到一台新机器上再手动配一遍环境,直接把盒子拿过去,启动,就能跑。
至于镜像、容器、仓库这些概念,真要展开讲当然也能讲很多,但这篇我不准备往教程文的方向写太深。够用就行,先把问题解决,比把概念背熟更重要。
装好还不够,配置得一次到位
因为后面主要是服务器场景,所以这里还是以 Ubuntu 20.04 为例。
如果系统里已经有旧版 Docker,稳妥起见可以先卸一下。包名不一定叫 docker,也可能是 docker.io、docker-engine 之类:
sudo apt-get remove docker docker-engine docker.io containerd runc卸不掉也不用太慌,很多时候可以直接继续往下装。安装过程我还是沿用官方源这一套:
sudo apt update sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common 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" sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io
装完之后,先看服务有没有正常起来:
sudo systemctl status docker正常情况下会看到 active (running)。如果你不想以后每次都在前面加 sudo,还可以顺手把当前用户加进 Docker 用户组:
sudo usermod -aG docker $USER然后重新登录一次,让权限生效。
不过说实话,真正麻烦的其实不是“装上 Docker”,而是“装完以后别留下隐患”。我现在基本会顺手把 daemon.json 一次配好,主要处理三件事:配置镜像源、限制日志大小、顺手打开 IPv6。这里面最值得强调的其实是日志限制,因为这玩意平时不响不动,一旦没管住,最后很容易把磁盘慢慢吃满。
Docker 默认日志如果不做限制,真的会把硬盘慢慢吃满。
这种问题平时不响不动,等你发现的时候,往往已经开始影响服务了。
我当时记录下来还能用的镜像源是这些。注意,这只是 2024-11-03 当时的可用情况,不是永久有效清单:
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerhub.icu",
"https://docker.anyhub.us.kg",
"https://docker.1panel.live"
]
}
我最后实际使用的配置如下:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
},
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef:c0::/80",
"experimental": true,
"ip6tables": true,
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerhub.icu",
"https://docker.anyhub.us.kg",
"https://docker.1panel.live"
]
}
如果懒得手动编辑,可以直接这样写进去:
cat > /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
},
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef:c0::/80",
"experimental": true,
"ip6tables": true,
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerhub.icu",
"https://docker.anyhub.us.kg",
"https://docker.1panel.live"
]
}
EOF
写完之后记得重载并重启:
sudo systemctl daemon-reload && sudo systemctl restart docker当然,镜像站这件事也别抱太大幻想。刚开始遇到拉取失败时,第一反应通常都是“找个国内镜像站不就行了”,但真折腾下来就会发现,很多镜像站只同步热门镜像,稍微冷门一点的就未必有;就算有,也可能限流、限速,高峰期体验很差;再往深一点说,第三方镜像服务的同步和维护策略,普通用户其实也很难完全验证。
所以我现在的态度很简单:
镜像站可以救急,但别把它当成唯一依赖。
对稳定性要求高的时候,还是得想办法把仓库、网络、部署链路做得更可控。
顺便提一句,阿里云以前那套镜像源我现在基本不考虑了。老早就有“不再更新”的说法,很多不热门镜像的版本确实偏旧,用起来总让人不踏实。
顺手记一份常用命令
前面解决的是“拉不拉得下来”的问题,下面这部分更像我自己的日常备忘录。不是面面俱到,但基本覆盖了平时最常用的操作。
先说镜像。查看本地镜像最简单:
docker imagesdocker images -q搜索和拉取镜像的命令我最常用下面这几条:
docker search mysql docker search mysql --filter=STARS=3000 docker pull mysql docker pull mysql:5.7
删除镜像也很直接:
docker rmi -f 镜像ID到了容器这一层,最常见的还是 docker run。虽然参数很多,但平时高频也就那么几个:--name 指定名字,-d 后台运行,-it 交互进入,-p 做端口映射,-v 做数据挂载,-e 传环境变量。记住这些,日常已经够用了。
查看容器:
docker psdocker ps -a控制容器的生命周期:
docker start 容器ID docker restart 容器ID docker stop 容器ID docker kill 容器ID docker rm 容器ID
这里有个很基础但经常忘的点:正在运行的容器不能直接删,先停掉。
查问题时我最常看的三条命令也放一起:
docker logs -tf --tail 10 容器ID docker top 容器ID docker inspect 容器ID
进入容器一般我都用:
docker exec -it 容器ID /bin/bash docker attach 容器ID
其中 docker exec -it 明显更顺手,attach 我平时其实用得不多。至于容器和宿主机之间拷文件,也偶尔会用到:
docker cp 容器ID:/xxx/aaa.txt /xxx另外,数据挂载这件事我建议别偷懒。很多人刚开始图省事,容器跑起来就行,不挂卷;等容器删了、数据没了,才开始后悔,数据库尤其如此。下面这个 MySQL 例子,基本就是我自己平时会直接照着改的版本:
docker run -d \ -p 3310:3306 \ -v /home/mysql/conf:/etc/mysql/conf.d \ -v /home/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ --name mysql01 \ mysql:5.7
- 把宿主机
3310映射到容器3306 - 把 MySQL 配置目录挂出来
- 把数据库数据目录挂出来
- 设置 root 密码
- 后台运行,并命名为
mysql01
对于本地开发和轻量部署来说,这种方式已经够用了。至少容器删了还能再建,数据不会跟着一起没。
如果项目稍微复杂一点,比如同时要起 MySQL、Redis、Nginx、前后端服务,那就别继续硬写一长串 docker run 了。我后来基本默认:单容器临时测试用 docker run,多容器项目直接上 docker compose。最常用的命令也就这一条:
docker compose up -d关键不在命令本身,而在 docker-compose.yml 写得好不好。小项目手写,大一点的项目参考现成部署方案再改,这样通常更省事。
如果以后真要彻底卸载 Docker,也可以顺手记一下:
docker container stop $(docker container ls -aq) docker system prune -a --volumes sudo apt purge docker-ce sudo apt autoremove
写在最后
这篇其实不是“我来教你 Docker”,而更像是一次被环境教育之后的收拾现场。
我原本只是想在服务器上顺手部署个项目,结果从拉镜像开始就一路磕绊。到最后回头看,真正浪费时间的并不是 Docker 本身,而是那些明明不属于业务、却又不得不处理的环境问题。
很多技术问题最烦的地方,不是难,
而是它不创造价值,却持续消耗你。
所以我现在的做法很简单:只要准备长期用 Docker,就把镜像源、日志限制、卷挂载这些基础项先配好。这样后面真正开始跑项目时,至少不会再被这些低级但高频的小坑反复绊住。
至于国内 Docker 环境什么时候能重新变得省心一点——老实说,我不太乐观。所以与其等环境变好,不如先把自己的工具链收拾利索。

评论区
评论加载中...