文章目录

1 Docker介绍

1.1 Docker简介

1.1.1 什么是Docker

**定义:**Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
**核心价值:**Build Once, Run Anywhere:一次构建,到处运行。
**轻量级:**容器共享宿主机内核,无需像虚拟机那样模拟完整的操作系统。

Docker是管理容器的引擎,为应用打包、部署平台,就好比比传统的货运集装箱,而非单纯的虚拟化技术。

特点和优势:

  1. 轻量级虚拟化:启动一个Docker容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。
  2. 一致性:开发、测试、生产环境完全一样,告别“环境不一致”问题。
  3. 可移植性:本地打包好的容器,可以无缝部署到云服务器上。
  4. 高效的资源利用:一台机器能跑上百个容器,而虚拟机只能跑几十个。
  5. 易于部署和扩展:流量大了多开几个容器,小了关掉,非常灵活。

Docker极大地简化了应用程序的开发、部署和管理流程,提高了开发效率和运维的便利性。它在现代软件开发和云计算领域得到了广泛的应用。

1.1.2 Docker在企业中的应用场景

Docker把应用打包成一个 “标准小盒子”,走到哪都能直接跑,不用再配环境、不用再装依赖、也就不会出现 “环境不一致” 的问题。

场景
  1. 统一开发、测试、生产环境

    开发打包好一个 Docker 镜像,测试直接用,上线也直接用;环境完全一致,不会出现 “版本不一样、依赖不一样” 导致的 bug。

  2. 快速部署、快速扩容

    以前部署一个服务要装 Java、装数据库、配配置文件,可能半小时;用 Docker 一条命令启动,几秒钟搞定;当流量大了就多启动几个容器,流量小了关掉,非常灵活。

  3. 节省服务器资源

    虚拟机要占一整个操作系统,很重;Docker 共享宿主机内核,非常轻量;一台机器能跑几十上百个容器,资源利用率高很多。

  4. 微服务架构的基石

    现在企业都拆微服务:订单、用户、支付、商品…… 每个服务一个容器;Docker就是微服务的 “最小运行单元”。

  5. CI/CD 自动化发布流水线

    代码提交–>自动构建镜像–>自动测试–>自动上线;整个流程无人干预,Docker 是核心载体。

云计算的三层服务模式
  • Docker:把应用打包成标准盒子,轻量、一致、随处可跑。
  • IaaS:给你服务器,你自己搭环境。
  • PaaS:给你运行平台,你只管代码。
  • SaaS:给你现成软件,直接用。
  1. IaaS(Infrastructure as a Service):基础设施即服务

    买的是"服务器硬件"本身。

    • 云厂商给:虚拟机、硬盘、网络、IP
    • 自己装:操作系统、数据库、中间件、应用
    • 例子:阿里云 ECS、华为云 ECS、AWS EC2
  2. PaaS(Platform as a Service):平台即服务

    买的是"运行平台",不用管服务器。

    • 云厂商给:操作系统、运行环境、数据库、中间件
    • 只需要:上传代码运行
    • Docker + Kubernetes 本质就是企业自建的 PaaS 平台
  3. SaaS(Software as a Service):软件即服务

    买的是"直接能用的软件"

    • 不用部署、不用维护,打开就用
    • 例子:钉钉、企业微信、飞书、阿里云邮箱、各种在线 CRM
Docker跟这三层的关系

SaaS 软件即服务
直接用:钉钉/飞书

PaaS 平台即服务
只写代码:Docker+K8s

IaaS 基础设施即服务
买服务器:云主机ECS

Docker

  • 传统应用跑在:IaaS 虚拟机里
  • Docker容器也可以跑在:IaaS 虚拟机上
  • 一堆 Docker 用 K8s 管理—>就变成了企业自己的 PaaS 平台
  • 企业把服务做成 Docker 镜像发布–>对外就是 SaaS

1.1.3 Docker与虚拟化的对比

在这里插入图片描述

对比维度虚拟机 (VM)Docker 容器核心差异
操作系统宿主机上运行独立的虚拟机 OS共享宿主机 OS 内核容器无需完整 OS,仅打包应用 + 依赖
架构层级Hypervisor 虚拟化层Docker Engine 容器引擎层容器直接运行在宿主机内核,无 Hypervisor overhead
存储/镜像大小镜像较大(GB 级别)镜像极小(MB 级别)容器镜像仅包含运行时必要组件,无冗余系统文件
性能/资源占用有操作系统额外的 CPU、内存消耗,资源占用高几乎无性能损耗,资源占用低容器共享宿主机内核,无独立 OS 的资源开销
启动速度慢,分钟级快,秒级容器无需启动完整操作系统,仅启动应用进程
隔离性完全隔离(强隔离)进程级安全隔离(基于 Namespace/Cgroups)虚拟机隔离性更强,容器隔离性满足业务需求且更高效
移植性/迁移笨重,与虚拟化技术耦合度高轻量、灵活迁移容器镜像标准化,可在任意 Docker 环境一致运行
部署效率慢,分钟级部署快速,秒级部署容器支持 CI/CD 流水线,实现秒级发布 / 回滚
运行密度单机一般仅能运行几十个单机支持上千个容器容器资源利用率极高,大幅提升服务器承载能力

选虚拟机:需要强安全隔离、运行不同 OS、对环境完全可控的场景(如多租户隔离、传统单体应用)

选 Docker 容器:追求高效、快速部署、微服务架构、CI/CD 自动化的场景(如云原生、弹性扩容)

核心特性虚拟机Docker 容器
本质硬件级虚拟化,模拟完整计算机操作系统级虚拟化,隔离进程
资源高(独立 OS)低(共享内核)
启动分钟级秒级
隔离强(完全隔离)中(进程级隔离)
镜像GB 级MB 级
适用场景强隔离、多 OS 需求微服务、快速部署、CI/CD

1.2 容器工作方法

在这里插入图片描述

宿主机

共享内核

管理

容器

应用程序

依赖库

Docker Engine

宿主机内核

容器与宿主机共享操作系统内核,每个容器运行在独立的命名空间中,实现了资源隔离与轻量级虚拟化。

