Appearance
Docker 学习指南
导航目录
- 一、Docker 初体验
- 二、Docker 镜像操作
- 三、Docker 容器操作
- 四、Docker 数据卷操作
- 五、Spring Boot 项目部署
- 六、Docker Compose
- 七、Docker 网络管理
- 八、Docker 命令总结
- 九、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 的优势包括:
可移植性:Docker 容器可以在任何支持 Docker 的环境中运行,包括本地开发环境、测试环境和生产环境,从而提高了应用程序的可移植性。
可伸缩性:Docker 容器可以根据负载的变化进行快速扩展和收缩,从而更好地满足应用程序的需求。
隔离性:Docker 容器提供了隔离的运行环境,从而使得不同容器中运行的应用程序互相隔离,避免了应用程序之间的干扰。
轻量级:Docker 容器共享宿主机的操作系统内核,不需要模拟整个操作系统,因此比虚拟机更加轻量级,启动速度更快。
版本控制: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 核心组件:
Docker Client(客户端):Docker 客户端是用户与 Docker 交互的主要方式,通过命令行或 API 发送请求给 Docker 守护进程。
Docker Daemon(守护进程):Docker 守护进程是 Docker 的服务器端组件,负责构建、运行和分发 Docker 容器。
Docker Image(镜像):Docker 镜像是一个只读模板,包含创建 Docker 容器的指令。
Docker Container(容器):Docker 容器是镜像的运行实例,可以被启动、停止、删除等。
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-engine1.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 version1.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 info1.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列介绍:
- name:镜像仓库源名称
- description:镜像的描述
- official:是否 Docker 官方发布
- stars:镜像的收藏数,收藏数越多表示此镜像的受欢迎程度越高
- automated:是否自动构建
搜索过滤:
shell
# 只显示官方镜像
docker search --filter "is-official=true" redis
# 只显示收藏数大于100的镜像
docker search --filter "stars=100" redis2.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.102.3 查看本地镜像
相关命令如下所示:
shell
# 命令:
docker images
# 示例:
docker images
# 只显示镜像ID
docker images -q
# 显示所有镜像(包括中间层镜像)
docker images -a
# 只显示指定镜像
docker images redis列介绍:
- repository:镜像来源仓库名称
- tag:镜像标签
- image id:镜像 id
- created:创建时间
- 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.102.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 # 查看本地正在运行的容器列介绍:
- container id:容器 ID
- image:镜像名称
- command:容器启动时所执行的命令
- created:创建时间
- status:容器状态
- ports:端口映射情况
- names:容器的名称
常见参数选项:
shell
-a,--all # 查询所有的镜像,包含未运行的容器
-q,--quiet # 查询容器的id
# 示例1:查询所有的容器包含未运行的容器
docker ps -a
# 示例2:查询容器的id
docker ps -q
# 示例3:显示容器大小
docker ps -s
# 示例4:显示最近创建的容器
docker ps -l3.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.103.3 容器服务管理
容器管理的相关命令如下所示:
shell
# 关闭容器
docker stop 容器名称/容器id
# 启动容器
docker start 容器名称/容器id
# 重启容器
docker restart 容器名称/容器id
# 暂停容器
docker pause 容器名称/容器id
# 恢复容器
docker unpause 容器名称/容器id
# 杀死容器
docker kill 容器名称/容器id3.4 删除容器
删除容器的常见命令如下所示:
shell
# 命令: docker rm
# 格式:docker rm 容器名称/容器的id # 删除容器
# 示例:删除mycentos10容器
docker rm mycentos10注意:上述的命令只能删除已经关闭的容器,如果想删除正在运行的容器,可以通过添加 -f 参数进行实现。
删除所有的容器:
shell
# 删除所有容器(包括运行中的)
docker rm $(docker ps -aq)
# 删除所有已停止的容器
docker container prune3.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 /rootdocker attach 与 docker exec 的区别:
shell
# docker attach:进入容器正在执行的终端,退出会导致容器停止
docker attach 容器名称/容器id
# docker exec:在容器中打开新的终端,退出不会导致容器停止(推荐使用)
docker exec -it 容器名称/容器id /bin/bash3.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),提供很多有用的特性:
- 数据卷可以在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新不会影响镜像
- 数据卷默认会一直存在,即使容器被删除
为什么需要数据卷?
Docker 容器产生的数据,如果不通过 docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。为了能保存数据,Docker 使用了数据卷。
数据卷的特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
4.2 数据卷操作命令
shell
# 创建数据卷
docker volume create 数据卷名称
# 查看所有数据卷
docker volume ls
# 查看数据卷详情
docker volume inspect 数据卷名称
# 删除数据卷
docker volume rm 数据卷名称
# 删除所有未使用的数据卷
docker volume prune4.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.tarcommit 命令详解:
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 部分:
- 基础镜像信息(必选)
- 维护者信息(可选)
- 镜像操作指令(可选)
- 容器启动时执行的指令(可选)
常用命令:
| 指令 | 用法 | 作用 |
|---|---|---|
| FROM | FROM image_name:tag | 指定一个构建镜像的基础源镜像,如果本地没有就会从公共库中拉取,没有指定镜像的标签会使用默认的 latest 标签,可以出现多次,如果需要在一个 dockerfile 中构建多个镜像。 |
| MAINTAINER | MAINTAINER user_name | 描述镜像的创建者,名称和邮箱 |
| RUN | RUN "command" "param1" "param2" | 用来执行一些命令,可以写多条 |
| ENV | ENV key value | 设置容器的环境变量,可以写多条。 |
| ADD | ADD source_dir/file | 将宿主机的文件复制到容器内,如果是压缩文件,则复制后自动解压 |
| COPY | COPY source_dir/file | 将宿主机的文件复制到容器内(不会自动解压) |
| ENTRYPOINT | ENTRYPOINT "command" "param1" "param2" | 用来指定容器启动时所执行的命令 |
| CMD | CMD "command" "param1" "param2" | 指定容器启动时默认执行的命令,可以被 docker run 参数覆盖 |
| WORKDIR | WORKDIR path | 指定工作目录 |
| EXPOSE | EXPOSE port | 声明暴露的端口 |
| VOLUME | VOLUME ["path"] | 创建挂载点 |
| ARG | ARG key=value | 定义构建时的变量 |
| USER | USER username | 指定运行容器时的用户名或 UID |
5.1.2 入门案例
需求:使用 Dockerfile 来构建一个包含 Jdk17 的 centos7 镜像
分析:
- 基础的镜像的应该选择 centos:7
- 在自己所构建的镜像中需要包含 Jdk17,就需要把 Jdk17 添加到 centos:7 的基础镜像中
- 为了方便的去使用自己构建的镜像中的 Jdk17,就需要去配置环境变量
- 因为 Jdk17 仅仅是一个开发工具,并不是一个服务进程,因此在启动容器的时候可以不指定任何的执行命令
实现步骤:
- 将 Jdk17 的安装包上传到 linux 服务器的指定目录下
- 在 Jdk17 所在的目录下创建一个 dockerfile 文件
- 使用 docker build 命令构建镜像
- 使用 docker images 查看镜像构建情况
- 使用自己所构建的镜像创建容器,测试 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/bashDockerfile 最佳实践:
- 使用.dockerignore 文件排除不需要的文件
- 使用多阶段构建减小镜像大小
- 合并 RUN 指令减少镜像层数
- 使用特定版本标签而不是 latest
- 尽量使用官方镜像作为基础镜像
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 all4. 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-serverCMD 与 ENTRYPOINT 的区别:
| 特性 | CMD | ENTRYPOINT |
|---|---|---|
| 作用 | 设置容器默认启动命令 | 设置容器主命令 |
| 是否可被覆盖 | 可被 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=production7. 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/c10. 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 appuser14. 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上使用PowerShell5.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:从第一阶段复制文件
# 最终镜像只包含第二阶段的内容,大小大幅减小多阶段构建的优势:
- 减小镜像大小
- 分离构建环境和运行环境
- 提高安全性(不包含构建工具)
5.2 案例介绍与需求分析
需求:将提供的 Spring Boot 项目使用容器化进行部署
刚才的入门案例中,构建过程是手动镜像构建的过程。现在我们可以使用 Maven 的 Docker 插件实现镜像的自动化部署。
分析:
- Spring Boot 项目中使用到了 Mysql 环境,因此需要先使用 Docker 部署 Mysql 环境
- 要将 Spring Boot 项目使用 Docker 容器进行部署,就需要将 Spring Boot 项目构建成一个 Docker 镜像
实现步骤:
- 使用 Docker 部署 Mysql
- 在 pom.xml 文件中添加 Maven 的 Docker 插件
- 开启 Docker 服务端的远程访问
- 在工程的根目录下创建 Dockerfile 文件
- 使用 Maven 的打包命令进行打包
- 创建容器并访问
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 插件
实操:
- 在 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>- 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- 编写 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"]- 执行 Maven 的打包命令
shell
# 打包跳过测试
mvn clean package -DskipTests
# 打包跳过测试的同时提高构建
mvn clean package -DskipTests -DskipdockerBuild- 创建容器并进行访问
shell
# 创建并运行容器,映射端口8082到容器的8081端口
docker run -d --name ebuy-docker -p 8082:8081 ebuy-docker:latest5.5 推送镜像
推送到阿里云镜像:
- 开通阿里云镜像仓库(打开阿里云登录页,让学生扫码登录,演示从零到一开通过程)
- 登录镜像仓库
- 重命名镜像,按照阿里云规范
- 推送镜像
推送镜像到 Docker Hub:
shell
# 登录Docker Hub
docker login
# 为镜像打标签
docker tag ebuy-docker:latest username/ebuy-docker:v1.0
# 推送镜像
docker push username/ebuy-docker:v1.05.6 测试
访问测试: http://192.168.6.131:8081
六、Docker Compose
6.1 Docker Compose 简介
- Docker Compose 是一个工具,用于定义和运行多容器应用程序的工具;
- Docker Compose 通过 yml 文件定义多容器的 Docker 应用;
- Docker Compose 通过一条命令根据 yml 文件的定义去创建或管理多容器;
Docker Compose 是用来做 Docker 的多容器控制,有了 Docker Compose 你可以把所有繁复的 Docker 操作全都一条命令,自动化的完成。
官网地址:https://docs.docker.com/compose/install/linux/
Docker Compose 的优点:
- 单主机多容器部署
- 快速搭建开发环境
- 项目编排管理
- 简化多容器应用的管理
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 version6.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/bashDocker 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 私有仓库搭建
为什么需要私有仓库?
- 企业内部镜像需要保密
- 加速镜像下载
- 节省带宽
- 统一管理镜像
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 -d6.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 docker6.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/list6.6.4 从私有仓库拉取镜像
shell
# 从私有仓库拉取镜像
docker pull 192.168.136.142:5000/redis:7.0.106.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:50006.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.10Harbor Web 界面访问:http://192.168.136.142
默认账号:admin 默认密码:Harbor12345
七、Docker 网络管理
7.1 Docker 网络概述
Docker 网络是 Docker 容器之间以及容器与外部世界通信的桥梁。Docker 提供了多种网络模式,满足不同场景的需求。
7.2 Docker 网络模式
Docker 支持以下几种网络模式:
- bridge 模式(默认):桥接网络,容器通过网桥与宿主机通信
- host 模式:容器使用宿主机的网络命名空间
- none 模式:容器没有网络接口
- container 模式:容器共享另一个容器的网络命名空间
- 自定义网络:用户创建的网络
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 redis027.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.10CPU 限制参数说明:
| 参数 | 说明 |
|---|---|
| --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 | |
| Compose | docker 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:latest9.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:80809.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 | jq9.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: 5s9.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 镜像拉取失败
问题:拉取镜像时出现连接超时或下载速度很慢
解决方案:
- 配置国内镜像加速器
- 使用代理服务器
- 使用私有镜像仓库
10.2 容器无法启动
问题:容器启动后立即退出
解决方案:
- 查看容器日志:
docker logs 容器名称 - 检查容器配置是否正确
- 检查镜像是否完整
10.3 端口冲突
问题:启动容器时提示端口已被占用
解决方案:
- 查看端口占用情况:
netstat -tunlp | grep 端口号 - 更换映射端口
- 停止占用端口的服务
10.4 磁盘空间不足
问题:Docker 占用磁盘空间过大
解决方案:
shell
# 查看Docker磁盘使用情况
docker system df
# 清理未使用的镜像
docker image prune
# 清理未使用的容器
docker container prune
# 清理未使用的数据卷
docker volume prune
# 清理所有未使用的资源
docker system prune10.5 容器时间不正确
问题:容器内时间与宿主机时间不一致
解决方案:
shell
# 方案1:挂载宿主机时区文件
docker run -v /etc/localtime:/etc/localtime:ro 镜像名称
# 方案2:设置环境变量
docker run -e TZ=Asia/Shanghai 镜像名称10.6 容器无法访问外网
问题:容器内部无法访问外部网络
解决方案:
- 检查宿主机网络是否正常
- 检查 Docker 网络配置
- 重启 Docker 服务
10.7 Docker 最佳实践
镜像优化
- 使用多阶段构建减小镜像大小
- 合并 RUN 指令减少镜像层数
- 使用.dockerignore 排除不需要的文件
容器管理
- 使用数据卷持久化数据
- 设置容器资源限制
- 使用健康检查
安全建议
- 不要使用 root 用户运行容器
- 定期更新基础镜像
- 使用私有镜像仓库
性能优化
- 合理设置容器资源限制
- 使用合适的存储驱动
- 优化 Dockerfile 构建过程