Docker 生命周期
Docker 从镜像管理到容器运行的全生命周期
客户端 Client
docker-cli:客户端通过命令行工具与 Docker 主机通信
常用命令:
- docker pull redis:从 Registry(镜像市场)拉取 Redis 镜像。
- docker run redis:运行 Redis 容器。
- docker build xxx:根据 Dockerfile 构建镜像。
- docker push xxx:将镜像推送到 Registry。
Docker 主机 Docker Host
- Docker Daemon:Docker 守护进程,负责处理来自客户端的命令并与操作系统交互。
- Containers (容器):运行中的实例,通过镜像创建,容器是独立的运行环境。
- Images (镜像):容器的只读模板,包含运行应用所需的文件和环境。
镜像仓库 Registry
- 公共或私有镜像市场:例如 Docker Hub,存储和管理镜像。
- 常见镜像:
- MySQL、NGINX、Redis 等常用服务镜像。
- 基础镜像如 Ubuntu 和 OpenJDK。
数据流动关系
- 从客户端通过 docker pull 下载镜像到主机
- 主机使用镜像运行容器 docker run
- 本地构建的镜像通过通过 docker push 推送到 Registry
理解容器
传统部署
应用直接运行在操作系统上,每个应用依赖于操作系统,并共享硬件资源。
问题:
- 应用之间容易产生依赖冲突(例如库版本不兼容)
- 部署效率低,环境搭建复杂
- 扩展性差,一个应用的问题可能影响整个系统
虚拟化部署
使用 Hypervisor(虚拟机管理器)在一台物理机上运行多个虚拟机。每个虚拟机都有自己的操作系统,应用运行在其上的独立环境中
优点:
- 隔离性高,虚拟机之间互不干扰
- 提供硬件资源利用率
问题:
- 资源开销大:每个虚拟机需要运行独立的操作系统
- 启用慢:虚拟机启动需要加在完整的操作系统
- 效率低下:资源占用高
容器部署
容器通过共享主机的操作系统(OS Kernel)实现轻量化隔离。应用与其依赖的库、文件等打包成独立的容器镜像运行在容器运行时(如 Docker)。
优点:
- 轻量化:不需要单独的操作系统,容器共享宿主机的内核
- 快速启动:容器启动速度比虚拟机快
- 高效利用资源:容器之间隔离性高,但资源占用比虚拟机低
- 跨平台一致性:容器运行环境保证“开发环境和生产环境一致”
- 便捷部署:镜像可以快速分发和部署,实现应用的版本管理和管理
安装 Docker
参考官网:CentOS | Docker Docs
先删除旧版本 Docker
sudo dnf remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine
配置 Docker 仓库
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装 Docker
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
启动 Docker
sudo systemctl enable --now docker
该指令会每次开机时自动启动 docker 服务,如果只是启动 docker,可以执行以下指令
sudo docker run hello-world
Docker 实践操作
实验:启动 nginx,并将它首页改成自己的页面,发布出去,让所有人使用
步骤:下载镜像 -> 启动容器 -> 修改页面 -> 保存镜像 -> 分享社区
下载镜像相关指令:
docker search 检索
docker pull 下载
docker images 列表
docker rmi 删除
docker rmi
删除指令中,可以通过docker rmi:latest
删除指定 tag 的镜像,如果不指定版本包,会默认删除 docker rmi xxx:latest
版本号为latest
的,也可以通过docker rmi 7c045cd63280
删除指定 IMGAE ID 的镜像。
启动容器相关指令:
docker run 运行
docker ps 查看
docker stop 停止
docker start 启动
docker restart 重启
docker stats 状态
docker logs 日志
docker exec 进入
docker rm 删除
start,stop,restart,rm 指令可以通过 docker ps -a
指令查看到的 CONTAINER ID (容器 ID 不需要全部,只需要前缀的一部分,表示唯一)或者 NAMES (容器名)进行操作
比如docker start 5b46
和 docker stop confident_driscoll
,这些都是对案例中 nginx 镜像的操作
通过 docker rm
指令完成删除容器记录,但是正在运行的容器是不允许删除的,会 container is running: stop the container before removing or force remove
错误,如果要强制删除正在运行的进行,需要执行docker rm -f
如果要一次性删除所有容器,需要先查询所有容器的 ID,
docker ps -aq
,根据这些 ID 再进行删除,整合在一起,就是docker rm -f $(docker ps -aq)
案例:docker run -d --name mynginx -p 8088:80 nginx
案例执行的指令意思是后台启动自定义名为 mynginx 的 nginx 容器,并将容器 80 端口映射到主机 8088 端口(如果无法正常启动,需要检查云服务器的安全组设置); 需要注意的是,80 端口是容器的,所以可以同时将多个容器的 80 端口映射到主机上,但是 8088 端口是主机的,是唯一的,所以只能是多个容器的 80 端口映射到主机的不同端口上,而不是映射到同一个端口上。
docker exec -it my-nginx /bin/bash
根据 Docker Hub Nginx 的介绍,默认首页位于
/usr/share/nginx/html
以交付模式进入 Docker 容器的 bash 控制台,进入 Docker 容器发现,镜 像中的 Linux 系统为了轻量化,只有 Linux 系统,甚至连 Vim 相关指令都没有。因此,为了修改 Nginx 的静态页面,echo
指令修改静态页面
echo "<h1>Hello World</h1>" > index.html
最后通过exit
退出容器
docker commit 提交
docker save 保存
docker load 读取
docker commit -m "uplate nginx index.html" my-nginx my-nginx:v1.0
Docker 提交操作类似 Git 的,提交完容器后,能用docker images
本地镜像指令中发现通过commit
指令创建的的新镜像
docker save -o mynginx.tar my-nginx:v1.0
docker load -i mynginx.tar
save
将 Docker 本地镜像保存成一个 tar 格式的压缩包,load
将 Docker 读取镜像压缩包,并存储在本地镜像库
docker login
docker tag
docker push
Docker 存储
Docker 容器的可写层是临时的,若容器删除,数据也会随之丢失,因此,Docker 提供了以下机制来实现数据持久。
绑定挂载 Bind Mount
docker run -d --name my-nginx -v /app/nghtml:/usr/share/nginx/html -p 8088:80 nginx
主机映射到容器中
通过run
的-v
选项,将容器的/usr/share/nginx/html
挂载到主机的/app/nghtml
,如果主机还没该文件夹,执行执行时会自动创建文件夹。容器启动成功后,如果进入容器的/usr/share/nginx/html
中,其实是进入了主机的/app/nghtml
,所以在容器对html
文件夹进行操作,实际就是对nghtml
进行操作
将主机的目录或设备挂载到容器内类似于我们将一个 U 盘插入到主机中并访问其内容。这种方式模拟了直接将外部存储设备连接到主机的操作。
在 Docker 中,绑定挂载(Bind Mount)实现了类似的概念:
- 宿主机的某个目录(或设备,如 U 盘)被挂载到容器中。
- 容器访问这个目录,就像访问自己的文件系统一样。
- 实际数据存储在宿主机上,而不是容器的存储层。
卷映射 Volume
docker run -d --name my-nginx -v ngconf:/etc/nginx nginx
docker volume create 创建
docker volumne inspect 查看配置
docker volumne rm 删除
docker volumne ls 查看
容器映射到主机中
与绑定挂载指令类似,唯一不同的是,绑定挂载指令中是指定主机的哪个路径,而卷映射指令是指定哪个卷,Docker 映射卷存储在主机的/var/lib/docker/volumes/
中,容器映射数据都在每个卷的_data
文件夹中
- 数据卷的本质是将宿主机的一个目录绑定到容器内的某个目录。
- 容器的数据不是直接映射到主机上,而是 容器通过挂载点访问数据卷存储的数据。
区别
特性 | 数据卷(Volume) | 绑定挂载(Bind Mount) |
---|---|---|
管理方式 | Docker 自动管理 | 用户显式指定宿主机路径 |
存储位置 | Docker 默认路径(如 /var/lib/docker/volumes ) | 用户定义的宿主机路径 |
持久化 | 支持,独立于容器生命周期 | 支持,与宿主机数据路径一致 |
跨容器共享 | 支持,通过同一数据卷实现 | 通过挂载同一宿主机路径实现 |
实时同步 | 容器层与卷之间的操作需要通过挂载点交互 | 容器与宿主机路径之间实时同步 |
灵活性 | 专注于容器化环境的存储 | 灵活,可挂载任意宿主机路径或设备 |
权限控制 | 由 Docker 管理 | 依赖宿主机文件权限 |
性能 | 更高,特别是对于大量 I/O 操作 | 性能取决于宿主机路径所在的文件系统 |
指令 | docker run -d --name my-nginx -v ngconf:/etc/nginx nginx | docker run -d --name my-nginx -v /app/nghtml:/usr/share/nginx/html -p 8088:80 nginx |
Docker 网络
Docker 网络默认是 bridge 桥接模式,安装 Docker 后会在主机中创建名为docker 0
的网络(通过ip a
指令查看 IP 地址),Docker 的每个容器会加入这个网络环境,每个容器 Docker 都会再分配 IP(通过docker inspect
指令查看容器配置)。容器连接到 docker0 网桥,容器之间可以通过 IP 通信。容器可以通过宿主机的网络接口访问外部网络,但外部无法直接访问容器,除非映射端口(-p 或 --publish 参数)。
Docker 为每个容器分配了唯一 IP,使用的是容器 IP + 容器端口可以互相访问
桥接模式的缺点:
- 默认情况下,容器与外部网络隔离:容器默认只能通过宿主机 NAT 转换访问外部网络,外部网络无法直接访问容器内部的服务,除非手动配置端口映射(使用 -p 或 --publish 参数)
- 网络性能开销:桥接模式下,容器的网络流量必须经过 docker0 网桥。宿主机通过 NAT 转换将容器的请求路由到外部网络,增加了额外的网络层处理。
- IP 地址分配:默认情况下,Docker 会为桥接网络分配一个子网(如 172.17.0.0/16)。如果宿主机所在网络的 IP 范围与 Docker 的默认子网冲突,可能会导致网络通信问题。
- 容器间通信的隔离性较低:同一桥接网络下的容器可以通过 IP 直接互相访问,没有额外的隔离机制。
- 动态配置复杂:桥接模式在动态网络环境中(例如容器频繁启动和停止时)可能需要额外管理,特别是当多个容器需要不同的网络配置时。
- 安全性不足:桥接模式默认允许所有容器互相通信。没有内置的防火墙规则或访问控制策略。
通过docker network ls
可以查看 Docker 的网络模式,默认已经创建了 bridge,host 以及 none 三种模式,默认网络模式为 bridge 桥接模式。
也可以通过docker network create mynet
自定义网络, 使用自定义网络之后,容器名就是可以被访问的稳定域名,但是运行容器时需要--newtwork
参数指定自定义网络, docker run -d --name my-nginx --network mynet nginx
。
多个容器都指定同一个自定义网络之后,可以通过各自容器名作为域名进行访问,比如 docker1 可以通过curl http://docker2:80
访问 docker2 的 nginx 静态页面
案例:Redis 主从同步集群
效果图:
redis01 创建指令
docker run -d --name redis02 \
-p 6380:6379 \
-v '/Users/xx/Desktop/DockerMount/rd2':'/bitnami/redis/data' \
-e REDIS_REPLICATION_MODE=slave \
-e REDIS_PASSWORD=123456 \
--network mynet \
bitnami/redis
redis02 创建指令
docker run -d --name redis02 \
-p 6380:6379 \
-v '/Users/mayerjohnson/Desktop/DockerMount/rd2':'/bitnami/redis/data' \
-e REDIS_REPLICATION_MODE=slave \
-e REDIS_PASSWORD=123456 \
-e REDIS_MASTER_PASSWORD=123456 \
-e REDIS_MASTER_HOST=redis01 \
--network mynet \
bitnami/redis
测试的时候,只能在 redis01 中进行写入,redis02 中只能读取
总结
Docker 的主要功能和在使用容器时的关键配置,包括命令、网络、存储、环境变量、端口映射等内容
- 容器与命令:docker 通过命令行工具(如 docker run、docker stop 等)管理容器的生命周期
- 网络
- 容器网络配置:容器追案可以通过网络进行通信,Docker 提供了几种常见的网络模式
- Bridge 桥接模式:默认网络模式,通过 docker0 网桥互相通信
- Host 主机模式:直接使用宿主机的网络
- None 无网络模式:容器没有任何网络连接
- 自定义网络:用户可以定义自己的网络,并配置容器的网络环境
- 端口映射
- 容器通过端口映射将服务暴露给外部
- 容器网络配置:容器追案可以通过网络进行通信,Docker 提供了几种常见的网络模式
- 存储:数据持久化
- Volume 数据卷:由 Docker 管理,适合长久保存数据。通过多个容器共享同一个数据卷的方法实现数据共享
- Bind Mount 绑定挂载:绑定宿主机的目录或者文件到容器
- 环境变量:定义容器运行时的环境变量
- 环境变量常用于容器化的应用程序,例如数据库连接字符串或 API 密钥
Docker Compose
启动指令: docker compose -f compose.yaml up -d
创建 compose.yaml
name: myblog-test
services:mysql:container_name: myblog-mysqlrestart: alwaysimage: mysql:8.0environment:MYSQL_ROOT_PASSWORD: 123456MYSQL_DATABASE: myblogMYSQL_USER: userMYSQL_PASSWORD: 123456ports:- "3306:3306"networks:- blogvolumes:- mysql_data:/var/lib/mysql- /Users/mayerjohnson/Desktop/DockerMount/myconfig:/etc/mysql/conf.dwordpress:container_name: myblog-wordpressimage: wordpressports:- "8080:80"environment:WORDPRESS_DB_HOST: myblog-mysqlWORDPRESS_DB_USER: userWORDPRESS_DB_PASSWORD: 123456WORDPRESS_DB_NAME: myblogvolumes:- wordpress:/var/www/htmlnetworks:- blogdepends_on:- mysqlvolumes:mysql_data:driver: localwordpress:driver: localnetworks:blog:driver: bridge
执行 compose.yaml
控制台输出
~/Desktop/DockerMount/compose-file ❯ docker compose -f compose.yaml up -d 15:45:08
[+] Running 5/5✔ Network myblog-test_blog Created 0.0s✔ Volume "myblog-test_wordpress" Created 0.0s ✔ Volume "myblog-test_mysql_data" Created 0.0s✔ Container myblog-mysql Started 0.2s✔ Container myblog-wordpress Started
Docker run 细节
基本语法:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
1. 容器运行模式
- -d:以 后台模式 运行容器(detached 模式)。容器启动后不会绑定到当前终端。
- -it:
- -i:保持容器的标准输入打开。
- -t:分配一个伪终端(TTY)。
2. 容器名称
- –name:指定容器的名称。
docker run --name mycontainer nginx
如果不指定,Docker 会随机生成一个名称。
3. 端口映射
- -p 或 --publish:将容器内部的端口映射到主机上的端口。
docker run -p 8080:80 nginx
- -P 或 --publish-all:自动随机映射容器的所有暴露端口到主机。
4. 挂载卷
- -v 或 --volume:将主机目录挂载到容器。
docker run -v /host/path:/container/path nginx
- –mount:新格式的挂载方式,支持更复杂的挂载配置。
docker run --mount type=bind,source=/host/path,target=/container/path nginx
5. 环境变量
- -e 或 --env:设置环境变量。
docker run -e ENV_VAR=value nginx
- –env-file:从文件中加载环境变量。
docker run --env-file env.list nginx
6. 网络
- –network:指定容器使用的网络模式。
docker run --network bridge nginx
7. 重启策略
- –restart:设置容器的重启策略。 - no(默认):容器退出后不重启。 - on-failure:当容器因非零状态退出时重启。 - always:无论退出原因,始终重启。
docker run --restart always nginx
8. 限制资源
- –memory 或 -m:限制容器的内存使用。
docker run -m 512m nginx
- –cpus:限制容器的 CPU 使用量。
docker run --cpus 1.5 nginx
9. 删除容器
- –rm:容器退出时自动删除。
docker run --rm nginx
10. 工作目录
- -w 或 --workdir:指定容器中的工作目录。
docker run -w /app nginx
Docker 连接超时问题
执行 Docker 指令时可以出现请求接口超时的问题
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)Error response from daemon: Get "https://index.docker.io/v1/search?q=nginx&n=25": dial tcp 208.101.60.87:443: i/o timeout
解决办法一:更新网络配置
对于 Alibaba Cloud Linux3 系统,网络服务使用 NetworkManager,重启网络服务指令为sudo systemctl restart NetworkManager
,每次重启网络会重置/etc/resolve.conf
配置文件
因为resolv.conf
文件是由 /etc/sysconfig/network-scripts/ifcfg-eth0
生成的,所以可以更改ifcfg-eth0
配置文件,也可以更改resolv.conf
读写权限
sudo chattr +i /etc/resolv.conf %% 设置只读 %%
sudo chattr -i /etc/resolv.conf %% 取消只读权限 %%
在resolv.conf
配置文件新增
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 144.144.144.144
参考:
- 解决 Linux 重启后 resolv.conf 重置问题-阿里云开发者社区
- 修改/etc/resolve.conf 重启 NetworkManager 之后自动还原-CSDN 博客
解决办法二:Docker 镜像加速
在/etc/docker/daemon.json
配置文件中设置镜像加速源
{"registry-mirrors": ["https://registry.docker-cn.com","https://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn"]
}
如果这些镜像加速链接都不行,只好去阿里云申请 Docker 镜像加速服务,生成个人的镜像加速链接
最后重读配置并重启服务
sudo systemctl daemon-reload
sudo systemctl restart docker
阿里云镜像加速有一整套指令,可以直接复制使用
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{"registry-mirrors": ["https://[个人id].mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
参考:
- Docker 镜像加速 | 菜鸟教程
- 配置镜像加速器_容器镜像服务(ACR)-阿里云帮助中心
- 尚硅谷3小时速通Docker教程,名师带练docker部署到实战!_哔哩哔哩_bilibili