1.3 Docker 的三大核心组件

  • **镜像 (Image):**只读模板,包含运行容器所需的代码、库、环境变量和配置文件。(类比:类的定义)
  • **容器 (Container):**镜像的运行实例。可以被启动、停止、删除。(类比:类的实例)
  • **仓库 (Registry):**集中存放镜像文件的场所。分为公有仓库(Docker Hub)和私有仓库(Harbor)。

1.4 容器底层技术原理

为什么这么轻量又隔离

  • **Namespace (命名空间):**提供视图隔离(PID, NET, IPC, UTS, USER, MNT)。
  • **Cgroups (控制组):**限制资源使用(CPU, 内存, 磁盘 I/O)。
  • **UnionFS (联合文件系统):**支持分层镜像,实现Copy-on-Write (写时复制)。

2 Docker镜像管理

2.1 镜像基本操作

操作命令示例说明
搜索镜像docker search nginx在Docker Hub中搜索镜像
拉取镜像docker pull nginx:alpine从仓库下载镜像
查看镜像docker images列出本地所有镜像
导出镜像docker save -o nginx.tar nginx:alpine-o指定导出路径,支持.tar.gz压缩
删除镜像docker rmi nginx:alpine删除本地镜像
# 1.搜索镜像
[root@Docker-node1 ~]# docker search  nginx
NAME           DESCRIPTION                                      STARS     OFFICIAL
nginx          Official build of Nginx.                         20094     [OK]
………………
# NAME-->镜像名称;DESCRIPTION-->镜像说明;STARS-->点赞数量;OFFICIAL-->是否是官方的

# 2.拉取镜像
# 从镜像仓库中拉取镜像
[root@Docker-node1 ~]# docker pull busybox
[root@Docker-node1 ~]# docker pull nginx:1.26-alpine

# 3.查看镜像
# 查看本地系统中的镜像列表
[root@Docker-node1 ~]# docker images
REPOSITORY                        TAG           IMAGE ID       CREATED         SIZE
nginx                             latest        900dca2a61f5   7 weeks ago     188MB
nginx                             1.26-alpine   b32ed582bddb   7 weeks ago     43.2MB
ubuntu                            latest        35a88802559d   2 months ago    78.1MB
busybox                           latest        65ad0d468eb1   15 months ago   4.26MB
centos                            7             eeb6ee3f44bd   2 years ago     204MB
centos                            latest        5d0da3dc9764   2 years ago     231MB
gcr.io/distroless/base-debian12   latest        7273f3276b21   N/A             20.7MB
gcr.io/distroless/base-debian11   latest        2a6de77407bf   N/A             20.6MB
# alpine 版本:nginx镜像的最小安装发型版本
# 查看镜像的详细信息
[root@Docker-node1 ~]# docker image inspect nginx:1.26-alpine
# 查看对镜像的更改记录
[root@docker-node1 ~]# docker history  nginx:latest

# 4.导出镜像
# 保存镜像
[root@Docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz
[root@Docker-node1 ~]# docker image save nginx:latest nginx:1.26-alpine -o nginx.tag.gz
# 保持所有镜像    
[root@Docker-node1 ~]# docker save  `docker images | awk 'NR>1{print $1":"$2}'` -o images.tar.gz

# 5.删除镜像
[root@Docker-node1 ~]# docker rmi nginx:latest
[root@Docker-node1 ~]# docker rmi  `docker images | awk 'NR>1{print $1":"$2}'`

2.2 镜像获取方式

方式命令示例说明
从仓库拉取docker pull nginx:alpine从Docker Hub等公共仓库下载
从本地文件加载docker load -i nginx.tar导入之前导出的镜像包
从Dockerfile构建docker build -t mynginx:v1 .使用当前目录的Dockerfile构建
从容器提交docker commit container myimage不推荐,企业应用请用Dockerfile

2.3 Docker镜像结构

在这里插入图片描述

镜像层 - 只读

容器层 - 可读写

共享内核

宿主机内核

可写层

应用层

中间件层

Base镜像层

  • 共享宿主机的内核
  • Base镜像提供最小的Linux发行版
  • 同一Docker主机支持运行多种Linux发行版
  • 分层结构的最大好处是:共享资源
  • 一个镜像最多127层

写时复制(Copy-on-Write):容器层以下所有镜像层都是只读的。当容器需要修改某个文件时,Docker会将该文件从只读层复制到容器可写层,然后修改可写层的副本。原镜像保持不变,因此同一个镜像可以启动无数个容器而互不干扰。

2.4 镜像构建(Dockerfile)

2.4.1 常用指令

指令说明
FROM指定base镜像,eg:FROM busybox:version
COPY复制文件,eg:COPY file /file 或 COPY ["file","/"]
LABEL添加元数据,eg:LABEL maintainer="user@example.com"
ADD类似COPY,支持压缩文件自动解压或URL,eg:ADD test.tar /mnt
ENV指定环境变量,eg:ENV FILENAME test
EXPOSE暴露容器端口,eg:EXPOSE 80
VOLUME声明数据卷挂载点,eg:VOLUME ["/var/www/html"]
WORKDIR切换工作目录,eg:WORKDIR /mnt
RUN在构建时执行的指令,eg:RUN touch file
CMD容器启动时执行的命令,可被docker run覆盖
ENTRYPOINT容器启动时执行的命令,不可被覆盖,与CMD可组合使用

2.4.2 构建命令

docker build -t [镜像名]:[标签] [构建上下文路径]

2.4.3 镜像优化策略

方法实现方式效果
缩减镜像层使用&&连接多个RUN命令,合并为单层减少层数
多阶段构建在Dockerfile中使用多个FROM,只复制最终产物减小最终镜像
使用精简镜像选用alpine、distroless等基础镜像大幅减小体积
方法1 缩减镜像层
[root@docker-node1 docker]# vim Dockerfile
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.23.3 && yum clean all
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@docker-node1 docker]# docker build -t webserver:v2 .
[root@docker-node1 docker]# docker images  webserver
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
webserver    v2        caf0f80f2332   4 seconds ago       317MB
webserver    v1        bfd6774cc216   About an hour ago   494MB
方法2 多阶段构建
[root@ docker-node1 docker]# vim Dockerfile
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.23.3 && yum clean all

# 第二阶段:运行阶段(只有二进制文件)
FROM centos:7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

