知识库目录
返回知识库
文章大纲
更新于 2026/06/10Docker

Docker

Docker 学习笔记整理版
本文档由原始 Docker 笔记重新整理而来,主要做了这些处理:清理 HTML/字体标签、统一标题层级、把命令整理为代码块、按学习路径重新分章,并对部分高风险示例做了占位符处理。
注意:原文中的示例密码已替换为 <MYSQL_ROOT_PASSWORD>,镜像仓库地址、宿主机 IP 等也尽量使用占位符表示。实际执行时请替换成自己的真实值。

#1. Docker 架构

Docker 主要由以下几个部分组成:

  • Docker Client:客户端,负责向 Docker daemon 发送命令。
  • Docker daemon / dockerd:Docker 守护进程,负责管理镜像、容器、网络、数据卷等对象。
  • Docker Image:镜像,容器运行的模板。
  • Docker Container:容器,由镜像启动出来的运行实例。
  • Docker Network:容器网络。
  • Docker Volume:容器数据持久化方案。
  • Docker Registry:镜像仓库,例如 Docker Hub、阿里云 ACR、私有 Registry。
    Docker 客户端和 Docker 守护进程之间通过 Docker API 通信。通信方式通常是 UNIX Socket,也可以是 TCP 网络接口。
    常见 Docker 客户端包括:
  • Docker CLI
  • Docker Desktop
  • Docker Compose
  • 各语言的 Docker API Client SDK

#2. Docker 镜像与 Dockerfile

#2.1 使用 Dockerfile 构建镜像

Dockerfile 是用来构建 Docker 镜像的文本文件,由一条条指令组成。
构建流程:
编写 Dockerfile -> docker build 构建镜像 -> docker run 启动容器
示例:基于 Ubuntu 镜像安装 net-tools 和 iputils-ping。

