Docker
概念
Docker 是一种用于开发、交付和运行应用程序的开放平台。它允许您在容器中打包应用程序及其依赖关系,并提供了一种轻量级、可移植和自包含的环境。以下是 Docker 的一些核心概念和特点:
- 容器化:Docker 利用 Linux 容器技术,将应用程序及其所有依赖项打包到一个容器中,这使得应用程序可以在任何环境中以相同的方式运行。
- 轻量级:与传统虚拟机相比,Docker 容器更加轻量级,在性能和资源消耗上都有优势。
- 可移植性:由于 Docker 容器封装了应用程序及其依赖项,因此可以轻松地在不同的主机上进行部署和运行。
- 自动化:Docker 提供了丰富而强大的 API 和工具集,帮助用户自动化构建、部署和扩展应用服务。
- 镜像与容器:Docker 使用镜像来打包应用程序及其环境,并使用容器来实际运行这些镜像。
Docker 通过提供一种简单且易于管理的方式来进行软件交付与部署,使得开发人员、系统管理员以及整个组织可以更高效地构建、交付和管理应用。
Docker 包括三个基本概念
- 镜像(
Image
)- 容器(
Container
)- 仓库(
Repository
)
分层存储
Docker 镜像采用分层存储机制,在构建过程中每一步操作都会在当前基础上创建新一层,并将其中间结果保存为新层。这种分层存储机制使得 Docker 镜像具备了以下特点:
- 重用性:多个不同的容器可以共享相同底层图层(Layer),减少磁盘空间占用。
- 可复制性:如果需要修改某个图层,则只需修改对应图层数字即可,而无需重新复制整个文件系统。
- 分发性:由于每个图层都可以单独存在并被推送到注册表中,因此也更易于分发和分享。
镜像
镜像是 Docker 中的核心概念,它是用于打包应用程序及其依赖项的轻量级、可移植的部署单元。镜像实际上是一个只读的模板,它包含了运行应用程序所需的所有文件系统内容、运行时配置和环境变量。
使用方法:
- 拉取镜像:要使用某个镜像,首先需要从 Docker Hub 或其他注册表中拉取该镜像。可以使用
docker pull
命令来拉取指定版本或标签的镜像。 - 运行容器:一旦有了所需的镜像,可以使用
docker run
命令基于该镜像创建并运行一个容器实例。 - 定制与构建:如果现有的公共镜像不满足需求,可以通过编写 Dockerfile 来定义自己的定制化镜像,并通过
docker build
命令来构建这个新版本的自定义镜像。
-
容器
镜像(Image
)和容器(Container
)的关系,就像是面向对象程序设计中的 类
和 实例
一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。
仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个 仓库(Repository
);每个仓库可以包含多个 标签(Tag
);每个标签对应一个镜像
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签>
的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest
作为默认标签。
Docker Registry 公开服务
Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。
私有 Docker Registry
除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。
安装
Docker确实分为三个更新频道:stable、test和nightly。以下是这三个更新频道的详细说明:
- Stable(稳定版):
- 这是Docker的正式发布版本,经过充分测试,适合生产环境使用。
- 用户可以依赖于此版本的稳定性和安全性,通常包含经过验证的功能和修复。
- Test(测试版):
- 这个频道包含最新的功能和修复,但尚未经过全面的生产环境测试。
- 适合开发者和测试人员使用,以便在新功能正式发布之前进行试用和反馈。
- Nightly(夜间版):
- 这是每日构建的版本,包含最新的代码更改和功能。
- 由于是最新构建,可能会包含未经过测试的功能,因此不建议在生产环境中使用。
- 适合开发者希望测试最新功能或参与Docker开发的用户。
Ubuntu 安装 Docker
- 更新现有的包索引
首先,打开终端并更新现有的包索引:
1 | $ sudo apt-get update |
- 使用 APT 安装
由于 apt
源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
1 | $ sudo apt-get install \ |
- 添加Docker的官方GPG密钥
1 | $ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg |
- 添加Docker的稳定版仓库
向 sources.list
中添加 Docker 软件源
1 | $ echo \ |
- 安装 Docker
更新 apt 软件包缓存,并安装 docker-ce
:
1 | $ sudo apt-get update |
- 启动Docker并设置为开机自启
安装完成后,启动Docker服务并设置为开机自启:
1 | $ sudo systemctl start docker |
- 验证Docker安装
可以通过运行以下命令来验证Docker是否安装成功:
1 | $ sudo docker --version |
- 可选)将当前用户添加到Docker组
默认情况下,docker
命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root
用户和 docker
组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root
用户。因此,更好地做法是将需要使用 docker
的用户加入 docker
用户组。
1 | $ sudo groupadd docker |
- 测试 Docker 是否安装正确
1 | $ docker run --rm hello-world |
如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker 国内镜像加速
国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了国内加速器服务,例如:
- 阿里云加速器(点击管理控制台 -> 登录账号(淘宝账号) -> 右侧镜像工具 -> 镜像加速器 -> 复制加速器地址)
- 网易云加速器
https://hub-mirror.c.163.com
- 百度云加速器
https://mirror.baidubce.com
由于镜像服务可能出现宕机,建议同时配置多个镜像。
MacOS
Docker Desktop for Mac 要求系统最低为 macOS Mojave 10.14。
安装
- 使用 Homebrew 安装
Homebrew 的 Cask 已经支持 Docker Desktop for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装:
1
$ brew install --cask docker
- 手动下载安装
如果需要手动下载,请点击以下 链接 下载 Docker Desktop for Mac。
你可以在 官方文档 查阅已知的问题。
双击下载的
.dmg
文件,然后将那只叫 Moby 的鲸鱼图标拖拽到Application
文件夹即可(其间需要输入用户密码)。运行
从应用中找到 Docker 图标并点击运行
你可以在终端通过命令检查安装后的 Docker 版本。
1
2$ docker --version
Docker version 20.10.0, build 7287ab3如果
docker version
、docker info
都正常的话,可以尝试运行一个 Nginx 服务器:1
$ docker run -d -p 80:80 --name webserver nginx
要停止 Nginx 服务器并删除执行下面的命令:
1
2$ docker stop webserver
$ docker rm webserver
Windows 10/11
- Windows 10 64-bit:需要使用Windows 10 Professional、Enterprise或Education版本。
- Windows 10 Home:从Docker Desktop 2.3.0.2版本开始,Docker Desktop也支持Windows 10 Home,但需要启用WSL 2(Windows Subsystem for Linux 2)。
安装
手动下载安装
点击以下 [链接](https://desktop.docker.com/win/main/amd64/Docker Desktop Installer.exe) 下载 Docker Desktop for Windows。
下载好之后双击
Docker Desktop Installer.exe
开始安装。使用 winget 安装
1
$ winget install Docker.DockerDesktop
运行
在 Windows 搜索栏输入 Docker 点击 Docker Desktop 开始运行
镜像使用
获取镜像
从 Docker 镜像仓库获取镜像的命令是 docker pull
。其命令格式为:
1 | $ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] |
- Docker 镜像仓库地址:地址的格式一般是
<域名/IP>[:端口号]
。默认地址是 Docker Hub(docker.io
)。 - 仓库名:如之前所说,这里的仓库名是两段式名称,即
<用户名>/<软件名>
。对于 Docker Hub,如果不给出用户名,则默认为library
,也就是官方镜像。
比如:
1 | $ docker pull ubuntu:18.04 |
上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub (docker.io
)获取镜像。而镜像名称是 ubuntu:18.04
,因此将会获取官方镜像 library/ubuntu
仓库中标签为 18.04
的镜像。docker pull
命令的输出结果最后一行给出了镜像的完整名称,即: docker.io/library/ubuntu:18.04
。
使用镜像
1 | $ docker run -it --rm ubuntu:18.04 bash |
-it
:这是两个参数,一个是-i
:交互式操作,一个是-t
终端。我们这里打算进入bash
执行一些命令并查看返回结果,因此我们需要交互式终端。--rm
:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动docker rm
。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用--rm
可以避免浪费空间。ubuntu:18.04
:这是指用ubuntu:18.04
镜像为基础来启动容器。bash
:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是bash
。
进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release
,这是 Linux 常用的查看当前系统版本的命令
列出镜像
要想列出已经下载下来的镜像,可以使用 docker image ls
命令。
1 | $ docker image ls |
如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a
参数。
把所有的虚悬镜像的 ID 列出来,-q
参数。
自定义输出格式
使用 --format
选项可以根据需要输出特定的字段。例如,下面的命令只会显示容器的ID和名称:
1 | $ docker ps --format "{{.ID}}: {{.Names}}" |
在 docker ps
的 --format
选项中,可以使用以下字段:
ID
:容器IDImage
:使用的镜像Command
:运行的命令Created
:创建日期RunningFor
:运行时间Ports
:端口映射Status
:容器状态Size
:容器大小Names
:容器名称Labels
:容器标签Mounts
:挂载的卷
在 docker image ls
的 --format
选项中,可以使用以下字段:
ID
:镜像IDRepository
:镜像仓库名称Tag
:镜像标签Created
:创建日期Size
:镜像大小
Docker容器操作
docker run Hello-word
docker run 执行流程(工作流程)
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问
DockerServer接收到Docker-Client的指令,就会执行这个命令
docker相比传统的VM
Docker 相比传统虚拟机(VM)快
主要有以下几点:
- 轻量级架构:
- Docker 使用容器技术,而虚拟机则运行完整的操作系统。容器共享宿主机的操作系统内核,而虚拟机需要完整的操作系统及其所需的资源(如内存、CPU等),因此启动和运行速度更快。
- 资源利用率:
- 容器在宿主操作系统之上运行,它们直接共享宿主机的资源而无需进行额外的虚拟化层。这使得 Docker 能够实现更高效的资源利用,减少了资源的开销。
- 快速启动:
- Docker 容器能够在几秒钟内启动,因为它们不需要加载完整的操作系统,而是直接运行应用程序。因此,与虚拟机相比,容器的启动和停止时间显著缩短。
- 更少的开销:
- Docker 使用的资源较少,因为它只包含了运行应用所需的最小文件系统。容器可以快速复制和部署,减少了磁盘和内存的使用。
- 便捷的管理和部署:
- Docker 的图像和容器管理工具(如 Docker Hub、Docker Compose 等)使得开发、分发和部署变得更加简单和高效,可以快速创建新的环境。
Docker 命令
常用命令
帮助命令
1 | docker version # 显示docker版本信息 |
镜像命令
查看镜像 -
docker images
1
2
3
4
5docker images # 查看所有镜像
参数
-a 显示所有镜像
-f 过滤
-q 只显示id
查询镜像 -
docker search
1
docker search mysql # 查询mysql镜像
下载镜像 -
docker pull
1
2docker pull mysql # 下载镜像
docker pull mysql:8.0.20删除镜像 -
docker rmi
1
2
3
4docker rmi -f e73346bdf465 # id 为 docker images 下的IMAGE ID
docker rmi -f id1, id2, id3
删除所有镜像
docker rmi -f $(docker images -aq)
容器命令
容器基于镜像,创建容器首先要有镜像
用于学习容器命令,可以准备一个centos容器:docker pull centos
新建/启动容器 -
docker run image
1
2
3
4
5
6
7
8
9docker run [可选参数] image
参数说明
--name 命名容器名称
-d 后台运行
-it 使用交互方式运行,
-P 指定容器的端口
-P 主机端口:容器端口(-P 65505:3306) 指定主机的端口跟容器端口之间的联系
-P ip:主机端口:容器端口
-p 随机指定端口退出容器并停止容器 -
exit
不停止容器退出 -
Ctrl+P+Q
查看当前运行的环境 -
docker ps
1
2
3
4
5docker ps # 查看后台运行的容器
docker ps -a # 查看所有运行过的容器,包括已退出的
docker ps -n=x # 查看最近使用的容器,n为展示数量
docker -q # 只展示 CONTAINER ID
docker -aq # 只展示所有容器 CONTAINER ID删除容器 -
docker rm
1
2
3docker rm 容器id # 注:运行中不能删除
docker rm -f 容器id # 强制删除所有容器,包括运行中
docker rm -f $(docker ps -aq) # 删除所有容器停止运行的容器 -
docker stop
1
2
3docker stop 容器id
强制停止
docker kill 容器id启动容器 -
docker start
1
docker start 容器id
重新启动容器 -
docker restart
1
docker restart 容器id
后台启动容器 -
docker run -d
1
2
3docker run -d 容器id
通过 docker run -d 启动容器,会导致容器停止;docker容器在后台运行,就必须要有一个前台进程,docker发现没有应用进程,就会自动停止
docker run -d 容器id /bin/sh -c "while true; do echo '123asd'; sleep 2;done" # 后台打开容器,并执行shell脚本命令查看日志 -
docker logs
1
2
3
4docker logs [可选参数] 容器id
参数使用
docker logs -tf 容器id # 查看全部日志 -t为带上时间戳
docker logs -t --tail 20 容器id # 查看最后20行日志查看容器进程 -
docker top
1
docker top 容器id # 查看容器内部的进程
查看容器cpu状态 -
docker stats
1
docker stats
查看镜像源数据/ 查看当前容器启动信息
1
docker inspect 容器id
进入当前正在进行的容器
- 方式一:
docker exec
1
docker exec -it 容器id bashShell # 进入的是一个新的终端
- 方式二:
docker attach
1
docker attach 容器id # 进入当前容器正在运行的终端
- 方式一:
文件传输 -
docker cp
1
2从容器内拷贝文件到主机:
docker cp 容器id:容器内路径 目的主机路径
案例
部署Nginx
1 | 搜索nginx版本 - docker管网 https://hub.docker.com |
部署Tomcat
1 | 额外使用方式:下载并启动Tomcat docker ; --rm : 即一次性,用完即删。可用来测试 |
部署ES+Kibana
1 | ES 特点:暴露端口多;十分耗内存;数据需要放置到安全目录(挂载) |
可视化
Rancher
portainer
1 | docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer |
Docker 镜像原理
镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,包含某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件
- 结构:Docker 镜像是由多层文件系统组成的,每一层都是只读的,代表了 Dockerfile 中的指令。下层通常是基础镜像,随后是应用层和配置层。
- 分层文件系统:每一层都会在文件系统中产生变化,可以看作是对上层的一次增量更新。
UnionFS 联合文件系统
UnionFS 联合文件系统:Union文件系统是一种分层、轻量级并且高性能的文件系统,它允许用户将多个文件系统的内容合并在一起,形成一个统一的视图。这种技术常用于Linux和Unix系统中,能够提高灵活性和效率,特别是在容器化和虚拟化的环境中。
UnionFS的工作原理
UnionFS通过以下方式工作:
- 层叠结构:UnionFS能够将多个文件系统(层)叠加在一起。用户看到的文件和目录实际上是这些层的组合。
- 读写分离:在这种结构中,通常会有一个只读的底层文件系统和一个可读写的上层文件系统。对文件的修改会发生在上层文件系统中,而底层文件系统保持不变。
- 文件合并:当用户访问文件时,UnionFS会检查上层,如果上层没有这个文件,才会去底层查找。这样,用户可以同时使用多个文件系统中的文件,而不需要复杂的管理
Docker 镜像的加载原理
Docker 镜像的加载原理主要涉及到 Docker 的分层文件系统和镜像存储机制。
Docker 镜像的加载与 rootfs
的形成过程如下:
- 归档与解压:
- 当你使用
docker load
命令加载镜像时,实际上是从一个.tar
文件中解压出镜像的分层。 - 每一层都会被展开,存储在 Docker 的存储驱动管理的区域中。
- 当你使用
- **构建
rootfs
**:- Docker 从镜像的最底层开始,逐层堆叠,最终形成完整的
rootfs
。这时,所有的只读层结合在一起,形成一个可供容器使用的文件系统。
- Docker 从镜像的最底层开始,逐层堆叠,最终形成完整的
- 挂载文件系统:
- 在容器启动时,这个
rootfs
被挂载为容器的文件系统。Docker 的存储驱动负责将这些只读层与写层组合在一起。 - 写层通常是可写的,所有对文件的修改都会体现在这一层,而不会影响前面的只读层。
- 在容器启动时,这个
- 执行容器:
- 一旦容器启动,
rootfs
成为其运行时的基础文件系统,允许容器执行命令和读写文件。
- 一旦容器启动,
Docker 分层原理
Docker 的分层原理是其设计中非常重要的特性,允许镜像和容器以高效和可复用的方式管理文件系统。
分层文件系统简介
Docker 镜像是由多个只读层(read-only layers)组成的,每个层都代表了文件系统的一个快照。这种结构使得 Docker 能够实现镜像的快速构建、共享和存储。
分层的基本概念
在 Docker 中,分层的基本概念包括以下几个方面:
- 基础镜像:每个镜像都可以基于其他镜像,以此来构建新的镜像。例如,
FROM ubuntu
表明这个镜像是建立在 Ubuntu 基础镜像之上。 - 镜像层:在 Dockerfile 中的每一条指令创建一个新的镜像层。例如,
RUN
,COPY
,ADD
等指令都会生成一个新的层。 - 只读特性:每个镜像层是只读的,只能被访问而不能被修改。当修改文件时,Docker 会在文件系统的最上层创建一个可写层(writeable layer)。
分层的工作机制
- 创建与下载:当你构建或下载镜像时,Docker 将检查该镜像的每一层。如果某一层已经存在于本地,Docker 将不会重复下载或创建这层,而是直接复用。这一特性显著提高了镜像的构建和分发效率。
- 层的合并:当容器启动时,Docker 将所有的只读层与一个可写层合并形成一个完整的文件系统(
rootfs
)。在该过程中,所有的文件操作(如创建、修改、删除)都会在可写层中进行,而不会影响到已经存在的只读层。 - 写时复制(Copy-on-Write, CoW):当容器对文件进行修改时,Docker 会在可写层中复制这个文件的只读版本,然后对其进行修改。这意味着任何对文件的改动只在可写层中存在,而原有的只读层保持不变。
可以使用 docker image inspect redis:latest
来查看层级
如何提交一个自己的镜像 - commit
镜像
1 | docker commit -a="作者" -m="提交记录" 容器id 别名:版本 |
容器数据卷
理念:数据都在容器中,如果删除了容器,数据就会丢失
怎么实现数据持久化?容器数据之间如何共享?
概念
容器数据卷(Volume)是容器化技术(如Docker)中的一个重要概念,用于持久化和管理容器内的数据。数据卷可以解决一些重要的问题,诸如容器重启、更新或者卸载时如何保留数据、实现容器间的数据共享等。
原理:容器数据卷技术:即将容器内的目录,挂载到Linux上面;
容器内可以访问容器外数据,容器内处理保存的数据,在Linux主机上
当两个容器共用同一个数据卷,则这两个容器数据共享
数据卷的特点
- 持久性:数据卷的生命周期独立于使用它的容器。即使容器被删除,数据卷中的数据仍然存在。
- 共享和重用:多个容器可以共享同一个数据卷。这使得数据能够在容器间进行共享和重用。
- 性能:数据卷通常比在容器文件系统中存储数据要快。对数据卷的读写操作可以获得更好的性能。
- 方便备份和恢复:数据卷使得备份和恢复操作变得简单方便。只需对数据卷进行备份,而不需要关心哪个容器在使用它。
数据卷的种类
- 管理卷(Named Volumes):由Docker管理,存储在主机上的特定位置。适合用于持久化数据。
- 匿名卷(Anonymous Volumes):没有名称,临时使用后可以被删除。
- 绑定挂载(Bind Mounts):直接将主机的目录或文件挂载到容器内,可以实现对主机文件的直接访问和修改。适用于开发环境。
数据卷的使用
挂载数据卷
使用 -v
参数来挂载数据卷
1 | docker run -it -v 主机目录:容器内目录 |
1 | 查看镜像详细 |
具名挂载&匿名挂载&指定路径挂载
-v 容器内路径 匿名挂载
-v 卷名: 容器内路径 具名挂载
-v /宿主主机路径: 容器内路径 指定路径挂载
匿名挂载
匿名挂载,在创建容器的时候 -v
只写了容器内的路径,没有写容器外的路径
1 | docker run -d --name Nginx01 -v /etc/nginx nginx |
具名挂载
即通过 -v
传入 卷名:容器内路径
1 | docker run -d --name Nginx01 -v Nginx_mount:/etc/nginx nginx |
查看具体容器内的制定目录
1
docker volume inspect [VOLUME NAME]
拓展
-v 参数还可以在容器内路径后加 :ro
或 :rw
;来控制读写权限
1 | docker run -d --name Nginx01 -v Nginx_mount:/etc/nginx:ro nginx |
ro
即:
readonly
只读权限 ;这个路径职能通过宿主主机来操作,容器内部无法操作rw
(默认)即:
readwrite
可读可写
数据卷容器
多个容器共享使用一个数据挂载目录,实现容器数据共享
–volumes-from
--volumes-from
是 Docker 中一个用于挂载其他容器数据卷的选项。它允许你将一个容器的卷(Volumes)挂载到另一个容器中,使得这两个容器之间能够共享数据。
使用场景
- 服务分离:假设你的应用程序由多个服务组成,每个服务都运行在不同的容器中,但它们需要访问同一个数据存储。
- 简化容器管理:当你需要多个容器使用相同的数据卷时,使用
--volumes-from
可以避免重复设置相同的卷挂载
注意事项和拓展
数据卷的生命周期:使用
--volumes-from
挂载的卷,他们的生命周期与源容器的生命周期相关。当源容器删除时,挂载的卷仍然存在,但它们的使用受到限制。只读和读写:可以使用
:ro
选项来使挂载的卷为只读,例如1
docker run -it --name app_container --volumes-from db_data:ro ubuntu /bin/bash
限制:
--volumes-from
只能用于已经存在的容器,不能用于直接挂载新的卷。
示例
启动一个存储数据的容器
1
2创建了一个名为 db_data 的容器,并在其中创建了一个名为 /data/db 的数据卷
docker run -d --name db_data -v /data/db busybox运行另一个容器并挂载第一个容器的卷
1
2该命令启用了一个名为 app_container 的新容器,并将 db_data 容器的所有数据卷挂载到此容器中
docker run -it --name app_container --volumes-from db_data ubuntu /bin/bash进入
app_container
容器后,你可以看到db_data
容器中/data/db
路径下的数据
Dockerfile
概述
Dockerfile 是一种文本文件,包含了一系列指令,用于自动化 Docker 镜像的构建。通过 Dockerfile,开发者可以定义应用程序的环境、所需的依赖、运行特性等,从而简化软件的部署和分发流程。
Docker 镜像的层次结构
Docker 镜像的构建是基于分层文件系统(Layered Filesystem)概念的,每个镜像都是由多个层(Layers)堆叠而成的。每个层代表了镜像的一部分,并且这些层是不可变的。当你基于一个已有镜像创建新的镜像时,Docker 会在现有镜像的基础上添加新的层。
- 基础镜像:每个 Docker 镜像都以一个基础镜像为起点,比如
ubuntu
、alpine
或python
等。基础镜像本身也可以是由其他镜像构建而成的。 - 中间层:在 Dockerfile 中,每执行一条命令(如
RUN
、COPY
、ADD
等)时,Docker 创建一个新的层。这个层包含了该命令执行后文件系统的变化。例如,安装软件包或复制文件时会产生新的层。 - 顶层:构建完成的镜像的最上层是你在 Dockerfile 中最后指定的内容,比如
CMD
或ENTRYPOINT
。这个层定义了容器启动时的行为。
Dockerfile构建过程
Dockerfile 的构建过程是 Docker 为了创建镜像而执行的一系列步骤。这个过程是由 docker build
命令启动的,Docker 根据 Dockerfile 中定义的指令逐步创建镜像。
编写 Dockerfile
创建一个名为 Dockerfile 的文件,文件中包含你要执行的指令,例如安装软件、复制文件等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 使用 ubuntu:20.04 作为基础镜像
FROM ubuntu:20.04
# 更新包索引并安装 Python
RUN apt-get update && apt-get install -y python3
# 创建应用目录
WORKDIR /app
# 复制应用代码到镜像中
COPY . .
# 安装应用所需依赖
RUN pip3 install -r requirements.txt
# 指定容器启动时运行的命令
CMD ["python3", "app.py"]构建镜像
使用
docker build
命令构建镜像。1
2
3docker build -t my_docker_image .
# -t my_docker_image 指定镜像的标签为 my_docker_image
# . 指定上下文为当前目录。构建过程的详细步骤
在构建过程中,Docker 按照指令执行,并将每一步的结果保存为一个镜像层(Layer)。这些步骤包括:
3.1 解析 Dockerfile
Docker 开始解析 Dockerfile,从上到下依次处理指令。
3.2 构建基础镜像
- FROM:使用指定的基础镜像。在这个例子中,Docker 从
ubuntu:20.04
开始。 - 如果该镜像不存在于本地,Docker 会从 Docker Hub 拉取该镜像。
3.3 执行运行指令
- RUN:每次执行 RUN 指令时,Docker 会在现有镜像的基础上执行该指令,并为其创建新层。例如,执行更新仓库与安装 Python。
每个 RUN 指令都会启动一个新的容器,执行该指令,并将更改保存为新镜像层。
3.4 设置工作目录
- WORKDIR:设置容器内的工作目录,所有后续的指令都将在这个目录下执行。如果目录不存在,Docker 会自动创建它。
3.5 复制文件
- COPY:将主机文件系统中的文件复制到镜像中的工作目录中。复制过程会将源路径中的所有文件和目录复制到目标路径中。
3.6 安装依赖
在这个例子中,使用 RUN 指令再次安装应用程序所需的 Python 包。
3.7 设置默认命令
- CMD:配置容器启动时的默认命令。当容器运行时,会执行这个命令。
- FROM:使用指定的基础镜像。在这个例子中,Docker 从
镜像层的结构
Docker 每执行一次指令,都会生成一个新的镜像层。这些镜像层是分层文件系统的一部分,因此可以利用层的重用性来加快构建过程。每一层都只保存了自上一个层以来的数据更改。
例如,如果你更改了 Dockerfile 中某一步,Docker 只会重新构建那个步骤及其之后的所有步骤,而不会重建整个镜像。
查看镜像
使用
docker images
命令查看已构建的镜像运行容器
使用
docker run
命令从生成的镜像启动一个容器。
Dockerfile 指令
FROM:指定基础镜像
1
FROM ubuntu:20.04
MAINTAINER: 用于指定镜像的维护者信息
1
MAINTAINER yourName@example.com
LABEL: 为镜像添加元数据
1
LABEL version="1.0" description="My Sample Image"
RUN: 为镜像构建期间执行命令。通常用来安装依赖软件包
1
RUN apt-get update && apt-get install -y python3
CMD: 指定容器启动时执行的命令。 可以被docker run 传递命令覆盖
1
CMD ["python3", "app.py"]
ENTRYPOINT: 配置容器启动时的主命令,可以与CMD配合使用
1
2
3
4
5ENTRYPOINT ["python3", "app.py"]
# CMD与 ENTRYPOINT 区别
# CMD 容器启动时要运行的命令,只有最后一个会生效,可以被docker run 传递命令覆盖,可被替代
# ENTRYPOINT 容器启动时要运行的命令,可以追加命令COPY: 将本地文件或目录复制到镜像中
1
COPY . /app
ADD: 类似于COPY,但支持从URL下载文件和解压归档文件
1
ADD myapp.tar.gz /app
WORKDIR: 设置工作目录,后续的RUN,CMD,ECTRYPOINT等命令都会在这个目录下运行
1
WORKDIR /app
EXPOSE: 声明容器要监听的端口。该指令不实际执行任何操作,仅用于文档化
1
EXPOSE 80
ENV: 设置环境变量
1
ENV APP_ENV=production
VOLUME: 创建一个可供容器使用的挂载点,可以挂载数据卷
1
VOLUME ["/data"]
USER: 指定在容器内运行命令时使用的用户
1
USER appuser
ARG: 定义在构建时传递的变量
1
ARG VERSION=1.0
SHELL: 改变RUN指令所使用的默认
shell
1
SHELL ["/bin/bash", "-c"]
ONBUILD: 当构件一个被继承
DockerFile
这个时候就会运行ONBUILE指令
实例
假设,我要构建一个简单的 Python Flask 应用。这个应用将在一个 Ubuntu 基础镜像中运行,并允许用户通过访问 Flask Web 服务器来获取信息。
项目目录
1 | my-flask-app/ |
Dockerfile
1 | # 使用 Ubuntu 作为基础镜像 |
1 | # 在终端中进入到 my-flask-app 目录,然后运行以下命令来构建 Docker 镜像 |
访问应用
打开浏览器并访问 http://localhost:5000/
Docker 网络
网络驱动程序
Docker 支持多种网络驱动程序
bridge(桥接网络) - 默认
- 默认情况下,Docker 会创建一个名为
bridge
的网络,所有新创建的容器都会连接到这个网络。 - 每个容器都有一个虚拟的 IP 地址,通过 NAT(网络地址转换)与主机通信。
- 适用于大多数容器间通信的场景
1
2
3# 创建一个默认的 bridge 网络并启动一个容器
docker run -d --name my-container nginx
docker run -d --name my-container --network bridge nginx- 默认情况下,Docker 会创建一个名为
host(主机网络)
- 容器与宿主机共享网络栈,容器内的服务将直接使用宿主机的 IP 地址及接口。
- 不适合需要隔离的场景,因为容器的网络与宿主机是完全相同的。
- 适合高性能需求的网络应用。
1
2# 使用主机网络模式运行一个容器
docker run -d --name my-container --network host nginxoverlay(叠加网络)
- 允许在多台 Docker 主机之间进行跨主机的网络通信,通常用于 Docker Swarm 集群。
- 可以将多个 Docker 主机上的容器连接到同一个虚拟网络。
- 适合微服务架构和需要跨主机通信的应用。
1
2# 创建 overlay 网络
docker network create -d overlay my-overlay-networkmacvlan(MAC 虚拟网络)
- 为每个容器分配一个独立的 MAC 地址,容器可以直接在物理网络上通信。
- 可以将容器直接暴露到物理网络中,适合一些特殊场景。
- 需要网络管理员的支持来配置。
1
2# 创建 macvlan 网络
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 my-macvlannone(无网络)
- 容器没有网络接口,适合一些需要完全隔离的特定场景。
- 只允许容器通过内部 IPC 通信。
1
2# 使用 none 网络模式运行一个容器
docker run -d --name my-container --network none nginx
常用网络命令
查看所有网络(网卡)
1
docker network ls
查看网络详细信息
1
docker network inspect <network_name>
创建网络
1
docker network create <network_name>
删除网络
1
docker network rm <network_name>
网络连接和通信
容器可以通过名称相互访问:在同一网络下,容器可以通过名称直接访问彼此。例如,在 Docker Compose 中,服务可以通过服务名称互相访问。
端口映射:使用
-p
选项将主机的端口映射到容器的端口,允许外部流量访问容器服务。1
docker run -d -p 8080:80 nginx
环境变量和 DNS:Docker 提供了内置的 DNS 服务,可以通过容器名称解析到相应的 IP 地址。
Docker Compose 中的网络
在 Docker Compose 中,可以定义服务使用的网络
1 | # web 和 app 服务都连接到名为 my-network 的桥接网络。这样,它们可以通过服务名称互相访问。 |
容器互通 (–link)
--link
是 Docker 早期版本中用于实现容器之间互通的一个参数。它提供了一个简单的方式,使一个容器能够通过指定的别名与另一个容器进行通信。尽管在某些场景中它是有用的,但由于其局限性和不够灵活,Docker 官方已经不推荐使用 --link
,并建议使用用户自定义的网络来实现容器之间的通信。
基本方法
创建容器
1
docker run -d --name redis-server redis
创建另一个容器并链接到第一个容器
1
2# 在创建第二个容器时,使用 --link 选项将其与 Redis 容器链接
docker run -it --name redis-client --link redis-server:redis redis sh连接效果
一旦容器通过
--link
选项连接,Docker 会在redis-client
容器中自动设置相应的环境变量,例如1
2
3
4
5
6# 容器 redis-client 可以通过环境变量直接访问 Redis 服务
REDIS_PORT=tcp://172.17.0.2:6379
REDIS_PORT_6379_TCP=tcp://172.17.0.2:6379
REDIS_PORT_6379_TCP_PROTO=tcp
REDIS_PORT_6379_TCP_PORT=6379
REDIS_NAME=redis-server实例
进入
redis-client
容器并使用redis-cli
连接到redis
容器1
redis-cli -h redis-server -p 6379
自定义网络
Docker允许用户自定义网络来连接容器,以便它们可以相互通信或连接到外部网络。通过自定义网络,用户可以在容器之间创建私有网络,以增强安全性和隔离性。
创建网络
docker network create
命令允许您在Docker中创建一个自定义网络。下面是docker network create
命令的详细使用方法:
1 | docker network create [OPTIONS] NETWORK |
常用的选项:
--driver
:指定网络的驱动程序。默认驱动程序为bridge
。--subnet
:指定网络的子网。--gateway
:指定网络的网关。--ip-range
:指定可用于网络中的IP地址范围。--internal
:创建一个内部网络,该网络只能被本地容器访问。--attachable
:允许其他容器连接到此网络,即使未被指定为其默认网络。
例如,要创建一个名为my_network
的网络,子网为172.18.0.0/16
,网关为172.18.0.1
,可以使用以下命令:
1 | docker network create --driver=bridge --subnet=172.18.0.0/16 --gateway=172.18.0.1 my_network |
运行容器并连接到自定义网络
在启动容器时,可以使用--network
选项将容器连接到自定义网络
1 | docker run --network <network_name> -d <image> |
断开容器与自定义网络的连接
1 | docker network disconnect <network_name> <container_name> |
其他
只要容器连接到同一个自定义网络中,即使不使用--link
参数,也可以通过容器名称进行通信。在自定义网络中,Docker会自动管理容器之间的DNS解析,使得容器名称可以直接用于通信。
网络联通
当两组不同的自定义网络或默认网络(docker0)与自定义网络下的docker容器进行连接
docker network connect
命令用于将现有容器连接到指定的网络。通过这个命令,可以实现容器在不同网络之间的快速切换和移动,便于网络配置的灵活性
将容器连接到新创建的自定义网络
*问题**: 假设您已经创建了一个名为
my_network
的自定义网络,并且有一个正在运行的容器my_container_1
,您想将其连接到my_network
网络中,可以使用以下命令1
docker network connect my_network my_container_1
为连接的容器指定IP地址
为连接的容器分配特定的IP地址,可以使用
--ip
选项。例如,将容器my_container_1
连接到my_network
网络并分配IP地址172.18.0.20
1
docker network connect --ip 172.18.0.20 my_network my_container_1
为连接的容器指定别名
使用
--alias
选项为容器指定别名。例如,将容器my_container_1
连接到my_network
网络并为其指定别名webserver
1
docker network connect --alias webserver my_network my_container_1
查看容器连接的网络
要查看容器连接到了哪些网络,以及容器在网络中的IP地址等信息,可以使用
docker network inspect
命令。例如,查看my_container_1
连接到的网络信息1
docker network inspect my_network
原理
在Linux系统上,Docker利用Linux的网络命名空间来实现容器的网络隔离。每个容器都运行在一个独立的网络命名空间中,这样可以保证容器之间的网络互相隔离,避免网络冲突。当容器连接到一个网络时,实际上是将容器加入到该网络命名空间,使得容器网络能够直接与该网络中的其他容器或主机进行通信。
案例: 部署redis集群
部署Redis集群通常采用分片(sharding)、高可用(high availability)和负载均衡(load balancing)的方式来提供性能和可靠性。在Docker中,可以通过使用多个Redis容器和一些额外的组件来实现这些功能。下面是一个简单的示例,演示如何在Docker中部署Redis集群,包括分片、高可用和负载均衡:
设置网络服务
- 创建redis 网卡
1
docker network create redis --subnet 172.38.0.0/16
- 查看网卡信息&网络详细信息
1
2docker network ls
docker network inspect redis创建Redis集群:
- 创建6个redis.conf ,根据redis.conf 创建6个不同redis容器
- 使用Docker Compose创建一个包含多个Redis容器(例如6个容器)的集群。
- 配置每个Redis容器的端口映射,确保它们之间可以互相通信。
- 配置Redis复制和集群插件,以实现数据的复制和分片。
使用Sentinel进行高可用性管理:
- 在集群中添加Redis Sentinel容器,用于监控Redis主从节点的健康状态,并在主节点故障时自动切换。
- 配置Sentinel监控的Redis节点,并设置故障转移和故障恢复的策略。
使用Nginx进行负载均衡:
- 部署一个Nginx容器作为负载均衡器,用于将客户端请求分发给多个Redis节点。
- 配置Nginx的负载均衡策略,如轮询、IP哈希等。
SprintBoot 微服务打包jar包发布docker镜像
Docker Compose
Docker Compose 是一个用于定义和运行多个 Docker 容器的工具。通过一个简单的 YAML 文件来配置应用程序的服务,然后可以使用一个命令来启动、停止和重建这些服务
1 | version: '3' |
在这个 YAML 配置文件中,我们定义了两个服务:web_app 和 db。每个服务都包含一些配置信息,例如使用的 Docker 镜像、端口映射、环境变量、数据卷等。
详细说明:
version: '3'
:指定 Docker Compose 配置文件的版本。services
:定义应用程序的服务列表,每个服务都可以包含一些配置选项。web_app
:定义了一个名为 web_app 的服务。image: nginx:latest
:指定使用的 Docker 镜像为最新版的 nginx。ports: "80:80"
:将容器内部的 80 端口映射到宿主机的 80 端口。volumes: "./web_app:/var/www/html"
:将宿主机当前目录下的 web_app 文件夹挂载到容器内的 /var/www/html 目录。depends_on: db
:指定该服务依赖于 db 服务,即在启动 web_app 之前需要先启动 db。
db
:定义了一个名为 db 的服务。image: mysql:latest
:指定使用的 Docker 镜像为最新版的 mysql。environment
:设置环境变量,例如 root 用户的密码和数据库名称。volumes: "./db_data:/var/lib/mysql"
:将宿主机当前目录下的 db_data 文件夹挂载到容器内的 /var/lib/mysql 目录,用于持久化数据库数据。
Docker Swarm (docker 集群管理)
概述
Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。
在 Docker Swarm 中,主要有三个重要的概念:
- Node:节点,即参与容器编排的主机,可以是物理机也可以是虚拟机。每个节点上都有一个 Docker 引擎,用于运行容器。
- Service:服务,用于定义容器应该如何运行。一个服务可以包含多个容器实例,可以指定所需的镜像、环境变量、网络等配置。
- Task:任务,是 Docker Swarm 中最小的工作单元,用于表示在节点上运行的一个容器实例。
Docker Swarm 提供了一些核心功能,如高可用性、负载均衡、滚动更新等。用户可以通过简单的命令创建集群,部署服务,并对服务进行扩展和更新
原理
swarm 集群由管理节点(manager)和工作节点(work node)构成
- swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
- work node:即图中的 available node,主要负责运行相应的服务来执行任务(task)
Docker Swarm指令
常用的 Docker Swarm 命令:
初始化 Docker Swarm
1
2
3
4
5
6docker swarm init
# 可以获得一个token。后续将节点加入到这个集群中
# 后续可以使用以下命令得到该令牌token,
docker swarm join-token manager # 生成主节点令牌
docker swarm join-token worker # 生成工作节点令牌当前docker机器加入到某个集群
1
docker swarm join --token <token> <manager-ip>
查看 Swarm 节点列表(开启swarm的docker机器)
1
docker node ls
创建一个服务
1
docker service create --replicas <num-replicas> --name <service-name> <image> <command>
列出所有服务
1
docker service ls
缩放服务的实力数量
1
docker service scale <service-name>=<num-replicas>
查看某个服务的详细信息
1
docker service inspect <service-name>
查看服务日志
1
docker service logs <service-name>
更新服务
1
docker service update --image <new-image> <service-name>
删除服务
1
docker service rm <service-name>
拓展:Raft 一致性算法
在Docker Swarm中,Raft一致性算法用于实现集群管理的决策一致性和问题解决。在一个Docker Swarm集群中,每个主节点都有一个Raft组件,用来实现领导者选举、日志复制等功能。Raft算法能够确保集群中的所有主节点都拥有相同的状态和数据,保证了集群的一致性。
Docker Swarm中Raft一致性算法的应用包括以下几个方面:
- 领导者选举:当一个主节点需要进行某项操作时(比如启动一个服务),Raft算法会通过领导者选举机制选出一个领导者节点来负责进行这个操作,其他主节点则成为追随者节点。
- 日志复制:领导者节点会将自己的操作日志发送给追随者节点,一旦大多数节点都复制了相同的日志,就能够保证操作的一致性,避免数据丢失。
- 容错性:Raft一致性算法能够容忍主节点的故障或者网络分区等问题,通过选举机制重新选举领导者节点,保证集群的正常运行。