Skip to content

Docker 学习指南

导航目录

一、Docker 初体验

1.1 Docker 简介

问题:为什么会有 Docker 出现?

一款产品从开发到上线,从操作系统,到运行环境,再到应用配置。作为开发+运维之间的协作,我们需要关心很多东西,这也是很多互联网公司都不得不面对的问题,特别是各种版本的迭代之后,不同版本环境的兼容,对运维人员都是考验。这个时候 Docker 横空出世,是因为它对此给出了一个标准化的解决方案。

环境配置如此麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时"在我的机器上可正常工作"的问题。

  • Docker 官网地址:https://www.docker.com/

  • Docker 是一个开源的应用容器引擎,基于 Go 语言开发。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

  • Docker 的主要目标是"Build,Ship and Run Any App,Anywhere",也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的 APP(可以是一个 WEB 应用或数据库应用等等)及其运行环境能够做到"一次封装,到处运行"。

  • 总之一句话:只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。

1.2 Docker 的优势

Docker 的优势包括:

  1. 可移植性:Docker 容器可以在任何支持 Docker 的环境中运行,包括本地开发环境、测试环境和生产环境,从而提高了应用程序的可移植性。

  2. 可伸缩性:Docker 容器可以根据负载的变化进行快速扩展和收缩,从而更好地满足应用程序的需求。

  3. 隔离性:Docker 容器提供了隔离的运行环境,从而使得不同容器中运行的应用程序互相隔离,避免了应用程序之间的干扰。

  4. 轻量级:Docker 容器共享宿主机的操作系统内核,不需要模拟整个操作系统,因此比虚拟机更加轻量级,启动速度更快。

  5. 版本控制:Docker 镜像可以进行版本控制,方便回滚和管理。

1.3 Docker 和虚拟机的区别

隔离性:在于隔离性上面,由于 VM 对操作系统也进行了虚拟化,隔离的更加彻底。而 Docker 共享宿主机的操作系统,隔离性较差。

运行效率:由于 VM 的隔离操作,导致生成虚拟机的速率大大低于容器 Docker 生成的速度,因为 Docker 直接利用宿主机的系统内核。它们的启动速度是在数量级上的差距。

资源利用率:在资源利用率上虚拟机由于隔离更彻底,因此利用率也会相对较低。

对比表格

特性Docker 容器虚拟机(VM)
启动速度秒级分钟级
硬盘占用MB 级别GB 级别
性能接近原生有损耗
系统支持量单机支持上千个容器单机支持几十个虚拟机
隔离性进程级别隔离操作系统级别隔离
操作系统共享宿主机内核独立内核

经典名句:虚拟机已死,容器才是未来

1.4 Docker 架构

  • Docker 是一个客户端-服务器(C/S)架构程序。Docker 客户端只需要向 Docker 服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。Docker 提供了一个命令行工具 docker 以及一整套 RESTful API。你可以在同一台宿主机上运行 Docker 守护进程和客户端,也可以从本地的 Docker 客户端连接到运行在另一台宿主机上的远程 Docker 守护进程。

Docker 核心组件

  1. Docker Client(客户端):Docker 客户端是用户与 Docker 交互的主要方式,通过命令行或 API 发送请求给 Docker 守护进程。

  2. Docker Daemon(守护进程):Docker 守护进程是 Docker 的服务器端组件,负责构建、运行和分发 Docker 容器。

  3. Docker Image(镜像):Docker 镜像是一个只读模板,包含创建 Docker 容器的指令。

  4. Docker Container(容器):Docker 容器是镜像的运行实例,可以被启动、停止、删除等。

  5. Docker Registry(仓库):Docker 仓库用于存储和分发 Docker 镜像。

1.5 Docker 镜像与容器

镜像:类似虚拟机镜像,是一个特殊的文件系统。

操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

镜像分层结构

  • Docker 镜像采用分层存储的架构
  • 镜像在构建时会一层层构建,前一层是后一层的基础
  • 每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层

容器:类似 Linux 系统环境,运行和隔离应用。是镜像运行时的实体。

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

仓库:集中存放镜像文件的地方。

镜像构建完成后,可以很容易的在当前宿主上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中存储、分发镜像的地方,比如后面我们要学的,Docker Registry 就是这样的服务。

1.6 Docker Hub

  • Docker 用 Registry 来保存用户构建的镜像。Registry 分为公共和私有两种。Docker 公司运营公共的 Registry 叫做Docker Hub。用户可以在 Docker Hub 注册账号,分享并保存自己的镜像(说明:在 Docker Hub 下载镜像很慢,可以自己构建私有的 Registry)。

  • 访问 Docker Hub 搜索 Redis 镜像:https://hub.docker.com/

  • 一般都会选择官方的子镜像仓库,在子镜像仓库中会存在很多版本的镜像。

国内镜像加速: 由于国内访问 Docker Hub 速度较慢,建议配置国内镜像加速器,如阿里云、DaoCloud 等。

1.7 Docker 的安装与卸载

  • Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版)和 EE(Enterprise Edition: 企业版),CE 版本是免费的,EE 版本是收费的。本次我们使用社区版。

  • Docker 的安装和卸载可以参考官方文档:https://docs.docker.com/engine/install/centos/

1.7.1 卸载 Docker

shell
# 卸载Docker相关组件
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

1.7.2 安装 Docker

  • 第一步 检查系统版本 注意:这里建议安装在 CentOS7.x 以上的版本,在 CentOS6.x 的版本中,安装前需要安装其他很多的环境,而且 Docker 很多补丁不支持更新。
shell
# 确定是CentOS7.x及其以上版本
cat /etc/redhat-release
  • 第二步 检查环境,安装 gcc 和 g++
shell
# 安装gcc编译器
yum -y install gcc
# 安装g++编译器
yum -y install gcc-c++
  • 第三步 安装必要的一些系统工具
shell
# 安装必要的系统工具
yum install -y yum-utils device-mapper-persistent-data lvm2
  • 第四步 添加软件源信息(设置阿里云镜像地址,提高下载速度)
shell
# 添加阿里云Docker镜像源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  • 第五步 更新 yum 软件包索引并安装 Docker-CE
shell
# 更新yum软件包索引
yum makecache fast

# 安装Docker-CE及其相关组件
yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 第六步 启动 Docker 并设置开机自启
shell
# 启动Docker服务
systemctl start docker

# 设置Docker开机自启
systemctl enable docker

# 查看Docker版本
docker version

1.8 Docker 服务相关命令

Docker 服务操作的相关命令如下所示:

shell
# 查看Docker服务的运行状态
systemctl status docker

# 启动Docker服务
systemctl start docker

# 关闭Docker服务
systemctl stop docker

# 重启Docker服务
systemctl restart docker

# 设置Docker开机自启
systemctl enable docker

# 取消Docker开机自启
systemctl disable docker

# 查看Docker服务信息
docker info

1.9 配置镜像加速器

Docker 的使用过程中,需要从远程仓库下载镜像,但是默认为国外网站,所以在下载时可能会出现下载连接超时导致下载失败,因此需要为其配置镜像加速器,以提高下载速度。

1.9.1 国内配置的镜像地址

受目前网络环境影响,其它加速器可能暂时不能使用,参考下面网站推荐的加速器地址:

https://www.coderjia.cn/archives/dba3f94c-a021-468a-8ac6-e840f85867ea

1.9.2 配置过程

  • 创建文件 daemon.json
shell
# 编辑Docker守护进程配置文件
vim /etc/docker/daemon.json
  • 文件中添加如下内容
json
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me",
    "https://ccr.ccs.tencentyun.com"
  ]
}
  • 重启 Docker 生效
shell
# 重新加载配置文件
systemctl daemon-reload

# 重启Docker服务使配置生效
systemctl restart docker