[root@server1 docker-node1 docker]# docker build -t webserver:v3 .
[root@server1 docker-node1 docker]# docker images  webserver
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
webserver    v3        1ac964f2cefe   29 seconds ago      205MB
webserver    v2        caf0f80f2332   3 minutes ago       317MB
webserver    v1        bfd6774cc216   About an hour ago   494MB
方法3 使用最精简镜像

使用google提供的最精简镜像,下载地址:https://github.com/GoogleContainerTools/distroless

# 下载镜像
[root@docker-node1 ~]# docker pull gcr.io/distroless/base

# 利用最精简镜像构建
[root@docker-node1 ~]# mkdir new
[root@docker-node1 ~]# cd new/
[root@docker-node1 new]# vim Dockerfile
FROM nginx:1.23 AS base

# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE

RUN mkdir -p /opt/var/cache/nginx && \
    cp -a --parents /usr/lib/nginx /opt && \
    cp -a --parents /usr/share/nginx /opt && \
    cp -a --parents /var/log/nginx /opt && \
    cp -aL --parents /var/run /opt && \
    cp -a --parents /etc/nginx /opt && \
    cp -a --parents /etc/passwd /opt && \
    cp -a --parents /etc/group /opt && \
    cp -a --parents /usr/sbin/nginx /opt && \
    cp -a --parents /usr/sbin/nginx-debug /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libpcre* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
    cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime

FROM gcr.io/distroless/base-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
[root@docker-node1 new]# docker build -t webserver:v4 .
[root@docker-node1 new]# docker images  webserver
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
webserver    v4        c0c4e1d49f3d   4 seconds ago       34MB
webserver    v3        1ac964f2cefe   12 minutes ago      205MB
webserver    v2        caf0f80f2332   15 minutes ago      317MB
webserver    v1        bfd6774cc216   About an hour ago   494MB

2.5 镜像仓库管理

2.5.1 什么是Docker仓库

Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。

它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。

类型:

  • 公共仓库:如Docker Hub,任何人都可以访问和使用其中的镜像。许多常用软件(nginx、redis、mysql)都有官方镜像。
  • 私有仓库:由组织或个人自己搭建和管理,用于存储内部使用的、不希望公开的镜像。

在这里插入图片描述

2.5.2 Docker Hub与镜像加速

Docker Hub是Docker官方提供的公共镜像仓库,拥有大量官方和社区镜像。

国内访问Docker Hub较慢时,可配置镜像加速器:

# 编辑/etc/docker/daemon.json(如果不存在则创建)
{
  "registry-mirrors": ["https://docker.m.daocloud.io"]
}
# 重启Docker服务
systemctl restart docker
# 配置完成后,docker pull会自动从镜像加速器下载。

2.5.3 Docker仓库的工作原理

三个角色

仓库涉及三个角色:

  • Index:索引服务,负责用户认证、镜像校验、命名空间管理。
  • Registry:镜像存储仓库,不提供用户认证,依赖Index进行Token验证。
  • Registry Client:Docker客户端,执行push/pull。
Pull流程(下载镜像)

在这里插入图片描述

# 镜像拉取分为以下几步:
1.docker客户端向index发送镜像拉去请求并完成与index的认证
2.index发送认证token和镜像位置给dockerclient
3.dockerclient携带token和根据index指引的镜像位置取连接registry
4.Registry会根据client持有的token跟index核实身份合法性
5.index确认此token合法性
6.Registry会根据client的请求传递镜像到客户端
Registry仓库 Index服务 Docker Client Registry仓库 Index服务 Docker Client 1. 拉取请求 + 认证 2. 返回Token + 镜像位置 3. 携带Token请求镜像 4. 验证Token 5. Token合法 6. 返回镜像
Push流程(上传镜像)

在这里插入图片描述

# 镜像上传的步骤:
1.client向index发送上传请求并完成用户认证
2.index会发方token给client来证明client的合法性
3.client携带index提供的token连接Registry
4.Registry向index合适token的合法性
5.index证实token的合法性
6.Registry开始接收客户端上传过来的镜像
Registry仓库 Index服务 Docker Client Registry仓库 Index服务 Docker Client 1. 上传请求 + 认证 2. 返回Token 3. 携带Token上传镜像 4. 验证Token 5. Token合法 6. 接收镜像

2.5.4 私有仓库方案

为什么需要私有仓库?

  • Docker Hub需要互联网连接,内网环境无法访问
  • 公开仓库所有人可访问,企业镜像需要保密
  • 企业安全策略要求镜像存储在内网
方案特点适用场景
简单Registry无认证、无UI、无高可用,一个容器搞定测试环境、开发环境
Registry + TLS增加HTTPS传输加密,防止中间人攻击有一定安全要求
Registry + 认证增加登录认证(HTTP Basic Auth或Token),需要搭配nginx等内部团队使用
Harbor企业级:RBAC权限控制、图形化UI、镜像复制、漏洞扫描、审计日志、垃圾回收生产环境推荐

Harbor简介:由VMware开源的企业级Docker Registry项目,是目前最流行的私有仓库解决方案。它提供的功能如下:

  • 基于角色的访问控制(RBAC):可以为不同用户分配项目级别的权限
  • 镜像复制:支持在多个Harbor实例之间同步镜像(主备、异地)
  • 图形化用户界面:方便管理项目、镜像、用户
  • 审计日志:记录所有操作,满足合规要求
  • 漏洞扫描:自动扫描镜像中的已知漏洞
  • 垃圾回收:清理无用的镜像层,释放存储空间

2.5.4 仓库相关命令

操作命令
登录仓库docker login [仓库地址]
给镜像打标签docker tag nginx:latest myrepo/nginx:v1
推送镜像docker push myrepo/nginx:v1
拉取镜像docker pull myrepo/nginx:v1
登出仓库docker logout

3 Docker容器操作

3.1 容器生命周期管理

