9
0
0

01-Docker 基础:安装、镜像容器与容器操作

2026-10-22
2026-10-22

📝 笔记摘要:Docker 基础,安装、镜像容器与容器操作

Docker 说白了就是「把一整套运行环境打包成一个文件」。装 MySQL 不用再纠结版本兼容,装 Java 不用配环境变量,镜像往服务器上一扔就起来了。

但新手栽的坑大多不在「跑不起来」,而在「跑起来了但不是你要的样子」:容器起来了访问不了、命令报权限错误、镜像拉下来了但跑的版本不对。这篇按「装 → 理解 → 用」的顺序捋一遍,每一步都写清楚它到底解决什么问题。

Docker 系列 共 4 篇,这是第 1 篇
  01-Docker 基础 安装、概念与容器操作 ← 本篇
  02 Docker 镜像与数据卷 分层结构、挂载与 Dockerfile
  03 Docker 网络与 Compose 容器互访与多容器编排
  04 Docker 常见问题排查 守护进程、权限与镜像拉取

1. 装 Docker

Linux 上装 Docker 现在只有一条路:官方那个 get.docker.com 脚本。它自己判断发行版、自己配源、自己装依赖,比手抄 apt / yum 命令靠谱得多——手抄的那套命令十个里有三个是过期的。

# 全系统通用,Debian / Ubuntu / CentOS / RHEL / Rocky 都能跑
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

脚本装完不会自动配开机自启
  它会装好 systemd 服务,但 enable 这一步要自己补
  sudo systemctl enable docker
  少这一步的现象很典型:今天还好好的,重启一次 docker ps 就报连不上守护进程
装完验三个东西,缺一不可
  docker --version    客户端版本
  docker info      守护进程连不连得上
  docker run hello-world 真拉一个镜像跑起来
  前两个过了不代表第三个也能过,第三个才是端到端的验证
版本别追新
  Docker Engine 29 是当前主线,25 还在维护期
  生产环境的镜像更别用 latest——latest 是会动的指针,不是版本号
  要用就钉死成 nginx:1.27.5 这种带版本号的 tag

CentOS 7 得多做一步

CentOS 7 已经在 2024 年 6 月 30 日停止维护,官方 yum 源整个下线了。mirrorlist.centos.org 不再提供任何内容,yum 会直接报 Could not resolve host 或者 Cannot find a valid baseurl。

这不是网络故障,是源没了。得先把 yum 指向归档仓库,再谈装 Docker:

# 官方源换成归档仓库,国内用阿里云的 centos-vault
sudo sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo
sudo sed -i 's|#baseurl=http://mirror.centos.org|baseurl=https://mirrors.aliyun.com/centos-vault|g' /etc/yum.repos.d/CentOS-*.repo

sudo yum clean all
sudo yum makecache
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

CentOS 7 上的 Docker 版本会被卡住
  新的 Docker CE 要求 CentOS 8 以上,7 上能装的最高是 20.10 系列
  这不是 yum 的问题,是包依赖真的不支持
  要新版本就换 Rocky Linux 或 AlmaLinux,它们跟 CentOS 7 是二进制兼容的,迁移成本很低
CentOS 7 上的坑不止 Docker
  它自己的防火墙行为也跟现在的规则不一样,Docker 还能绕过 firewalld
  见 CentOS 7 防火墙常用操作 那篇

2. 配镜像加速

Docker Hub 的服务器在境外,国内直连的状态是「看运气」:小镜像可能就过来了,几 G 大的 CUDA、PyTorch 这类基本是拉到一半超时。

