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 确保依赖服务 “可用”(不只是容器启动)
  • healthchecktest 需根据服务类型自定义(如 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)。
  • 存储持久化:数据库类服务需挂载卷,避免重启后数据丢失。
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