操作命令示例说明
启动容器docker run [选项] [镜像] [命令]常用选项:-d后台运行、-it交互式终端、--name指定名称、-p端口映射、--rm停止后自动删除、--network指定网络
查看运行容器docker ps加-a查看所有容器(包括已停止)
停止/启动/重启docker stop/start/restart [容器名或ID]容器内的第一个进程必须保持运行,否则容器会退出
删除容器docker rm [容器名或ID]加-f强制删除运行中的容器
进入运行中的容器docker exec -it [容器名] /bin/bash推荐使用,避免docker attach
# 1.启动容器
[root@Docker-node1 ~]# docker run  -d --name mario -p 80:8080 timinglee/mario
[root@Docker-node1 ~]# docker run -it --name centos7 centos:7
[root@3ba22e59734f /]#	#进入到容器中,按<ctrl>+<d>退出并停止容器,#按<ctrl>+<pq>退出但不停止容器
#重新进入容器
[root@docker ~]# docker attach centos7
[root@3ba22e59734f /]#

# 2.查看运行容器
[root@Docker-node1 ~]# docker ps					# 查看当前运行容器
[root@Docker-node1 ~]# docker ps -a					# 查看所有容器
[root@Docker-node1 ~]# docker inspect busybox		# 查看容器运行的详细信息

# 3.停止/启动/重启
[root@Docker-node1 ~]# docker stop busybox			# 停止容器
[root@Docker-node1 ~]# docker kill busybox			# 杀死容器,可以使用信号
[root@Docker-node1 ~]# docker start busybox			# 开启停止的容器
# 容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!

# 4.删除容器
[root@Docker-node1 ~]# docker rm centos7			#删除停止的容器
[root@Docker-node1 ~]# docker rm -f busybox			#删除运行的容器
[root@Docker-node1 ~]# docker container prune -f	#删除所有停止的容器

# 5.进入运行中的容器
#在容器中执行命令
[root@docker ~]# docker exec -it  test ifconfig
lo        Link encap:Local Loopback
………………

3.2 容器信息与日志

操作命令说明
查看容器日志docker logs [容器名]加-f实时跟踪日志
查看容器详情docker inspect [容器名或ID]显示容器的详细配置信息
查看容器进程docker top [容器名]查看容器内运行的进程
查看容器统计docker stats实时查看容器资源使用情况
[root@Docker-node1 ~]# docker logs web
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
……………………

3.3 文件传输与提交

操作命令说明
文件传输docker cp [宿主机路径] [容器名]:[容器路径] docker cp [容器名]:[容器路径] [宿主机路径]支持宿主机与容器之间双向复制
提交容器镜像docker commit [容器名] [新镜像名]不推荐,企业应用请用Dockerfile
[root@Docker-node1 ~]# docker cp  test2:/leefile /mnt		# 把容器中的文件复制到本机
Successfully copied 1.54kB to /mnt
[root@Docker-node1 ~]# docker cp /etc/fstab  test2:/fstab	# 把本机文件复制到容器中

3.4 容器资源限制与安全优化

Docker 安全依赖 Linux 内核:命名空间隔离、Cgroups 资源控制、Capability 权限控制、Docker 服务端安全。

Docker容器的安全性高度依赖Linux系统自身(Linux内核),主要的安全维度如下:

  • Linux命名空间提供的容器隔离安全
  • Linux Cgroups对资源控制的安全
  • Linux Capability带来的细粒度权限安全
  • Docker服务端本身的抗攻击能力
  • 其他安全增强机制(如 LXCFS)

容器本质是宿主机上的特殊进程,多个容器共享同一个内核,所以隔离不是绝对彻底,部分资源(如磁盘)无法完全 Namespace 化。

  1. 命名空间隔离的安全:

    Docker启动容器时会自动创建独立Namespace(pid、net、mnt、ipc、uts、user),提供最基础隔离。

    • 作用:提供最基础的隔离,使容器看起来像是一个独立的系统。
    • 局限性:容器本质是宿主机上的特殊进程,共享同一个内核。与虚拟机相比,隔离不彻底,部分资源(如磁盘、内核参数)无法被 Namespace 完全隔离。
  2. 控制组(Cgroups)资源控制的安全:

    当使用docker run启动容器时,Docker会在后台为容器创建一个独立的控制组(Cgroups)策略集合。

    • **资源公平分配:**确保各容器可以公平地分享主机的内存、CPU、磁盘 IO 等资源,避免 “邻里纠纷”。
    • **防DDoS攻击:**确保容器内发生的资源压力(如死循环占满 CPU)不会影响到本地主机系统及其他容器,防止单个容器拖垮整个宿主机。
    • 防止资源争抢导致整体雪崩

    rhel9 cgroup说明:rhel9默认使用 cgroup-v2,但不利于观察 Docker 资源限制,可以切换为cgroup-v1

    grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
    --args="systemd.unified_cgroup_hierarchy=0 systemd.legacy_systemd_cgroup_controller"
    

    默认情况下,容器内并未被强制隔离资源,容器内看到的资源信息与宿主机无异。

    # 1. 启动一个 busybox 容器
    [root@docker ~]# docker run -it --name test busybox
    # 2. 查看容器内内存情况(显示的是宿主机总量)
    / # free -m
          total    used    free    shared    buff/cache    available
    Mem:   3627     648     516      16        2463         2678
    Swap:  2063       1    2062
    # 3. 退出容器,查看宿主机内存
    / # exit
    [root@docker ~]# free -m
    # 结果与容器内基本一致,说明默认未做资源隔离。
    

    为了实现安全的资源控制,需要通过 docker run 的参数手动限制,否则容器可以无限制消耗主机资源。

  3. 内核能力机制:

    **能力机制(Capability)**是Linux内核的一个强大特性,为容器权限控制提供了细粒度的支持。

    • 核心逻辑:大部分情况下,容器并不需要"真正的"root 权限(UID=0)。root 权限过大,风险过高;Capability将权限拆分成多个小块,容器只需要申请必要的能力即可。
    • Docker策略:默认情况下,Docker采用 "白名单"机制,严格禁用"必需功能"之外的其他权限,最小化攻击面。

    这就是为什么即使在容器内执行 ip a 等网络操作也不会被完全限制,但无法修改系统关键内核参数的原因。

  4. Docker服务端防护:

    Docker的核心是服务端(daemon),其安全性直接决定了整个平台的安危。

    • 访问控制:必须确保只有可信的用户才能访问Docker服务接口(避免未授权接管主机)。
    • 权限映射:将容器内的 root 用户映射到本地主机上的非root用户,减轻容器与主机之间因权限提升引起的安全隐患。
    • **非root运行:**允许Docker服务端在非root权限下运行,并利用安全可靠的子进程来代理执行需要特权的操作。这些子进程被严格限制在特定范围内,降低了整体风险。

