Docker核心揭秘:轻量级虚拟化的革命
一、Docker 简介
1.1 Docker 简介
Docker = 隔离性(namespace) + 可配额/可度量(Cgroup) + 移动性 (images)
-
隔离性(namespace) - 每个用户实例之间相互隔离, 互不影响。 硬件虚拟化方法给出的方法是VM, LXC给出的方法是container,更细一点是kernel namespace
-
可配额/可度量(Cgroup) - 每个用户实例可以按需提供其计算资源,所使用的资源可以被计量。硬件虚拟化方法因为虚拟了CPU, memory可以方便实现, LXC则主要是利用cgroups来控制资源
-
移动性 (images)- 用户的实例可以很方便地复制、移动和重建。硬件虚拟化方法提供snapshot和image来实现,docker(主要)利用AUFS实现
1.1.1 什么是 Docker?
-
Docker 是一个用于管理容器的引擎,也是为应用提供打包、部署的平台,并非单纯的虚拟化技术,它是一个开放的分布式应用平台,主要包含 Docker Engine(可移植、轻量级的运行时和打包工具)和 Docker Hub(用于共享应用和自动化工作流的云服务)。
1.1.2 Docker 的核心特点与优势
轻量级虚拟化、一致性、可移植性、高效资源利用、易于部署和扩展
-
轻量级虚拟化:相比传统虚拟机更轻量高效,启动停止快速,例如启动 Docker 容器仅需几秒,而虚拟机可能需要几分钟,能节省系统资源。
-
一致性:保障应用在开发、测试、生产等不同环境中运行表现一致,无论本地还是云端,运行环境相同,减少环境差异引发的问题。
-
可移植性:可轻松在不同平台间迁移 Docker 容器,无需担忧依赖和环境配置差异,如本地开发的容器可无缝部署到云服务器。
-
高效资源利用:多个 Docker 容器可共享主机操作系统内核,更高效地利用系统资源。
-
易于部署和扩展:能快速部署新应用实例,并可根据需求轻松实现水平扩展。
1.1.3 Docker 的对于工作者优势
-
对开发人员:Build once、Run anywhere(一次构建,随处运行)。
-
对运维人员:Configure once、Run anything(一次配置,运行任何应用),容器技术大幅提升 IT 人员工作幸福感。
1.1.4 Docker 缺点及劣势
-
多个容器共用宿主机的内核,各应用之间的隔离不如虚拟机彻底
-
由于和宿主机之间的进程也是隔离的,需要进入容器查看和调试容器内进程等资源,变得比较困难和繁琐
-
如果容器内进程需要查看和调试,需要在每个容器内都需要安装相应的工具,这也造成存储空间的重复浪费
1.1.5 Docker 在企业中的应用场景
-
Docker 在企业中作为业务最小载体被广泛应用,企业借助 Docker 能更高效地部署应用且更节省资源,可应用于 SaaS(如网站、微店、云盘等)、PaaS(如 Redis、MySQL、Nginx、MongoDB 等)层面,构建基于 Docker 的云平台。
-
IaaS(Infrastructure as a Service):基础设施即服务。
-
PaaS(Platform as a Service):平台即服务。
-
SaaS(Software as a Service):软件运营服务。
-
1.1.6 Docker 与虚拟化的对比
1.1.6.1 底层原理与架构
维度 | Docker(容器) | 传统虚拟化(虚拟机) |
---|---|---|
隔离粒度 | 进程级隔离(共享宿主机内核) | 完全隔离(每个虚拟机有独立内核、操作系统、硬件模拟) |
核心依赖 | 依赖 Linux 内核的namespace(命名空间,实现资源隔离)和cgroups(控制组,限制资源) | 依赖 Hypervisor(虚拟化层,如 KVM、VMware ESXi)模拟硬件资源 |
操作系统 | 容器内通常是精简的操作系统(如 Alpine Linux),与宿主机共享内核 | 每个虚拟机运行完整的操作系统(如 Windows、Linux),内核独立于宿主机 |
启动依赖 | 无需启动完整操作系统,直接运行进程 | 必须先启动虚拟机的操作系统,再运行应用 |
1.1.6.2 关键特性对比
特性 | Docker(容器) | 传统虚拟化(虚拟机) |
---|---|---|
启动速度 | 极快(秒级甚至毫秒级),直接启动进程 | 较慢(分钟级),需启动完整操作系统 |
资源占用 | 轻量,共享宿主机内核和资源,仅占用应用自身所需资源 | 重量级,每个虚拟机需分配独立的 CPU、内存、磁盘等资源,资源利用率低 |
隔离性 | 隔离性较弱(共享内核,内核级漏洞可能影响所有容器) | 隔离性强(完全独立的内核和硬件模拟,一个虚拟机故障不影响其他) |
移植性 | 极高,基于镜像打包应用和依赖,可在任何支持 Docker 的环境中运行(“一次构建,到处运行”) | 较差,虚拟机镜像与硬件和 Hypervisor 绑定,跨平台迁移复杂(如 VMware 到 KVM) |
镜像大小 | 很小(通常 MB 级,如 Alpine 镜像仅几 MB),基于分层存储(复用基础镜像层) | 很大(通常 GB 级),包含完整操作系统 |
适用场景 | 微服务、持续集成 / 部署(CI/CD)、应用隔离、快速扩展 | 运行不同操作系统(如 Windows 和 Linux 并存)、强隔离需求(如多租户场景)、旧系统迁移 |
3. 典型使用场景
1.2 部署 Docker
1.2.1 docker 组成
-
其中,runc是docker最底层的核心引擎,是轻量级的通用运行时容器,遵守OCI规范,是实现OCI接口最低级别的组件,它与内核交互创建并运行容器
-
Docker 主机(Host): 一个物理机或虚拟机,用于运行Docker服务进程和容器,也称为宿主机,node节点
-
Docker 服务端(Server): Docker守护进程,运行docker容器
-
Docker 客户端(Client): 客户端使用 docker 命令或其他工具调用docker API
-
Docker 镜像(Images): 镜像可以理解为创建实例使用的模板,本质上就是一些程序文件的集合
-
Docker 仓库(Registry): 保存镜像的仓库
1.2.2 容器工作方法
-
涉及 Client(客户端)、DOCKER_HOST(Docker 主机,包含 Docker daemon、Containers、Images)、Registry(仓库),主要操作有 docker build(构建镜像)、docker pull(拉取镜像)、docker run(运行容器,如运行 NGINX)
1.2.3 部署第一个容器
# 进入yum源配置目录配置docker镜像[root@docker01 ~] vim /etc/yum.repos.d/docker.repo[docker]name=docker-cebaseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stablegpgcheck=0
# 添加镜像加速器[root@docker01 ~] cat /etc/docker/daemon.json {"registry-mirrors":["https://docker.m.daocloud.io"]}
-
安装 docker-ce 并启动服务
# 安装docker[root@docker01 ~] yum install -y docker-ce # 编辑docker启动文件,设定使用iptables的网络设定方式(默认使用nftables)vim /usr/lib/systemd/system/docker.service# 修改ExecStart行如下ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true# 设置docker开机自启并立即启动[root@docker01 ~] systemctl enable --now docker
# 查看 docker 信息[root@docker01 ~]# docker infoClient: Docker Engine - Community # 客户端类型:Docker 社区版Version: 28.5.1 # 客户端版本号Context: default # 当前使用的上下文(默认上下文,用于管理Docker环境连接)Debug Mode: false # 未启用调试模式Plugins: # 客户端安装的插件buildx: Docker Buildx (Docker Inc.) # Docker Buildx插件(官方提供,增强镜像构建功能)Version: v0.29.1 # 插件版本Path: /usr/libexec/docker/cli-plugins/docker-buildx # 插件安装路径compose: Docker Compose (Docker Inc.) # Docker Compose插件(官方提供,管理多容器应用)Version: v2.40.0 # 插件版本Path: /usr/libexec/docker/cli-plugins/docker-compose # 插件安装路径Server:Containers: 0 # 总容器数:0(包括所有状态)Running: 0 # 运行中容器数:0Paused: 0 # 暂停状态容器数:0Stopped: 0 # 已停止容器数:0Images: 0 # 本地存储的镜像数:0Server Version: 28.5.1 # 服务端(Docker引擎)版本号(与客户端一致)Storage Driver: overlay2 # 存储驱动:overlay2(Docker推荐的高效存储驱动)Backing Filesystem: xfs # 底层文件系统:xfs(宿主机的文件系统类型)Supports d_type: true # 支持d_type(文件类型识别,overlay2依赖此特性)Using metacopy: false # 未启用metacopy模式(关闭时性能更优,依赖底层文件系统)Native Overlay Diff: true # 使用原生overlay差异计算(高效存储容器与镜像的差异)userxattr: false # 未启用用户扩展属性(xattr,用于高级权限控制)Logging Driver: json-file # 默认日志驱动:json-file(容器日志以JSON格式存于宿主机文件)Cgroup Driver: systemd # cgroup驱动:systemd(用于管理容器的CPU/内存等资源限制)Cgroup Version: 2 # cgroup版本:v2(Linux内核资源管理机制,比v1更统一)Plugins: # 服务端支持的插件Volume: local # 卷插件:local(本地卷,容器数据存储在宿主机目录)Network: bridge host ipvlan macvlan null overlay # 网络插件# bridge:默认桥接网络(容器通过虚拟网桥通信)# host:容器使用宿主机网络栈# ipvlan/macvlan:为容器分配独立IP/MAC,模拟物理设备# null:无网络(容器无法联网)# overlay:跨主机网络(用于Swarm集群)Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog # 日志驱动# 支持对接AWS/GCP日志服务、fluentd、journald等(默认使用json-file)CDI spec directories: # CDI(容器设备接口)配置目录(用于暴露宿主机设备给容器)/etc/cdi/var/run/cdiSwarm: inactive # Docker Swarm(容器编排)状态:未激活(未启用集群模式)Runtimes: runc io.containerd.runc.v2 # 支持的容器运行时(负责创建和运行容器进程)# runc:OCI标准运行时(默认)# io.containerd.runc.v2:containerd集成的runc运行时Default Runtime: runc # 默认运行时:runcInit Binary: docker-init # 容器初始化程序:docker-init(处理容器内进程管理,如回收僵尸进程)containerd version: b98a3aace656320842a23f4a392a33f46af97866 # containerd(容器运行时管理器)版本runc version: v1.3.0-0-g4ca628d1 # runc运行时版本init version: de40ad0 # docker-init工具版本Security Options: # 启用的安全选项seccomp # seccomp(安全计算模式):限制容器可调用的系统调用Profile: builtin # 使用Docker内置的seccomp安全策略cgroupns # cgroup命名空间:隔离容器的cgroup视图,增强安全性Kernel Version: 5.14.0-362.8.1.el9_3.x86_64 # 宿主机内核版本(适用于RHEL 9.3)Operating System: Red Hat Enterprise Linux 9.3 (Plow) # 宿主机操作系统:RHEL 9.3(代号Plow)OSType: linux # 操作系统类型:Linux(Docker原生支持)Architecture: x86_64 # CPU架构:x86_64(64位Intel/AMD处理器)CPUs: 4 # 宿主机CPU核心数:4Total Memory: 1.879GiB # 宿主机总内存:约1.9GBName: docker01 # 宿主机/节点名称:docker01ID: 6f00beda-f59d-4762-86c9-2c3637b09409 # Docker服务端唯一标识符(用于节点身份)Docker Root Dir: /var/lib/docker # Docker根目录(存储镜像、容器数据、配置等的默认路径)Debug Mode: false # 服务端未启用调试模式Experimental: false # 未启用实验性特性(实验特性可能不稳定)Insecure Registries: # 非安全镜像仓库(不验证TLS证书)::1/128 # 本地IPv6地址127.0.0.0/8 # 本地IPv4地址段(通常用于测试)Registry Mirrors: # 镜像仓库加速器(加速拉取Docker Hub镜像)https://docker.m.daocloud.io/ # DaoCloud提供的加速器地址Live Restore Enabled: false # 未启用Live Restore(Docker服务重启时,容器不会继续运行)
-
激活内核网络选项
注意:
我是使用的是9.3版本Redhat,不需要激活 | 如果为7版本则需要激活内核# 添加内核模块配置echo br_netfilter > /etc/modules-load.d/docker_mod.conf# 加载模块modprobe br_netfilter# 编辑内核参数配置文件vim /etc/sysctl.d/docker.conf# 添加以下内核参数net.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1net.ipv4.ip_forward = 1# 应用内核参数sysctl --system# 重启docker服务systemctl restart docker
二、Docker 的基本操作
2.1 Docker 镜像管理
2.1.1 搜索镜像
[root@docker01 ~] docker search nginx搜索镜像会搜索很慢或拉取失败(为正常现象,可以忽略,进行直接拉去)输出结果包含 NAME(镜像名称)DESCRIPTION(镜像说明)STARS(点赞数量)OFFICIAL(是否为官方镜像)
2.1.2 拉取镜像
-
拉取镜像若不指定版本则拉取后版本均为
latest
# 从镜像仓库拉取busybox镜像[root@docker01 ~] docker pull busyboxUsing default tag: latestlatest: Pulling from library/busybox80bfbb8a41a2: Pull complete Digest: sha256:2f590fc602ce325cbff2ccfc39499014d039546dc400ef8bbf5c6ffb860632e7Status: Downloaded newer image for busybox:latestdocker.io/library/busybox:latest# 拉取指定版本(1.23)的nginx镜像[root@docker01 ~]# docker pull nginx:1.231.23: Pulling from library/nginxf03b40093957: Pull complete 0972072e0e8a: Pull complete a85095acb896: Pull complete d24b987aa74e: Pull complete 6c1a86118ade: Pull complete 9989f7b33228: Pull complete Digest: sha256:f5747a42e3adcb3168049d63278d7251d91185bb5111d2563d58729a5c9179b0Status: Downloaded newer image for nginx:1.23docker.io/library/nginx:1.23# 查看本地镜像[root@docker01 ~] docker imagesREPOSITORY(仓库名) TAG(标签 / 版本) IMAGE ID(镜像 ID) CREATED(创建时间) SIZE(镜像大小)busybox latest 0ed463b26dae 12 months ago 4.43MBnginx 1.23 a7be6198544f 2 years ago 142MB
2.1.3 查看镜像信息
# 可查看镜像的详细配置信息[root@docker01 ~] docker image inspect nginx:1.23[{"Id": "sha256:a7be6198544f09a75b26e6376459b47c5b9972e7aa742af9f356b540fe852cd4","RepoTags": ["nginx:1.23"],"RepoDigests": ["nginx@sha256:f5747a42e3adcb3168049d63278d7251d91185bb5111d2563d58729a5c9179b0"],"Parent": "","Comment": "","Created": "2023-05-23T08:51:38.011802405Z","DockerVersion": "20.10.23","Author": "","Architecture": "amd64","Os": "linux","Size": 142145851,"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/d10331966ed5f307a7164aed6d131bf6a6015663b9a5a5a81acad3b550692557/diff:/var/lib/docker/overlay2/3b33f62f9d962dee76ae3beed2b3a1026b3638992222ed4043296eed5cd13bc4/diff:/var/lib/docker/overlay2/a463d970450193c66b9b639581276b69960dbd60a01abd58e3e4703fdada2e87/diff:/var/lib/docker/overlay2/076312549c7578157eb2491d51953f3f9cf4b844d43b1b336771a3e3046922f7/diff:/var/lib/docker/overlay2/2b347d40ba6a2ea28fad68574ff38a7a18014ea6ade6972a0e393d9f8337e775/diff","MergedDir": "/var/lib/docker/overlay2/856acfd6d4c9ca8cd2fa945b085c317cd031dca76100a52292f7a994ebbadea5/merged","UpperDir": "/var/lib/docker/overlay2/856acfd6d4c9ca8cd2fa945b085c317cd031dca76100a52292f7a994ebbadea5/diff","WorkDir": "/var/lib/docker/overlay2/856acfd6d4c9ca8cd2fa945b085c317cd031dca76100a52292f7a994ebbadea5/work"},"Name": "overlay2"},"RootFS": {"Type": "layers","Layers": ["sha256:8cbe4b54fa88d8fc0198ea0cc3a5432aea41573e6a0ee26eca8c79f9fbfa40e3","sha256:5dd6bfd241b4f4d0bb0a784cd7cefe00829edce2fccb2fcad71244df6344abff","sha256:043198f57be0cb6dd81abe9dd01531faa8dd2879239dc3b798870c0604e1bb3c","sha256:2731b5cfb6163ee5f1fe6126edb946ef11660de5a949404cc76207bf8a9c0e6e","sha256:6791458b394218a2c05b055f952309afa42ec238b74d5165cf1e2ebe9ffe6a33","sha256:4d33db9fdf22934a1c6007dcfbf84184739d590324c998520553d7559a172cfb"]},"Metadata": {"LastTagTime": "0001-01-01T00:00:00Z"},"Config": {"Cmd": ["nginx","-g","daemon off;"],"Entrypoint": ["/docker-entrypoint.sh"],"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", # 环境变量"NGINX_VERSION=1.23.4","NJS_VERSION=0.7.11","PKG_RELEASE=1~bullseye"],"ExposedPorts": {"80/tcp": {}},"Labels": {"maintainer": "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e"},"OnBuild": null,"StopSignal": "SIGQUIT","User": "","Volumes": null,"WorkingDir": ""}}]
2.1.4 导出镜像
-o 用于指定导出镜像的位置,可同时导出多个镜像到一个文件,指定.tar.gz 格式可导出并压缩
# 保存nginx:latest镜像到指定文件[root@docker01 ~] docker image save nginx:latest -o nginx-latest.tar.gz# 同时保存多个镜像到一个文件[root@docker01 ~] docker image save nginx:latest nginx:1.26-alpine -o nginx.tag.gz# 保存所有镜像到一个压缩文件[root@docker01 ~] docker save `docker images | awk 'NR>1{print $1":"$2}'` -o images.tar.gz
2.1.5 删除镜像
# 删除指定镜像[root@docker01 ~] docker rmi busybox:latest# 删除所有镜像[root@docker01 ~] docker rmi `docker images | awk 'NR>1{print $1":"$2}'`
2.2 容器的常用操作
2.2.1 启动容器
# 后台运行nginx容器,端口映射(主机80端口映射到容器80端口)[root@docker01 ~] docker run -d --name nginx -p 80:80 nginx:latest7ecb34aa2e5812adbccb1b01fad77e7185536eba402ea2d133d9fbf16f4599ef[root@docker01 ~] docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES7ecb34aa2e58 nginx:latest "/docker-entrypoint.…" 36 seconds ago Up 36 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx# 删除该运行容器[root@docker01 ~] docker rm -f nginxnginx# 交互式运行busybox容器,打开终端[root@docker01 ~] docker run -it --name busybox busybox:latest- 若是执行 `<ctrl>+<pq>`,即可 docker attach busybox:latest 可重新进入# 删除该运行容器[root@docker01 ~] docker rm -f busybox=======================交互式容器操作===================`<ctrl>+<d>`退出并停止容器`<ctrl>+<pq>`退出但不停止容器。=======================参数说明========================-d:后台运行-i:交互式运行-t:打开一个终端-it: 当打开一个交互式的终端--name:指定容器名称-p:端口映射,格式为 “主机端口:容器端口”--rm:容器停止后自动删除容器--network:指定容器使用的网络
-
在容器中执行命令:
docker exec -it test ifconfig
2.2.2 查看容器运行信息
-
docker ps
:查看当前运行的容器 -
docker ps -a
:查看所有容器(包括已停止的) -
docker inspect busybox
:查看容器运行的详细信息
2.2.3 停止和启动容器
-
docker stop busybox
:停止容器 -
docker kill busybox
:杀死容器(可使用信号) -
docker start busybox
:启动已停止的容器 -
说明:容器内的第一个进程必须持续运行,否则容器会处于退出状态。
2.2.4 删除容器
-
docker rm centos7
:删除已停止的容器 -
docker rm -f busybox
:强制删除运行中的容器 -
docker container prune -f
:删除所有已停止的容器
2.2.5 容器内容提交
-
默认情况:容器删除后,内部所有操作(包括文件)会被清理,若需永久保存,需提交容器生成新镜像。
# 运行test容器并在其中创建文件[root@docker01 ~] docker run -it --name test busyboxtouch testfile# 退出容器后删除,再运行新容器,文件不存在[root@docker01 ~] docker rm test[root@docker01 ~] docker run -it --name test busybox# 提交容器生成新镜像[root@docker01 ~] docker commit -m "add testfile" test busybox:v1# 查看新生成的镜像[root@docker01 ~] docker images# 查看镜像历史记录[root@docker01 ~] docker image history busybox:v1
2.2.6 系统与容器间文件传输
-
docker cp test2:/leefile /mnt
:将容器 test 中的 testfile 文件复制到主机 /mnt 目录 -
docker cp /etc/fstab test2:/fstab
:将主机 /etc/fstab 文件复制到容器 test 中
2.2.7 查询容器内部日志
-
docker logs web
,可查看 web 容器的日志输出,如 nginx 容器的启动配置、请求记录等信息。