docker 存储驱动
docker默认存储驱动overlay2
docker info 查看
docker 和虚拟化区别
docker
docker是在宿主机以进程的方式运行
启动速度快,占用资源少
隔离环境使用系统自带的kernel实现轻量隔离。以及进程的形式。 隔离性不如虚拟机
docker可以在不同环境中运行
docker 启动速度更快
docker不需要为每个应用运行独立的操作系统节省CPU和内存
适合运行微服务
运行容器的服务器上如果操作系统坏了所有的容器就坏了,如果是虚拟机的操作系统坏了其他虚拟机不受影响
虚拟机
适合重量级运行需求
强隔离性,每个虚拟机运行独立的内核
启动速度较慢
容器:使用 Namespace 和 Cgroups 实现轻量级隔离。虚拟机隔离性更强
每个容器基于镜像启动,镜像包含应用程序所需的运行环境(如语言运行时、库、配置文件等)。Python 应用的镜像包含 Python 解释器和相关依赖。Java 应用的镜像包含 JVM 和相关库。Go 应用的镜像可能只包含编译后的二进制文件。
使用 Docker 镜像可以确保开发、测试和生产环境完全一致,避免“在我机器上能运行”的问题。
容器适合运行微服务,虚拟机适合运行重载应用
docker安装
如果安装出问题
devicemapper 存储驱动已经在 docker 18.09 版本中被废弃,所以在后续的安Docker装中无需安装devicemapper支持。
root@localhost ~# yum install -y yum-utils device-mapper-persistent-data lvm2 vim
root@localhost~#wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo
root@localhost ~# sudo sed -i 's+download.docker.com+mirrors.huaweicloud.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
root@localhost ~# yum makecache
allin 安装
[root@docker ~]# yum install -y docker-ce
[root@docker ~]# systemctl enable docker.service --now
加速器配置
镜像加速器配置的位置:/etc/docker/daemon.json
因为docker去github拉取镜像的时候国内访问会非常慢需要加速器
华为云SMR镜像服务 ----- 镜像资源 ---- 镜像中心 ---- 点右上角镜像加速器 复制提供的内容
{
"registry-mirrors": [ "https://c7b5a5cd001e46f9af87bc7bb7cf0c17.mirror.swr.myhuaweicloud.com" ]
}
配置到/etc/docker/daemon.json
systemctl restart docker 重启服务
docker info 输出的内容有加速器地址说明配置成功
分离部署
客户端安装docker-ce-cli
服务端安装docker-ce
服务端在docker配置添加监听端口
关闭防火墙和selinux
root@client ~# docker -H 192.168.108.31 run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete
Digest: sha256:f7931603f70e13dbd844253370742c4fc4202d290c80442b2e68706d8f33ce26
Status: Downloaded newer image for hello-world:latest
杀掉主进程会导致容器停止
原因:容器的生命周期由其主进程(PID 1)决定。当主进程退出时,容器运行时(如 Docker 或 containerd)会认为容器的任务已完成,从而停止容器并清理资源。
runtime:是真正运行容器的地方
runc是docker自己开发的runtime
docker-ce包括docker-cli安装包
删除所有容器
docker rm -f $(docker ps -aq)
docker rm -r hello-world
完成配置后,按 Ctrl+P 和 Ctrl+Q 退出容器,保持容器运行。
使用以下命令查看正在运行的容器 ID:docker ps
提交容器为镜像: 使用 docker commit 将容器保存为新的镜像:docker commit my-custom-image:latest
组件
Docker client
Docker daemon
Docker image
Registry
Docker container
Linux Kernel是linux自带的组件 提供了关键的特性
例如:
Namespace:用于隔离进程、网络、文件系统等资源。
Cgroups:限制进程组可以使用的 CPU、内存、磁盘 I/O 等资源
Union File System:支持分层镜像和高效的存储管理。
Docker Runtime 利用这些 Kernel 特性来创建和管理容器。
容器本质上是以进程的形式运行的,容器的核心是一个或多个运行在宿主机上的进程,这些进程被封装在一个隔离的环境中。容器中的进程通过 Namespace 被隔离,只能看到自己的资源视图
Containerd 是一个高级容器运行时(High-Level Runtime),负责管理容器的生命周期。
接收来自 Docker Daemon 的请求,负责容器的实际创建、启动、停止、删除等操作。
管理镜像、存储卷、网络等资源。
runc 是一个低级容器运行时,直接与 kernel内核交互,使用内核特性(如 namespaces 和 cgroups)创建隔离的运行环境。启动初始进程。runc 的功能较为单一,专注于容器的“启动”和“运行”。
它的主要职责包括:调用 Kernel 提供的 Namespace 和 Cgroups API 来启动容器。管理镜像的分层存储。
运行过程
docker run 实现流程
docker 的cli和REST api交互,将cli转化为 RESTapi请求,并通过api打包给daemon
Docker Daemon 接收到请求后,检查本地是否已存在目标镜像。如果不存在,自动调用 docker pull 从docker hub拉取镜像。
daemon根据用户的资源需求生成运行时配置,然后将实际创建和管理交给containerd(容器运行时)
containerd生成配置文件
containerd调用runc来启动容器
runc 在容器内启动用户指定的命令或默认的入口点
容器启动完成后,Docker Daemon 将结果返回给 CLI,CLI 显示容器的运行状态。
docker build
cli解析参数准备构建上下文
cli通过API发送请求到Daemon
Docker Daemon 解析 Dockerfile 中的指令(如 FROM, RUN, COPY 等),并按顺序执行
每条指令都会生成一个新的镜像层:
如果该层已存在于缓存中,则直接复用。
如果没有缓存,则执行指令并生成新层。
每一层的构建结果会被存储在 Image Store 中。
所有指令执行完成后,Docker Daemon 将所有层合并为一个完整的镜像
在 Docker 镜像构建过程中,每一条指令都会生成一个新的镜像层。这些层是只读的,在容器启动时会添加一个可写层
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y curl
COPY file.txt /app/file.txt
CMD ["echo", "Hello, World!"]
自下而上看s
+-----------------------------+
| Layer 4: CMD (元数据) |
+-----------------------------+
| Layer 3: COPY file.txt |
+-----------------------------+
| Layer 2: RUN apt-get install|
+-----------------------------+
| Layer 1: RUN apt-get update |
+-----------------------------+
| Base Image: ubuntu:20.04 |
+-----------------------------+
当启动容器时,会在镜像的顶层添加一个可写层
+-----------------------------+
| 可写层(容器层) |
+-----------------------------+
| Layer 4: CMD (元数据) |
+-----------------------------+
| Layer 3: COPY file.txt |
+-----------------------------+
| Layer 2: RUN apt-get install|
+-----------------------------+
| Layer 1: RUN apt-get update |
+-----------------------------+
| Base Image: ubuntu:20.04 |
+-----------------------------+
Dockerfile
指令从上到下对按顺序构建成镜像
启动运行镜像为容器时则不关注顺序,因为创建镜像时已经检验了
上下文路径是运行 docker build 命令时指定的路径,Docker 会将该目录下的所有文件打包并发送到 Docker 守护进程(Docker Daemon)。
可以通过指定路径来更改上下文路径。
如果上下文路径中包含大量未使用的文件(如日志、临时文件、依赖缓存等),会导致:构建时间增加网络带宽占用。
如果上下文路径中包含敏感文件(如私钥、密码文件、配置文件等),即使这些文件未被 Dockerfile 引用,它们仍然会被发送到 Docker 守护进程。
=====================================================================
拉取镜像:从远程 Registry 下载镜像。
构建镜像:根据 Dockerfile 构建新的镜像。
运行容器:基于镜像启动一个新的容器实例。
Docker 使用 Union File System(如 OverlayFS)将多个层合并为一个统一的文件系统。
Union File System:实现镜像的分层存储,支持高效的镜像管理和容器启动。
Namespace 隔离:Docker 使用 Linux Namespace 技术隔离容器的资源视图。使得每个容器只能看到自己的资源。隔离进程id,网络
Cgroups 资源限制:Docker 使用 Linux Cgroups 技术限制容器的资源cpu,内存,磁盘使用。
client输入命令
docker pull:拉取镜像
作用:从远程镜像仓库(如 Docker Hub 或私有 Registry)下载已有的镜像到本地。
执行过程:根据指定的镜像名称和标签,从远程仓库查找对应的镜像。下载镜像的所有分层(layers)到本地
docker pull从远程仓库拉取镜像 1解析镜像名称 2检查本地缓存 3分层下载 4存储镜像
docker build构建新的镜像 1. 解析构建参数 2. 发送上下文 3. 逐行执行 Dockerfile 4. 生成镜像
docker run基于镜像启动容器 1. 检查本地镜像 2. 创建容器 3分配资源 4启动主进程 5监控状态
docker run 如果在本地没有找到该镜像会先去镜像仓库pulll再run
docker容器创建的前几12个ID就是docker container ls看到的前一部分ID
当执行 docker pull 或构建镜像时,Docker 会将镜像存储在本地的镜像缓存中。这个缓存是持久化的,存储在 Docker 的数据目录中,通常位于以下路径 Linux: /var/lib/docker
文件命名
在 Docker 中,默认情况下,构建镜像时使用的文件必须命名为 Dockerfile。然而,如果你希望使用其他文件名来定义构建指令,也是可以的,只需要通过 docker build 命令的 -f 选项指定自定义文件名即可。
如果你直接运行以下命令:
docker build -t my-image .
Docker 会默认在当前目录(.)中寻找名为 Dockerfile 的文件。
如果找不到 Dockerfile,会报错:
如果希望使用其他文件名(如 MyDockerfile 或 prod.Dockerfile),可以通过 -f 选项指定文件路径。
docker build -t my-image -f <path-to-dockerfile> <context-path>
docker build -t my-image -f MyDockerfile .
OCI 标准与 Runtime 实现
Docker Runtime 遵循 OCI(Open Container Initiative)标准,常见的 Runtime 包括:
runc:Docker 默认的 Runtime,直接与 Kernel 交互。
crun:轻量级的替代 Runtime,性能更高。
containerd:更高级别的容器运行时,管理容器生命周期。
这些 Runtime 通过调用 Kernel 的底层功能来实现容器的启动和管理。
镜像
系统启动时,bootfs 负责加载 kernel 并初始化硬件。之后 bootfs 会被卸载掉。容器和底层host共用bootfs,包含启动内核和初始化所需的文件。主机和容器共享同一个bootfs
rootfs包含操作系统的最基本文件系统。容器的 rootfs 是独立的,由镜像提供。每个容器都有自己隔离的 rootfs。 Docker 从官方镜像仓库拉取 CentOS 7 的基础镜像。这个镜像只是一个含有其rootfs的包,所以很小
容器运行时直接使用主机(Host)的操作系统内核,而不是镜像中自带的内核。 -也就是kernel,linux宿主机对于容器来说主要的作用就是提供kernel
容器本质上是基于 Linux 内核的轻量级虚拟化技术,依赖于主机内核提供的的 Namespace 和 Cgroups 提供隔离和资源限制。
base 镜像来底层直接用 Host 的 kernel
加载完成后,kernel 挂载 rootfs,进入用户空间并启动用户级进程。
第二行 ADD 指令添加到镜像的 tar 包就是 CentOS 7 的 rootfs。
空镜像scratch
镜像的构建是Dockerfile从上到下
如果构建的镜像后一步是前一步实现的前提那么执行会失败:
镜像的分层
Docker 镜像是由多个只读层(Layer)组成的,每一层代表镜像的一个状态快照。这些层通过 Union File System(如 OverlayFS、AUFS)合并为一个统一的文件系统。
镜像:
镜像是一个只读的模板,包含运行应用程序所需的所有文件和依赖。
镜像是由多个只读层组成的,每一层对应 Dockerfile 中的一条指令。
镜像是不可变的(Immutable),不能直接修改。
构建镜像
1 docker commit
2 dockerfile
docker commit例子
apt-get update是一个在基于 Debian 或 Ubuntu 的 Linux 系统中用于更新软件包索引的命令。以下是详细解释:apt-get update 会从配置的软件源(repositories)中下载最新的软件包列表。这些列表包含了可用软件包的名称、版本号以及依赖关系等信息。
[root@localhost ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 97bed23a3497 6 weeks ago 78.1MB
[root@localhost ~]# docker run -it ubuntu
root@de57def27b51:/# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
root@de57def27b51:/# apt-get update
Get:1 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB]
Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Fetched 34.7 MB in 3min 11s (182 kB/s)
Reading package lists... Done
root@de57def27b51:/# apt-get install -y vim
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
(选择时区)
Processing triggers for libc-bin (2.39-0ubuntu8.6) ...
root@de57def27b51:/# vim
root@de57def27b51:/#
[root@localhost ~]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
de57def27b51 ubuntu "/bin/bash" 9 minutes ago Up 9 minutes competent_khorana
#competent_khorana是docker随机为我们提供的名称
[root@localhost ~]# docker commit competent_khorana ubuntu_with_vim
sha256:a9d3d2698e238ccd4467475bc2eed219ad5000763b15ad130cde5f3ae888754f
[root@localhost ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu_with_vim latest a9d3d2698e23 25 seconds ago 206MB
ubuntu latest 97bed23a3497 6 weeks ago 78.1MB
这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。比如要在 debian base 镜像中也加入 vim,还得重复前面的所有步骤。更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。
缓存特性
Docker 在构建镜像时会复用之前构建同一镜像时生成的缓存。
缓存仅限于当前 Docker 环境中的镜像层,不会跨镜像查找缓存。
构建缓存失效 如果上下文路径中的文件发生变化(即使这些文件未被 Dockerfile 使用),Docker 会认为上下文发生了变化,从而可能导致构建缓存失效。
示例: 假设上下文路径中有一个未使用的日志文件 app.log,每次运行 docker build 时,如果 app.log 内容发生变化,Docker 会重新计算上下文哈希值,导致缓存失效。
- 缓存命中:如果某一步的输入没有变化,则直接使用缓存。
- 缓存失效:如果某一步的输入发生变化,则该步骤及其后续步骤都会重新执行。
在构建开始时,Docker 会计算整个上下文路径的哈希值(包括所有文件和目录)。
如果上下文路径中的任何文件发生变化(即使这些文件未被 Dockerfile 使用),Docker 会认为上下文发生了变化,从而导致缓存失效。
Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。 也就是说,如果我们改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。
缓存
如果某一层可以复用缓存,则直接跳过该层的执行,继续处理下一层。
复用缓存并不意味着“提前执行”,而是跳过执行并使用已有的结果
不使用缓存 在命令结尾加上 --no-cache
举例说明,比如交换前面 RUN 和 COPY 的顺序:
Dockerfile常用指令
FROM 指定base镜像
MAINTAINER 设置镜像的作者,可以是任意字符串。
COPY 将文件从构建上下文复制到镜像,不能自动解压。
ADD 复制文件。自动解压tar文件和下载远程URL文件
ENV 环境变量可被后面的指令使用
EXPOSE 指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来
VOLUME 创建挂载点,用于数据持久化。
WORKDIR 为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工
作目录如果 WORKDIR 指定了一个目录,但后续命令引用的文件在指定的工作目
录中不存在,会导致构建或运行失败。
RUN 在镜像构建阶段执行命令,用于安装软件、配置环境等操作。
CMD 容器启动时运行指定的命令。Dockerfile 中可以有多个 CMD 指令,但只有最 后一个生效。CMD 可以被 docker run 之后的参数替换
ENTRYPOINT 与 CMD 不同,ENTRYPOINT 不会被 docker run 提供的参数覆盖
RUN , ENTRYPOINT ,CMD
不论Dockerfile内的顺序;容器启动时ENTRYPOINT的参数优先级最高,其次是RUN,
如果定义了 ENTRYPOINT,命令行参数会被作为 ENTRYPOINT 的参数传递。命令行参数会完全覆盖 CMD。
docker run 命令行参数会覆盖 CMD,但不会直接覆盖 ENTRYPOINT。
EXEC格式和Shell格式
Shell 使用字符串形式,默认通过 /bin/sh -c 执行
EXEC使用数组形式,需要显示指定 Shell
ENTRYPOINT使用EXEC格式时,会作为主命令及主参数,RUN或CMD作为附参数被传递,如果EXNTRYPOINT使用shell格式,会只显示ENTRYPOINT的内容,完全覆盖CMD和RUN,包括其参数
EXEC不会调用变量的替换 shell可以
如果希望在EXEC格式使用环境变量,照如下修改
ENTRYPOINT 的优先级高于 CMD:
如果 ENTRYPOINT 存在,CMD 的内容会被作为参数传递给 ENTRYPOINT。
如果 ENTRYPOINT 不存在,CMD 定义的命令会直接执行。
Dockerfile 中的指令顺序只影响镜像的构建过程,而不影响容器运行时的行为。
Dockerfile 的指令顺序不影响运行时行为:ENTRYPOINT 和 CMD 的交互规则决定了容器启动时的最终命令。
ENTRYPOINT的exec格式后的内容被看作纯字符串,后面$的变量替换会失效
root@docker ~# vim Dockerfile
FROM busybox
ENV name gqdENTRYPOINT "/bin/echo", "Hello, $name"# docker run dockerfile2
hello,$name
如果希望使用环境变量:
root@docker ~# vim Dockerfile
FROM busybox
ENV name gqd ENTRYPOINT "/bin/sh", "-c", "echo Hello, $name"
通过/bin/sh -c显式引入了一个shell。
=================================================================
exec格式使用数组形式显式指定命令及参数,不会主动调用shell
shell格式默认使用/bin/bash -c
run
ENTRYPOINT的优先级高于CMD和run
ENTRYPOINT和CMD同时存在时。如果ENTRYPOINT是shell格式会把CMD的参数覆盖掉
如果想要把CMD的参数传递,ENTRYPOINT需要使用exec格式
本地registry
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2
#启用registry容器
docker tag httpd:latest localhost:5000/httpd:v1
#固定格式local:5000
docker push localhost:5000/httpd:v1
docker pull localhost:5000/httpd:v1
v1: Pulling from httpd
302e3ee49805: Already exists
4669bea11670: Pull complete
4f4fb700ef54: Pull complete
ca8887d72588: Pull complete
c7c900975bf7: Pull complete
95eac36196b2: Pull complete
Digest: sha256:f432c26db81bdb6eb2c60c61d5d607615398f2e983eaaaff87ade6bbb2fec875
存储到私有镜像仓库的镜像格式严格要求为127.0.0.1:5000/镜像名:标签
作用跨主机分发
如果你有多台机器(如开发机、测试机、生产环境),可以通过 Registry 将镜像从一台机器推送到其他机器。
# 在机器 A 上推送镜像到 Registrydocker push localhost:5000/my-image
# 在机器 B 上拉取镜像docker pull localhost:5000/my-image
版本控制
Registry 支持镜像的多版本管理。通过镜像标签(Tag),可以区分不同版本的镜像。
# 推送不同版本的镜像docker tag my-image localhost:5000/my-image:v1
docker push localhost:5000/my-image:v1
docker tag my-image localhost:5000/my-image:v2
docker push localhost:5000/my-image:v2
企业用harbor仓库
wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz
# 解释:使用 wget 命令从 Harbor 的 GitHub 发布页面下载 v2.9.1 版本的离线安装包。
tar -xvf harbor-offline-installer-v2.9.1.tgz
# 解释:使用 tar 命令解压 harbor-offline-installer-v2.9.1.tgz 文件,提取其中的内容。
mkdir /opt/harbor
# 解释:在 `/opt` 目录下创建一个名为 `harbor` 的文件夹,用于存放 Harbor 的相关文件。
mv harbor/* /opt/harbor/
# 解释:将解压后的内容从临时目录移动到 `/opt/harbor` 目录中,便于后续操作。
cd /opt/harbor/
# 解释:进入 `/opt/harbor` 目录,准备执行后续的安装和配置命令。
docker load -i harbor.v2.9.1.tar.gz
# 解释:使用 `docker load` 命令加载 Harbor 提供的本地镜像文件(harbor.v2.9.1.tar.gz),以便后续运行 Harbor 服务。
cp -ar harbor.yml.tmpl harbor.yml
# 解释:将 Harbor 的配置模板文件 `harbor.yml.tmpl` 复制为 `harbor.yml`,作为实际使用的配置文件,后续可以根据需要修改该文件。
hostname定义本机地址 http开放,关掉了htts端口 登陆密码是huawei
./prepare
./install.sh
登录WEB界面:http://192.168.108.30
#./prepare:用于生成配置文件和准备运行环境。
#./install.sh:用于启动服务并完成最终部署。
[root@docker ~]# vim /etc/docker/daemon.json
{
"insecure-registries": ["192.168.108.30"],
"registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}
[root@docker ~]# systemctl restart docker
#重新执行安装命令
[root@docker harbor]# ./install.sh
将内网服务器的 IP 地址(如 192.168.108.30)添加到 insecure-registries 中。
允许 Docker 客户端与未启用 HTTPS 的私有镜像仓库通信。
如果私有镜像仓库没有配置 HTTPS(仅使用 HTTP)Docker 默认会拒绝与其通信。
添加到 insecure-registries 后,Docker 会允许通过 HTTP 访问该仓库。
容器
容器是基于镜像创建的一个运行实例。
容器在镜像的基础上添加了一个可写层(也称为容器层),用于保存运行时的修改。可写层是容器特有的,用于存储容器运行时的修改(如添加、删除或修改文件)。
可写层是临时的,容器删除后,如果未持久化,修改的内容会丢失。如果希望将这些修改持久化为只读层,则需要将其保存为新的镜像
每次启动一个容器时,都会为其分配一个新的可写层。这个可写层会记录容器运行期间的所有更改(例如文件的创建、修改或删除)一次操作到关闭容器结束算一次可写层
容器运行中的读取顺序
1. 读操作
当容器需要读取某个文件时,Docker 会从上到下查找:
先检查 可写层(Container Layer) 是否存在该文件。
如果存在,则直接返回该文件内容。
如果不存在,则继续向上查找镜像层(从最新层到最底层)。
一旦在某一层找到文件,就不会再往下查找,因此不会“重复读取”未修改的原始数据。
2. 写操作
当容器尝试修改一个文件时:
如果该文件在只读层中存在,Docker 会先将其 复制到可写层(写时复制)。
然后在可写层中进行修改。
修改后的文件只存在于可写层中,原始镜像层保持不变。
进入容器attach和exec
docker attach <容器ID>
docker exec -it <容器ID>
attach 是连接到容器自身的主进程,退出后彻底关闭容器
exec是开启一个新进程,退出后不一定关闭容器
容器资源限制
docker 容器内存和CPU的资源限制没有严格的顺序位置要求
容器限制内存
docker run -it -m 200M --memory-swap=300M ubuntu-with-vim
限制容器内存使用
docker run -it -m 200m --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 280M -v
容器限制CPU资源使用优先级
docker run --name "container_A" -c 1024 ubuntu
docker run --name "container_B" --cpu-shares 502 ubuntu
-c = -cpu-shares
A的分到的CPU资源比B多
限制容器使用CPU颗数
docker run --name "container_B" -it ubuntu-with-vim --cpus 4 -v
docker run --name "comntainer_B" -it ununtu-with-vim -cpus 4 -v
导出导入
export和import只能对容器 导出的文件是容器的完整文件系统快照。
docker export httpd1 -o myhttpd.tar
docker import myhttpd.tar myweb:v1
save 和load只能对镜像
# 保存镜像到本地
docker save -o my_image.tar my_image:latest
# 加载镜像
docker load -i my_image.tar
# 查看加载后的镜像
docker images
dokcer save -o 创建的压缩包是包含元数据信息和日志记录等等,而docker export 创建的压缩包是只包含路径内的数据,没有镜像构建时的分层信息
docker save 和docker export 区别
docker save: 将镜像保存为文件,save会保存该镜像的所有元数据和历史记录。
docker export`保留文件系统内容: 不保留环境变量,启动时的命令,其他元数据,运行时日志,挂载的卷
docker load 和docker import 的区别
docker export 导出的文件是一个容器文件系统的快照,缺少镜像的分层信息和元数据。
docker load 期望的是一个完整的镜像文件,包含所有分层和元数据。
cgroup
cgroup实现了物理资源上的隔离,CPU,内存,IO, 在命令行可以进行CPU,内存,IO的限额
对容器进行内存。cpu限额后去/sys/fs/cgroup/cpu/docker路径下linux为每个容器创建了以容器长ID命名的文件,那里定义了cpu限额。 同样的/sys/fs/cgroup./memory/docker 定义了内存限额等等
namespace
实现资源隔离
mount namespace 实现文件系统视图的隔离,让每一个容器自己看起来有独立完整的文件系统
UTS nemsepace 让容器有自己的hostname
User namespace 用户资源隔离
Network namespace 网络资源隔离
IPC namespace 互相容器间通信
PID namespace 让容器以进程运行
网络
查看docker的网络类型
docker network ls
运行容器定义网络类型
docker run --name my_container --network bridge -d nginx
只有--subnet创建的网络可以指定静态ip使用
网络类型
none:就是没有网络,无法与外界通信
host:网络就是共享主机的network namespace 比如即hosts使用了的端口,属于host网络的容器就不能再使用
bridge: dockeer 安装后提供的docker0就是 linux 的一个bridge。可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。如果不指定`--network`,创建的容器默认都会挂到 `docker0` 上。
Docker 就创建了在主机和所有容器之间一个虚拟共享网络 当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包), 这对接口
- 一端在容器内即 eth0;
- 另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)
通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。
bridge桥网络
默认情况下两个桥网络互相隔离
docker 安装后在宿主机会有个docker0的桥网络,docker0是默认创建的一个桥接网络为容器的bridge网络提供通往外界的网关
创建一个容器时就会创建一对veth pair接口 这个接口一端在容器叫etho0,一端在本地宿主机名称以veth开头。在容器查看看到是24:etho@if25那么在宿主机就是25: vethddb2744@if24
宿主机的docker0就是容器网络和外部通信使用的网关 172.16.0.0/16,足够大的范围确保分配足够的容器,容器创建时候就会自动从172.16.0.0/16随机分配一个IP给容器
在虚拟机内看到的veth开头的网络都属于docker0,br-开头的都是自定义创建的网络
不同网桥通信
创建自定义网络(如尚未存在)
docker network create \
--subnet 172.22.16.0/24 \
my_net2
确认:
docker network ls
docker network inspect my_net2
启动两个容器(分别在不同网络)
busybox1(在 docker0)
docker run -dit --name busybox1 busybox sh
busybox2(在 my_net2)
docker run -dit --name busybox2 --network my_net2 busybox sh
此时:
- busybox1:只有
eth0@docker0 - busybox2:只有
eth0@my_net2 - 二者无法互通(iptables DOCKER-ISOLATION 生效)
将 busybox1 连接到 my_net2
docker network connect my_net2 busybox1
这一步是“打通通信”的本质手段。
容器内网络状态验证
busybox1(双网卡)
docker exec busybox1 ip addr
典型结果:
eth0: 172.17.0.x (docker0)
eth1: 172.22.16.x (my_net2)
busybox2(单网卡)
docker exec busybox2 ip addr
eth0: 172.22.16.y
通信验证
busybox1 → busybox2(走 my_net2)
docker exec busybox1 ping 172.22.16.y
busybox2 → busybox1(走 my_net2)
docker exec busybox2 ping 172.22.16.x
本质就是 让 busybox1 拥有 busybox2 所在网络的网卡,这样两个容器就能直接在同一二层网络上通信,而不再受 Docker-ISOLATION 规则限制
==============================================================================
假设有一个名为 my_network 的用户定义网络和一个名为 my_container 的容器:
bash
docker network connect my_network my_container
Docker DNS server
docker容器内嵌了DNS,只要在启动运行容器时带上--name 对方就能根据容器名ping通彼此
使用 docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。
存储
storage driver
实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图
bind mount 是hosts宿主机文件系统的数据,容器删除后,即使是在容器挂载期间,文件被写入的数据也不会消失
CentOS Stream 8 用的overlay2,底层文件系统是xfs,各层数据存放在 /var/lib/docker
持久化存储:Data Volume
data volume分为:docker managed volume,bind mount
bind mount 将宿主机上的任意目录或文件直接挂载到容器中。
docker manage volume Docker 自动管理的数据卷,存储在宿主机的特定路径下
bind mount
Bind Mount:绑定挂载,将宿主机上的任意文件或目录挂载到容器中。
示例:
docker run -d -p 80:80 -v /root/htdocs:/usr/local/apache2/htdocs httpd
容器运行期间写入的数据不会因为容器删除消失
docker manager volume
docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了
docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
Data Volume:数据卷,是 Docker 中用于持久化数据的一种机制。数据卷绕过存储驱动,直接在宿主机文件系统上创建,
具有以下特点:数据卷在容器之间共享和重用。对数据卷的修改会直接生效,不需要通过存储驱动。
docker inspect c75f36c4bf32 可以看到卷的路径在/var/lib/docker/volumes/。。。。。
docker managed volume 的创建过程:
- 容器启动时,简单的告诉 docker "我需要一个 volume 存放数据,帮我 mount 到目录 /abc"。
- docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源。
- 如果 /abc 已经存在,则将数据复制到 mount 源,
- 将 volume mount 到 /abc
命名卷和匿名卷
命名卷
显式命名 易于管理,可以通过名称查找,迁移备份
docker volume create my-named-volume
docker run -v my-named-volume:/path/to/mount my-image
匿名卷
创建卷时随机生成的
docker run -v /path/to/mount my-image
使用卷时使用 --rm 可以确保删除容器时,卷会同时删除
docker run --rm -v /path/to/mount my-image
共享数据
容器和host共享
直接把主机的路径内容拷贝到容器
主机同时给多个容器共享
docker 运行三个http服务容器,三个容器服务路径映射到主机的一个路径
宿主机写入内容到容器挂哉的主机路径,三个容器查看到一样的内容
volume container共享
主机 ----- 容器 ----- 容器s
创建一个容器指定它映射的主机路径,不运行服务
docker create --name vc_data \
-v ~/htdocs/:/usr/local/apache2/htdocs \
-v /other/userful/tools \
busybox
bb4a33bf34aa7817ea752db83079aff15a5dfd77c23363f2e8dd3096d1cb910f
其他容器通过 --volume-from 使用这个存储
docker run --name web1 -d -p 80 --volumes-from vc_data httpd
docker inspect <容器ip>可以看到其他容器使用了这个存储
只在容器之间的共享data-packed volume container
vim Dockerfile
FROM busybox:latest
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs
volume作用与-v等效
docker build -t datapacked
docker create --name vc_data datapacked
docker run -d -p 80:80 --volumes-from vc_data httpd