# 验证加速器是否生效
docker info | grep "Registry Mirrors" -A 5

二、Docker 镜像操作

2.1 搜索远程镜像

相关命令如下所示:

shell
# 命令:
docker search

# 格式:
docker search 镜像关键字

# 示例:搜索镜像名称中包含redis关键字的镜像
docker search redis

列介绍

  1. name:镜像仓库源名称
  2. description:镜像的描述
  3. official:是否 Docker 官方发布
  4. stars:镜像的收藏数,收藏数越多表示此镜像的受欢迎程度越高
  5. automated:是否自动构建

搜索过滤

shell
# 只显示官方镜像
docker search --filter "is-official=true" redis

# 只显示收藏数大于100的镜像
docker search --filter "stars=100" redis

2.2 拉取镜像

相关命令如下所示:

shell
# 命令:
docker pull

# 格式: tag表示的镜像的标签,也可以理解为就是镜像的版本
docker pull 镜像名称[:tag]

# 示例1: 默认拉取的是最新的redis镜像
docker pull redis

# 示例2: 拉取redis7.0.10镜像,一个镜像到底存在哪些标签,需要上docker hub中进行查看
docker pull redis:7.0.10

# 示例3: 拉取指定平台的镜像
docker pull --platform linux/amd64 redis:7.0.10

2.3 查看本地镜像

相关命令如下所示:

shell
# 命令:
docker images

# 示例:
docker images

# 只显示镜像ID
docker images -q

# 显示所有镜像(包括中间层镜像)
docker images -a

# 只显示指定镜像
docker images redis

列介绍

  1. repository:镜像来源仓库名称
  2. tag:镜像标签
  3. image id:镜像 id
  4. created:创建时间
  5. size:镜像的大小

2.4 删除本地镜像

相关命令如下所示:

shell
# 命令:
docker rmi

# 删除单个镜像(-f 强制删除):
docker rmi -f 镜像ID

# 删除多个镜像:
docker rmi -f 镜像名1:TAG 镜像名2:TAG
# 根据镜像的id或者镜像的名称进行删除,如果不添加镜像的标签删除的就是最新的镜像

# 示例:
docker rmi redis:7.0.10				# 删除redis:7.0.10镜像
  • 注意:如果一个镜像存在对应的容器,此时这个镜像是无法进行删除的。

  • 删除所有镜像:

shell
# 慎用此命令,会删除所有本地镜像
docker rmi $(docker images -q)

2.5 镜像标签管理

shell
# 为镜像添加标签
docker tag 原镜像名:标签 新镜像名:标签

# 示例:为redis:7.0.10添加一个新标签
docker tag redis:7.0.10 myredis:v1

# 查看镜像详细信息
docker inspect redis:7.0.10

# 查看镜像历史
docker history redis:7.0.10

2.6 镜像导入导出

shell
# 导出镜像为tar文件
docker save -o redis.tar redis:7.0.10

# 从tar文件导入镜像
docker load -i redis.tar

# 导出镜像并压缩
docker save redis:7.0.10 | gzip > redis.tar.gz

# 从压缩文件导入镜像
docker load < redis.tar.gz

三、Docker 容器操作

3.1 查询容器

相关命令如下所示:

shell
# 命令:docker ps
# 格式:docker ps [options]	# 可以添加一些参数选项,如果不添加表示查询本地所有正在运行的容器
# 示例: docker ps 			# 查看本地正在运行的容器

列介绍

  1. container id:容器 ID
  2. image:镜像名称
  3. command:容器启动时所执行的命令
  4. created:创建时间
  5. status:容器状态
  6. ports:端口映射情况
  7. names:容器的名称

常见参数选项

shell
-a,--all												# 查询所有的镜像,包含未运行的容器
-q,--quiet												# 查询容器的id

# 示例1:查询所有的容器包含未运行的容器
docker ps -a
# 示例2:查询容器的id
docker ps -q

# 示例3:显示容器大小
docker ps -s

# 示例4:显示最近创建的容器
docker ps -l

3.2 创建容器

  • 容器分类
  1. 交互型容器:具有和用户交互的输入和输出终端,容器创建后自动进入容器中,退出容器后,容器自动关闭。

  2. 守护型容器:没有和用户交互终端,需要使用 docker exec 进入容器,退出后,容器不会关闭。

  • 命令介绍
shell
# 命令:  docker run
# 格式: docker run [OPTIONS] 镜像的名称:镜像标签/镜像id [COMMAND] [ARG...]

# 类型参数选项:
# -i:表示运行容器
# -t:表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端。
# --name :为创建的容器命名。
# -v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上。
# -d:在run后面加上-d参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器,如果只加-i -t两个参数,创建后就会自动进去容器)。
# -p:表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个-p做多个端口映射
# -e:表示为容器设置环境变量,相当于在容器内部的操作系统中定义 KEY=VALUE 格式的环境变量,容器内的应用程序可以读取这些变量来调整运行行为
# --restart:设置容器重启策略
# --network:指定网络模式
# -m:设置容器内存限制
# --cpus:设置容器CPU限制
  • 交互式方式创建容器

以交互式方式创建并启动容器,启动完成后,直接进入当前容器。使用 exit 命令退出容器。需要注意的是以此种方式启动容器,如果退出容器,则容器会进入停止状态,可以理解成交互式容器是前台容器。

shell
# 交互式创建容器命令
docker run -it --name=容器名称 镜像名称:标签 /bin/bash

# 示例:创建一个名为mycentos的交互式容器
docker run -it --name=mycentos centos:7 /bin/bash

# 命令解释:
# docker run:表示创建容器
# -it:表示运行容器并进入它的命令行
# --name=mycentos:给当前的容器命名
# centos:7:使用该镜像创建
# /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash
  • 守护式方式创建容器
shell
# 守护式容器和交互式容器的创建方式区别:
# -it 换成 -di
# 去掉后面的 /bin/bash
docker run -di --name=容器名称 镜像名称:标签

# 示例:创建一个名为mycentos10的守护式容器
docker run -di --name=mycentos10 centos:7
  • 创建容器常用示例
shell
# 创建Redis容器
docker run -d --name=redis01 -p 6379:6379 redis:7.0.10

# 创建MySQL容器
docker run -d --name=mysql01 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 mysql:8.0.30

# 创建Nginx容器
docker run -d --name=nginx01 -p 80:80 nginx:latest

# 创建容器并设置重启策略
docker run -d --name=redis02 --restart=always -p 6380:6379 redis:7.0.10

# 创建容器并设置资源限制
docker run -d --name=redis03 -m 512m --cpus=1 -p 6381:6379 redis:7.0.10

3.3 容器服务管理

容器管理的相关命令如下所示:

shell
# 关闭容器
docker stop 容器名称/容器id

# 启动容器
docker start 容器名称/容器id

# 重启容器
docker restart 容器名称/容器id

# 暂停容器
docker pause 容器名称/容器id

# 恢复容器
docker unpause 容器名称/容器id

# 杀死容器
docker kill 容器名称/容器id

3.4 删除容器

删除容器的常见命令如下所示:

shell
# 命令: docker rm
# 格式:docker rm 容器名称/容器的id							#  删除容器
# 示例:删除mycentos10容器
docker rm mycentos10
  • 注意:上述的命令只能删除已经关闭的容器,如果想删除正在运行的容器,可以通过添加 -f 参数进行实现。

  • 删除所有的容器:

shell
# 删除所有容器(包括运行中的)
docker rm $(docker ps -aq)

# 删除所有已停止的容器
docker container prune

3.5 进入容器

进入容器命令如下所示:

shell
# 命令:docker exec
# 格式:docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
# 常见的参数选项:
# -t, --tty														# 分配一个虚拟终端,通常和-i参数一起使用
# -i,--interactive												# 把交互界面一直保留,通常和-t参数一起使用