3.4.1 资源控制(Linux Cgroups)

Linux Cgroups(Linux Control Group)用于限制容器(一个进程组能够使用)CPU、内存、磁盘 IO等资源上限,对进程进行优先级设置、审计,以及将进程挂起和恢复等操作,防止单个容器耗尽主机资源(防 DDoS、保证稳定性)。

基于上述Cgroups机制,通过命令行限制容器资源示例如下:

限制CPU资源

# 限制容器最多使用 20% 的 CPU 时间
docker run -it --rm --cpu-period 100000 --cpu-quota 20000 ubuntu

# 设置 CPU 权重(优先级)
docker run -it --rm --cpu-shares 512 ubuntu

限制内存资源

# 限制内存 200M,且内存+Swap 等于 200M(禁用额外Swap)
docker run -d --name test --memory 200M --memory-swap 200M nginx

限制磁盘 IO

# 限制写入速度为 30MB/s
docker run -it --rm --device-write-bps /dev/sda:30M ubuntu

总结

资源类型限制参数示例命令
CPU使用量--cpusdocker run --cpus=2 ...
CPU优先级--cpu-sharesdocker run --cpu-shares=512 ...
内存限制-m / --memorydocker run -m 512m ...
磁盘IO--device-read-bps / --device-write-bpsdocker run --device-write-bps /dev/sda:1mb

3.4.2 容器隔离增强与权限管理

Docker容器默认不是完全隔离的,容器内的root用户只是宿主机上的一个普通用户(通过命名空间映射)。但某些操作(如修改网络配置、挂载文件系统)默认被禁止。

  1. 容器隔离增强:

    • **隔离缺陷:**容器内free命令看到的是宿主机的资源信息,容易导致应用误判。

    • **LXCFS修复:**LXCFS是解决此问题的利器,可挂载到容器中,让容器内进程看到准确的自身资源限制。

      # 1. 运行 LXCFS 服务
      lxcfs /var/lib/lxcfs &
      
      # 2. 启动容器并挂载 LXCFS
      docker run -it -m 256m \
      -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \
      -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \
      ubuntu
      

      效果:容器内free -m将显示 256M,而非宿主机的大容量。

  2. 容器权限配置:

    • 特权模式(高危):

      • docker run -it --privileged busybox
        
      • 拥有近乎宿主机root的权限。

      • 注意:生产环境严禁随意使用,风险极高。

    • 白名单机制(推荐):

      • docker run -it --cap-add NET_ADMIN busybox
        
      • NET_ADMIN仅开放网络管理能力,无法操作磁盘,安全性远高于--privileged。

方式说明风险
默认容器内root受限,无法修改系统配置(如iptables、modprobe)较低
--privileged=true获得宿主机几乎全部权限(接近宿主机root)高,仅调试用
--cap-add / --cap-drop精确添加或删除特定Linux Capability,遵循最小权限原则推荐生产使用

capabilities手册地址:http://man7.org/linux/man-pages/man7/capabilities.7.html

常用Capability示例:

  • NET_ADMIN:允许网络管理(如配置iptables)
  • SYS_TIME:允许修改系统时间
  • CAP_SYS_ADMIN:允许挂载文件系统、执行特权系统调用(权限很大,慎用)
  • DAC_OVERRIDE:绕过文件读/写/执行权限检查

4 Docker数据卷与持久化

4.1 为什么需要数据卷

Docker容器默认的文件系统是临时的:容器删除后,所有在容器内写入的数据都会丢失。数据卷(Volume)就是为了解决这个问题。

特性容器分层文件系统数据卷
性能较差与主机磁盘相同
生命周期随容器删除而消失独立于容器,持久保存
跨容器共享困难支持多容器挂载
迁移能力无仅限本地(需额外工具)

4.2 三种数据卷对比

选 bind mount:需要直接在宿主机编辑容器内文件、共享宿主机配置 / 日志,不考虑跨主机迁移

选 管理卷:标准的容器数据持久化方案,适合数据库、微服务等生产环境,可移植性强

选 tmpfs:仅需临时存储、对性能要求极高、数据无需持久化(如临时缓存、敏感凭证)

对比项bind mount(绑定挂载)docker managed volume(Docker 管理卷)tmpfs mount(临时内存挂载)
定义方式-v 宿主机路径:容器路径 --mount type=bind,src=宿主机路径,dst=容器路径-v 容器路径 / -v 卷名:容器路径 --mount type=volume,src=卷名,dst=容器路径--tmpfs 容器路径 --mount type=tmpfs,dst=容器路径
宿主机位置任意指定宿主机文件系统路径/var/lib/docker/volumes/卷名/_data宿主机内存(RAM),不落地磁盘
可移植性差(强依赖宿主机路径结构,跨主机需手动同步)好(Docker 统一管理,支持 docker volume 命令备份 / 迁移)无(容器销毁即数据丢失,不可移植)
数据初始化无(宿主机目录内容直接覆盖容器内对应路径)若容器路径已有数据,会自动复制到新创建的卷中无(内存挂载,容器启动时初始化空目录)
数据持久性持久化(容器销毁后数据仍保留在宿主机)持久化(容器销毁后卷数据独立保留)临时(仅容器运行时存在,容器停止 / 销毁即数据丢失)
性能受宿主机磁盘 IO 性能影响受宿主机磁盘 IO 性能影响极高(直接读写内存,无磁盘 IO 开销)
适用场景宿主机与容器共享配置文件、日志文件;需要直接编辑容器内文件数据库数据持久化、容器间数据共享、无宿主机路径依赖的持久化存储敏感临时数据(如密码、密钥)、高 IO 临时缓存、无需持久化的中间数据
权限控制完全由宿主机文件权限控制,需手动配置Docker 统一管理,支持卷级权限配置可通过 --tmpfs-size/--tmpfs-mode 限制大小、设置权限
跨容器共享支持(多个容器挂载同一宿主机路径)支持(多个容器挂载同一命名卷)支持(多个容器挂载同一内存路径,容器销毁即失效)