dockerfile
1FROM ubuntu:latest2 3RUN apt-get update \4    && apt-get install -y net-tools iputils-ping \5    && apt-get clean \6    && rm -rf /var/lib/apt/lists/*7 8CMD ["/bin/bash"]

构建镜像:

bash
1docker build -t ccby/ubuntu .

查看镜像构建历史:

bash
1docker image history ccby/ubuntu

#2.2 Dockerfile 基础规则

  • Dockerfile 指令通常使用大写,例如 FROM、RUN、COPY、CMD。
  • 第一条有效指令必须是 FROM。
  • 指令按照从上到下顺序执行。
  • #表示注释。

  • 每条指令都会创建一个新的镜像层。

#2.3 常用 Dockerfile 指令

指令作用
FROM指定基础镜像。
RUN构建镜像时执行命令。
COPY从宿主机复制文件到镜像中。
ADD类似 COPY,额外支持自动解压和 URL。一般优先用 COPY。
WORKDIR设置工作目录。
ENV设置环境变量。
EXPOSE声明容器监听端口。
CMD容器启动时默认执行的命令。
ENTRYPOINT容器入口命令,通常用于固定启动程序。

#2.4 镜像优化建议

选择更小的基础镜像
例如使用 Alpine:

dockerfile
1FROM alpine:latest2 3RUN apk add --no-cache python34COPY . /app5CMD ["python3", "/app/app.py"]

合并 RUN 命令,减少镜像层

dockerfile
1RUN apk update \2    && apk add --no-cache python3 curl

清理缓存
Debian / Ubuntu 系镜像:

dockerfile
1RUN apt-get update \2    && apt-get install -y python3 \3    && apt-get clean \4    && rm -rf /var/lib/apt/lists/*

利用 Docker 构建缓存
Docker 构建镜像时会缓存每一层。建议:

  • 不常变化的依赖安装步骤放在前面。
  • 经常变化的业务代码复制步骤放在后面。
  • 先复制依赖清单,例如 package.json、requirements.txt,再安装依赖,最后复制业务代码。
    Node.js 示例:
dockerfile
1FROM node:20-alpine2 3WORKDIR /app4 5COPY package*.json ./6RUN npm ci --omit=dev7 8COPY . .9 10EXPOSE 300011CMD ["node", "server.js"]

#3. Docker 常见命令

#3.1 查看 Docker 信息

bash
1docker info2docker --help3docker system df

#3.2 镜像命令

bash
1# 查看本地镜像2docker images3 4# 查看所有镜像,包括中间层镜像5docker images -a6 7# 只显示镜像 ID8docker images -q9 10# 搜索镜像11docker search nginx12 13# 拉取镜像14docker pull nginx15 16# 删除镜像17docker rmi nginx:latest18 19# 强制删除镜像20docker rmi -f nginx:latest21 22# 删除多个镜像23docker rmi -f 镜像1:TAG 镜像2:TAG24 25# 删除全部镜像,慎用26docker rmi -f $(docker images -qa)

#3.3 容器命令

bash
1# 运行容器2docker run 镜像名3 4# 查看正在运行的容器5docker ps6 7# 查看所有容器,包括已经退出的容器8docker ps -a9 10# 查看最近创建的容器11docker ps -l12 13# 查看最近 n 个创建的容器14docker ps -n 515 16# 只显示容器 ID17docker ps -q18 19# 启动容器20docker start 容器ID或容器名21 22# 停止容器23docker stop 容器ID或容器名24 25# 强制停止容器26docker kill 容器ID或容器名27 28# 删除已停止容器29docker rm 容器ID或容器名30 31# 强制删除容器,包括正在运行的容器32docker rm -f 容器ID或容器名33 34# 查看容器日志35docker logs 容器ID或容器名36 37# 持续查看日志38docker logs -f 容器ID或容器名39 40# 查看容器详细信息41docker inspect 容器ID或容器名42 43# 查看容器资源使用情况44docker stats

#3.4 容器文件复制与导入导出

bash
1# 从容器复制文件到宿主机2docker cp 容器ID:/容器内路径 /宿主机路径3 4# 从宿主机复制文件到容器5docker cp /宿主机路径 容器ID:/容器内路径6 7# 导出整个容器文件系统8docker export 容器ID > nginx.tar9 10# 从导出的 tar 文件导入为镜像11cat nginx.tar | docker import - 用户名/镜像名:版本号

#4. 容器运行、进入与退出

#4.1 docker run 常用参数

bash
1docker run [参数] 镜像名 [命令]

常用参数:

参数作用
--name指定容器名称。
-d后台运行容器。
-i交互模式。
-t分配伪终端,通常和 -i 一起使用。
-p指定端口映射。
-P随机端口映射。
-v挂载数据卷。
--network指定容器网络。
--restart设置重启策略。
端口映射示例:
bash
1# 宿主机 8080 -> 容器 802docker run -d -p 8080:80 nginx3 4# 指定监听地址5docker run -d -p 10.0.0.1:8080:80 nginx

启动交互式 Ubuntu 容器:

bash
1docker run -it --name ubuntu ubuntu /bin/bash

#4.2 退出容器

进入交互式容器后:
exit
exit 会退出容器终端,并且如果该 shell 是容器主进程,容器也会停止。
如果希望退出终端但不停止容器,可以使用:
Ctrl + P,然后 Ctrl + Q

#4.3 exec 和 attach 的区别

进入正在运行的容器:

bash
1docker exec -it 容器ID或容器名 /bin/bash

或者:

bash
1docker attach 容器ID或容器名

区别:

命令特点
docker exec在容器中启动一个新的进程。退出该进程不会导致容器停止。推荐使用。
docker attach进入容器主进程的终端。退出可能导致容器停止。

#4.4 为什么 Ubuntu 后台运行会自动停止

执行下面命令时:

bash
1docker run -d ubuntu

Ubuntu 容器可能会马上退出。原因是 Ubuntu 镜像默认没有长期运行的前台进程。容器的生命周期依赖于主进程,主进程结束后容器就会退出。
解决方式:

bash
1docker run -it --name my_ubuntu_container ubuntu /bin/bash

或者让容器执行一个长期运行的命令:

bash
1docker run -d --name my_ubuntu_container ubuntu tail -f /dev/null

#5. 镜像分层与 docker commit

#5.1 为什么 Docker 镜像要分层

Docker 镜像由多层只读层组成,容器运行时会在镜像层之上增加一个可写层。
分层设计的好处:

  1. 共享和复用:多个镜像可以共享相同的基础层,节省磁盘空间。
  2. 快速部署:本地已有的镜像层不需要重复下载。
  3. 减少存储占用:更新镜像时只需要变更发生变化的层。
  4. 便于回滚:镜像层天然支持增量管理。
  5. 增量传输:推送和拉取镜像时只传输缺失层。
  6. 安全性更好:基础镜像层只读,容器只修改自己的可写层。
    底层通常依赖联合文件系统,例如 OverlayFS、AUFS、Btrfs 等。

#5.2 docker commit

bash
1docker commit 可以把当前容器的状态提交成一个新的镜像。

语法:

bash
1docker commit -m="提交描述" -a="作者" 容器ID 目标镜像名:标签

示例:

bash
1docker commit -m="vim cmd add ok" -a="caiyaobin" 628daf79a302 cyb/ubuntu:24.04.1

注意:生产环境更推荐使用 Dockerfile 构建镜像,而不是长期依赖 docker commit。Dockerfile 更容易版本管理、复现和审计。

#6. 镜像仓库与镜像推送

#6.1 推送镜像到阿里云 ACR

基本流程:

  1. 登录阿里云容器镜像服务。
  2. 创建命名空间。
  3. 创建镜像仓库。
  4. 登录镜像仓库。
  5. 给本地镜像打 tag。
  6. 推送镜像。
    示例:
bash
1# 查看本地镜像2docker images3 4# 给镜像打 tag5docker tag 本地镜像ID registry.example.com/namespace/image_name:tag6 7# 推送镜像8docker push registry.example.com/namespace/image_name:tag9 10# 拉取镜像11docker pull registry.example.com/namespace/image_name:tag

#6.2 搭建本地私有 Registry

拉取 Registry 镜像:

bash
1docker pull registry

创建数据目录:

bash
1mkdir -p /caiyaobin/myregistry

运行私有仓库:

bash
1docker run -d \2  -p 5000:5000 \3  -v /caiyaobin/myregistry:/var/lib/registry \4  --name my-registry \5  registry

提交容器为镜像:

bash
1docker commit -m="vim cmd add" -a="cyb" 9d0b5683c0c8 ubuntu:24.04.1

推送到本地私有仓库:

bash
1docker tag ubuntu:24.04.1 127.0.0.1:5000/ubuntu:24.04.12docker push 127.0.0.1:5000/ubuntu:24.04.1

#7. Docker 数据卷

#7.1 数据卷的作用

Docker 数据卷用于持久化容器数据,解决以下问题:

  • 容器删除后数据仍然保留。
  • 容器重建后可以继续使用原数据。
  • 多个容器之间可以共享数据。
  • 容器内数据可以备份到宿主机。

#7.2 挂载宿主机目录

bash
1docker run -it \2  -v /宿主机绝对路径:/容器内路径 \3  镜像名

示例:

bash
1docker run -it \2  -v /data/test:/app/data \3  ubuntu /bin/bash

#7.3 只读挂载

bash
1docker run -it \2  -v /宿主机绝对路径:/容器内路径:ro \3  镜像名

ro 表示容器内部只读,不能写入该挂载目录。

#7.4 SELinux 权限问题

如果在 CentOS / Rocky / RHEL 等系统中挂载目录后出现:
cannot open directory: Permission denied
常见原因是 SELinux 限制。
可以临时使用:

bash
1docker run --privileged=true ...

但 --privileged=true 会放大容器权限,不建议作为长期方案。更推荐根据实际情况使用:

bash
1# 共享 SELinux 标签2docker run -v /宿主机目录:/容器目录:z 镜像名3 4# 私有 SELinux 标签5docker run -v /宿主机目录:/容器目录:Z 镜像名

或者调整宿主机目录权限和 SELinux 上下文。

#7.5 卷的继承和共享

使用 --volumes-from 让一个容器继承另一个容器的数据卷:

bash
1docker run -it \2  --volumes-from 父容器名或ID \3  --name 新容器名 \4  镜像名

#8. Docker 网络

#8.1 查看与管理 Docker 网络

bash
1# 查看 Docker 网络2docker network ls3 4# 创建网络,默认类型是 bridge5docker network create 网络名6 7# 创建指定网段的 bridge 网络8docker network create \9  --driver bridge \10  --subnet 192.168.50.0/24 \11  my_custom_network12 13# 查看网络详情14docker network inspect 网络名15 16# 删除网络17docker network rm 网络名

#8.2 默认 bridge 和自定义 bridge 的区别

对比项默认 bridge自定义 bridge
容器名解析默认不支持通过容器名互相解析。内置 DNS,支持通过容器名或别名互相访问。
隔离性所有未指定网络的容器默认加入该网络,隔离性较弱。只有加入该网络的容器才能互通,隔离性更好。
生产推荐不推荐作为生产主要网络。更推荐。
配置灵活性较弱。可以自定义网段、网关、别名等。

#8.3 把容器加入自定义网络

bash
1# 创建自定义网络2docker network create my_custom_network3 4# 将已存在的容器连接到自定义网络5docker network connect my_custom_network my_container

如果希望从默认 bridge 迁移到自定义网络:

bash
1# 停止容器2docker stop my_container3 4# 断开默认 bridge 网络5docker network disconnect bridge my_container6 7# 连接到自定义网络8docker network connect my_custom_network my_container9 10# 启动容器11docker start my_container

#8.4 bridge 网络和 docker0

安装 Docker 后,宿主机会自动创建 docker0 网桥。
容器通过 bridge 网络访问外部的大致流程:
容器 eth0 -> veth pair -> docker0 -> iptables NAT -> 宿主机物理网卡 -> 外部网络
关键点:

  • Docker 会为容器和宿主机创建一对虚拟网卡,也就是 veth pair。
  • 容器一端在容器 Network Namespace 中。
  • 宿主机一端连接到 docker0 或自定义 bridge。
  • 容器访问外网时,Docker 通过 iptables 做 SNAT/MASQUERADE。

#8.5 host 网络

host 模式下,容器和宿主机共享同一个 Network Namespace。
特点:

  • 容器不再拥有独立 IP。
  • 容器直接使用宿主机 IP 和端口。
  • 不需要做 Docker bridge NAT。
  • 性能开销更低,但端口冲突风险更高,隔离性更弱。
    示例:
bash
1docker run -d --network host --name t1 tomcat

适用场景:

  • 容器需要大量网络连接。
  • 对网络性能敏感。
  • 可以接受网络隔离性降低。

#8.6 none 网络

none 模式下,Docker 不为容器配置网络。
特点:

  • 容器只有 loopback。
  • 没有默认网卡、IP、路由。
  • 需要用户自己手动配置网络。
    示例:
bash
1docker run -it --network none ubuntu /bin/bash

#8.7 container 网络

container 网络模式表示新容器共享另一个已有容器的网络命名空间。
特点:

  • 两个容器共享 IP、端口、路由等网络配置。
  • 文件系统、进程空间仍然隔离。
  • 常见于 sidecar 模式。
    示例:
bash
1# 先启动一个 tomcat 容器2docker run -d -p 8080:8080 --name t1 tomcat3 4# nginx 容器共享 t1 的网络命名空间5docker run -d --network container:t1 --name nginx-sidecar nginx

注意:使用 --network container:t1 时,新容器不能再单独使用 -p 暴露端口,因为它已经共享了目标容器的端口空间。

#8.8 固定容器 IP 的注意事项

可以在自定义网络中指定固定 IP,但不建议在业务代码里长期写死容器 IP。
原因:

  • 容器重建后 IP 可能变化。
  • 固定 IP 容易造成 IP 冲突。
  • 服务迁移和扩容不灵活。
    更推荐:
  • 使用自定义网络中的容器名解析。
  • 使用 Docker Compose 的 service name。
  • 使用服务发现或反向代理。

#8.9 Docker网络进阶学习

当Docker进程启动以后,会自动创建一个docker 0的网桥,每当启动一个容器后,会分别在容器和宿主机上创建一个虚拟网卡,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 eth0(容器的网卡),另一端放在主机中,以 vethxxx 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。

bash
1# 使用docker inspect查看容器对应的Pid

[root@jenkins ~]# docker inspect test | grep Pid
"Pid": 3425,
"PidMode": "",
"PidsLimit": null,

bash
1# 然后使用nsenter进行查看容器的网络

nsenter -t 3425 -n
[root@jenkins ~]# 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
2: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 9a:d9:b5:42:46:69 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

可以看出分别会在宿主机和容器内部创建一个虚拟网卡进行互联

容器A
┌─────────┐
│ eth0 │ 172.17.0.2
└────┬────┘

veth pair

┌────┴────┐
│vethabcd │
└────┬────┘

┌────┴────┐
│docker0 │
└────┬────┘

宿主机

#9. Docker Compose

Docker Compose 是 Docker 官方提供的多容器编排工具,用于通过一个 YAML 文件管理多个容器。
典型文件名:

bash
1docker-compose.yml

基本操作:

bash
1# 启动

Docker Compose V2 推荐:

bash
1docker compose up -d2 3# 老版本命令:4docker-compose up -d5 6# 停止并删除容器、网络7docker compose down8 9# 查看服务状态10docker compose ps11 12# 查看日志13docker compose logs -f14 15# 重新拉取镜像16docker compose pull

Compose 适合管理:

  • Web 服务 + 数据库。
  • Nginx + 应用容器。
  • Redis / MySQL / Kafka 等中间件组合。
  • 本地开发环境。

#10. Portainer 可视化管理

Portainer 是一个轻量级 Docker 图形化管理工具,支持单机 Docker 和部分集群环境。
新版镜像使用:
portainer/portainer-ce
启动命令:

bash
1docker run -d \2  -p 8000:8000 \3  -p 9000:9000 \4  --name portainer \5  --restart=always \6  -v /var/run/docker.sock:/var/run/docker.sock \7  -v portainer_data:/data \8  portainer/portainer-ce:2.13.0-alpine

参数说明:

  • --restart=always:Docker 引擎重启后自动拉起容器。
  • /var/run/docker.sock:允许 Portainer 管理本机 Docker。
  • portainer_data:/data:持久化 Portainer 数据。

#11. Docker daemon 配置与日志排错

#11.1 daemon.json

daemon.json 是 Docker daemon 的配置文件,通常路径为:
/etc/docker/daemon.json
示例:开启 live-restore。
{
"live-restore": true
}
live-restore 的作用:

  • Docker daemon 重启或异常退出时,尽量不影响已经运行的容器。
  • 可以减少 Docker 升级、维护时对业务容器的影响。
    修改后重新加载 Docker 配置:
bash
1systemctl reload docker

如果 reload 不生效,可以重启 Docker:

bash
1systemctl restart docker

#11.2 Docker 日志排错

查看 Docker 服务日志:

bash
1journalctl -xu docker.service

查看最近日志:

bash
1journalctl -u docker.service -n 100

持续查看:

bash
1journalctl -u docker.service -f

#12. 常用软件部署示例

#12.1 Tomcat

拉取镜像:

bash
1docker pull tomcat

运行容器:

bash
1docker run -d \2  -p 8080:8080 \3  --name tomcat \4  tomcat

如果访问 http://IP:8080 显示 404,可以进入容器调整 webapps:

bash
1docker exec -it tomcat /bin/bash

rm -rf webapps
mv webapps.dist webapps

#12.2 MySQL 单机部署

基础启动:

bash
1docker run -d \2  -p 3306:3306 \3  -e MYSQL_ROOT_PASSWORD=<MYSQL_ROOT_PASSWORD> \4  --name mysql5.7 \5  mysql:5.7

带数据卷启动:

bash
1docker run -d \2  -p 3306:3306 \3  --privileged=true \4  -v /data/mysql/log:/var/log/mysql \5  -v /data/mysql/data:/var/lib/mysql \6  -v /data/mysql/conf:/etc/mysql/conf.d \7  -e MYSQL_ROOT_PASSWORD=<MYSQL_ROOT_PASSWORD> \8  --name mysql5.7 \9  mysql:5.7

进入容器:

bash
1docker exec -it mysql5.7 /bin/bash2mysql -uroot -p

查看字符集:

sql
1SHOW VARIABLES LIKE 'character%';

在宿主机 /data/mysql/conf/my.cnf 中添加:
[client]
default_character_set=utf8

[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
重启容器:

bash
1docker restart mysql5.7

再次查看字符集:

sql
1SHOW VARIABLES LIKE 'character%';

#12.3 MySQL 主从复制

启动主库容器

bash
1docker run -d \2  -p 3307:3306 \3  --name mysql-master \4  --privileged=true \5  -v /data/mysql-master/log:/var/log/mysql \6  -v /data/mysql-master/data:/var/lib/mysql \7  -v /data/mysql-master/conf:/etc/mysql/conf.d \8  -e MYSQL_ROOT_PASSWORD=<MYSQL_ROOT_PASSWORD> \9  mysql:5.7

主库配置文件:/data/mysql-master/conf/my.cnf
[mysqld]
server_id=101
binlog-ignore-db=mysql
log-bin=mall-mysql-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
重启主库:

bash
1docker restart mysql-master

进入主库创建复制用户:

sql
1docker exec -it mysql-master mysql -uroot -p2CREATE USER 'repl'@'%' IDENTIFIED BY '<REPL_PASSWORD>';3GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'%';4FLUSH PRIVILEGES;

查看主库状态:

sql
1SHOW MASTER STATUS;

记录输出中的:

  • File
  • Position
    启动从库容器
bash
1docker run -d \2  -p 3308:3306 \3  --name mysql-slave \4  --privileged=true \5  -v /data/mysql-slave/log:/var/log/mysql \6  -v /data/mysql-slave/data:/var/lib/mysql \7  -v /data/mysql-slave/conf:/etc/mysql/conf.d \8  -e MYSQL_ROOT_PASSWORD=<MYSQL_ROOT_PASSWORD> \9  mysql:5.7

从库配置文件:/data/mysql-slave/conf/my.cnf
[mysqld]
server_id=102
binlog-ignore-db=mysql
log-bin=mall-mysql-slave1-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
relay_log=mall-mysql-relay-bin
log_slave_updates=1
read_only=1
重启从库:

bash
1docker restart mysql-slave

进入从库配置主库信息:

sql
1docker exec -it mysql-slave mysql -uroot -p2CHANGE MASTER TO3  MASTER_HOST='<宿主机IP或主库地址>',4  MASTER_USER='repl',5  MASTER_PASSWORD='<REPL_PASSWORD>',6  MASTER_PORT=3307,7  MASTER_LOG_FILE='mall-mysql-bin.000001',8  MASTER_LOG_POS=777,9  MASTER_CONNECT_RETRY=30;

注意:

  • MASTER_LOG_FILE 要和主库 SHOW MASTER STATUS 的 File 一致。
  • MASTER_LOG_POS 要和主库 SHOW MASTER STATUS 的 Position 一致。
    查看从库状态:
sql
1SHOW SLAVE STATUS\G;

重点关注:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
启动复制:

sql
1START SLAVE;

测试方式:

  1. 在主库创建数据库、表、插入数据。
  2. 在从库查看是否同步成功。

#12.4 Redis 单机部署

拉取镜像:

bash
1docker pull redis:6.0.8

运行 Redis:

bash
1docker run -d \2  -p 6379:6379 \3  --name redis \4  redis:6.0.8

#12.5 Redis 三主三从集群

启动 6 个 Redis 节点,使用 host 网络:

bash
1docker run -d --name redis-node-1 --net host --privileged=true \2  -v /data/redis/share/redis-node-1:/data \3  redis:6.0.8 --cluster-enabled yes --appendonly yes --port 63814 5docker run -d --name redis-node-2 --net host --privileged=true \6  -v /data/redis/share/redis-node-2:/data \7  redis:6.0.8 --cluster-enabled yes --appendonly yes --port 63828 9docker run -d --name redis-node-3 --net host --privileged=true \10  -v /data/redis/share/redis-node-3:/data \11  redis:6.0.8 --cluster-enabled yes --appendonly yes --port 638312 13docker run -d --name redis-node-4 --net host --privileged=true \14  -v /data/redis/share/redis-node-4:/data \15  redis:6.0.8 --cluster-enabled yes --appendonly yes --port 638416 17docker run -d --name redis-node-5 --net host --privileged=true \18  -v /data/redis/share/redis-node-5:/data \19  redis:6.0.8 --cluster-enabled yes --appendonly yes --port 638520 21docker run -d --name redis-node-6 --net host --privileged=true \22  -v /data/redis/share/redis-node-6:/data \23  redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

创建集群:

bash
1redis-cli --cluster create \2  <宿主机IP>:6381 \3  <宿主机IP>:6382 \4  <宿主机IP>:6383 \5  <宿主机IP>:6384 \6  <宿主机IP>:6385 \7  <宿主机IP>:6386 \8  --cluster-replicas 1

进入节点查看集群:

bash
1redis-cli -p 63812cluster info3cluster nodes

#12.6 分布式存储:哈希取余算法

哈希取余算法常用于把数据分散到多个节点:
node_index = hash(key) % 节点数量
优点:

  • 实现简单。
  • 数据可以按 key 分散到多个节点。
    缺点:
  • 节点数量变化时,大量 key 需要重新映射。
  • 扩容和缩容成本较高。
    Redis Cluster 使用的是槽位机制,而不是简单的哈希取余。Redis Cluster 一共有 16384 个 hash slot,key 会映射到某个 slot,再由 slot 分配到具体节点。

#13. Nginx + Docker Compose 示例

#13.1 问题说明

如果直接使用 Docker Compose 挂载 Nginx 配置目录,而宿主机目录是空的,可能导致 Nginx 容器反复重启。
原因:

  • 容器内 /etc/nginx 被宿主机空目录覆盖。
  • Nginx 启动时找不到默认配置文件。
    解决思路:
  1. 先创建宿主机目录。
  2. 使用临时 Nginx 容器把默认配置复制到宿主机。
  3. 再通过 Compose 挂载目录启动 Nginx。

#13.2 创建目录结构

bash
1mkdir -p /data/nginx/conf2mkdir -p /data/nginx/html3mkdir -p /data/nginx/log

#13.3 初始化默认配置

bash
1docker run --rm \2  -v /data/nginx/conf:/mnt/conf \3  -v /data/nginx/html:/mnt/html \4  nginx bash -c "cp -r /etc/nginx/* /mnt/conf/ && cp -r /usr/share/nginx/html/* /mnt/html/"

#13.4 docker-compose.yml

文件路径:/data/nginx/docker-compose.yml
services:
nginx:
image: nginx:latest
container_name: nginx-server
ports:
- "80:80"
- "443:443"
volumes:
- /data/nginx/conf:/etc/nginx
- /data/nginx/html:/usr/share/nginx/html
- /data/nginx/log:/var/log/nginx
restart: unless-stopped
启动:

bash
1cd /data/nginx2docker compose up -d

如果使用旧版本 Compose:

bash
1docker-compose up -d

#13.5 一键部署脚本

#!/bin/bash

set -e

BASE_DIR="/data/nginx"
CONF_DIR="$BASE_DIR/conf"
HTML_DIR="$BASE_DIR/html"
LOG_DIR="$BASE_DIR/log"
COMPOSE_FILE="$BASE_DIR/docker-compose.yml"

echo "Step 1: 创建目录结构..."

bash
1mkdir -p "$CONF_DIR" "$HTML_DIR" "$LOG_DIR"

echo "Step 2: 初始化默认配置和 HTML 文件..."

bash
1docker run --rm \2  -v "$CONF_DIR":/mnt/conf \3  -v "$HTML_DIR":/mnt/html \4  nginx bash -c "cp -r /etc/nginx/* /mnt/conf/ && cp -r /usr/share/nginx/html/* /mnt/html/"

echo "Step 3: 生成 docker-compose.yml 文件..."

bash
1cat > "$COMPOSE_FILE" << EOF

services:
nginx:
image: nginx:latest
container_name: nginx-server
ports:
- "8011:80"
- "443:443"
volumes:
- $CONF_DIR:/etc/nginx
- $HTML_DIR:/usr/share/nginx/html
- $LOG_DIR:/var/log/nginx
restart: unless-stopped
EOF

echo "docker-compose.yml 已生成在 $COMPOSE_FILE"
echo "Step 4: 启动容器..."

bash
1cd "$BASE_DIR"2 3docker compose up -d || docker-compose up -d

echo "Nginx 容器已启动。"
echo "访问地址:http://服务器IP:8011"
echo "日志目录:$LOG_DIR"
echo "如需热加载配置:docker exec nginx-server nginx -s reload"

#14. 学习建议:按这个顺序掌握 Docker

建议按照下面顺序学习和练习:

  1. 镜像和容器基础:docker run、docker ps、docker logs、docker exec。
  2. Dockerfile:自己构建镜像,理解构建缓存和镜像层。
  3. 数据卷:掌握 -v、named volume、宿主机目录挂载。
  4. Docker 网络:理解 bridge、host、none、container、自定义网络。
  5. Compose:把多个服务写进一个 docker-compose.yml。
  6. 排错:看容器日志、Docker daemon 日志、端口占用、挂载权限、网络连通性。
  7. 生产化:镜像仓库、重启策略、日志策略、资源限制、安全权限控制。
    常用排错命令:
bash
1# 看容器状态2docker ps -a3 4# 看日志5docker logs -f 容器名6 7# 看容器详细配置8docker inspect 容器名9 10# 进入容器11docker exec -it 容器名 /bin/bash12 13# 看端口监听14ss -lntup15 16# 看 Docker 网络17docker network ls18docker network inspect 网络名19 20# 看 Docker 服务日志21journalctl -u docker.service -n 100