# 示例:进入到mycentos10容器中并打开一个shell窗口
docker exec -it mycentos10 /bin/bash

# 示例:在容器中执行命令(不进入容器)
docker exec mycentos10 ls /root

docker attach 与 docker exec 的区别

shell
# docker attach:进入容器正在执行的终端,退出会导致容器停止
docker attach 容器名称/容器id

# docker exec:在容器中打开新的终端,退出不会导致容器停止(推荐使用)
docker exec -it 容器名称/容器id /bin/bash

3.6 其他命令

如下所示:

shell
# 查询容器内进程日志,-f参数表示实时监控日志信息
docker logs -f 容器名称/容器的id

# 查看容器的详情信息(包括目录映射、端口映射、IP地址等)
docker inspect 容器名称/容器的id

# 完成容器和宿主机之间的文件copy
docker cp

# 查看容器中的进程信息
docker top 容器名称/容器的id

# 查看容器资源使用情况
docker stats 容器名称/容器的id

# 查看容器端口映射
docker port 容器名称/容器的id

# 导出容器
docker export 容器名称/容器的id > 容器.tar

# 导入容器
docker import 容器.tar 镜像名:标签

# 示例1: 实时查看redis01容器中的日志信息
docker logs -f redis01

四、Docker 数据卷操作

4.1 数据卷简介

什么是数据卷?

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS(Union File System),提供很多有用的特性:

  1. 数据卷可以在容器之间共享和重用
  2. 对数据卷的修改会立马生效
  3. 对数据卷的更新不会影响镜像
  4. 数据卷默认会一直存在,即使容器被删除

为什么需要数据卷?

Docker 容器产生的数据,如果不通过 docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。为了能保存数据,Docker 使用了数据卷。

数据卷的特点

  1. 数据卷可在容器之间共享或重用数据
  2. 卷中的更改可以直接生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续到没有容器使用它为止

4.2 数据卷操作命令

shell
# 创建数据卷
docker volume create 数据卷名称

# 查看所有数据卷
docker volume ls

# 查看数据卷详情
docker volume inspect 数据卷名称

# 删除数据卷
docker volume rm 数据卷名称

# 删除所有未使用的数据卷
docker volume prune

4.3 数据卷挂载

方式一:使用-v 参数挂载数据卷

shell
# 格式
docker run -v 数据卷名称:容器内路径 镜像名称

# 示例:创建容器并挂载数据卷
docker run -di --name=centos1 -v volume1:/root centos:7

# 说明:
# volume1:数据卷名称(如果不存在会自动创建)
# /root:容器内的路径

方式二:直接挂载宿主机目录

shell
# 格式
docker run -v 宿主机目录:容器内目录 镜像名称

# 示例:将宿主机的/root目录挂载到容器的/root目录
docker run -di --name=centos2 -v /root/host_data:/root/container_data centos:7

# 说明:
# /root/host_data:宿主机目录(必须使用绝对路径)
# /root/container_data:容器内目录

方式三:挂载文件

shell
# 挂载单个文件
docker run -di --name=nginx01 -v /root/nginx.conf:/etc/nginx/nginx.conf:ro nginx:latest

# 说明:
# :ro 表示只读(read-only),容器内无法修改该文件
# :rw 表示可读写(默认值)

4.4 数据卷容器

什么是数据卷容器?

命名的容器挂载数据卷,其他容器通过挂载这个容器实现数据共享,挂载数据卷的容器,称之为数据卷容器。

创建数据卷容器

shell
# 创建一个数据卷容器
docker run -di --name=data_container -v /data centos:7

# 其他容器挂载数据卷容器
docker run -di --name=centos3 --volumes-from data_container centos:7
docker run -di --name=centos4 --volumes-from data_container centos:7

# 说明:
# centos3和centos4共享data_container的数据卷
# 即使data_container容器停止,数据卷仍然可以被其他容器访问

4.5 数据卷应用案例

案例 1:MySQL 数据持久化

shell
# 创建MySQL容器并挂载数据卷
docker run -d --name=mysql \
  -p 3306:3306 \
  -v mysql_data:/var/lib/mysql \
  -v mysql_conf:/etc/mysql \
  -e MYSQL_ROOT_PASSWORD=1234 \
  mysql:8.0.30

# 说明:
# mysql_data:存储MySQL数据文件
# mysql_conf:存储MySQL配置文件
# 即使删除容器,数据也不会丢失

案例 2:Nginx 静态资源挂载

shell
# 创建Nginx容器并挂载静态资源目录
docker run -d --name=nginx \
  -p 80:80 \
  -v /root/html:/usr/share/nginx/html \
  -v /root/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
  nginx:latest

# 说明:
# 将宿主机的html目录挂载到Nginx的静态资源目录
# 修改宿主机的html文件,Nginx会立即生效

案例 3:Redis 数据持久化

shell
# 创建Redis容器并开启持久化
docker run -d --name=redis \
  -p 6379:6379 \
  -v redis_data:/data \
  redis:7.0.10 redis-server --appendonly yes

# 说明:
# redis_data:存储Redis持久化数据
# --appendonly yes:开启AOF持久化

4.6 数据卷权限管理

shell
# 挂载时指定读写权限
docker run -v 数据卷:容器路径:ro 镜像名称  # 只读
docker run -v 数据卷:容器路径:rw 镜像名称  # 可读写(默认)

# 挂载时指定用户和组
docker run -v 数据卷:容器路径 --user 1000:1000 镜像名称

# 挂载时设置SELinux标签
docker run -v 数据卷:容器路径:z 镜像名称   # 私有标签
docker run -v 数据卷:容器路径:Z 镜像名称   # 共享标签

4.7 数据卷备份与恢复

备份数据卷

shell
# 备份数据卷到宿主机
docker run --rm \
  -v 数据卷名称:/data \
  -v /root/backup:/backup \
  centos:7 \
  tar cvf /backup/backup.tar /data

# 说明:
# --rm:容器执行完毕后自动删除
# 第一个-v:挂载要备份的数据卷
# 第二个-v:挂载宿主机备份目录
# tar命令:将数据卷内容打包

**恢复数据卷**