4.3 数据卷常用命令

操作命令说明
创建数据卷docker volume create [卷名]创建命名卷,方便管理
查看数据卷列表docker volume ls列出所有数据卷
查看数据卷详情docker volume inspect [卷名]显示卷的挂载点、驱动等信息
挂载数据卷docker run -v [卷名]:[容器路径] ...使用命名卷启动容器
清理未使用卷docker volume prune危险操作,删除所有未被任何容器使用的卷
删除数据卷docker volume rm [卷名]删除指定卷(必须未被使用)

4.4 数据卷容器

数据卷容器是一个专门用于共享数据卷的容器,本身不运行业务进程(通常使用busybox或alpine作为基础镜像)。其他容器通过--volumes-from挂载同一个数据卷,实现数据共享。

数据卷容器

--volumes-from

--volumes-from

数据卷

业务容器A

业务容器B

操作步骤:

  1. 创建数据卷容器:docker create -v /data --name data_vol busybox
  2. 其他容器使用:docker run --volumes-from data_vol ...

4.5 备份与迁移数据卷

由于数据卷的物理位置在宿主机上,可以通过启动一个临时容器来备份卷内容。

备份:

# 运行一个临时容器,挂载要备份的数据卷和宿主机的备份目录
docker run --rm --volumes-from data_vol -v $(pwd):/backup alpine \
  tar czf /backup/backup.tar.gz /data

# --rm:备份完成后自动删除容器;--volumes-from data_vol:继承数据卷容器的挂载点;-v $(pwd):/backup:将当前目录挂载到容器的/backup;tar czf /backup/backup.tar.gz /data:压缩/data目录

恢复:

# 先创建一个新的数据卷容器(或直接挂载到目标容器)
docker run --rm --volumes-from data_vol -v $(pwd):/backup alpine \
  tar xzf /backup/backup.tar.gz -C /

5 Docker网络模型

5.1 默认网络

Docker安装后自动创建3种默认网络:

NETWORK ID     NAME      DRIVER    SCOPE
2a93d6859680   bridge    bridge    local
4d81ddd9ed10   host      host      local
8c8c95f16b68   none      null      local

5.1.1 原生bridge网络

docker安装时会创建一个名为 docker0 的Linux bridge,新建的容器会自动桥接到这个接口。

[root@docker-note1 mnt]# ip link show type bridge
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:5f:e2:34:6c brd ff:ff:ff:ff:ff:ff
  • bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
  • 容器通过宿主机的NAT规则后可以访问外网

在这里插入图片描述

