前言
之前做过一个小项目,需要把一套 Python 服务部署到服务器上,我就说试着玩玩 Docker 吧,听说一次打包就能到处跑,很省心(・ω・),而且网上Docker的教程也很多,当时觉得应该很快就能搞定了。结果从装好 Docker 到服务正常跑起来,我整整折腾了一个周末,这期间踩的坑不算高级,很多都能顺利解决,但还是有些坑让我很抓狂。今天就把这些坑记录下来,给刚入坑 Docker 的朋友避避雷。

第一个坑:docker ps 报权限不足
装好 Docker 之后,我兴冲冲地敲下第一个命令:
docker ps结果直接甩我一脸报错:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/images/json: dial unix /var/run/docker.sock: connect: permission denied难道我装错了吗?(;一_一)
查了一些相关知识才知道,Docker 进程默认用 Unix Socket 通信,这个 socket 文件属于 root 用户,普通用户没有访问权限。每次命令前加 sudo 能解决,但每敲一次就要输一次密码,就很烦。
永久解决办法是把当前用户加进 docker 用户组:
# 1. 创建 docker 用户组(已存在会提示,不用管)
sudo groupadd docker
# 2. 把当前登录用户加入 docker 用户组
sudo gpasswd -a $USER docker
# 3. 更新用户组,让设置立即生效
newgrp docker
# 4. 测试
docker ps注意:newgrp docker 只对当前终端会话生效,如果你开了好几个终端,其他终端还是没权限,得重新登录或者每个终端都执行一遍。我一开始不知道,在另一个窗口敲 docker ps 还是报错,一度以为方法没生效。
第二个坑:docker attach 退出把容器搞停了
容器跑起来之后,我想进去看看里面的文件结构。
docker attach ubuntu-test进去之后看了几眼,顺手敲了个 exit 想退出来,结果容器也跟着停了(╯°□°)╯︵ ┻━┻。
我当时就懵了,退个终端怎么把服务也退了?后来查了文档才知道,docker attach 连接到的是容器的主进程终端,你在里面敲 exit,等于把主进程结束了,容器自然就停了。
正确做法是用 docker exec:
docker exec -it ubuntu-test /bin/bashexec 是在容器里新开一个进程,你退出的时候只结束这个新进程,容器本身继续在后台跑。
我后来养成了习惯,只要容器是在后台跑的,一律用 exec 进去,attach 基本不用了。
第三个坑:docker export 和 docker save 分不清
项目要迁移到另一台服务器,我想把容器打包带走。docker export 能把容器导出成 tar 文件,于是就用了:
docker export ubuntu-test > ubuntu1.tar导出的文件拷到新服务器,用 docker import 导入:
cat ubuntu.tar | docker import - test/ubuntu:v1导入成功了,镜像也生成了,但启动之后发现里面装的东西全没了,只剩下一个空壳系统。(´-ω-`)
折腾半天才搞明白,docker export 导出的是容器的文件系统快照,不包含镜像的层历史和元数据,而 docker save 导出的是镜像,保留完整的层结构和历史记录。这两个命令名字像,用途完全不同:
docker export / import:操作对象是容器,导出文件系统,适合做容器快照备份。
docker save / load:操作对象是镜像,保留完整层历史,适合迁移镜像。
我要迁移的是配置好的镜像,应该用 docker save 才对。
第四个坑:镜像下载慢到怀疑人生
第一次执行 docker pull ubuntu 的时候,我盯着终端看了五分钟,进度条纹丝不动。
Pulling from library/ubuntu就这一行,然后没了。(;´д`)ゞ
原来Docker Hub 的服务器在国外,国内直接拉取经常慢到超时。解决办法是配置国内镜像源,在 /etc/docker/daemon.json 里加上:
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}然后重启 Docker:
bash
sudo systemctl daemon-reload
sudo systemctl restart docker配完之后速度确实快了不少。这里提醒一下,镜像源地址可能会有变动,用之前最好搜一下当前可用的源,有些老教程里的地址已经失效了。
第五个坑:容器删了,磁盘还占着
项目调了一段时间,我删了几个不用的容器:
docker rm -f ubuntu-test以为这样删完就干净了。结果某天服务器磁盘告警,df -h 一看,根分区快满了。
用 docker system df 查了一下,发现 volume、镜像层、停止的容器 占了一大堆空间。原来 docker rm 只删容器本身,容器挂载的数据卷、构建产生的中间镜像层都还留着。
清理命令:
# 查看 Docker 磁盘占用
docker system df
# 清理停止的容器、无用镜像、无用网络
docker system prune
# 连数据卷一起清理(谨慎使用)
docker system prune --volumes--volumes 这个参数要小心,它会删掉所有没被使用的数据卷。如果哪个卷里有重要数据,又刚好没被容器挂载,那就一起没了。
个人总结
折腾了念了很久的Docker,我的感受是:教程多,入门确实不难,但是需要注意细节。
权限问题:加 docker 用户组,注意
newgrp只对当前终端生效。进入容器:后台容器用 docker exec,别用
docker attach,除非你知道自己在干什么。备份迁移:迁移镜像用 docker save / load,做容器快照用 docker export / import,别搞混。
镜像下载:配国内镜像源,省时间。
磁盘清理:定期
docker system df看看,别等磁盘满了才想起来。
Docker 的命令本身不多,常用的就那十几个。真正花时间的,是搞明白每个命令“做了什么”和“没做什么”,还是需要在测试环境,多多地实际上手,踩过坑之后,才能记住和理解这些命令。
感谢您阅读到这里!