解法是在 /etc/docker/daemon.json 里配 registry-mirrors,让 Docker 先问国内的中转站:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
  "registry-mirrors": [
    "https://docker.1panel.live",
    "https://docker.m.daocloud.io",
    "https://docker.nju.edu.cn"
  ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

改完验证一下有没有真的加载上:

docker info | grep -A 5 "Registry Mirrors"

加速源是缓存,不是代理
  镜像没被缓存过时,加速站会转发到 Docker Hub 去拉,第一次照样慢
  拉过一次之后才有本地缓存,第二次才是真的快
  所以「配了加速还是慢」很多时候是正常现象,多拉两次就快了
多配几条,故障切换用
  这些站点随时可能挂,Docker 会自动试下一条
  只配一条等于单点故障,那条挂了就是全线拉不动
阿里云那个得登录才有
  控制台 → 容器镜像服务 → 镜像工具 → 镜像加速器
  给你一个专属地址,带独立带宽,不跟大众源挤
  国内机器上这是最稳的一个,比公共源优先级高
自己搭一个更可控
  把 Docker Hub 反代到自己域名下,缓存也是自己的
  公共源全挂了也不影响你,见 docker 搭建 docker 仓库代理
有一批地址已经死了,别再抄
  huecker.io、dockerhub.timeweb.cloud、noohub.ru 这几个俄罗斯源
  2026 年 10 月实测全部连不上,配进去只会让 Docker 多等几秒再超时,不会更快
  加速源的生命周期很短,抄来的地址三个月后再验一次

3. 镜像、容器、仓库

这三个词最容易混。分清了,后面所有概念都通顺。

镜像 image 一套只读的模板
  里面是完整的文件系统:二进制、依赖库、配置文件
  本身不能跑,它只是个模板
容器 container 镜像跑起来的一个实例
  在上面加一层可写层,进程真正跑在里面
  镜像可以起无数个容器,彼此隔离
仓库 repository 存镜像的地方
  Docker Hub 是公共的,自己的服务器也能建一个
  镜像只有拉下来才能用,本地没有就是拉

镜像为什么能做得这么小、为什么几个镜像能共享数据,见 Docker 镜像与数据卷 那篇的分层结构部分。

4. 数据都放在哪

容器是「用完即弃」的东西,宿主机上真正占地方的是 /var/lib/docker。

镜像层、容器可写层、卷,全在这一个目录下
  /var/lib/docker/overlay2  镜像层和容器层
  /var/lib/docker/volumes  具名卷的真实数据
  /var/lib/docker/containers 每个容器的日志 json 文件
容器日志不轮转会把磁盘吃满
  stdout / stderr 会被 Docker 存成 json 文件,它不会自动清理
  跑上几个月的服务,日志涨几十 G 是常事
  磁盘告警先来这里看,见 Docker 常见问题排查
数据目录能不能整个搬走
  能,Docker 支持 data-root 改到别的盘
  但要停服务再搬,不能在线改
  根分区小的话,镜像多的话这个很值得提前规划

5. 常用参数

docker ps                # 只看运行中的容器
docker ps -a             # 连没启动的、已退出的都列出来
docker ps -q             # 只打印容器 ID,脚本里好用
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

docker images            # 本地镜像列表
docker images -a         # 连中间层和悬空镜像都列出来

docker stats            # 实时看 CPU / 内存 / 网络
docker system df        # 看 Docker 占了多少磁盘,分几类
docker system prune -a  # 清理没用的镜像和容器,慎用

-a 和 -q 是两个正交的维度
  -a 决定「列多少」,-q 决定「输出成什么格式」
  -a 是 all,-q 是 quiet(只出 ID),两个能叠
排查问题先看 docker ps -a
  一个容器「起不来」,去 docker ps -a 里能看到它躺在那儿,状态是 Exited
  光看 docker ps 是看不到的,这个差异经常让人以为容器根本没创建
docker system prune -a 会删掉没在用的镜像
  包括那些「暂时没容器在跑但你还想留」的镜像
  执行前先 docker system df 看一眼到底能省多少

6. 容器为什么自己停了

docker run -d 之后容器立刻变成 Exited,这是新手最常撞的一个现象。

容器跟着主进程走
  Dockerfile 里 CMD / ENTRYPOINT 指定的那条命令,就是容器的主进程
  主进程一退出,容器立刻停止,这是设计,不是 bug
三种典型原因
  命令跑完就结束了 比如 CMD echo "hello",打印完就退出
  容器里没有常驻服务 比如拿 centos 当底子,进去就是 bash,退出 bash 容器就死
  服务自己崩了 端口冲突、配置文件缺失、连不上数据库
排查顺序
  docker ps -a      确认容器状态和退出码
  docker logs 容器名  看最后几行报错
  docker inspect 容器名 看 State.ExitCode 和 State.Error
  退出码 137 是被 kill(多半是 OOM),139 是段错误,其他非 0 值看日志
要它别停就加 --restart
  --restart=always  一直重启,Docker 守护进程起来也会拉
  --restart=unless-stopped  跟 always 差不多,但手动 stop 之后不自动拉起
  生产环境一律要加,服务器重启或者 Docker 守护进程重启后服务能自己回来
真的需要一个长驻容器
  把命令改成不会退出的,比如 tail -f /dev/null,然后用 docker exec 进去干活

7. 怎么进容器

两条命令都能进去,区别在于进的是「谁的进程」。

docker exec -it 容器名 /bin/bash   # 新开一个进程
docker attach 容器名              # 接管主进程的输入输出

exec 是日常该用的那个
  在容器里另起一个进程,不影响主进程
  进去以后 exit 退出,容器照常跑
  可以同时开好几个 exec,进出互不干扰
attach 会「抢」终端
  它接的是主进程的 stdin / stdout,你敲的键会直接喂给主进程
  主进程没在读输入的话,看起来就是卡住不动
  卡住时按 Ctrl+P 再按 Ctrl+Q 脱离,不要直接 Ctrl+C
  Ctrl+C 是发给容器里的进程的,不是断开会话
attach 还有个隐患
  你 attach 着的这段时间,docker logs 就看不到输出了,两边抢同一个 stdout
  排查问题用 docker logs,日常操作用 docker exec
镜像里没有 bash 怎么办
  精简镜像(alpine 那种)只有 /bin/sh,exec -it 容器名 /bin/bash 会报 not found
  换成 /bin/sh 就行

8. 部署 nginx

docker run -d --name nginx -p 3344:80 nginx

跑起来之后访问 http://服务器IP:3344,能出默认页面就成了。端口映射的格式是 宿主机端口:容器端口,左边那个可以随便改,右边那个是镜像里写死的,改不了。

容器内的 80 端口和你映射的 3344 是两回事
  镜像里 nginx 监听 80,Docker 负责把宿主机 3344 的流量转进容器的 80
  你也可以不映射,那就只能在容器内部访问,外面进不来
端口被占了换个宿主机端口
  报 bind: address already in use 就是这个原因,左边改个数字就行
  查谁占着:ss -tlnp | grep 3344
重启后 IP 会变,端口映射不会
  容器 IP 是临时的,-p 映射的端口是宿主机的,容器重建也不影响
  所以配置文件里写 http://宿主机IP:3344 是稳的,写容器 IP 不稳
要改配置就挂出来
  -v /data/nginx/conf.d:/etc/nginx/conf.d
  改宿主机的文件,容器里的 nginx 立刻读到,重载一下就生效

9. 部署 tomcat

docker run -d --name tomcat -p 8080:8080 tomcat:9

起完之后浏览器访问 http://服务器IP:8080,默认应该看到一个 Tomcat 页面。

页面空白的常见原因
  官方 Tomcat 镜像里的 webapps 目录是空的,它把示例应用挪到了 webapps.dist
  这不是镜像坏了,是官方镜像故意这么做——默认不跑示例应用
  想看默认页面就把它复制回去:
  docker exec tomcat cp -r webapps.dist webapps
  自己的项目要放在 webapps 里
  把 war 包挂进 /usr/local/tomcat/webapps,容器启动会自动解压部署
看日志确认部署结果
  docker logs tomcat 能看 Tomcat 启动和部署的完整过程
  war 包部署失败十有八九是 webapps 挂载位置不对

10. 找文件位置

容器里没有 which、locate 这类工具的时候,用 whereis。

whereis docker        # 列出程序、源码、手册的路径
whereis nginx
whereis java

whereis 查的是「安装位置」,不是「你 cd 到的位置」
  它搜的是 /usr/bin、/usr/sbin 这些固定目录
  它不查当前目录,也不查 PATH 里的任意位置
  想找当前目录树里的文件,用 find
whereis 和 which 的区别
  which 查 PATH 里第一个匹配,whereis 查固定安装目录
  脚本里判断某个命令存不存在用 which 更准

11. 图形化管理

命令敲烦了可以用面板。Portainer 是最常见的一个,开源免费。

docker volume create portainer_data

docker run -d \
  -p 9443:9443 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

浏览器打开 https://服务器IP:9443,自签证书浏览器会报警告,点「继续前往」就行。

端口是 9443 不是 9000
  早期的 Portainer 走 9000 明文 HTTP,新版改成了 9443 自签 HTTPS
  照着老文章敲 -p 9000:9000 会连不上
镜像名是 portainer/portainer-ce
  不是 portainer/portainer,那个名字已经停更了
数据一定要挂出来
  -v portainer_data:/data 存的是账号、设置、镜像加速配置
  不挂的后果是重建容器后全部丢失,得重新设一遍
挂 docker.sock 等于交出宿主机
  面板通过它直接控制 Docker 守护进程,能建特权容器、能删卷
  面板被攻破和宿主机被攻破是同一件事
  不要直接把面板端口扔公网,要么 VPN 兜住,要么只监听内网
国产面板可以对比着看
  docker 搭建 Dpanel 容器管理面板 那篇讲授权边界讲得比较细
  DPanel 是自定义非商业授权,商用要买,个人自用随便用

12. 权限:把用户加进 docker 组

普通用户敲 docker ps 报权限错误,解法就一条命令:

sudo gpasswd -a $USER docker
newgrp docker

newgrp 这步不能省
  改的是组数据库,当前这个已经登录的 shell 不会自动知道
  忘了这步的现象是「命令还是报同样的错」,很多人以为上面那条没生效
  重新登录一次也一样
docker 组基本等于免 sudo
  能进这个组,就能通过挂 socket 起特权容器把宿主机根目录挂进去
  只把确实需要用 Docker 的账号加进去
  别图省事 chmod 666 /var/run/docker.sock,那是把整个守护进程对全机开放
报的是 permission denied 但 daemon 明明在跑
  这两种报错长得像,根因完全不同:
  connect: permission denied 是 socket 权限问题,加组
  Cannot connect to the Docker daemon 是守护进程没起来或者 socket 路径不对
  详细区分见 Docker 常见问题排查 那篇

💡 补充几个容易忽略的:
用官方脚本装最省事,但别在生产机上随手跑
  脚本会把仓库配置、软件源、启动服务一次性全改掉
  想看清每一步做了什么就手动装,或者在测试机上先验一遍
国内机器先想清楚要不要配加速
  配了就得知道配的是哪几个地址,加速源会挂,要能自己换
生产环境镜像一律钉版本
  nginx:1.27.5 而不是 nginx:latest
  latest 变了不会通知你,重启一次拉到的可能就是另一个版本
容器的日志在宿主机上是 json 文件
  不是 /var/log 下面,是 /var/lib/docker/containers 里
  这个目录不做轮转,磁盘满了第一个被撑爆的就是它
Docker Desktop 和服务器上的 Docker 不是一回事
  Mac 和 Windows 上的 Desktop 有图形界面、能一键起虚拟机
  但生产环境用的永远是服务器上的原生 Docker,行为有差异,别拿 Desktop 的经验套
镜像瘦身是有收益的
  生产镜像用 -slim 或 -alpine 变体,拉取快、攻击面小
  代价是某些系统工具没有,需要的时候再手动装

🔥 一句话总结:装 Docker 用官方 get.docker.com 脚本,装完记得 systemctl enable docker;国内机器在 daemon.json 里配多条 registry-mirrors,注意加速源只是缓存、第一次照样慢;镜像只读、容器可写、仓库存镜像,这三个词分清后面都通顺;容器跟着主进程走,主进程一退容器就停,排查先看 docker ps -a 再看 docker logs;进容器日常用 docker exec -it 而不是 attach;普通用户用不了 Docker 就加进 docker 组并记得 newgrp docker,但要清楚这个组基本等于免 sudo。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!