[TOC] #### 1. 认识容器 --- 容器是一种轻量化虚拟化技术,可以把软件、运行依赖库、配置文件打包在一起,形成一个独立、可快速运行的隔离环境 + 核心特点:共享宿主机内核,只隔离应用层级资源 + 运行速度:秒级启动,占用内存、CPU 极小 虚拟机是完整的硬件级虚拟化,会虚拟出 CPU、内存、硬盘、网卡等全套硬件,内部需要独立安装完整操作系统 + 核心特点:拥有独立内核,完全硬件隔离 + 运行速度:分钟级启动,资源消耗高 容器和虚拟机核心对比: | 对比维度 | 容器(Docker) | 虚拟机(VMware/VirtualBox) | | ------------ | ------------ | ------------ | | 底层依赖 | 共享宿主机系统内核 | 独立完整操作系统 + 独立内核 | | 启动速度 | 秒级启用,快速部署 | 开机缓慢,耗时较长 | | 资源占用 | 超轻量,一台机器可跑上百个 | 笨重,资源消耗大,数量受限 | | 隔离级别 | 应用级隔离,安全性一般 | 硬件级隔离,安全性更高 | | 系统兼容 | 仅限同内核系统(Linux 容器通用) | 可运行 Windows / Linux 任意系统 | | 典型用途 | 项目打包、微服务、快速部署 | 多系统运行、测试环境、桌面虚拟化 | [Docker](https://www.docker.com) 是一个开源的容器化平台,用于将应用程序及其运行环境打包到一个独立的容器中,实现 “一次构建,到处运行” 简单来说: > Docker 就像一个轻量级的虚拟机,但它不需要安装完整的操作系统,因此启动更快、占用资源更少 #### 2. 环境准备 --- 学习阶段可以使用虚拟机进行测试使用,因为它属于硬件级隔离,独立于宿主机系统,怎么操作都不会影响宿主机本身 本文使用的操作系统及软件介绍: | 名称 | 描述 | 文章 | | ------------ | ------------ | ------------ | | Windows 10 专业版 | 在 Windows 系统上使用虚拟机软件 | | | Oracle VirtualBox | 虚拟机软件(Windows 版本) | [VirtualBox 介绍及安装](https://www.itqaq.com/index/627.html) | | ubuntu-24.04.3-live-server-amd64.iso | Ubuntu24.04 Server 版镜像文件 | [Ubuntu 镜像文件下载地址](https://ubuntu.com/download/server) | | Oh My Zsh | Zsh 终端配置管理工具 | [Oh My Zsh 介绍及安装](https://www.itqaq.com/index/362.html) | | zsh-autosuggestions | 根据历史命令自动提示并补全命令 | [Oh My Zsh 第三方插件](https://www.itqaq.com/index/568.html) | Ubuntu24.04 Server LTS 操作系统安装完成后,记得将网络修改为 `桥接模式`,然后运行以下命令: ```bash # 更新软件包列表 sudo apt update # 安装 openssh-server 服务,使 Ubuntu 系统支持 SSH 连接 sudo apt install openssh-server -y ``` 将默认的终端 Shell 类型 `bash` 切换为 `zsh`,然后安装 `Oh My Zsh`: ```bash # 将终端切换为 zsh sudo apt install zsh -y chsh -s $(which zsh) # 重新打开终端,安装 Oh My Zsh sh -c "$(wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)" ``` #### 3. 安装 Docker --- 在 Ubuntu 24.04 上安装 Docker,可以在 Docker 官方文档的 [Ubuntu 安装 Docker 手册](https://docs.docker.com/engine/install/ubuntu) 查看最权威的安装教程 ```bash sudo apt update # 添加 Docker 官方 GPG 密钥 sudo apt install -y ca-certificates sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc # 将存储库添加到 apt 源代码中 sudo tee /etc/apt/sources.list.d/docker.sources <<EOF Types: deb URIs: https://download.docker.com/linux/ubuntu Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") Components: stable Architectures: $(dpkg --print-architecture) Signed-By: /etc/apt/keyrings/docker.asc EOF sudo apt update # 安装 Docker 包,如果想要安装最新版本,请运行: sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ``` 安装后,确认 Docker 是否在运行(安装完成后会自动启动 docker 服务,并且设置开机自启): ```bash # 查看 docker 状态 sudo systemctl status docker # 如果 Docker 未运行,请手动启动 sudo systemctl start docker ``` 运行以下命令会报错: ```plaintext $ docker ps permission denied while trying to connect to the docker API at unix:///var/run/docker.sock ``` 这个错误表明当前用户没有权限访问 Docker 守护进程的 socket 文件,这是一个典型的权限问题 + `/var/run/docker.sock` 默认属于 `root` 用户和 `docket` 用户组 + 普通用户不在 `docket` 组中,所以无法执行 `docket` 命令,解决方案就是将其添加到 `docket` 用户组 ```bash # 将当前用户加入 docker 组 sudo usermod -aG docker $USER # 刷新组权限(或者重新打开终端) newgrp docker ``` 重新运行 `docker ps`,如果能看到以下结果,就代表将权限问题解决了 ```plaintext $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ``` #### 4. docker run 第一个容器 --- docker run 通用基础语法(创建并启动容器) ```plaintext docker run [参数] 镜像名称:标签 ``` 常用核心参数解析: + `-d`: 后台守护进程运行容器(挂机不退出) + `-p 宿主机端口:容器端口`: 端口映射 + `--name`: 自定义容器名称(方便管理) 拉取镜像 ```bash docker pull registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 ``` ```bash # 拉取指定镜像 + 启动容器一键执行 docker run -d --name my-nginx -p 80:80 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 # 如果想要再部署一个 nginx,运行以下命令(仅修改容器名称和宿主机端口即可) docker run -d --name my-nginx2 -p 81:80 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 ``` 验证容器运行状态 ```plaintext $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ff33949f1ab registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 "docker-entrypoint.s…" 2 seconds ago Up 1 second 0.0.0.0:81->80/tcp, [::]:81->80/tcp my-nginx2 47d945ff43f8 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp my-nginx ``` 访问 Nginx 服务 ```bash # 本地命令行访问测试 curl localhost # 外部浏览器访问 http://192.168.1.43 ``` 常用衍生命令 ```bash # 停止 Nginx 容器 docker stop my-nginx # 启动 Nginx 容器 docker start my-nginx # 删除容器(需要先停止容器,才能删除) docker rm my-nginx ``` #### 5. docker 基础命令 --- ##### docker ps 查看容器状态 `docker ps` 是 Docker 最常用的命令之一,用于查看容器列表,默认只显示运行中的容器 ```plaintext docker ps [参数] ``` ```bash # 无参数,仅查看正在运行的容器 docker ps # 查看所有容器(运行中+已停止) docker ps -a # 仅显示正在运行的容器 ID docker ps -q # 查看所有容器 ID(运行中+已停止) docker ps -aq ``` 接下来,我们学习一下其常用参数以及实操演示,为了更好的了解参数的作用,先停止一个容器: + 运行命令后,两个容器的状态:运行中的 my-nginx,未运行的 my-nginx2 ```bash docker stop my-nginx2 ``` 不带参数,直接运行命令,默认只查看正在运行的容器 ```plaintext $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 47d945ff43f8 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 "docker-entrypoint.s…" 23 minutes ago Up 23 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp my-nginx ``` 解读:CONTAINER ID(容器 ID)IMAGE(使用的镜像)STATUS(运行状态)PORTS(端口映射)NAMES(容器名称) 查看所有容器(运行中 + 已停止) + 重点关注 STATUS,显示 Exited 代表容器是停止状态 ```plaintext $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ff33949f1ab registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 "docker-entrypoint.s…" 25 minutes ago Exited (0) 14 minutes ago my-nginx2 47d945ff43f8 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 "docker-entrypoint.s…" 29 minutes ago Up 29 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp my-nginx ``` 查看所有正在运行的容器 ID(方便后续操作) ```plaintext $ docker ps -q 47d945ff43f8 ``` 查看所有容器 ID ```plaintext $ docker ps -aq 9ff33949f1ab 47d945ff43f8 ``` ##### docker images 查看本地镜像 核心作用:用于查看本地已拉取的所有镜像,了解镜像名称、版本、大小等信息 基础语法 ```plaintext docker images [参数] ``` 无参数,查看本地所有镜像,并且显示镜像名称、镜像ID、大小等信息 ```plaintext $ docker images IMAGE ID DISK USAGE CONTENT SIZE EXTRA registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 55dcb729c46f 771MB 202MB U ``` `-q`:仅显示所有镜像的 IMAGE ID(方便批量删除) ```plaintext $ docker images -q 55dcb729c46f ``` ##### docker rm 删除容器 核心作用:删除无用的容器(注意:只能删除已停止的容器,运行中的容器无法直接删除) 基础语法 ```plaintext docker rm 容器ID/容器名称 ``` 步骤1:先停止容器 ```bash # 查看容器状态 docker ps -a # 如果容器正在运行,先停止容器 docker stop my-nginx2 # 或通过容器ID停止(仅需输入ID的前 3-4 位即可,无需完整输入) docker stop 9ff33 ``` 步骤2:删除容器 ```bash # 通过容器名称删除 docker rm my-nginx2 # 通过容器ID删除 docker rm 9ff33949f1ab ``` ##### docker rmi 删除镜像 核心作用:删除本地无用的镜像(注意:若镜像正在被容器使用,无法直接删除,需先删除关联容器) 基础语法: ```plaintext docker rmi 镜像ID/镜像名称:标签 ``` 方式1:通过镜像ID删除(推荐,避免版本混淆) ```bash # 查看镜像ID docker images # 删除指定ID的镜像(输入前 3-4 位即可) docker rmi 55dcb ``` 方式2:通过镜像名称+标签删除(精准删除指定版本) ```bash docker rmi registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 ``` #### 6. docker exec 进入容器 --- 核心说明:`docker exec` 是进入运行中容器的核心命令,只能作用于正在运行的容器,已停止的容器无法使用该命令 前置准备 ```bash # 确保 Docker 服务已启动 systemctl status docker # 确认准备进入的容器处于运行状态(STATUS 显示 UP) docker ps -a ``` 基础语法 ```plaintext docker exec [参数] 容器ID/容器名称 要执行的命令 ``` 高频核心参数(零基础必记): + `-i`:保持标准输入(STDIN)打开,允许容器交互 + `-t`:分配一个伪终端(Terminal),模拟真实终端环境 + `-it`:组合使用(最常用),进入容器的交互式终端,可直接输入命令操作 进入容器交互式终端(执行成功后,终端提示符会变为类似 `root@容器ID:/#` 的样式): ```bash docker exec -it my-nginx /bin/bash ``` 进入容器后,可执行常见 Linux 命令,示例如下: ```plaintext $ docker exec -it my-nginx /bin/bash [root@ba824001598d /]# cat /etc/os-release NAME="Anolis OS" VERSION="8.6" ID="anolis" ID_LIKE="rhel fedora centos" VERSION_ID="8.6" PLATFORM_ID="platform:an8" PRETTY_NAME="Anolis OS 8.6" ANSI_COLOR="0;31" HOME_URL="https://openanolis.cn/" [root@ba824001598d /]# hostname ba824001598d [root@ba824001598d /]# date Sat May 30 16:24:07 UTC 2026 [root@ba824001598d /]# ls bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var ``` 退出容器 重点注意:退出容器时,不要用 `exit` 命令(部分场景会导致容器停止),推荐用以下两种安全方式: + 方式1:快捷键退出,按下 `Ctrl + P + Q` 依次按三个键,退出后容器仍保持运行状态 + 方式2:若已输入 `exit` 退出,立即执行 `docker start 容器ID`,重启容器即可 > 注意:用 `exit` 退出容器时,若容器是通过 `docker exec -it` 进入的,大部分情况下容器不会停止,但为了保险,零基础优先用 `Ctrl + P + Q` 退出 不进入容器,也可以直接执行命令 若无需进入容器,仅需执行单个命令,可直接用 `docker exec` 执行,无需加 `-it` 参数: ```bash # 不进入容器,直接查看容器内部的 Nginx 版本 docker exec my-nginx nginx -v # 不进入容器,直接查看容器内部的 /etc 目录下的文件 docker exec my-nginx ls /etc ``` #### 7. 镜像是什么?容器是什么? --- 理解镜像(Image)和容器(Container)是学习 Docker 最核心的一步,它们的关系非常简单,可以通过几个例子来理解 面向对象编程的类比: + 镜像就像是代码里的类(Class),它是一个静态的定义和模板 + 容器就像是根据这个类实例化出来的对象(Object)。它是动态运行的实体,一个镜像可以启动无数个容器 日常软件的类比: + 镜像就像是软件的安装包(比如 `.exe` 或 `.dmg` 文件),它里面包含了程序运行需要的所有东西 + 容器就是你双击安装包后,“正在运行的软件进程” 集装箱的类比(Docker 名字的由来): + 镜像就像是标准化的 “货运集装箱”,把货物(PHP代码、Nginx、配置文件等)严严实实地打包在里面 + 容器就是这个集装箱被放到卡车、轮船(服务器)上开始运输的 “实际状态” 什么是 Docker 镜像(Image)? 镜像是一个只读的静态模板,把运行某个应用所需的所有环境、代码、依赖库以及配置文件全部打包在了来一起 + 比如 Nginx 镜像,就包含了 Nginx 服务的所有运行文件和依赖 镜像的核心特点(零基础必记): + 静态性:不允许、不占用 CPU/内存资源,仅占用磁盘空间 + 只读性:不能直接修改镜像内容,若需修改,需基于原镜像创建新镜像 + 可复用性:一个镜像可以启动多个容器(比如一个 Nginx 镜像,可启动无数个 Nginx 容器) + 获取方式:从 Docker 仓库(如阿里云、openanolis 仓库)拉取 `docker pull`,或本地构建 什么是 Docker 容器(Container)? 容器就是镜像的 “运行实例”,是镜像的 “运行状态版本”,可以执行/交互/停止/删除,运行时会占用 CPU、内存等系统资源 当执行 `docker run` 命令时,Docker 就会在镜像的最顶层加上一块 “可写的临时层”,并启动一个隔离的进程,这就是容器 容器的核心特点(零基础必记): + 动态性:运行时占用 CPU、内存资源,可执行命令、交互操作 + 独立性:每个容器都是独立的运行环境,互不干扰(比如两个 Nginx 容器,配置可不同) + 可操作性:可以启动(docker start)、停止(docker stop)、删除(docker rm) + 依赖镜像:容器必须基于镜像启动,没有镜像无法创建容器,删除镜像前需先删除关联的容器 #### 8. Docker Hub 下载官方镜像 --- [Docker Hub 官方镜像(解决拉取官方镜像失败问题)](https://www.itqaq.com/index/755.html) #### 9. Dockerfile 入门(form run copy cmd) --- [Dockerfile 文件用法介绍](https://www.itqaq.com/index/711.html) #### 10. Docker 数据卷 volume 入门 --- 数据卷(volume)是 Docker 中 **用于持久化容器数据** 的独立存储空间,它独立于容器生命周期 + 容器删除后,数据卷中的数据不会丢失 + 同时可以实现 “本地目录” 与 “容器内部目录” 的双向数据同步,方便数据管理和备份 简单来说,数据卷解决了 “容器删除,数据丢失” 的问题,同时方便本地管理容器数据(不用进入容器,直接在本地修改数据) 数据卷的核心优势(零基础必记) + 持久化:容器删除,数据卷中的数据不丢失,实现数据长期保存 + 可共享:一个数据卷可以挂载到多个容器,实现多个容器之间的数据共享 + 易管理:无需进入容器,直接在本地操作数据卷中的数据(修改、删除、备份) + 双向同步:本地目录/数据卷与容器内部目录,数据实时同步(本地修改,容器内可见;容器内修改,本地可见) 本文重点讲解 4 个核心操作:创建数据卷、查看数据卷、挂载数据卷、删除数据卷,命令简单,零基础可直接复制执行 操作1:创建数据卷 核心作用:创建一个独立的数据卷(相当于新建一个 “存储文件夹”,专门用于存放容器数据) ```bash # 基础语法 docker volume create 数据卷名称 # 使用示例:创建名为 nginx-volume 的数据卷,名称自定义,好记即可 docker volume create nginx-volume ``` 执行后无复杂输出,仅显示数据卷名称,说明创建成功(Docker 会自动在本地生成对应存储目录,无需手动创建) 注意:数据卷名称可自定义,建议贴合用途(如:挂载 MySQL 数据,命名为 mysql-volume),方便后续管理 操作2:查看数据卷 核心作用:查看本地所有数据卷,或查看某个数据卷的详细信息(如:存储路径) ```bash # 查看本地所有数据卷 docker volume ls # 查看某个数据卷的详细信息(以 nginx-volume 为例) # 输出结果会显示数据卷的存储路径 /var/lib/docker/volumes/nginx-volume/_data # 这个路径是本地的真实路径,可以直接访问操作 docker volume inspect nginx-volume # 如果想要访问这个目录,需要切换为 root 用户,因为普通用户没有权限 # 先切换为 root 用户,再进入该目录 sudo su cd /var/lib/docker/volumes/nginx-volume/_data # 切换到普通用户 vboxuser su - vboxuser ``` 操作3:挂载数据卷到容器(重点学习) 将创建好的数据卷挂载到容器的指定目录,实现数据同步和持久化;挂载后,容器内该目录的所有数据都会存储到数据卷中 ```bash # 基础语法(docker run 时挂载,核心参数 -v) docker run -d --name 容器名称 -p 宿主机端口:容器端口 -v 数据卷名称:容器内部目录 镜像名称:标签 # 核心参数解读:-v 数据卷名称:容器内部目录 -> 实现数据卷与容器目录的挂载 ``` 使用示例(挂载 nginx-volume 到 Nginx 容器,同步网页目录): + 第一步:启动 Nginx 容器,挂载数据卷(会自动将容器内部目录中的文件下载到数据卷中) ```bash # 启动容器,挂载 nginx-volume 到容器的 /var/www/html 目录(Nginx 默认网页目录) docker run -d --name nginx-volume-demo \ -p 8081:80 \ -v nginx-volume:/var/www/html/ \ my-nginx:v1 ``` + 第二步:验证挂载效果(双向同步) ```bash # 1. 本地操作:进入数据卷的本地存储路径,修改测试网页内容 # 查看数据卷存储路径(复制 inspect 输出中的 Mountpoint 路径) docker volume inspect nginx-volume sudo su cd /var/lib/docker/volumes/nginx-volume/_data vim index.html # 2. 访问容器服务,验证数据同步(正确输出,说明本地数据卷的文件,已同步到容器内部,挂载成功) curl localhost:8080 ``` + 第三步:验证数据持久化(容器删除,数据不丢失) ```bash # 1. 删除挂载数据卷的容器 docker stop nginx-volume-demo docker rm nginx-volume-demo # 2. 查看数据卷中的文件(依然存在) cat /var/lib/docker/volumes/nginx-volume/_data/index.html # 依然能看到之前创建的 index.html 文件,说明数据卷中的数据没有随着容器的删除而丢失,实现了持久化 ``` 注意事项: + 挂载时,容器内部目录可以是已存在的,也可以是不存在的(Docker 会自动创建) + 挂载参数 `-v` 后面是 “数据卷名称:容器内部目录”,顺序不能颠倒 + 一个数据卷可以挂载到多个容器,实现数据共享 操作4:删除数据卷 核心作用:删除无用的数据卷(注意:删除数据卷会彻底删除里面的数据,无法恢复,需谨慎操作) ```bash # 1. 删除指定数据卷(需确保该数据卷未被任何容器挂载) docker volume rm 数据名称 # 示例:删除 nginx-volume docker volume rm nginx-volume # 2. 删除所有未被挂载的数据卷(批量清理),执行时会提示确认,输入 y 即可 docker volume prune ``` 注意事项:若数据卷正在被容器挂载,无法直接删除,需先停止并删除关联容器,再删除数据卷 #### 11. Docker 网络 bridge 基础 --- Bridge 网络是 Docker 默认的网络模式,它在宿主机内部创建一个虚拟网桥(docker0),所有连接到该网桥的容器都可以互相通信,并通过 NAT 访问外部网络 它相当于一个 “虚拟交换机”,负责连接宿主机和容器,以及容器与容器之间的网络通信,实现容器的 “联网功能” + 没有 bridge 网络,容器无法访问外网、无法被外部访问,也无法与其它容器通信 核心概念: + Bridge:虚拟交换机/网桥 + docker0:默认的 bridge 网络接口 + 容器通过 veth pair(虚拟以太网对)连接到网桥 通俗类比:bridge 网络(docker0)= 家里的路由器,宿主机 = 家里的宽带主线、容器 = 家里的手机电脑设备 + bridge 网络:给每台容器分配一个专属的内网IP,负责设备之间、设备与外网之间的通信 + 宿主机:bridge 网络连接到宿主机,通过宿主机的网络访问外网 + 容器:通过 bridge 网络获取 IP,实现与其它容器、宿主机、外网的连通 Docker 安装完成后,会自动创建一个 bridge 网络,名为 `docker0`,这是所有容器的默认网络 + 若启动容器时不指定网络,容器会自动连接到 docker0 网络 运行以下命令可以看到 `docker0` 网卡: ```bash ip a ``` 操作1:查看 Docker 所有网络(核心命令) 通过命令查看本地所有 Docker 网络,确认默认 bridge 网络(docker0)存在 ```bash # 基础语法,查看 Docker 所有网络 docker network ls ``` 执行后,会看到类似如下输出(重点关注 bridge 类型的网络) + bridge 网络默认名称对应的是 docker0(命令中显示的 NAME 为 bridge,实际对于宿主机的 docker0 网卡) ```plaintext NETWORK ID NAME DRIVER SCOPE 452bee2dae26 bridge bridge local 83d5446a5fd6 host host local 2760d156d02e none null local ``` 操作2:查看默认 bridge 网络(docker0)详细信息 ```bash # 查看默认 bridge 网络详细信息(NAME 为 bridge) docker network inspect bridge ``` 关键解读: + `IPAM.Config.Subnet`:bridge 网络的子网 IP 段(如: 172.17.0.0/16) + Docker 会给连接到该网络的容器,分配该网段内的 IP(如:172.17.0.2、172.17.0.3) + `Containers`:当前连接到该 bridge 网络的容器信息,包括容器ID、容器IP、端口映射等(容器启动后会显示) 操作3:启动容器,自动连接默认 bridge 网络 启动容器时,若不指定网络,容器会自动连接到 docker0 网络获取专属 IP,实现网络连通 ```bash # 启动一个容器,命名为 bridge-demo1 docker run -d --name bridge-demo1 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 # 查看容器的网络信息(重点看 IP 地址) docker inspect docker inspect -f '{{.NetworkSettings.Networks.bridge.IPAddress}}' bridge-demo1 # 执行后会输出容器的 IP 地址(如 172.17.0.4) # 这个 IP 就是 bridge 网络(docker)分配的内网 IP,容器可通过这个 IP 和其它容器、宿主机通信 ``` 验证网络的连通性(容器间、容器与宿主机) ```bash # 再创建一个容器,用于测试容器间的通信 docker run -d --name bridge-demo2 registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 # 运行以下命令,得出 bridge-demo1(172.17.0.4)bridge-demo2(172.17.0.5) docker inspect -f '{{.NetworkSettings.Networks.bridge.IPAddress}}' bridge-demo1 docker inspect -f '{{.NetworkSettings.Networks.bridge.IPAddress}}' bridge-demo2 # 进入 bridge-demo1 容器 docker exec -it bridge-demo1 /bin/bash # 可以发现能 ping 通,并且还可以使用 ip a 命令看到自己的 IP(172.17.0.4) ping 172.17.0.5 # 宿主机 ping 容器 IP ping 172.17.0.5 ``` bridge 网络核心特点(零基础必记): + 默认网络:Docker 安装后自动创建 docker0 bridge 网络,容器默认连接该网络 + 内网 IP:容器会获取 bridge 网络网段内的内网 IP,仅在宿主机和容器内可见 + 端口映射:需通过 -p 参数实现外部访问容器,否则外部无法访问容器服务 + 连通性:同一 bridge 网络下的容器可互相通信,容器与宿主机可互相通信 + 隔离性:不同网络的容器无法直接通信,确保网络安全 #### 12. docker port 端口映射 --- 容器默认使用内网 IP(如 ping 172.17.0.2),仅能在宿主机和其它容器内访问,外部设备(如本地电脑)无法直接访问 端口映射的作用,是将 “容器内部服务端口” 与 “宿主机端口” 绑定,外部设备访问宿主机端口,即可间接访问容器内部服务 `docker port` 命令的核心作用:查看已启动容器的端口映射关系,知道 “宿主机哪个端口” 映射到 “容器哪个端口” ```bash # 格式1:查看指定容器的所有端口映射(最常用) docker port 容器名称/容器ID # 格式2:查看指定容器的某个具体端口映射(了解即可) docker port 容器名称/容器ID 容器内部端口 ``` 实操演示:查看端口映射关系 先启动一个带端口映射的容器,再用 `docker port` 查看映射关系 ```bash # 1. 启动容器,配置端口映射(宿主机端口 8080 --> 容器端口 80) docker run -d --name port-demo \ -p 8080:80 \ registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 # 2. 用 docker port 查看该容器的端口映射 docker port port-demo ``` 执行后输出示例(核心解读): ```plaintext 80/tcp -> 0.0.0.0:8080 80/tcp -> [::]:8080 ``` + `80/tcp`:容器内部 80 端口,协议为 TCP(容器服务常用协议) + `0.0.0.0:8080`:宿主机所有 IP 的 8080 端口(即外部设备通过宿主机任意 `IP:8080`,均可访问容器 80 端口) 端口映射配置(启动容器时用 -p 参数,重点) `docker port` 是 “查看” 映射关系,而端口映射的 “配置”,是在启动容器时通过 `-p` 参数实现的 基础映射格式(必记) ```bash # 格式1:基础映射(最常用)-> 宿主机端口:容器内部端口 docker run -d --name 容器名称 -p 8080:80 镜像名称:标签 # 格式2:指定宿主机IP映射 -> 宿主机IP:宿主机端口:容器内部端口(仅允许指定IP访问) docker run -d --name 容器名称 -p 192.168.1.43:8080:80 镜像名称:标签 # 格式3:随机端口映射 -> -P(大写 P),Docker 自动分配宿主机随机端口映射容器端口 docker run -d --name 容器名称 -P 镜像名称:标签 ``` 配置端口映射,访问容器内服务(结合 Nginx 服务,演示端口映射的完整用法) 第一步:启动容器,配置端口映射(宿主机端口 8081 -> 容器 80) ```bash # 启动容器,命名 port-map,映射 8080:80 docker run -d --name port-map \ -p 8080:80 \ registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 ``` 第二步:用 `docker port` 查看映射关系 ```bash docker port port-map # 输出:80/tcp -> 0.0.0.0:8080,说明映射成功(宿主机 8080 端口映射容器 80 端口) ``` 第三步:验证映射效果(外部访问容器服务) ```bash # 1. 宿主机本地访问 curl localhost:8080 # 2. 外部设备访问(如:本地电脑,输入宿主机IP:8080) # 示例:宿主机IP是 192.168.3.19,那么浏览器输入 http://192.168.3.19:8080 ``` 补充:`docker port` 与 `docker inspect` 查看映射的区别 ```bash # 1. 简洁,仅显示端口映射关系(推荐零基础使用) docker port 容器名称 # 2. 显示容器所有详细信息,需筛选端口映射内容(适合排查复杂网络问题) docker inspect -f '{{.NetworkSettings.Ports}}' 容器名称 ``` #### 13. docker logs 查看容器日志 --- `docker logs` 是查看容器运行日志最核心的命令,它默认会收集并输出容器内的标准输出和标准错误 语法格式: ```plaintext docker log <选项> <容器ID/容器名称> ``` 先确保有一个运行中的容器,例如:Nginx ```bash # 启动一个测试容器 docker run -d --name my-nginx \ -p 80:80 \ registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 ``` 查看日志 ```bash docker logs my-nginx ``` 常用参数说明 | 参数 | 说明 | | ------------ | ------------ | | `-f` | 实时跟踪日志输出(类似 `tail -f`) | | `-t` | 显示日志时间戳 | | `--tail n` | 只显示最后 n 行日志 | | `-since` | 显示某个时间之后的日志 | 使用示例: ```bash # 实时查看日志 docker logs -f my-nginx # 显示时间戳 docker logs -t my-nginx # 只看最后 10 行日志 docker logs --tail 10 my-nginx # 实时 + 时间 + 最后 20 行 docker logs -f -t --tail 20 my-nginx # 查看最近 1 小时的日志 docker logs --since 1h my-nginx ``` #### 14. docker-compose 介绍及安装 --- Docker Compose 是什么 ? 它是 Docker 官方提供的多容器管理工具,无需手动逐个启动、配置多个容器(如 Nginx、MySQL、Redis 组合) + 只需通过一个 YAML 配置文件(docker-compose.yml),定义所有容器的配置(镜像、端口、网络、挂载等) + 执行一条命令即可启动/停止/管理所有关联容器 使用官方二进制文件安装 Docker Compose(推荐,零基础首选,步骤简单) ```bash # 1. 下载 Compose 二进制文件(指定稳定版本) sudo -E curl -L "https://github.com/docker/compose/releases/download/v2.40.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 2. 给文件添加执行权限(必须步骤,否则无法运行) sudo chmod +x /usr/local/bin/docker-compose # 3. 验证安装是否成功(核心步骤,确认安装有效) docker-compose --version ``` #### 15. 编写 docker-compose.yml 部署 nginx --- `docker-compose.yml` 是 Compose 的核心配置文件,用于定义和运行多容器 Docker 应用程序 + 采用 YAML 语法(大小写敏感、缩进严格),基础结构分为 3 层,可直接套用模板 ```yaml # 基础模板(可直接复制修改,缩进用2个空格,禁止用 tab) services: # 核心节点,所有容器配置都在这个节点下 容器名: # 自定义容器名(如 nginx-web,简洁易记) image: 镜像地址 # 必须使用指定镜像,不可替换 ports: # 端口映射(宿主机端口 -> 容器端口,实现外部访问) - "宿主机端口:容器端口" # 格式固定,冒号分隔 restart: always # 可选配置,容器异常退出时自动重启(推荐添加) container_name: 容器名 # 显式指定容器名,避免自动生成随机名称 ``` 编写 `docker-compose.yml`(实操步骤,直接复制) + 步骤1:创建并进入自定义目录(规范管理配置文件,避免混乱) ```bash # 创建目录(自定义名称,如 nginx-compose)并进入目录 mkdir ~/nginx-compose && cd ~/nginx-compose ``` + 步骤2:编写 `docker-compose.yml` 配置文件(可以使用 vim 编辑器) ```bash vim docker-compose.yml ``` 粘贴以下配置内容(完整可直接使用,无需修改,重点关注 image 配置) ```yaml services: nginx-web: # 自定义容器名,简洁易记,可修改(如 nginx-test) image: registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 # 必须使用指定镜像,不可替换 ports: - "8080:80" # 端口映射:宿主机8080端口 -> 容器80端口 restart: always # 可选配置,容器异常退出时自动重启(推荐添加) container_name: nginx-web # 显式指定容器名,避免自动生成随机名称 ``` 部署并验证 Nginx 在 `docker-compose.yml` 所在目录(nginx-compose 目录),执行以下命令,完成部署和验证 ```bash # 1. 拉取指定镜像(可选,Compose 启动时会自动拉取,手动拉取可避免启动卡顿) docker pull registry.openanolis.cn/openanolis/nginx:1.14.1-8.6 # 2. 启动 Nginx 容器(通过 Compose 部署,后台运行) docker-compose up -d # 3. 查看容器运行状态(验证部署是否成功) docker-compose ps # 4. 查看容器日志(排查启动失败问题) docker-compose logs -f # 5. 停止/重启/删除部署(后续操作) # 停止 docker-compose down # 重启(修改配置后重新启动) docker-compose down && docker-compose up -d ``` #### 16. Compose 一键启动 LNMP 基础版 --- LNMP 是 Linux + Nginx + MySQL + PHP 的组合,通过 Compose 一键管理所有组件,无需逐个启动容器 配置 Docker 镜像加速器(镜像站)通常是通过修改 Docker 的 `daemon.json` 文件完成的 ```bash # 配置 Docker 镜像加速器(镜像站) sudo sh -c 'cat > /etc/docker/daemon.json <<EOF { "registry-mirrors": [ "https://docker.1ms.run", "https://docker.1panel.live", "https://docker.ketches.cn" ] } EOF' # 重载并重启 Docker sudo systemctl daemon-reload sudo systemctl restart docker ``` 验证配置是否生效 ```bash docker info ``` 输出中应能看到类似内容,说明配置已经生效: ```plaintext Registry Mirrors: https://docker.1ms.run/ https://docker.1panel.live/ https://docker.ketches.cn/ ``` ##### 拉取 nginx/mysql 镜像 先拉取 nginx 和 mysql 的镜像,加速后续下载 ```bash docker pull nginx:latest docker pull registry.openanolis.cn/openanolis/mysql:8.0.30-8.6 ``` ##### 构建自定义PHP8.2镜像 创建并进入自定义目录(规范管理配置文件,避免混乱) ```bash mkdir -p ~/lnmp-compose/nginx/conf.d ~/lnmp-compose/www ~/lnmp-compose/php-dockerbuild cd ~/lnmp-compose/php-dockerbuild ``` 目录结构如下: ```plaintext 当前目录结构: ├── nginx │ └── conf.d ├── php-dockerbuild └── www 后续计划目录结构: ├── docker-compose.yml ├── nginx │ └── conf.d │ └── default.conf ├── php-dockerbuild │ ├── Dockerfile │ ├── php.ini │ └── www.conf └── www └── index.php ``` 运行以下命令生成 `Dockerfile` 文件(自定义 php8.2 镜像): ```bash cat > ~/lnmp-compose/php-dockerbuild/Dockerfile<<'EOF' FROM alpine:3.19 # 维护信息 LABEL maintainer="docker@php" LABEL php.version="8.2" LABEL os="Alpine Linux 3.19" ENV TZ=Asia/Shanghai # 安装 PHP8.2 + 必备扩展 RUN set -eux \ # 切换阿里云镜像(国内加速) && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ # 安装依赖 && apk add --no-cache \ tzdata \ curl \ bash \ # 安装 PHP8.2 核心+扩展 php82 \ php82-fpm \ php82-cli \ php82-curl \ php82-gd \ php82-mbstring \ php82-openssl \ php82-pdo \ php82-pdo_mysql \ php82-mysqli \ php82-redis \ php82-json \ php82-xml \ php82-zip \ php82-bcmath \ php82-opcache \ php82-sockets \ php82-exif \ php82-intl \ # 创建工作目录 && mkdir -p /var/www/html \ # 设置市区 && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \ # 清理缓存 && rm -rf /var/cache/apk/* # 复制 PHP 配置(可选优化) COPY php.ini /etc/php82/php.ini COPY www.conf /etc/php82/php-fpm.d/www.conf # 工作目录 WORKDIR /var/www/html EXPOSE 9000 CMD ["php-fpm82", "-F", "-R"] EOF ``` 运行以下命令,会生成 `php.ini`、`php-fpm` 配置文件并且写入内容 ```bash # 创建 php.ini 配置文件 cat > php.ini<<'EOF' [PHP] date.timezone = Asia/Shanghai max_execution_time = 3000 post_max_size = 50M upload_max_filesize = 50M memory_limit = 256M max_input_vars = 10000 display_errors = Off log_errors = On error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT [opcache] opcache.enable = 1 opcache.enable_cli = 0 opcache.memory_consumption = 128 opcache.interned_strings_buffer = 8 opcache.max_accelerated_files = 10000 opcache.revalidate_freq = 60 EOF # 创建 php-fpm 配置文件 cat > www.conf<<'EOF' [www] user = nobody group = nobody listen = 0.0.0.0:9000 listen.mode = 0666 pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 EOF ``` 运行以下命令构建镜像: ```bash # 构建镜像 docker build -t php8.2-fpm-alpine . ``` ##### 编写 docker-compose.yml 编写 `docker-compose.yml` 配置文件(使用 vim 编辑器,内容可直接复制) ```bash # vim ~/lnmp-compose/docker-compose.yml services: nginx: image: nginx:alpine container_name: lnmp-nginx ports: - "80:80" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./www:/var/www/html depends_on: - php restart: always php: image: php8.2-fpm-alpine container_name: lnmp-php volumes: - ./www:/var/www/html restart: always mysql: image: registry.openanolis.cn/openanolis/mysql:8.0.30-8.6 container_name: lnmp-mysql ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: testdb TZ: Asia/Shanghai volumes: - mysql_data:/var/lib/mysql restart: always command: --default-authentication-plugin=mysql_native_password volumes: mysql_data: ``` 准备 `nginx` 配置文件 ```bash vim ~/lnmp-compose/nginx/conf.d/default.conf ``` ```plaintext server { listen 80; server_name localhost; root /var/www/html; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ``` 网站默认测试页 ```bash cat > ~/lnmp-compose/www/index.php<<'EOF' <?php phpinfo(); EOF ``` 在 `docker-compose.yml` 所在目录(lnmp-compose),执行以下命令,一键启动所有服务: ```bash # 一键启动 LNMP 所有组件(后台运行) docker-compose -f ~/lnmp-compose/docker-compose.yml up -d # 查看所有服务运行状态 docker-compose ps # 查看单个服务日志(如 MySQL,排查启动问题) docker-compose logs -f mysql # 停止所有服务(后续清理环境) docker-compose down # 重启所有服务(修改配置后使用) docker-compose down && docker-compose up -d ``` 使用示例: ```plaintext $ docker-compose -f ~/lnmp-compose/docker-compose.yml up -d [+] Running 11/11 ✔ nginx Pulled 33.4s ✔ 2d8223aa4623 Download complete 0.0s ✔ ab556c9e4280 Download complete 0.0s ✔ fbaed3f7fcbe Pull complete 24.9s ✔ 43f834d60d8a Pull complete 2.8s ✔ 6a0ac1617861 Pull complete 3.5s ✔ abaae85d1626 Pull complete 3.8s ✔ de1b677d8c00 Pull complete 2.1s ✔ e654dbbbb9e1 Pull complete 2.6s ✔ a5008f4a4b25 Pull complete 24.6s ✔ 94d083cf706a Pull complete 9.3s [+] Running 5/5 ✔ Network lnmp-compose_default Created 0.0s ✔ Volume lnmp-compose_mysql_data Created 0.0s ✔ Container lnmp-mysql Started 0.4s ✔ Container lnmp-php Started 0.3s ✔ Container lnmp-nginx Started ``` 此时,使用浏览器访问 `http://192.168.3.19` 如果能看到 `phpinfo()` 的输出页面,说明容器服务启动成功 #### 17. Docker 镜像备份与加载 --- 在备份前,先确认要备份的镜像名称或 ID ```bash docker images ``` 将镜像保存为 `.tar` 归档文件 ```bash # 基础语法 docker save -o 保存文件名.tar 镜像名称:标签 # 使用示例 docker save -o nginx-alipine.tar nginx:alpine # 同时备份多个镜像 docker save -o images.tar nginx:alpine php8.2-fpm-alpine:latest ``` 实操演示: ```bash # 创建镜像备份文件存放目录 mkdir ~/mirror-bak # 分别打包多个镜像 docker save -o ~/mirror-bak/nginx-alpine.tar nginx:alpine docker save -o ~/mirror-bak/php8.2-fpm-alpine.tar php8.2-fpm-alpine:latest docker save -o ~/mirror-bak/mysql8.0.30-8.6.tar registry.openanolis.cn/openanolis/mysql:8.0.30-8.6 # 多个镜像打包(打包到一个文件) docker save -o ~/mirror-bak/lnmp.tar \ nginx:alpine \ php8.2-fpm-alpine:latest \ registry.openanolis.cn/openanolis/mysql:8.0.30-8.6 ``` 将备份的 `.tar` 文件恢复到 Docker,恢复成功后使用 `docker images` 即可看到恢复的镜像 ```bash # 基础语法 docker load -i 镜像备份文件.tar # 示例 docker load -i nginx-alpine.tar ``` 查看备份文件大小 ```bash ll -h ``` 镜像传输(在服务器之间传输备份文件) ```bash # 命令格式 scp nginx-alpine.tar root@目标服务器IP:/路径 # 使用示例(同一个局域网下,192.168.1.38 向 192.168.1.45 传输文件) scp hello.txt vboxuser@192.168.1.45:/home/vboxuser ``` 重点总结: + `docker save` 作用:导出镜像为文件,用于迁移、备份 + `docker load` 作用:从文件导入镜像到本地 Docker + save/load 操作的是完整镜像,包含所有层和元数据 + 导出文件名建议规范:`应用名-版本.tar`,方便识别 + 镜像迁移场景:离线环境、多服务器同步、重装系统前备份 #### 18. 常见问题排错 --- 排错核心逻辑:先查状态 -> 再看日志 -> 针对性解决 基础排错命令,无论什么故障,先执行前2条查看基本状态 ```bash # 1. 查看 Docker 服务状态 systemctl status docker # 2. 查看 Docker 运行日志(定位故障关键) sudo journalctl -u docker # 3. 查看容器运行状态(容器相关故障) docker ps -a # 4. 查看容器详细日志(容器启动/运行失败) docker logs 容器名/容器ID # 5. 重启 Docker 服务(临时解决服务类故障) systemctl restart docker # 6. 查看 Docker 版本(版本兼容问题排查) docker --version # 7. 检查 Docker 配置文件(配置错误排查) cat /etc/docker/daemon.json ``` #### 19. Docker 安全最佳实践 --- 核心原则:最小权限、镜像可信、容器隔离、日志可追溯 Docker 服务默认权限较高,需限制运行权限,降低安全风险 ```bash # 1. 查看当前 Docker 服务运行用户(默认 root) ps aux | grep docker # 2. 创建专属用户组和用户(用于运行 Docker,避免 root 直接运行) # groupadd -r docker # 不需要执行,因为安装 Docker 时已经自动创建了 docker 系统组 sudo useradd -r -g docker -s /sbin/nologin dockeruser # 3. 重启 docker 服务,确保权限配置生效 systemctl restart docker # 4. 授权普通用户操作 Docker(可选,避免每次用 root) sudo usermod -aG docker 普通用户名 # 替换普通用户名为你的系统用户名 newgrp docker # 立即生效 ``` 使用可信镜像,避免使用不明来源的镜像,导致系统被入侵: + 优先拉取官方镜像(镜像名不带前缀,如 nginx、mysql),避免第三方镜像 + 拉取镜像时,指定具体标签(如 nginx:alpine,避免用 latest,版本可控) + 禁止拉取来源不明、下载量极低的镜像 ```bash # 正确示例 docker pull nginx:alpine docker pull mysql:8.0.36 # 错误示例 docker pull 不知名前缀/nginx # 第三方镜像,风险高 docker pull nginx # 未指定标签,默认 latest,版本不可控 ``` 容器默认隔离性较弱,需做基础配置,防止容器故障影响宿主机: ```bash # 1. 禁止容器使用宿主机的IPC资源(避免容器越权访问宿主机) docker run -d --name nginx-safe -p 80:80 --ipc=private nginx:alpine # 2. 限制容器 CPU、内存使用(防止容器耗尽宿主机资源) # 示例:限制 CPU 使用 1 核,内存使用 512 M(超出会报错) docker run -d --name nginx-safe -m 512m --cpus=1 nginx:alpine # 3. 禁止容器以 root 用户运行(核心安全) # 示例:以普通用户身份运行容器 docker run -d --name nginx-safe -u 1000:1000 nginx:alpine # 可以看到容器是未启用的,其实是报错了 docker ps -a # 查看容器启动日志 docker logs -f nginx-safe # 日志内容:nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied) # 4. 禁止容器挂载宿主机敏感目录(如:/root、/etc) # 错误示例 docker run -v /root:/root nginx:alpine ```