Docker大全,包你满意
1、Docker介绍
什么是容器化技术
容器共享主机内核,轻量、隔离且高效,不像虚拟机需要完整的操作系统
下图展示了 Docker 容器的基本架构:
- 上层 是多个容器(App A~F),每个容器独立运行一个应用。
- 中间层 是 Docker,负责管理这些容器。
- 底层 是主机操作系统(Host OS)和基础设施,为容器提供硬件和系统支持。
Docker使用前提
- Docker 并非是一个通用的容器工具,它依赖于已存在并运行的 Linux 内核环境。
- Docker 实质上是在已经运行的 Linux 下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的 Linux 主机
- Docker 必须部署在 Linux 内核的系统上。如果其他系统想部署 Docker 就必须安装一个虚拟 Linux 环境,例如windows系统想用就要开启Hyper-V服务或者安装一个Linux虚拟机。
Docker 的应用场景
- 微服务架构:每个服务独立容器化,便于管理和扩展。
- CI/CD流水线:与 Jenkins/GitLab CI 集成,实现自动化构建和测试。
- 开发环境标准化:新成员一键启动全套依赖服务(如数据库、消息队列)。
- 云原生基础:Kubernetes 等编排工具基于 Docker 管理容器集群。
Docker核心优势
- 跨平台一致性:解决"在我机器上能跑"的问题,确保开发、测试、生产环境一致。
- 资源高效:容器直接共享主机内核,无需虚拟化整个操作系统,节省内存和 CPU比虚拟机占用更少的资源。
- 快速部署:秒级启动容器,支持自动化扩缩容。
- 隔离性:每个容器拥有独立的文件系统、网络和进程空间。
2、帮助命令
docker version #现实版本信息
docker info #现实系统信息
docker 命令 --help #帮助命令
3、镜像命令
什么是镜像
- 镜像是一个只读的模板,包含了运行应用所需的所有内容:代码、运行时、库文件、环境变量和配置文件。
- 定义了容器的运行环境(如操作系统、软件配置等)。
- 通过分层存储(Layer)优化空间和构建速度。
镜像的获取
- Dockerfile创建
- 从远程仓库中拉取
什么是仓库
仓库是存储和分发镜像的地方,可以包含一个镜像的多个版本。
分类:
- 公共仓库:如 Docker Hub,任何人都可以使用
- 私有仓库:企业内部搭建,用于存储私有镜像
- 官方仓库:由软件官方维护的镜像仓库
Registry vs Repository:
- Registry:仓库注册服务器,如 Docker Hub
- Repository:具体的镜像仓库,如 nginx、mysql
docker images 查看本地主机上所有镜像信息
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756blae65 4 months ago 13.3kB
# 解释
镜像的仓库源/标签/id/创建时间/大小
# 可选项
-a,-all #列出所有镜像 docker imgaes -a
-q,-quiet #只显示镜像的id
-aq #列出所有镜像的id
#补充
镜像下载后存放在 /var/lib/docker。
Docker 相关的本地资源存放在 /var/lib/docker/ 目录下,其中 containers 目录存放容器信息,image 目录存放镜像信息,overlay2 目录下存放具体的镜像底层文件。
docker search 搜索镜像
docker search mysql
# 可选项
--filter=STARS=3000 #搜索出来的镜像就是STARS大于300的 docker search mysql --filter=SRARS=3000
#默认情况下docker 是去访问docker hub查询镜像,但是国内无法访问
docker search docker.1ms.run/nginx
#使用国内镜像地址查询
docker pull 拉取/下载镜像
docker pull 镜像 #默认下载最新版本
#docker pull nginx
docker pull 镜像[:tag] #下载指定版本
#docker pull mysql:5.7
docker tag 为本地镜像添加新标签
格式:docker tag 名称:[标签] 新名称:[新标签]
docker tag nginx:latest nginx:web #复制了一份镜像,并把新的镜像的nginx的标签:latest换成了web
docker tag nginx:latest newnginx:newweb #复制了一份镜像,并把新的镜像的nginx的标签:latest换成了newweb,并把镜像名称也换成饿了newnginx
docker rmi 删除镜像
docker rmi ngixn:1.8 #删除指定镜像标签的那个镜像
docker rmi -f 镜像id #删除指定镜像
docker rmi -f 镜像id 镜像id 镜像id #删除多个指定镜像
docker rmi -f $(docker images -aq) #删除全部镜像
docker inspect 镜像id 获取镜像详细信息
docker inspect centos
4、容器命令
什么是容器
Docker 容器是一个轻量级、可移植、自给自足的软件环境,用于运行应用程序。
Docker 容器将应用程序及其所有依赖项(包括库、配置文件、系统工具等)封装在一个标准化的包中,使得应用能够在任何地方一致地运行。
容器是操作系统级别的虚拟化,不需要运行完整的操作系统,启动和运行更为高效。
镜像与容器的关系
- 镜像(Image):容器的静态模板,包含了应用程序运行所需的所有依赖和文件。镜像是不可变的。
- 容器(Container):镜像的一个运行实例,具有自己的文件系统、进程、网络等,且是动态的。容器从镜像启动,并在运行时保持可变。
创建容器
格式:docker create [选项] 镜像
docker create -it nginx:latest /bin/bash #-it实现交互
新创建的容器默认处于停止状态,不运行任何程序,需要在其中发起一个进程来启动容器。
新建容器并启动 (一般直接使用这个run而不用create)
docker run [可选参数] image #run相当于先create再start
#参数说明
--name="Name" 容器名字 tomcat01,tomcat02 用来区分容器
--d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 8080:8080
-p ip :主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
容器端口
-p 随机指定端口
exit #从容器退回主机
# docker run -d --name nginx01 -p 3344:80 nginx
# docker run -it --rm tomcat:9.0 --rm一般用于测试,用完即删。
检查本地是否有指定镜像,如果有则直接使用本地镜像创建容器,如果没有则从仓库拉取镜像再创建容器。
docker ps [可选参数] 列出所有运行的容器
docker ps #列出当前所有运行的容器
docker ps -a #列出当前和曾经运行过的容器
docker ps -n=? #显示最近的容器
docker ps -q #只显示容器的编号
退出容器
exit #直接停止容器并退出
ctrl + p + q #容器不停止退出
删除容器
docker rm 容器id #删除指定容器,不能删除正在运行的容器
docker rm -f 容器id #可以删除正在运行的id
docker rm $(docker ps -aq)#删除所有的容器
docker ps -aq | xargs docker rm #删除所有容器
启动和停止容器
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前正在运行的容器
docker kill 容器id #强制停止当前容器
查看日志,进程信息,容器元数据
docker logs -t --tail 10 容器id
# -tail n 显示的日志条数 -t 显示时间戳
docker top 容器id
#显示进程信息
docker inspect 容器iod
进入容器
# 容器的进入,需要进入容器进行命令操作时,可以使用 docker exec 命令进入运行着的容器。
# 进入容器前,确保容器正在运行
docker exec -it 2592d3fad0fb /bin/bash
格式:docker exec -it 容器ID/名称 /bin/bash
-i # 选项表示让容器的输入保持打开;
-t # 选项表示让 Docker 分配一个伪终端。
exit
#退出容器后,容器仍在运行
docker attach 容器id
#与exec的区别
docker exec 进入容器后开启一个新的终端,可以在里面操作(常用)
docker attach 进入容器正在执行的终端,不会启动新的进程!
拷贝
touch yy.txt
echo 123 > yy.txt
#复制到容器中
docker cp 主机路径 容器id:容器内路径
docker cp yy.txt 2592d3fad0fb:/opt/
#从容器复制文件到主机
docker cp 容器id:容器内路径 目的主机路径
docker cp 2592d3fad0fb:/opt/yy.txt ~/abc123.txt
提交/保存/加载
docker commit -a="作者" -m="备注" 容器id 镜像名:[TAG]
eg:docker commit -a="rfh" -m="哈喽" 7eadadwadwa mytomacat:2.0, 版本号为::2.0
# 将容器id为:7eadadwadwa的容器复制保存为一个新的镜像,名为:mytomacat, TAG为:2.0
docker save -o 压缩包名(mytomacat.tar) 镜像名:版本号(mytomacat:2.0)
# 将mytomacat:2.0保存为一个压缩包:mytomacat.tar
docker load -i mytomacat.tar
# 将mytomacat.tar解压成镜像
5、容器数据卷
定义
-
容器之间有一个数据共享的技术,docker容器中产生的数据,同步到本地。
-
这就是卷技术,目录的挂载,将我们容器内的目录挂载到linux上面。
-
容器的持久化和同步操作,容器间也是可以数据共享的。
使用方式
方式一:直接使用命令来挂载 -v
# 使用数据卷
docker run -it -v 主机目录:容器内目录
eg: docker run -it -v /home/ceshi:/home centos /bin/bash
docker inspect id查看详细信息:
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi", # 主机内地址
"Destination": "/home", # 容器内地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
# 双向的,无论改变容器内还是主机内的,另一方都会自动同步 .
# 当容器停止后,在主机内修改挂载文件,再次启动后容器内的相对文件会自动同步.
具名挂载和匿名挂载
# 具名和匿名挂载
# 匿名挂载:-v 只写了容器内路径,没用写容器外的路径
# 具名挂载:-v 都写了
docker run -d -P --name nginx01 -v /ect/nginx nginx 匿名挂载
docker run -d -P --name nginx02 -v juming-nginx:/ect/nginx nginx 具名挂载
docker volume ls
DRIVER VOLUME NAME(卷名)
local 1e5ef9854fd5cf80623a1f4661d6d613d7297fc8f638fb62c27d4457396d8cf9 #匿名
local juming-nginx #具名
#卷名都在 /var/lib/docker/volumes里面
docker run -d -P --name nginx01 -v juming-nginx:/ect/nginx:ro nginx
docker run -d -P --name nginx01 -v juming-nginx:/ect/nginx:rw nginx
ro:只读 rw:读写 默认是rw
#ro说明容器内部无法操作,只能通过宿主机操作bb
方式二:数据卷容器
docker run -it --name docker01 user/centos:1.0 /bin/bash
# 创建一个容器docker01
docker run -it --name docker02 --volumes-from docker01 user/centos:1.0
# --volumes-from 同步docker01里面的所有卷内容
-
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没用容器使用为止。
-
但是一旦持久化到了本地,这个时候,本地的数据是不会删除的。
6、Dockerfile
定义
-
Dockerfile 就是用 来构建docker镜像的构建文件.
-
1.编写一个Dockerfile文件
-
2.docker build 构建成为一个镜像
-
3.docker run 运行镜像
-
4.docker push 发布镜像(DockerHub、阿里云镜像仓库)
特点:
-
1.每个保留关键字(指令)都必须是大写字母
-
2.执行从上到下执行
-
3.# 表示注释
-
4.每一个指令都会创建一个新的镜像层
Dockerfile文件中的常用指令
FROM #指定基础镜像
LABEL #添加镜像元数据,推荐键值对
RUN #构建镜像时需要运行的命令
ADD #copy文件,会自动解压ls
WORKDIR #镜像的工作目录
VOLUME #设置卷,挂载的目录
EXPOSE #指定对外端口
CMD #指定容器启动时要运行的命令,可以被docker run 的命令行参数指定的指令覆盖,如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
# eg:dockerfile 里面
FROM centos
CMD /bin/bash
CMD ["ls","-a"] 当build的时候只有这一条CMD命令会被执行
当docker run dockerfile -l 时,-l会把CMD中ls -l命令所覆盖,但是-l并不是个命令,所以会报错。
ENTRYPOINT #指定容器启动时要运行的命令,不会被docker run 的命令行参数指定的指令覆盖,如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
# eg:dockerfile 里面
FROM centos
ENTRYPOINT /bin/bash
ENTRYPOINT ["ls","-a"] 当build的时候只有这一条ENTRYPOINT命令会被执行
当docker run dockerfile -l 时,-l不会把CMD中ls -l命令所覆盖,而是追加,所以会执行ls -al
ONBUILD #触发指令,当该镜像被用作另一个构建过程的基础时,触发
COPY #将文件拷贝到镜像中
ENV #构建的时候设置环境变量
使用Dockerfile文件
创建dockerfile文件
FROM centos
LABEL authors="rfh"
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
#更换yum源,镜像默认官方yum源,更换阿里云源,不然太慢或无法连接
RUN yum -y install vim net-tools
EXPOSE 80
CMD /bin/bash
根据dockerfile创建镜像
[root@bogon dockerfile]# docker build -f dockerfile-centos -t mycentos:1.0 .
#完成后镜像就有了
[root@bogon dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.0 8fc808d28b73 45 seconds ago 298MB
根据镜像创建容器
[root@bogon dockerfile]# docker run -it mycentos:1.0
#vim 和ifconfig指令都下载了,所以都能使用
#因为ENV MYPATH /usr/local WORKDIR $MYPATH ,所以[root@9a32df936b9a local]# pwd 结果是/usr/local 而不是 /
上传DockerHub
# 先登录DockerHub
docker login -u 账户名 eg:docker login -u superrfh
# 然后上传
docker push 镜像名:[TAG]
到目前为止,Docker命令已经学了很多了,下面这张图更有助于你理解
7、网络
先看实例:
# 运行容器
docker run -d -P --name tomcat01 tomcat
# 查看容器的内部网络地址 ip addr 因为容器里面没有ip addr 指令,所以要先进去下载
docker exec -it tomcat01 /bin/bash
apt update && apt install -y iproute2 等待完毕即可ip addr
# 会有一个 eth0@if47 ip地址,docker分配的
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
46: eth0@if47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 退出容器,ip daar 会发现有下面这个 47: vethab2904e@if46跟46: eth0@if47是一对!
47: vethab2904e@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 22:de:d4:ff:bd:2e brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::20de:d4ff:feff:bd2e/64 scope link
valid_lft forever preferred_lft forever
#思考,linux能不能从docker ping 通docker容器内部, 答案是可以的。
ping 172.17.0.2
原理:
- 只要安装了docker,就会有一个网卡docker0
- 每创建一个docker容器,所有的容器不指定网络的情况下,都是docker0路由的,docker0会给容器分配一个默认的ip
- 桥接模式,使用的技术是 veth-pair 技术, veth-pair就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端连着彼此
自定义网络
docker network ls # 查看网络
NETWORK ID NAME DRIVER SCOPE
dfc02b4de4ce bridge bridge local
65ba1f8606d7 host host local
2944bf6252d6 none null local
# bridge :桥接 docker (默认) none :不配置网络 host :和宿主机共享网络
docker network -d bridge mynet #创建自己的网络
docker network inspect会发现多了下面内容 mynet #查看网络的信息
docker run -d -P --name tomcat01 --net mynet tomcat #使用自定义网络
docker run -d -P --name tomcat02 --net mynet tomcat #使用自定义网络
#再inspect会发现多了下面内容
"Containers": {
"967cb8fd4727daaae749cbf53dcccb19452a3a03a8d96eab363f11e47f447053": {
"Name": "tomcat02",
"EndpointID": "1c83a3ff406f50c1d10c0171eb52d74dd369c9711825705b7da65b63e730b9f6",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"ed44142a2c9e9712fe7d5d5925cedd28ed3c9f74ab192e7c623f03ec6928bda2": {
"Name": "tomcat01",
"EndpointID": "d66591239f5aa086f137544b7baa66aa745e4e8eb01e44777c4a6ca40eedfbf9",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
比较:
- 在默认网络docker0中,只能:ping 172.18.0.2
- 而在自定义网络里,可以直接ping容器名:ping tomcat02
两个网络下的容器之间不能直接连通,但是可以打通连接
# docker0下有docker01、docker02容器,test-net下有docker-net-01、docker-net-02容器
# docker01 不能连通 docker-net-01
# 通过connect打通docker01 - test-net
# docker network inspect test-net会发现,多了docker01
"Containers": {
"1ba20acc3c40337ea97289b4b96dfa26e7f69fee83092e11645a5883d7b7c5f9": {
"Name": "docker-net-02",
"EndpointID": "966dca8e4389c2f589253e437184a09a7dc1f6625b59921e7dc7722f724fd3b6",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"24eb22e9446e175a25f4ab70dd4fd53a1d5762e5f57d0cc7c089cdeb2fbe31b2": {
"Name": "docker01",
"EndpointID": "8ba3b64886f13cad2b6f05801bc9385cc783113dad66bd38b885baa28b3a94cf",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": ""
},
"6c7cbd8f9ef0edd3f13b638d39b67aa0a43bdb9e58a327ce4ec88c9ecc4e8b33": {
"Name": "docker-net-01",
"EndpointID": "2977445eff0f37478b75e358fd033c263b8eaed3a7020dcc42c3a1ecac44e6e4",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
# 打通之后就可以连接了
8、compose 容器编排
定义
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
compose 常用命令
docker-compose up # 启动所有docker-compose服务 ,可选项 -d 后台运行
docker-compose down #停止并删除容器,网络,卷,镜像
docker-compose exec yml里面的服务id #进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps #展示当前docker-compose编排过的运行的所有容器
docker-compose top #展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id #查看容器输出日志
docker-compose restart/start/syop
yml文件示例
#实例:
name: "myapp" # name:定义应用程序使用的名字(不指定该属性,则应用程序名默认使用yml文件所在目录名)每个名字只能包含小 写字母、数字、破折号(-)和下划线(_),且必须以小写字母或数字开头
services: # 定义应用程序所需的服务集合
appDB:
# image: mysql # 服务所使用的本地镜像名称或id
build: # 利用Dockerfile自定义构建镜像 用image就不能用这个
context: ./db # Dockerfile 使用的上下文目录
ports: # 服务使用的端口映射
- "3306:3306"
volumes: # 服务使用的数据卷
- ./db/conf,d:/etc/mysql/conf.d
- ./db/data:/var/lib/mysql
- ./db/my.cnf:/etc/mysql/my.cnf
networks: # 服务使用的网络,必须已经存在,一般用下面的网络
- test-net
# environment: # 服务所使用的环境变量
# - MYSQL_ROOT_PASSWORD=123456
env_file: # 服务所使用的环境变量文件,此处替代了environment
- .mysql_env
# 另外还有 expose:
# - "8080" # 服务对外暴露的端口
# depend_on:
# - 依赖的服务名 # 指定本服务所依赖的其他服务,应确保先启动所依赖的服务,后启动当前的服务
command 指定本服务启动后的默认命令
#eg: command: ["java","-jar","myapp.jar"]
networks: # 定义应用程序所使用的网络(网络不存在会自动创建)
test-net:
处理依赖关系
使用编排工具的健康检查机制判断服务是否就绪,只有依赖服务真正可用后才启动当前服务
version: '3.8' //可写可不写,写的话最好去官网查看
services:
# 依赖的服务(如数据库)
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: root
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] # 检查数据库是否可连接
interval: 5s # 每5秒检查一次
timeout: 5s # 检查超时时间
retries: 5 # 重试5次失败则认为不健康
# 依赖db的应用服务
app:
build: .
depends_on:
db:
condition: service_healthy # 仅当db健康时才启动app
关键点:
depends_on配合condition: service_healthy确保依赖服务 “可用”(不只是容器启动)healthcheck的test需根据服务类型自定义(如 HTTP 服务用curl检查接口)
编排启动失败
(1)查看容器日志(最关键)
日志是排查问题的首要依据,需查看失败容器的具体错误信息:
# 查看指定服务的日志(包括历史输出)
docker-compose logs -f 服务名
# 查看最近100行日志
docker-compose logs --tail=100 服务名
常见日志错误提示:
- 连接超时:可能是依赖服务未就绪或网络不通
- 权限错误:容器内用户权限不足(如无法写入文件)
- 配置错误:环境变量、配置文件缺失或格式错误
- 端口占用:容器端口与宿主机或其他容器冲突
(2)检查容器状态
确认容器是 “启动失败” 还是 “启动后立即退出”:
# 查看所有服务状态(Up/Restarting/Exited)
docker-compose ps
状态解读:
CrashLoopBackOff:容器启动后反复崩溃(需看日志找代码或配置问题)ImagePullBackOff:镜像拉取失败(检查镜像地址、仓库权限)Pending:资源不足或调度失败(检查节点资源、污点容忍配置)
(3)针对性解决常见失败场景
YAML 语法错误
- 问题:docker-compose.yml 格式错误(如缩进不一致、冒号后缺少空格、使用 Tab 键缩进等)。
- 现象:启动时直接报错 ERROR: yaml.scanner.ScannerError 或类似语法提示。
- 排查:
用 YAML 校验工具(如 YAML Lint)检查格式。
确保缩进使用空格(2 或 4 个),而非 Tab。
字符串包含特殊字符(如冒号、空格)时需用引号包裹(单 / 双引号均可)。
服务依赖配置错误
问题:depends_on 配置不当,或服务启动顺序不符合依赖关系(如数据库未就绪时应用已启动)。
现象:应用连接数据库失败(如 Connection refused),但单独启动数据库容器正常。
排查:
depends_on 仅保证容器启动顺序,不保证服务就绪,需在应用中添加重试逻辑,或使用 wait-for-it 等工具检测依赖服务可用性。
检查是否遗漏必要的依赖服务配置。
端口 / 路径映射错误
问题:端口被占用(ports 配置冲突),或挂载路径不存在、权限不足。
现象:
端口冲突:ERROR: for xxx Cannot start service xxx: Ports are not available。
路径问题:ERROR: for xxx Cannot start service xxx: error while mounting volume。
排查:
用 netstat -tuln 或 lsof -i :端口号 检查端口是否被占用,修改映射端口。
确保宿主机挂载路径(volumes 中的左侧路径)存在且有读写权限(可手动创建并赋权 chmod 777 路径 测试)。
镜像不存在或拉取失败
问题:本地无指定镜像,且远程仓库拉取失败(如网络问题、镜像名 / 标签错误)。
现象:ERROR: pull access denied for xxx, repository does not exist or may require 'docker login' 或拉取超时。
排查:
检查镜像名和标签是否正确(如 mysql:8.0 而非 mysql:latest,避免标签被意外修改)。
若为私有仓库,执行 docker login 仓库地址 登录。
网络问题:检查代理设置、DNS 配置,或手动 docker pull 镜像名 测试拉取。
环境变量配置错误
问题:environment 或 .env 文件中变量缺失、值错误,或变量引用格式错误。
现象:应用启动后因缺少必要变量报错(如数据库密码错误),或提示 undefined variable。
排查:
检查 .env 文件是否存在于 docker-compose.yml 同目录,变量是否用 KEY=VALUE 格式(无引号,除非值含特殊字符)。
确保 Compose 中引用变量的格式正确(如 ${DB_PASSWORD},而非 $DB_PASSWORD 或 {{DB_PASSWORD}})。
用 docker-compose config 命令验证变量是否正确加载。
网络配置冲突
问题:自定义网络名称冲突、IP 地址段重叠,或服务未加入指定网络。
现象:服务间无法通信(如 ping 不通其他服务),或启动时提示网络已存在。
排查:
检查 networks 配置,确保服务通过 networks 字段加入正确网络。
用 docker network ls 查看现有网络,避免名称重复;必要时删除冲突网络 docker network rm 网络名。
服务间通信应使用服务名作为主机名(如 db 服务可通过 db:3306 访问),而非 IP 地址。
权限不足
问题:宿主机用户无 Docker 操作权限,或容器内进程权限不足(如挂载目录被 root 占用,容器内用普通用户访问)。
现象:Permission denied 错误,或启动时提示 Got permission denied while trying to connect to the Docker daemon socket。
排查:
非 root 用户需加入 docker 组:sudo usermod -aG docker $USER(需重启生效)。
容器内权限问题:在 Dockerfile 中调整用户(USER root 临时测试),或修改宿主机挂载目录权限。
9、容器的重启策略
定义
Docker 容器的重启策略用于控制容器在退出或系统重启时的自动恢复行为,是保障服务高可用的重要机制。以下是 Docker 支持的几种重启策略及其适用场景:
以下是整理后的 Docker 容器重启策略对比表格:
| 策略 | 触发条件 | 典型应用场景 | 备注 |
|---|---|---|---|
| no | 容器退出时不自动重启 | 测试环境、临时任务 | 默认策略 |
| always | 无论退出状态如何都重启(包括手动停止后 Docker 服务重启) | 关键服务(如数据库、Web 服务器) | 可能因手动停止后意外恢复 |
| on-failure | 仅当容器异常退出(非0状态码)时重启 | 需要故障恢复但避免无限重启的服务 | 可设最大重试次数(如 on-failure:3) |
| unless-stopped | 类似 always,但排除手动停止的容器 | 生产环境长期运行服务 | Docker 服务重启后不会恢复手动停止的容器 |
配置方法
(1)启动容器时指定
docker run -d --restart=always nginx # 始终重启
docker run -d --restart=on-failure:5 redis # 异常时最多重启5次:cite[6]:cite[10]
(2)修改运行中的容器
docker update --restart=unless-stopped <容器名或ID>:cite[5]:cite[8]
(3)Docker Compose 配置yaml文件中
services:
web:
image: nginx
restart: unless-stopped
db:
image: postgres
deploy:
restart_policy:
condition: on-failure
max_attempts: 3:cite[1]:cite[9]
注意:
- 避免与 --rm 同时使用:–restart 和 --rm(退出后删除容器)冲突。
- 资源监控:频繁重启可能占用资源,建议为 on-failure 设置重试限制。
- 日志排查:自动重启的容器需结合日志分析根本原因(如 docker logs)。
- 存储持久化:数据库类服务需挂载卷,避免重启后数据丢失。
更多推荐


所有评论(0)