```shell
# 从备份文件恢复数据卷
docker run --rm \
  -v 数据卷名称:/data \
  -v /root/backup:/backup \
  centos:7 \
  tar xvf /backup/backup.tar -C /

# 说明:
# 将备份文件解压到数据卷中

# 示例 2: 查看 redis01 容器的详情信息

docker inspect redis01

# 示例 3: 把宿主机中 a.txt 文件拷贝到 redis01 的 root 目录中

docker cp a.txt redis01:/root

# 示例 4: 把容器中的 root 目录下的 a.txt 文件拷贝到宿主机中当前目录中

docker cp redis01:/root/a.txt .

3.7 备份与迁移

对某一个容器修改完毕以后,我们可以把最新的容器部署到其他的环境中。具体的流程操作如下所示:

涉及的 Docker 命令:

shell
# 把Docker容器保存成一个镜像
docker commit 容器名称/容器的id 镜像名称

# 把镜像保存为tar文件
docker save -o 镜像tar文件名称 镜像名称/镜像id

# 把tar文件恢复成为一个镜像
docker load -i tar文件的名称

示例代码:

shell
# 将mycentos10容器保存为一个镜像
docker commit mycentos10 mycentos

# 将mycentos镜像保存为一个tar文件
docker save -o mycentos.tar mycentos

# 删除之前的mycentos镜像
docker rmi mycentos

# 将mycentos.tar恢复成一个镜像
docker load -i mycentos.tar

commit 命令详解

shell
# 格式:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# -a, --author:作者信息
# -m, --message:提交信息
# -c, --change:应用Dockerfile指令

# 示例:提交容器并添加作者和说明信息
docker commit -a "author" -m "install vim" mycentos10 mycentos:v1

五、Spring Boot 项目部署

本章节主要讲解的就是如何把一个 Spring Boot 项目使用 Docker 进行部署,以减少整个项目的维护成本。

5.1 Dockerfile

5.1.1 Dockerfile 简介

前面我们所使用的镜像都是别人构建好的,但是别人构建好的镜像不一定能满足我们的需求。为了满足我们自己的某一些需求,此时我们就需要构建自己的镜像,怎么构建?使用 Dockerfile。

Dockerfile 就是一个文本文件,在这个文本文件中可以使用 Docker 所提供的一些指令来指定我们构建镜像的细节,后期就可以使用这个 Dockerfile 文件来构建自己的镜像。

Dockerfile 文件内容一般分为 4 部分:

  1. 基础镜像信息(必选)
  2. 维护者信息(可选)
  3. 镜像操作指令(可选)
  4. 容器启动时执行的指令(可选)

常用命令

指令用法作用
FROMFROM image_name:tag指定一个构建镜像的基础源镜像,如果本地没有就会从公共库中拉取,没有指定镜像的标签会使用默认的 latest 标签,可以出现多次,如果需要在一个 dockerfile 中构建多个镜像。
MAINTAINERMAINTAINER user_name描述镜像的创建者,名称和邮箱
RUNRUN "command" "param1" "param2"用来执行一些命令,可以写多条
ENVENV key value设置容器的环境变量,可以写多条。
ADDADD source_dir/file将宿主机的文件复制到容器内,如果是压缩文件,则复制后自动解压
COPYCOPY source_dir/file将宿主机的文件复制到容器内(不会自动解压)
ENTRYPOINTENTRYPOINT "command" "param1" "param2"用来指定容器启动时所执行的命令
CMDCMD "command" "param1" "param2"指定容器启动时默认执行的命令,可以被 docker run 参数覆盖
WORKDIRWORKDIR path指定工作目录
EXPOSEEXPOSE port声明暴露的端口
VOLUMEVOLUME ["path"]创建挂载点
ARGARG key=value定义构建时的变量
USERUSER username指定运行容器时的用户名或 UID

5.1.2 入门案例

需求:使用 Dockerfile 来构建一个包含 Jdk17 的 centos7 镜像

分析

  1. 基础的镜像的应该选择 centos:7
  2. 在自己所构建的镜像中需要包含 Jdk17,就需要把 Jdk17 添加到 centos:7 的基础镜像中
  3. 为了方便的去使用自己构建的镜像中的 Jdk17,就需要去配置环境变量
  4. 因为 Jdk17 仅仅是一个开发工具,并不是一个服务进程,因此在启动容器的时候可以不指定任何的执行命令

实现步骤

  1. 将 Jdk17 的安装包上传到 linux 服务器的指定目录下
  2. 在 Jdk17 所在的目录下创建一个 dockerfile 文件
  3. 使用 docker build 命令构建镜像
  4. 使用 docker images 查看镜像构建情况
  5. 使用自己所构建的镜像创建容器,测试 Jdk17 的安装情况

代码实现

shell
# 1、创建目录
mkdir –p /usr/local/dockerfilejdk17
cd /usr/local/dockerfilejdk17

# 2、下载jdk-17_linux-x64_bin.tar.gz并上传到服务器(虚拟机)中的/usr/local/dockerfilejdk17目录

# 3、在/usr/local/dockerfilejdk17目录下创建dockerfile文件,文件内容如下:
vim dockerfile

FROM centos:7
MAINTAINER atguigu
RUN mkdir -p /usr/local/java
ADD jdk-17_linux-x64_bin.tar.gz /usr/local/java/
ENV JAVA_HOME=/usr/local/java/jdk-17.0.7
ENV PATH=$PATH:$JAVA_HOME/bin

# 4、执行命令构建镜像;不要忘了后面的那个 .
docker build -t centos7-jdk17 .

# 5、查看镜像是否建立完成
docker images

# 6、创建容器
docker run -it --name atguigu-centos centos7-jdk17 /bin/bash

Dockerfile 最佳实践

  1. 使用.dockerignore 文件排除不需要的文件
  2. 使用多阶段构建减小镜像大小
  3. 合并 RUN 指令减少镜像层数
  4. 使用特定版本标签而不是 latest
  5. 尽量使用官方镜像作为基础镜像

5.1.3 Dockerfile 指令详解

1. FROM 指令

FROM 指令用于指定基础镜像,是 Dockerfile 的第一条指令。

dockerfile
# 格式
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>

# 示例
FROM centos:7                    # 使用centos:7作为基础镜像
FROM nginx:1.25-alpine          # 使用指定版本的nginx
FROM scratch                    # 从零开始构建(用于静态编译的程序)

2. MAINTAINER 指令

MAINTAINER 指令用于指定镜像维护者信息。

dockerfile
# 格式
MAINTAINER <name>

# 示例
MAINTAINER "zhangsan <zhangsan@example.com>"

3. RUN 指令

RUN 指令用于执行命令,有两种格式:

dockerfile
# Shell格式(推荐)
RUN <command>

# Exec格式
RUN ["executable", "param1", "param2"]

# 示例
RUN yum -y install vim           # Shell格式
RUN ["/bin/bash", "-c", "echo hello"]  # Exec格式

# 合并多个RUN指令(减少镜像层数)
RUN yum -y install vim && \
    yum -y install net-tools && \
    yum clean all

4. CMD 指令

CMD 指令指定容器启动时默认执行的命令,只能有一条 CMD 指令。

dockerfile
# Exec格式(推荐)
CMD ["executable", "param1", "param2"]

# Shell格式
CMD command param1 param2

# 作为ENTRYPOINT的默认参数
CMD ["param1", "param2"]

# 示例
CMD ["nginx", "-g", "daemon off;"]    # 启动nginx
CMD ["java", "-jar", "app.jar"]       # 启动Java应用

5. ENTRYPOINT 指令

ENTRYPOINT 指令配置容器启动时执行的命令,不会被 docker run 的参数覆盖。

dockerfile
# Exec格式(推荐)
ENTRYPOINT ["executable", "param1", "param2"]

# Shell格式
ENTRYPOINT command param1 param2

# 示例
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]                 # CMD作为ENTRYPOINT的默认参数

# 使用场景:制作一个可执行程序镜像
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["redis-server"]            # 默认启动redis-server

CMD 与 ENTRYPOINT 的区别

特性CMDENTRYPOINT
作用设置容器默认启动命令设置容器主命令
是否可被覆盖可被 docker run 参数覆盖不会被覆盖,参数会追加
数量限制只能有一条只能有一条
推荐用法作为 ENTRYPOINT 的默认参数定义可执行程序

6. ENV 指令

ENV 指令用于设置环境变量。

dockerfile
# 格式
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

# 示例
ENV JAVA_HOME=/usr/local/java/jdk-17
ENV PATH=$PATH:$JAVA_HOME/bin

# 设置多个环境变量
ENV APP_NAME=myapp \
    APP_VERSION=1.0 \
    APP_ENV=production

7. ADD 指令

ADD 指令用于复制文件,支持自动解压和 URL 下载。

dockerfile
# 格式
ADD <src> <dest>
ADD ["<src>", "<dest>"]

# 示例
ADD app.jar /app/app.jar              # 复制文件
ADD https://example.com/file.txt /tmp/  # 从URL下载
ADD jdk-17.tar.gz /usr/local/java/    # 自动解压tar.gz文件

8. COPY 指令

COPY 指令用于复制文件,功能比 ADD 简单,推荐使用。

dockerfile
# 格式
COPY <src> <dest>
COPY ["<src>", "<dest>"]

# 示例
COPY app.jar /app/app.jar
COPY config/ /app/config/
COPY *.sh /scripts/

# ADD与COPY的区别:
# - ADD支持URL下载和自动解压
# - COPY只支持本地文件复制
# - 推荐使用COPY,除非需要解压功能

9. WORKDIR 指令

WORKDIR 指令用于设置工作目录。

dockerfile
# 格式
WORKDIR <path>

# 示例
WORKDIR /app                      # 设置工作目录为/app
RUN pwd                           # 输出/app

# 可以使用多个WORKDIR
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd                           # 输出/a/b/c

10. EXPOSE 指令

EXPOSE 指令声明暴露的端口。

dockerfile
# 格式
EXPOSE <port> [<port>/<protocol>...]

# 示例
EXPOSE 80                         # 暴露80端口
EXPOSE 8080 8081                  # 暴露多个端口
EXPOSE 53/udp                     # 指定协议
EXPOSE 80/tcp 443/tcp             # 暴露HTTP和HTTPS端口

11. VOLUME 指令

VOLUME 指令创建挂载点。

dockerfile
# 格式
VOLUME ["<path>"]
VOLUME <path>

# 示例
VOLUME ["/data"]                  # 创建挂载点
VOLUME ["/data", "/log"]          # 创建多个挂载点
VOLUME /var/lib/mysql             # MySQL数据目录

12. ARG 指令

ARG 指令定义构建时的变量,只在构建时有效。

dockerfile
# 格式
ARG <name>[=<default value>]

# 示例
ARG VERSION=7.0
FROM centos:${VERSION}

# 使用docker build传递参数
# docker build --build-arg VERSION=8.0 -t myimage .

13. USER 指令

USER 指令指定运行容器时的用户。

dockerfile
# 格式
USER <user>[:<group>]
USER <UID>[:<GID>]

# 示例
USER nginx                        # 使用nginx用户运行
USER 1000:1000                    # 使用UID和GID

# 创建用户并切换
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser

14. HEALTHCHECK 指令

HEALTHCHECK 指令用于健康检查。

dockerfile
# 格式
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE                  # 禁用健康检查

# 示例
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

# 参数说明:
# --interval:检查间隔(默认30s)
# --timeout:超时时间(默认30s)
# --start-period:启动等待时间(默认0s)
# --retries:重试次数(默认3次)

15. ONBUILD 指令

ONBUILD 指令定义触发器,在子镜像构建时执行。

dockerfile
# 格式
ONBUILD <INSTRUCTION>

# 示例(创建一个基础镜像)
ONBUILD COPY . /app
ONBUILD RUN npm install
ONBUILD CMD ["npm", "start"]

# 当其他镜像FROM这个镜像时,上述命令会自动执行

16. LABEL 指令

LABEL 指令用于添加元数据。

dockerfile
# 格式
LABEL <key>=<value> <key>=<value>...

# 示例
LABEL version="1.0"
LABEL description="This is my app"
LABEL maintainer="zhangsan@example.com"

17. SHELL 指令

SHELL 指令用于指定默认 Shell。

dockerfile
# 格式
SHELL ["executable", "parameters"]

# 示例
SHELL ["/bin/bash", "-c"]         # 使用bash
SHELL ["powershell", "-command"]  # 在Windows上使用PowerShell

5.1.4 多阶段构建

多阶段构建可以大幅减小镜像大小。

dockerfile
# 第一阶段:构建阶段
FROM maven:3.8-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests

# 第二阶段:运行阶段
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

# 说明:
# AS builder:给第一阶段命名
# --from=builder:从第一阶段复制文件
# 最终镜像只包含第二阶段的内容,大小大幅减小

多阶段构建的优势

  1. 减小镜像大小
  2. 分离构建环境和运行环境
  3. 提高安全性(不包含构建工具)

5.2 案例介绍与需求分析

需求:将提供的 Spring Boot 项目使用容器化进行部署

刚才的入门案例中,构建过程是手动镜像构建的过程。现在我们可以使用 Maven 的 Docker 插件实现镜像的自动化部署。

分析

  1. Spring Boot 项目中使用到了 Mysql 环境,因此需要先使用 Docker 部署 Mysql 环境
  2. 要将 Spring Boot 项目使用 Docker 容器进行部署,就需要将 Spring Boot 项目构建成一个 Docker 镜像

实现步骤

  1. 使用 Docker 部署 Mysql
  2. 在 pom.xml 文件中添加 Maven 的 Docker 插件
  3. 开启 Docker 服务端的远程访问
  4. 在工程的根目录下创建 Dockerfile 文件
  5. 使用 Maven 的打包命令进行打包
  6. 创建容器并访问

5.3 Docker 部署 Mysql

使用 Docker 部署 Mysql 步骤如下所示:

shell
# 创建容器。-e: 设置环境变量 --privileged=true 开启root用户权限
docker run -di --name=mysql -p 3306:3306 -v mysql_data:/var/lib/mysql -v mysql_conf:/etc/mysql --privileged=true -e MYSQL_ROOT_PASSWORD=1234 mysql:8.0.30

# 进入容器
docker exec -it mysql /bin/bash

# 登录mysql
mysql -uroot -p

并创建对应的数据库和数据库表:

创建数据库:docker

创建表

sql
CREATE TABLE `tb_school` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

添加测试数据

sql
INSERT INTO `tb_school` VALUES (1, '尚硅谷-北京校区', '北京市昌平区宏福科技园2号楼3层');
INSERT INTO `tb_school` VALUES (2, '尚硅谷-上海校区', '上海市松江区谷阳北路166号大江商厦3层');
INSERT INTO `tb_school` VALUES (3, '尚硅谷-深圳校区', '深圳市宝安区西部硅谷大厦B座C区一层');
INSERT INTO `tb_school` VALUES (4, '尚硅谷-西安校区', '西安市雁塔区和发智能大厦B座3层');
INSERT INTO `tb_school` VALUES (5, '尚硅谷-成都校区', '成都市成华区北辰星拱青创园综合楼3层');
INSERT INTO `tb_school` VALUES (6, '尚硅谷-武汉校区', '武汉市东湖高新区东湖网谷6号楼4层');

5.4 Maven 的 Docker 插件

实操

  1. 在 pom.xml 文件中添加 Maven 的 Docker 插件
xml
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>1.2.2</version>

    <!--将插件绑定在某个phase执行-->
    <executions>
        <execution>
            <id>build-image</id>
            <!--将插件绑定在package这个phase(阶段)上。也就是说,用户只需执行mvn package,就会自动执行mvn docker:build-->
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>

    <configuration>
        <!--指定生成的镜像名-->
        <imageName>${project.artifactId}</imageName>

        <!--指定标签,也就是版本号,可以自定义-->
        <imageTags>
            <imageTag>v2.0</imageTag>
        </imageTags>

        <!--指定远程 docker api地址 也就是服务器ip+docker的端口号-->
        <dockerHost>http://192.168.136.142:2375</dockerHost>

        <!-- 指定 dockerfile 路径-->
        <dockerDirectory>${project.basedir}</dockerDirectory>

        <!-- 是否跳过docker构建 -->
        <skipdockerBuild>false</skipdockerBuild>

    </configuration>

</plugin>
  1. Docker 服务端开启远程访问
shell
# 修改Docker服务配置文件
vim /lib/systemd/system/docker.service

# 找到ExecStart行,修改成如下内容
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock

# 重启守护进程
systemctl daemon-reload

# 重启Docker服务
systemctl restart docker
  1. 编写 Dockerfile 文件

注意

  • 该文件的位置必须是和 pom.xml 处于同一个目录
  • 关闭防火墙
shell
FROM centos7-jdk17
MAINTAINER atguigu
EXPOSE 8081
ADD target/ebuy-docker-1.0-SNAPSHOT.jar /ebuy-docker-1.0-SNAPSHOT.jar

WORKDIR /
ENTRYPOINT ["java" , "-jar" , "ebuy-docker-1.0-SNAPSHOT.jar"]
  1. 执行 Maven 的打包命令
shell
# 打包跳过测试
mvn clean package -DskipTests

# 打包跳过测试的同时提高构建
mvn clean package -DskipTests -DskipdockerBuild
  1. 创建容器并进行访问
shell
# 创建并运行容器,映射端口8082到容器的8081端口
docker run -d --name ebuy-docker -p 8082:8081 ebuy-docker:latest

5.5 推送镜像

推送到阿里云镜像

  • 开通阿里云镜像仓库(打开阿里云登录页,让学生扫码登录,演示从零到一开通过程)
  • 登录镜像仓库
  • 重命名镜像,按照阿里云规范
  • 推送镜像

推送镜像到 Docker Hub

shell
# 登录Docker Hub
docker login

# 为镜像打标签
docker tag ebuy-docker:latest username/ebuy-docker:v1.0

# 推送镜像
docker push username/ebuy-docker:v1.0

5.6 测试

访问测试: http://192.168.6.131:8081

六、Docker Compose

6.1 Docker Compose 简介

  1. Docker Compose 是一个工具,用于定义和运行多容器应用程序的工具;
  2. Docker Compose 通过 yml 文件定义多容器的 Docker 应用;
  3. Docker Compose 通过一条命令根据 yml 文件的定义去创建或管理多容器;

Docker Compose 是用来做 Docker 的多容器控制,有了 Docker Compose 你可以把所有繁复的 Docker 操作全都一条命令,自动化的完成。

官网地址:https://docs.docker.com/compose/install/linux/

Docker Compose 的优点

  1. 单主机多容器部署
  2. 快速搭建开发环境
  3. 项目编排管理
  4. 简化多容器应用的管理

6.2 下载与安装

下载与安装

  • 在安装 Docker 时候已经完成了安装,直接查看版本号,查看是否安装成功
shell
# 创建指定目录存储docker compose
mkdir -p /usr/local/lib/docker/cli-plugins

# 下载并移动
curl -SL https://github.com/docker/compose/releases/download/v2.14.2/docker-compose-linux-x86_64 -o /usr/local/lib/docker/cli-plugins/docker-compose

# 给docker-compose文件赋予可执行权限
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

# 查看docker compose的版本
docker compose version

6.3 入门案例

需求:使用 Docker Compose 部署 Redis

docker-compose.yml 文件的内容如下所示:

yml
services:
  redis:
    image: redis:7.0.10
    container_name: redis
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    restart: always
volumes:
  redis-data: {}

Docker Compose 相关命令

shell
# 启动容器(如果不存在容器就创建、存在则修改)
docker compose -f docker-compose.yml up -d

# 删除所有容器
docker compose -f docker-compose.yml down

# 停止所有容器
docker compose -f docker-compose.yml stop

# 启动所有容器
docker compose -f docker-compose.yml start

# 重启所有容器
docker compose -f docker-compose.yml restart

# 查看容器状态
docker compose -f docker-compose.yml ps

# 查看容器日志
docker compose -f docker-compose.yml logs

# 进入容器
docker compose -f docker-compose.yml exec redis /bin/bash

Docker Compose 文件中其他的常见指令参考官方文档:https://docs.docker.com/compose/compose-file/05-services/

6.4 编排 Spring Boot 项目

需求:使用 Docker Compose 部署上一章节的 Spring Boot 项目

docker-compose.yml 文件的内容如下所示:

yaml
services:
  mysql:
    container_name: mysql
    image: mysql:8.0.30
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - mysql_conf:/etc/mysql
    privileged: true
    environment:
      - "MYSQL_ROOT_PASSWORD=1234"
    restart: always
  ebuy:
    container_name: ebuy
    image: ebuy-docker
    ports:
      - "8081:8081"
    depends_on:
      - mysql
    restart: always
volumes:
  mysql_data: {}
  mysql_conf: {}

6.5 Docker Compose 常用配置

yaml
version: "3.8" # 指定compose版本

services: # 定义服务
  web:
    image: nginx:latest # 指定镜像
    build: . # 构建镜像
    container_name: mynginx # 容器名称
    ports: # 端口映射
      - "80:80"
    volumes: # 数据卷挂载
      - ./html:/usr/share/nginx/html
    environment: # 环境变量
      - ENV=production
    networks: # 网络
      - mynetwork
    depends_on: # 依赖关系
      - db
    restart: always # 重启策略
    command: nginx -g "daemon off;" # 覆盖默认命令

networks: # 定义网络
  mynetwork:
    driver: bridge

volumes: # 定义数据卷
  mydata:

6.6 Docker 私有仓库搭建

为什么需要私有仓库?

  1. 企业内部镜像需要保密
  2. 加速镜像下载
  3. 节省带宽
  4. 统一管理镜像

6.6.1 搭建私有仓库

方式一:使用 Docker Registry

shell
# 1. 拉取registry镜像
docker pull registry:2

# 2. 创建私有仓库容器
docker run -d \
  --name=registry \
  -p 5000:5000 \
  -v /opt/registry:/var/lib/registry \
  --restart=always \
  registry:2

# 说明:
# -p 5000:5000:映射端口
# -v /opt/registry:/var/lib/registry:数据持久化
# --restart=always:容器自动重启

方式二:使用 Harbor(企业级推荐)

Harbor 是 VMware 开源的企业级 Docker Registry 项目,提供了更丰富的功能。

shell
# 1. 下载Harbor安装包
wget https://github.com/goharbor/harbor/releases/download/v2.5.0/harbor-offline-installer-v2.5.0.tgz

# 2. 解压
tar -xzf harbor-offline-installer-v2.5.0.tgz

# 3. 修改配置文件
cd harbor
cp harbor.yml.tmpl harbor.yml
vim harbor.yml

# 修改以下配置:
# hostname: 192.168.136.142  # 修改为本机IP
# http.port: 80
# harbor_admin_password: Harbor12345  # 管理员密码

# 4. 安装Harbor
./install.sh

# 5. 启动Harbor
docker-compose up -d

6.6.2 配置私有仓库地址

shell
# 修改Docker配置文件
vim /etc/docker/daemon.json

# 添加以下内容(将192.168.136.142替换为私有仓库地址)
{
  "registry-mirrors": ["https://docker.m.daocloud.io"],
  "insecure-registries": ["192.168.136.142:5000"]
}

# 重启Docker服务
systemctl daemon-reload
systemctl restart docker

6.6.3 推送镜像到私有仓库

shell
# 1. 标记镜像
docker tag redis:7.0.10 192.168.136.142:5000/redis:7.0.10

# 2. 推送镜像
docker push 192.168.136.142:5000/redis:7.0.10

# 3. 查看私有仓库中的镜像
curl http://192.168.136.142:5000/v2/_catalog

# 4. 查看某个镜像的所有标签
curl http://192.168.136.142:5000/v2/redis/tags/list

6.6.4 从私有仓库拉取镜像

shell
# 从私有仓库拉取镜像
docker pull 192.168.136.142:5000/redis:7.0.10

6.6.5 私有仓库认证

shell
# 1. 创建用户密码文件
docker run --entrypoint htpasswd httpd:2 -Bbn admin 123456 > /opt/registry-auth/htpasswd

# 2. 启动带认证的私有仓库
docker run -d \
  --name=registry-auth \
  -p 5000:5000 \
  -v /opt/registry:/var/lib/registry \
  -v /opt/registry-auth:/auth \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  --restart=always \
  registry:2

# 3. 登录私有仓库
docker login 192.168.136.142:5000

# 4. 推送/拉取镜像(需要先登录)
docker push 192.168.136.142:5000/redis:7.0.10

# 5. 退出登录
docker logout 192.168.136.142:5000

6.6.6 Harbor 使用指南

shell
# 登录Harbor
docker login 192.168.136.142

# 推送镜像到Harbor
docker tag redis:7.0.10 192.168.136.142/library/redis:7.0.10
docker push 192.168.136.142/library/redis:7.0.10

# 从Harbor拉取镜像
docker pull 192.168.136.142/library/redis:7.0.10

Harbor Web 界面访问http://192.168.136.142

默认账号:admin 默认密码:Harbor12345

七、Docker 网络管理

7.1 Docker 网络概述

Docker 网络是 Docker 容器之间以及容器与外部世界通信的桥梁。Docker 提供了多种网络模式,满足不同场景的需求。

7.2 Docker 网络模式

Docker 支持以下几种网络模式:

  1. bridge 模式(默认):桥接网络,容器通过网桥与宿主机通信
  2. host 模式:容器使用宿主机的网络命名空间
  3. none 模式:容器没有网络接口
  4. container 模式:容器共享另一个容器的网络命名空间
  5. 自定义网络:用户创建的网络

7.3 网络管理命令

shell
# 查看所有网络
docker network ls

# 创建网络
docker network create 网络名称

# 创建网络并指定驱动类型
docker network create -d bridge mynetwork

# 查看网络详情
docker network inspect 网络名称

# 删除网络
docker network rm 网络名称

# 删除所有未使用的网络
docker network prune

# 将容器连接到网络
docker network connect 网络名称 容器名称

# 将容器从网络断开
docker network disconnect 网络名称 容器名称

7.4 网络使用示例

shell
# 创建自定义网络
docker network create mynetwork

# 创建容器并连接到自定义网络
docker run -d --name=redis01 --network=mynetwork redis:7.0.10
docker run -d --name=redis02 --network=mynetwork redis:7.0.10

# 在同一网络中的容器可以通过容器名称互相访问
docker exec -it redis01 ping redis02

7.5 Docker 资源限制详解

Docker 可以通过设置资源限制来控制容器使用的 CPU、内存等资源,防止单个容器占用过多资源影响其他容器或宿主机。

7.5.1 内存限制

shell
# 设置内存限制
docker run -d --name=redis01 -m 512m redis:7.0.10

# 设置内存和交换内存限制
docker run -d --name=redis02 -m 512m --memory-swap=1g redis:7.0.10

# 设置内存软限制(允许超过,但在内存紧张时优先回收)
docker run -d --name=redis03 --memory-reservation=256m -m 512m redis:7.0.10

# 禁止容器使用交换内存
docker run -d --name=redis04 -m 512m --memory-swappiness=0 redis:7.0.10

# 设置内存限制后容器被杀死的退出状态码
# OOM (Out of Memory) 退出状态码: 137

内存限制参数说明

参数说明
-m, --memory设置内存使用上限
--memory-swap设置内存+交换内存的总上限
--memory-reservation设置内存软限制
--memory-swappiness设置使用交换内存的倾向(0-100)
--oom-kill-disable禁用 OOM Killer(需要设置-m 参数)
--oom-score-adj设置 OOM 优先级(-1000 到 1000)

7.5.2 CPU 限制

shell
# 设置CPU份额(相对权重,默认1024)
docker run -d --name=redis01 --cpu-shares=512 redis:7.0.10

# 设置CPU核数限制
docker run -d --name=redis02 --cpus=1.5 redis:7.0.10

# 指定使用的CPU核心
docker run -d --name=redis03 --cpuset-cpus="0,1" redis:7.0.10

# 设置CPU配额和周期
docker run -d --name=redis04 --cpu-quota=50000 --cpu-period=100000 redis:7.0.10

# 设置CPU实时运行时间
docker run -d --name=redis05 --cpu-rt-runtime=950000 --cpu-rt-period=1000000 redis:7.0.10

CPU 限制参数说明

参数说明
--cpus设置可使用的 CPU 核数(如 1.5 表示 1.5 核)
--cpu-shares设置 CPU 份额权重(相对值)
--cpuset-cpus指定使用的 CPU 核心(如 0,1,2)
--cpu-quota设置 CPU 配额(需要配合--cpu-period)
--cpu-period设置 CPU 周期(默认 100000 微秒)

7.5.3 磁盘 IO 限制

shell
# 设置块设备读写速率限制
docker run -d --name=redis01 \
  --device-read-bps=/dev/sda:10mb \
  --device-write-bps=/dev/sda:10mb \
  redis:7.0.10

# 设置块设备读写IOPS限制
docker run -d --name=redis02 \
  --device-read-iops=/dev/sda:1000 \
  --device-write-iops=/dev/sda:1000 \
  redis:7.0.10

# 设置IO权重(仅对CFQ调度器有效)
docker run -d --name=redis03 --blkio-weight=500 redis:7.0.10

磁盘 IO 限制参数说明

参数说明
--device-read-bps设置设备读取速率上限
--device-write-bps设置设备写入速率上限
--device-read-iops设置设备读取 IOPS 上限
--device-write-iops设置设备写入 IOPS 上限
--blkio-weight设置 IO 权重(10-1000)

7.5.4 综合资源限制示例

shell
# 创建一个资源受限的容器
docker run -d \
  --name=myapp \
  -m 1g \
  --memory-swap=2g \
  --cpus=2 \
  --cpuset-cpus="0,1" \
  --device-read-bps=/dev/sda:50mb \
  --device-write-bps=/dev/sda:50mb \
  --pids-limit=100 \
  nginx:latest

# 说明:
# - 内存限制1GB,内存+交换内存限制2GB
# - CPU限制2核,指定使用第0和第1核
# - 磁盘读写限制50MB/s
# - 进程数限制100个

7.5.5 查看容器资源使用情况

shell
# 查看所有容器的资源使用情况
docker stats

# 查看指定容器的资源使用情况
docker stats myapp

# 不刷新显示(只显示一次)
docker stats --no-stream

# 自定义输出格式
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# 查看容器的资源限制配置
docker inspect myapp | grep -A 20 "HostConfig"

7.5.6 使用 Docker Compose 设置资源限制

yaml
services:
  web:
    image: nginx:latest
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M

八、Docker 命令总结

8.1 Docker 命令速查表

分类命令及常用参数核心功能实用示例
镜像管理docker pull [镜像:标签]拉取远程镜像docker pull nginx:1.25
docker build -t 镜像:标签 .基于 Dockerfile 构建镜像docker build -t myapp:1.0 .
docker images [-a]列出本地镜像(-a 显示所有)docker images -a
docker rmi [-f] 镜像 / ID删除镜像(-f 强制删除)docker rmi -f nginx:1.25
docker tag 镜像 新镜像:标签为镜像添加标签docker tag nginx:1.25 mynginx:v1
docker save -o file.tar 镜像导出镜像docker save -o nginx.tar nginx:1.25
docker load -i file.tar导入镜像docker load -i nginx.tar
容器管理docker run [-d -p -name] 镜像创建并启动容器docker run -d -p 80:80 --name web nginx
docker ps [-a]查看容器(-a 显示所有状态)docker ps -a
docker exec -it 容器 bash进入运行中容器docker exec -it web bash
docker logs [-f] 容器查看容器日志(-f 实时跟踪)docker logs -f web
docker rm [-f] 容器删除容器(-f 强制删除运行中)docker rm -f web
docker start/stop/restart 容器启动/停止/重启容器docker start web
docker cp 容器:路径 宿主机路径容器与宿主机间复制文件docker cp web:/app/log.txt ./
存储管理docker volume ls/create列出 / 创建数据卷docker volume create myvol
docker volume inspect 数据卷查看数据卷详情docker volume inspect myvol
docker volume rm 数据卷删除数据卷docker volume rm myvol
网络管理docker network ls/create列出 / 创建网络docker network create mynet
docker network connect 网络名 容器名将容器连接到网络docker network connect mynet web
Composedocker compose up [-d]启动 Compose 服务(-d 后台)docker compose up -d
docker compose down [-v]停止并删除服务(-v 删除卷)docker compose down -v
docker compose logs [-f]查看 Compose 服务日志docker compose logs -f

8.2 Docker 帮助文档

Docker 中提供了很多命令,每一个命令也可以加很多的参数选项。把一个命令以及对应的参数选项都记住很显然是不太现实的。可以通过查看 Docker 帮助文档来学习 Docker 的常用命令以及参数选项的使用。

  • 帮助文档的使用如下所示:
shell
# 查询docker可以使用到的命令
docker --help

# 查询images命令的使用文档
docker images --help

# 查询run命令的使用文档
docker run --help

九、Docker 监控与日志管理

9.1 Docker 日志管理

9.1.1 查看容器日志

shell
# 查看容器日志
docker logs 容器名称

# 实时查看日志(类似tail -f)
docker logs -f 容器名称

# 查看最后100行日志
docker logs --tail 100 容器名称

# 查看指定时间段的日志
docker logs --since 2023-01-01 容器名称
docker logs --since 1h 容器名称          # 最近1小时
docker logs --until 2023-12-31 容器名称

# 查看日志并显示时间戳
docker logs -t 容器名称

9.1.2 日志驱动配置

Docker 支持多种日志驱动:

shell
# 创建容器时指定日志驱动
docker run -d \
  --name=nginx \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  nginx:latest

# 常用日志驱动:
# json-file:默认驱动,日志以JSON格式存储
# syslog:将日志发送到syslog
# journald:将日志发送到systemd journal
# none:禁用日志
# local:本地日志驱动,性能更好

日志驱动配置示例

shell
# 使用syslog日志驱动
docker run -d \
  --name=nginx \
  --log-driver syslog \
  --log-opt syslog-address=tcp://192.168.1.100:514 \
  nginx:latest

# 使用local日志驱动
docker run -d \
  --name=nginx \
  --log-driver local \
  --log-opt max-size=10m \
  --log-opt max-file=5 \
  nginx:latest

9.1.3 日志配置文件

在 daemon.json 中配置默认日志驱动:

json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

9.2 Docker 监控工具

9.2.1 Docker 内置监控

shell
# 实时监控容器资源使用
docker stats

# 查看容器进程信息
docker top 容器名称

# 查看容器详细信息
docker inspect 容器名称

# 查看容器事件
docker events

# 查看容器端口映射
docker port 容器名称

# 查看容器文件系统变化
docker diff 容器名称

9.2.2 cAdvisor(容器监控工具)

cAdvisor 是 Google 开源的容器监控工具:

shell
# 启动cAdvisor容器
docker run -d \
  --name=cadvisor \
  -p 8080:8080 \
  -v /:/rootfs:ro \
  -v /var/run:/var/run:ro \
  -v /sys:/sys:ro \
  -v /var/lib/docker/:/var/lib/docker:ro \
  google/cadvisor:latest

# 访问Web界面:http://localhost:8080

9.2.3 Prometheus + Grafana 监控方案

yaml
# docker-compose.yml
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - "--path.procfs=/host/proc"
      - "--path.sysfs=/host/sys"

volumes:
  grafana-data:

9.3 Docker 健康检查

9.3.1 Dockerfile 中配置健康检查

dockerfile
FROM nginx:latest

# 配置健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1

# 参数说明:
# --interval:检查间隔(默认30s)
# --timeout:超时时间(默认30s)
# --start-period:启动等待时间(默认0s)
# --retries:重试次数(默认3次)

9.3.2 运行时配置健康检查

shell
# 创建容器时配置健康检查
docker run -d \
  --name=nginx \
  --health-cmd="curl -f http://localhost/ || exit 1" \
  --health-interval=30s \
  --health-timeout=3s \
  --health-retries=3 \
  nginx:latest

# 查看容器健康状态
docker inspect --format='{{.State.Health.Status}}' nginx

# 查看健康检查历史
docker inspect --format='{{json .State.Health}}' nginx | jq

9.3.3 Docker Compose 中配置健康检查

yaml
services:
  web:
    image: nginx:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 5s

9.4 Docker 事件监控

shell
# 实时监控Docker事件
docker events

# 过滤特定事件
docker events --filter type=container
docker events --filter event=start
docker events --filter container=nginx

# 监控指定时间范围的事件
docker events --since 1h
docker events --since "2023-01-01" --until "2023-12-31"

# 格式化输出
docker events --format '时间: {{.Time}} 类型: {{.Type}} 动作: {{.Action}}'

9.5 日志聚合方案

9.5.1 ELK Stack(Elasticsearch + Logstash + Kibana)

yaml
# docker-compose.yml
services:
  elasticsearch:
    image: elasticsearch:8.8.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    ports:
      - "9200:9200"
    volumes:
      - es-data:/usr/share/elasticsearch/data

  logstash:
    image: logstash:8.8.0
    container_name: logstash
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    ports:
      - "5044:5044"
    depends_on:
      - elasticsearch

  kibana:
    image: kibana:8.8.0
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    depends_on:
      - elasticsearch

volumes:
  es-data:

9.5.2 使用 Filebeat 收集 Docker 日志

yaml
# filebeat.docker.yml
filebeat.inputs:
  - type: container
    paths:
      - "/var/lib/docker/containers/*/*.log"

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
shell
# 启动Filebeat容器
docker run -d \
  --name=filebeat \
  --user=root \
  -v /var/lib/docker/containers:/var/lib/docker/containers:ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -v ./filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro \
  elastic/filebeat:8.8.0

十、常见问题与解决方案

10.1 镜像拉取失败

问题:拉取镜像时出现连接超时或下载速度很慢

解决方案

  1. 配置国内镜像加速器
  2. 使用代理服务器
  3. 使用私有镜像仓库

10.2 容器无法启动

问题:容器启动后立即退出

解决方案

  1. 查看容器日志:docker logs 容器名称
  2. 检查容器配置是否正确
  3. 检查镜像是否完整

10.3 端口冲突

问题:启动容器时提示端口已被占用

解决方案

  1. 查看端口占用情况:netstat -tunlp | grep 端口号
  2. 更换映射端口
  3. 停止占用端口的服务

10.4 磁盘空间不足

问题:Docker 占用磁盘空间过大

解决方案

shell
# 查看Docker磁盘使用情况
docker system df

# 清理未使用的镜像
docker image prune

# 清理未使用的容器
docker container prune

# 清理未使用的数据卷
docker volume prune

# 清理所有未使用的资源
docker system prune

10.5 容器时间不正确

问题:容器内时间与宿主机时间不一致

解决方案

shell
# 方案1:挂载宿主机时区文件
docker run -v /etc/localtime:/etc/localtime:ro 镜像名称

# 方案2:设置环境变量
docker run -e TZ=Asia/Shanghai 镜像名称

10.6 容器无法访问外网

问题:容器内部无法访问外部网络

解决方案

  1. 检查宿主机网络是否正常
  2. 检查 Docker 网络配置
  3. 重启 Docker 服务

10.7 Docker 最佳实践

  1. 镜像优化

    • 使用多阶段构建减小镜像大小
    • 合并 RUN 指令减少镜像层数
    • 使用.dockerignore 排除不需要的文件
  2. 容器管理

    • 使用数据卷持久化数据
    • 设置容器资源限制
    • 使用健康检查
  3. 安全建议

    • 不要使用 root 用户运行容器
    • 定期更新基础镜像
    • 使用私有镜像仓库
  4. 性能优化

    • 合理设置容器资源限制
    • 使用合适的存储驱动
    • 优化 Dockerfile 构建过程