[root@docker-node1 mnt]# docker run -d --name web -p 80:80 nginx:1.23
defeba839af1b95bac2a200fd1e06a45e55416be19c7e9ce7e0c8daafa7dd470
[root@docker-node1 mnt]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:5fff:fee2:346c  prefixlen 64  scopeid 0x20<link>
        ether 02:42:5f:e2:34:6c  txqueuelen 0  (Ethernet)
        RX packets 21264  bytes 1497364 (1.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27358  bytes 215202237 (205.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
……………………
veth022a7c9: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::a013:5fff:fefc:c9e4  prefixlen 64  scopeid 0x20<link>
        ether a2:13:5f:fc:c9:e4  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 15  bytes 2007 (1.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# 其中veth022a7c9为容器使用的网卡
[root@docker-node1 mnt]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02425fe2346c       no              veth022a7c9

5.1.2 原生网络host

host网络模式需要在容器创建时指定 --network=host;host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。

在这里插入图片描述

[root@docker-node1 ~]# docker run -it --name test  --network host busybox
/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:5F:E2:34:6C
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:5fff:fee2:346c/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:21264 errors:0 dropped:0 overruns:0 frame:0
          TX packets:27359 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1497364 (1.4 MiB)  TX bytes:215202367 (205.2 MiB)

eth0      Link encap:Ethernet  HWaddr 00:0C:29:EC:FC:D3
          inet addr:172.25.254.100  Bcast:172.25.254.255  Mask:255.255.255.0
          inet6 addr: fe80::30b2:327e:b13a:31cf/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1902507 errors:0 dropped:0 overruns:0 frame:0
          TX packets:831640 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2202443300 (2.0 GiB)  TX bytes:849412124 (810.0 MiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:11819 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11819 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1279944 (1.2 MiB)  TX bytes:1279944 (1.2 MiB)

/ #

# 如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占用,在启动第二个nginx容器就会失败

5.1.3 原生网络none

none模式是指禁用网络功能,只有lo接口,在容器创建时使用–network=none指定。

[root@docker-node1 ~]# docker run -it --name test --rm --network none  busybox
/ # ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

5.2 自定义网络

自定义网络模式,docker提供了三种自定义网络驱动:bridge、overlay、macvlan。

bridge驱动类似默认的bridge网络模式,但增加了一些新的功能,overlay和macvlan是用于创建跨主机网络。

5.3.1 为什么需要自定义网络

使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。

  • DNS自动解析:自定义网络内置DNS服务,容器之间可以通过容器名直接通信,而不需要依赖可能变化的IP地址。默认bridge网络不支持这个功能。
  • 网络隔离:不同的自定义网络默认是隔离的,可以精细控制哪些容器可以相互通信。
  • 可配置性:可以指定子网、IP范围、网关等,方便与现有网络规划整合。

5.3.2 核心类型:自定义桥接网络

  • 在所有自定义网络类型中,自定义桥接网络最贴合日常部署需求的类型,核心是在宿主机上创建虚拟网桥,将容器连接到该网桥上,实现容器与宿主机、容器与容器之间的通信。
  • 相较于默认bridge网络,自定义桥接网络不仅保留了基础通信功能,还新增了DNS自动解析、更灵活的网络配置等特性,有效解决了默认bridge网络中IP动态变更、无法通过容器名通信的痛点。

自定义桥接网络支持两种创建方式,适配不同使用场景:

  • 默认创建:系统自动分配子网和网关,IP地址按单调递增规则分配,无需额外配置,适合快速部署。
  • 自定义配置创建:可手动指定子网、网关等参数,精准适配现有网络规划,满足复杂场景需求。

5.3.3 自定义网络命令

操作命令示例
创建桥接网络docker network create [网络名]
指定子网创建docker network create --subnet=172.20.0.0/16 mynet
查看网络列表docker network ls
查看网络详情docker network inspect [网络名]
连接网络docker network connect [网络名] [容器名]
断开网络docker network disconnect [网络名] [容器名]
删除网络docker network rm [网络名]

5.3.4 不同自定义网络互通

在这里插入图片描述

不同自定义网络之间的容器默认无法通信。如果需要互通,有两种方式:

  1. 将容器同时连接到两个网络:通过连接网络命令,将需要互通的容器加入两个目标网络,使其具备两个网络的通信权限。(容器连接多个网络后,会自动获取每个网络对应的IP地址,可正常与各个网络内的其他容器通信)

    # 需要手动将容器连接到另一个网络
    docker network connect net1 containerA
    docker network connect net2 containerA
    
  2. 通过宿主机或外部路由器进行路由:借助宿主机的路由功能或外部路由器,实现不同自定义网络之间的通信。(日常场景中优先使用容器多网络连接的方式。需注意,仅当有明确互通需求时才进行配置,避免破坏网络隔离的安全性。)

5.3.5 Joined容器网络

Joined容器是一种特殊的网络模式,核心特点是容器创建时通过--network=container:容器名参数,指定与另一个已运行的容器共享一个网络栈,无需额外配置即可通过localhost实现容器间的高效通信。

在这里插入图片描述

**核心说明:**Joined模式下,两个容器共享IP、端口等网络资源,一方容器的网络配置变更会同步影响另一方,适用于需要高效通信、共享网络环境的场景(如应用与依赖服务的紧密联动)。

**应用场景:**适用于需紧密联动的服务部署(如phpmyadmin与mysql),通过共享网络栈,让应用容器可直接通过localhost访问依赖服务,无需配置额外网络连接。

[!caution]

注意:Joined模式下的容器共享网络栈,需确保两个容器的服务端口不冲突,避免端口占用导致服务异常。

5.3.6 网络模式对比

网络模式创建方式特点适用场景
bridge(默认)不需要指定容器通过NAT访问外网,外部主机不能直接访问容器(需端口映射)。容器之间通过IP通信,不支持自动DNS解析单机默认模式
host--network=host容器共享宿主机网络栈,没有网络隔离。性能最好,但端口冲突风险高性能要求极高,且不需要网络隔离的场景
none--network=none仅有lo回环接口,完全无网络安全要求极高,不需要网络的服务
container--network=container:vm1新容器与指定容器共享网络栈,两者可以通过localhost通信多容器紧密协作,如sidecar模式
自定义docker network create内置DNS,支持通过容器名自动解析IP;网络隔离生产环境推荐

5.3 容器内外网访问

5.3.1 容器访问外网

  • 在rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网
  • 在rhel7之后的版本中通过nftables添加地址伪装来访问外网

Docker在宿主机上通过iptables/nftables添加地址伪装(MASQUERADE)规则,将容器的源IP转换为宿主机IP。

在这里插入图片描述

[root@docker-node1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  6    --  172.17.0.2           172.17.0.2           tcp dpt:80	# 内网访问外网策略

Chain DOCKER (0 references)
target     prot opt source               destination
DNAT       6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

5.3.2 外网访问容器

使用-p 主机端口:容器端口做端口映射,通过端口映射来暴漏端口从而达到访问效果。

docker-proxy和dnat在容器建立端口映射后都会开启,那个传输速录高走那个。

在这里插入图片描述

# 通过docker-proxy对数据包进行内转
[root@docker-node1 ~]# docker run  -d --name webserver -p 80:80 nginx
[root@docker ~]# ps ax
 133986 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
 133995 ?        Sl     0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container-port 80
 134031 ?        Sl     0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id cae79497a01c0b8c488c7597b43de4a43f361f21a398ff423b4504c0905db143 -address /run/containerd/containerd.sock
 134059 ?        Ss     0:00 nginx: master process nginx -g daemon off;
 134099 ?        S      0:00 nginx: worker process
 134100 ?        S      0:00 nginx: worker process

# 通过dnat策略来完成浏览内转
[root@docker-node1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  6    --  172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (0 references)
target     prot opt source               destination
DNAT       6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

5.4 跨主机网络

在生产环境中,容器往往分布在多台物理机上,所以需要具备跨主机通信能力。

  • 跨主机网络解决方案
    • docker原生的overlay和macvlan
    • 第三方的flannel、weave、calico
  • 众多网络方案是如何与docker集成在一起的
    • libnetwork docker容器网络库。
    • CNM(Container Network Model)这个模型对容器网络进行了抽象。

5.4.1 CNM模型

在这里插入图片描述

CNM分三类组件:

  • Sandbox:容器网络栈,包含容器接口、dns、路由表。(namespace)
  • Endpoint:作用是将sandbox接入network(veth pair)
  • Network:包含一组endpoint,同一network的endpoint可以通信

5.4.2 Macvlan网络

Macvlan是Linux内核提供的网卡虚拟化技术,允许为物理网卡创建多个虚拟子接口,每个子接口有自己的MAC地址和IP地址。容器直接使用这些虚拟接口,无需NAT。

核心特点:

  • 无需Linux bridge,直接使用物理接口,性能接近物理网卡,通信效率极高。

  • 容器获得与宿主机同网段IP(其接口直接与主机网卡连接),外部主机可直接访问,无需NAT转换或端口映射,外部主机可直接访问容器。

  • Macvlan会独占主机网卡,但可通过vlan子接口实现多Macvlan网络部署。

  • 使用前需在主机网卡上开启混杂模式,确保虚拟子接口正常通信。

    • # 在docker主机上添加一块网卡,打开网卡混杂模式:
      [root@docker-node1 ~]# ip link set eth1 promisc on
      [root@docker-node1 ~]# ip link set up eth1
      [root@docker-node1 ~]# ifconfig  eth1
      eth1: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST>  mtu 1500
              ether 00:0c:29:ec:fc:dd  txqueuelen 1000  (Ethernet)
              RX packets 83  bytes 8696 (8.4 KiB)
              RX errors 0  dropped 0  overruns 0  frame 0
              TX packets 0  bytes 0 (0.0 B)
              TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      
  • vlan技术可将物理二层网络划分为4094个逻辑网络(vlan id取值1~4094),各逻辑网络彼此隔离,适配多场景部署需求。

Macvlan网络的隔离与连通规则:

  • 隔离性:Macvlan网络在二层上默认相互隔离,不同Macvlan网络中的容器无法直接通信;
  • 连通性:可在三层上通过网关将不同Macvlan网络连通,Docker本身不做额外限制,按照传统vlan网络的管理方式操作即可。

Macvlan跨主机通信实现要点:

  1. **准备工作:**在参与跨主机通信的所有Docker主机上,各添加一块专用网卡,并开启该网卡的混杂模式。

  2. **创建网络:**在各主机上创建Macvlan网络,指定网络驱动为macvlan,同时配置子网、网关,并指定父接口(即开启混杂模式的网卡)。

    docker network create -d macvlan --subnet=子网段 --gateway=网关地址 -o parent=网卡名 网络名
    # 如
    docker network create -d macvlan --subnet=192.168.100.0/24 --gateway=192.168.100.1 -o parent=eth1 macnet
    
  3. 实现连通:不同主机上的容器若处于同一个子网内,可通过网关实现三层互通,无需额外配置Docker层面的连通规则。

5.4.3 跨主机网络方案对比

方案特点适用场景
OverlayDocker原生,基于VXLAN隧道封装,对底层网络无要求跨主机,网络环境不可控
Macvlan直接使用物理网卡,容器获得独立IP,性能最好性能要求高,网络可控(如数据中心)
Flannel/Weave/Calico第三方CNI插件,功能丰富,常用于KubernetesK8s集群网络

6 Docker Compose编排

6.1 概述

Docker Compose是用于定义和运行多容器Docker应用程序的工具,通过一个YAML文件来配置所有服务、网络和存储卷,然后用一条命令启动整个应用。

是官方的一个开源项目,托管到github上:https://github.com/docker/compose

6.1.1 核心概念(管理层)

  • 服务(Service):一个应用的容器,可以包含多个容器实例(通过scale扩展)
  • 项目(Project):一组关联服务组成的完整业务单元,由docker-compose.yml定义
  • 容器(Container):服务的具体运行实例

项目:myapp

依赖

依赖

服务:web
实例数:3

服务:redis
实例数:1

服务:postgres
实例数:1

6.1.2 主要功能

  1. 定义服务:
    • 使用 YAML 格式的配置文件来定义一组相关的容器服务。每个服务可以指定镜像、端口映射、环境变量、存储卷等参数。
    • 例如,可以在配置文件中定义一个 Web 服务和一个数据库服务,以及它们之间的连接关系。
  2. 一键启动和停止:
    • 通过一个简单的命令,可以启动或停止整个应用程序所包含的所有容器。这大大简化了多容器应用的部署和管理过程。
    • 例如,使用 docker-compose up 命令可以启动配置文件中定义的所有服务,使用 docker-compose down 命令可以停止并删除这些服务。
  3. 服务编排:
    • 可以定义容器之间的依赖关系,确保服务按照正确的顺序启动和停止。例如,可以指定数据库服务必须在 Web 服务之前启动。
    • 支持网络配置,使不同服务的容器可以相互通信。可以定义一个自定义的网络,将所有相关的容器连接到这个网络上。
  4. 环境变量管理:
    • 可以在配置文件中定义环境变量,并在容器启动时传递给容器。这使得在不同环境(如开发、测试和生产环境)中使用不同的配置变得更加容易。
    • 例如,可以定义一个数据库连接字符串的环境变量,在不同环境中可以设置不同的值。

6.1.3 工作原理

Compose会将项目名(默认为当前目录名)作为前缀,创建的资源名类似项目名_服务名_序号,避免与其他项目冲突。

Docker Engine Docker Compose 用户 Docker Engine Docker Compose 用户 loop [按依赖顺序(depends_on- )] docker-compose up 解析docker-compose.yml 创建网络(如果不存在) 创建卷(如果不存在) 创建/启动服务容器 服务已启动,输出日志
  1. 读取配置文件:Docker Compose 读取 YAML 配置文件,解析其中定义的服务和参数。
  2. 创建容器:根据配置文件中的定义,Docker Compose 调用 Docker 引擎创建相应的容器。它会下载所需的镜像(如果本地没有),并设置容器的各种参数。
  3. 管理容器生命周期:Docker Compose 监控容器的状态,并在需要时启动、停止、重启容器;它还可以处理容器的故障恢复,例如自动重启失败的容器。

6.2 常用命令

命令说明
docker-compose up -d启动所有服务(后台运行)
docker-compose down停止并删除所有服务、网络、卷
docker-compose start启动已存在的服务
docker-compose stop停止运行中的服务
docker-compose restart重启服务
docker-compose ps查看服务状态
docker-compose logs [服务名]查看日志
docker-compose build构建镜像
docker-compose up --build启动前重新构建
docker-compose exec [服务名] [命令]在容器中执行命令
docker-compose pull拉取服务所需镜像
docker-compose config验证并查看解析后的配置
docker-compose -f [文件] up指定配置文件

6.3 YAML文件结构

version: '3.8'  # Compose文件格式版本,3.x是最新版

services:
  web:          # 服务名
    image: nginx:latest           # 直接使用现有镜像
    # build: ./web                # 或者使用Dockerfile构建(二选一)
    ports:
      - "80:80"                    # 端口映射 "宿主机:容器"
    environment:
      - ENV_VAR=value              # 环境变量
    volumes:
      - ./html:/usr/share/nginx/html  # bind mount挂载
    networks:
      - appnet                     # 连接到appnet网络
    depends_on:
      - db                         # 依赖db服务,会先启动db
    command: nginx -g 'daemon off;'  # 覆盖默认CMD
    restart: always                # 重启策略

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - db_data:/var/lib/mysql     # 使用命名卷(docker managed volume)
    networks:
      - appnet
    restart: always

networks:
  appnet:                          # 自定义网络
    driver: bridge                 # 网络驱动,默认bridge

volumes:
  db_data:                         # 命名卷声明(否则会报错)

更多推荐