欢迎光临
我们一直在努力

Docker容器从入门到精通

Docker 从入门到企业实战

本笔记整合自多份 Docker 学习资料,涵盖从基础概念、核心原理到高级编排与生产运维的完整知识体系,适合系统学习与日常查阅。


目录

  • 一、Docker 概述
    • 1.1 虚拟化与容器化
    • 1.2 Docker 概述
    • 1.3 Docker 的应用场景
    • 1.4 Docker 与虚拟机比较
  • 二、Docker 核心组件
    • 2.1 Docker 引擎
    • 2.2 Docker 镜像
    • 2.3 Docker 容器
    • 2.4 Docker 仓库
  • 三、Docker 环境安装
    • 3.1 系统环境准备
    • 3.2 RHEL/Redhat 安装
    • 3.3 Ubuntu 安装
    • 3.4 脚本安装
    • 3.5 配置镜像加速
  • 四、Docker 核心原理
    • 4.1 Docker 内部结构
    • 4.2 容器生命周期
    • 4.3 命名空间(Namespace)
    • 4.4 控制组(Cgroups)
    • 4.5 联合文件系统(UnionFS)
  • 五、Docker 基本操作
    • 5.1 镜像管理
    • 5.2 容器管理
    • 5.3 仓库管理
  • 六、容器网络管理
    • 6.1 网络模式概览
    • 6.2 Bridge 网络模式
    • 6.3 Host 网络模式
    • 6.4 Container 网络模式
    • 6.5 None 网络模式
    • 6.6 端口映射与外部访问
    • 6.7 自定义网络与容器互联
    • 6.8 DNS 配置
  • 七、容器数据管理
    • 7.1 数据管理命令
    • 7.2 数据卷(Volume)操作
    • 7.3 数据卷容器(Data Volume Containers)
    • 7.4 tmpfs 挂载
    • 7.5 数据卷备份与恢复
  • 八、Dockerfile 镜像构建
    • 8.1 什么是 Dockerfile
    • 8.2 常用指令详解
    • 8.3 中级概念
    • 8.4 高级技巧
    • 8.5 调试与故障排除
    • 8.6 编写最佳实践
    • 8.7 常见错误避免
    • 8.8 镜像构建与管理
  • 九、Dockerfile 案例实战
    • 9.1 基于 CentOS 构建 Nginx 镜像
    • 9.2 基于 Debian 构建 Nginx 镜像
    • 9.3 基于 Alpine 构建 Nginx 镜像
    • 9.4 基于 Alpine 构建错误页面镜像
    • 9.5 构建 HTTPS 服务镜像
    • 9.6 构建 Python 计算镜像(马青公式)
  • 十、Swarm 集群管理
    • 10.1 Swarm 核心概念
    • 10.2 Swarm 安装
    • 10.3 Swarm 集群搭建
    • 10.4 服务管理
    • 10.5 滚动更新与回滚
    • 10.6 节点管理(污染与激活)
    • 10.7 路由网格
  • 十一、Docker Compose 编排
    • 11.1 Compose 概念
    • 11.2 Compose 安装
    • 11.3 docker-compose.yml 详解
    • 11.4 常用命令
    • 11.5 使用案例:Flask + Redis
    • 11.6 与 Swarm 集成
  • 十二、Harbor 私有仓库
    • 12.1 Harbor 概述
    • 12.2 环境准备
    • 12.3 安装 Docker 与 Compose
    • 12.4 Harbor 安装部署
    • 12.5 证书配置
    • 12.6 启动与配置服务
    • 12.7 测试本地仓库
  • 十三、案例实战:中间件容器化
    • 13.1 MySQL 安装
    • 13.2 Redis 安装
    • 13.3 Elasticsearch 安装
    • 13.4 Kibana 安装
    • 13.5 MySQL 主从复制
    • 13.6 MySQL 双主双从
    • 13.7 Nginx 高可用(Keepalived)
  • 附录:常用命令速查表

一、Docker 概述

1.1 虚拟化与容器化

1.1.1 虚拟化

在最早的时候,想要在线上部署一个应用,需要先购买服务器,然后安装操作系统及各种依赖环境,最后进行应用的部署。

存在的问题:

  • 部署应用上线过程时间非常长
  • 购买服务器的花费不菲
  • 物理服务器的资源容易浪费
  • 迁移和扩展比较困难
  • 为了解决上面的问题,出现了虚拟化技术。虚拟化技术就是在操作系统上多加了一个虚拟化层(Hypervisor),可以将物理机的 CPU、内存、硬盘、网络等资源进行虚拟化,再通过虚拟化出来的空间上安装操作系统,构建虚拟的应用程序执行环境。这就是通常说的虚拟机,比如 VMware、VirtualBox、KVM 等。

    虚拟化技术的优点:

    • 降低运维成本
    • 更快速地部署工作负载
    • 提高应用性能
    • 提高服务器可用性

    虚拟机的缺点:

    • 占用资源较多
    • 性能较差
    • 扩展能力较差
    • 环境迁移能力较差
    1.1.2 容器化

    容器化起源集装箱。在运输之前一次性将货物封装到集装箱里面,然后将集装箱直接放到卡车、火车、货轮上,而且集装箱是统一标准的,自然容易机械化,节省了大量的资源、物流成本大大降低。

    借鉴了集装箱的解决方案,提出了类似集装箱的方式封装应用以及它的运行环境,将应用和环境打包成一个轻量化、可移植、自包含的容器。

    容器的四个特点:

    • 容器共享宿主机内核
    • 容器使用内核的功能对进程进行分组和资源限制
    • 容器通过命名空间保证隔离
    • 容器像是轻量级的 VM(占用空间更少,速度更快),但不是虚拟机

    1.2 Docker 概述

    1.2.1 什么是 Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器或 Windows 机器上,也可以实现虚拟化。

    Docker 是一个主流容器管理工具,它是第一个基于 Linux 容器(LXC)的,但是现在被 runC 所取代了。Docker 容器支持分层的文件系统,因此它能够和宿主机共享系统内核。这个特性意味着即便一个 Docker 镜像基于一个 1GB 的操作系统,在同一个主机上运行 10 个容器实例并不需要消耗 10GB 的空间,相比之下,每一台虚拟机都需要一个完整的 1GB 操作系统。

    Docker 开源项目背景:

    Docker 是基于 Go 语言实现的开源容器项目,诞生于 2013 年年初,最初发起者是 dotCloud 公司(Docker Inc)的创始人 Solomon Hykes(所罗门·海克斯)。后来加入了 Linux 基金会,并遵循 Apache 2.0 协议,全部开源代码均在 https://github.com/docker/docker 上进行维护。

    Docker 的构想是要实现 “Build, Ship and Run Any App, Anywhere”,即通过对应用的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行(Runtime)等生命周期进行管理,达到应用组件"一次封装,到处运行"的目的。

    早期的 Docker 是基于 Linux 容器技术(LXC)的。最早的容器技术可以追溯到 1982 年 Unix 系列操作系统上的 chroot 工具。在 LXC 的基础上,Docker 进一步优化了容器的使用体验,提供了各种容器管理工具(如分发、版本、移植等)。Docker 通过引入分层文件系统构建(aufs)和高效的镜像机制,降低了迁移难度,极大地提升了用户体验。自 0.9 版本开始,Docker 开发了 libcontainer 项目,作为更广泛的容器驱动实现,从而替换掉了 LXC 的实现。

    1.3 Docker 的应用场景

  • 快速、一致地交付应用程序

    Docker 可以为开发人员提供标准化的本地工作环境,简化了开发生命周期。容器非常适合持续集成和持续交付(CI/CD)工作流程。

  • 响应式部署和扩展

    Docker 容器可以在开发人员的本地笔记本电脑、数据中心中的物理或虚拟机上、云提供商上或混合环境中运行。Docker 的可移植性和轻量级的特性可以轻松地动态管理工作负载,并根据业务需求实时扩展或拆除应用程序和服务。

  • 在同一个硬件上运行更多工作负载

    Docker 轻巧快速,为基于虚拟机管理程序的虚拟机提供了可行、经济高效的替代方案。

  • 1.4 Docker 与虚拟机比较

    特性容器虚拟机
    启动速度 秒级 分钟级
    性能 接近原生 较弱
    内存代价 很小 较多
    硬盘使用 一般为 MB 一般为 GB

    Docker 的优势:

    • 更高效的利用系统资源:Docker 对系统资源的利用率更高,一个相同配置的主机往往可以运行更多数量的应用。
    • 更快速的启动时间:可以做到秒级、甚至毫秒级的启动时间。
    • 一致的运行环境:不会再出现「这段代码在我机器上没问题啊」这类问题。
    • 持续交付和部署:使用 Dockerfile 使镜像构建透明化。
    • 更轻松的迁移:可以在很多平台上运行,运行结果一致。
    • 更轻松的维护和扩展:分层存储以及镜像的技术,使得应用重复部分的复用更为容易。

    二、Docker 核心组件

    2.1 Docker 引擎

    Docker 引擎是一个包含以下主要组件的客户端服务器应用程序:

    • 一种服务器,它是一种称为守护进程并且长时间运行的程序(dockerd)
    • REST API,用于指定程序可以用来与守护进程通信的接口
    • 一个有命令行界面(CLI)工具的客户端(docker 命令)

    Docker 客户端是用户与 Docker 交互的主要方式,与 Docker 守护进程进行通信。该守护进程完成了构建、运行和分发 Docker 容器的繁重工作。Docker 客户端和守护程序在 UNIX 套接字或网络接口上使用 REST API 进行通信。Docker 守护进程侦听 Docker API 请求并管理 Docker 对象,例如镜像、容器、网络和卷等。

    2.2 Docker 镜像

    操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。

    Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

    分层存储架构:

    因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。镜像并非是一个像 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说由多层文件系统联合组成。

    镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。分层存储的特征使得镜像的复用、定制变的更为容易。

    【多份笔记存在不同记录】部分笔记中 Docker 镜像描述为"相当于是一个 root 文件系统",另有笔记强调"镜像是一个虚拟的概念,由多层文件系统联合组成"。两者均正确,前者从功能角度描述,后者从技术实现角度描述。

    2.3 Docker 容器

    Docker 容器类似于一个轻量级的沙箱,Docker 利用容器来运行和隔离应用。容器是镜像的一个运行实例。容器可以被创建、启动、开始、停止、删除、暂停等,而这些容器都是彼此相互隔离的、互不可见的。可以把容器看做是一个简易版的 Linux 系统环境(包括 root 用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子。

    容器存储层:

    每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。

    按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

    数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。

    2.4 Docker 仓库

    Docker 仓库类似于代码仓库,它是 Docker 集中存放镜像文件的场所。一个 Docker Registry 中可以包含多个仓库(Repository),每个仓库可以包含多个标签(Tag),每个标签对应一个镜像。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

    以 Ubuntu 镜像为例,Ubuntu 是仓库的名字,其内包含有不同的版本标签,如 20.04、22.04、24.04。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。

    根据所存储的镜像公开分享与否,Docker 仓库可以分为**公开仓库(Public)和私有仓库(Private)**两种形式。目前,最大的公开仓库是官方提供的 Docker Hub。


    三、Docker 环境安装

    3.1 系统环境准备

    在安装 Docker 之前,需要对操作系统进行基础环境配置。

    # 1. 关闭防火墙
    systemctl disable –now firewalld.service

    # 2. 关闭 SELinux
    setenforce 0
    sed -i "s/SELINUX=enforcing/SELINUX=permissive/" /etc/selinux/config

    # 3. 关闭交换分区(Kubernetes 环境需要)
    swapoff -a
    sed -i "s/.*swap.*/#&/" /etc/fstab

    # 4. 安装基本软件
    dnf install -y net-tools nfs-utils vim wget curl tree bash-completion device-mapper-persistent-data psmisc ipvsadm

    # 5. 修改最大连接数
    cat >> /etc/security/limits.conf <<EOF
    * soft nofile 655350
    * hard nofile 655350
    * soft nproc 655350
    * hard nproc 655350
    * soft memlock unlimited
    * hard memlock unlimited
    EOF

    # 6. 开启路由转发
    echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
    sysctl -p

    # 7. 配置宿主机网卡转发(Docker 要求)
    cat > /etc/sysctl.d/docker.conf <<EOF
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward = 1
    EOF

    sysctl -p /etc/sysctl.d/docker.conf

    3.2 RHEL/Redhat 安装

    3.2.1 配置本地仓库(离线环境)

    cat > /etc/yum.repos.d/base.repo <<EOF
    [BaseOS]
    name=BaseOS
    baseurl=/mnt/BaseOS
    gpgcheck=0
    [AppStream]
    name=AppStream
    baseurl=/mnt/AppStream
    gpgcheck=0
    EOF

    # 挂载镜像
    mount /dev/sr0 /mnt
    echo '/dev/sr0 /mnt iso9660 defaults 0 0' >> /etc/fstab

    3.2.2 官方安装方法

    # 1. 删除旧版本
    sudo dnf remove docker docker-client docker-client-latest docker-common \\
    docker-latest docker-latest-logrotate docker-logrotate docker-engine podman runc

    # 2. 安装仓库
    dnf -y install dnf-plugins-core
    dnf config-manager –add-repo https://download.docker.com/linux/rhel/docker-ce.repo

    # 3. 安装 Docker 引擎
    dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    # 4. 启动 Docker
    systemctl enable –now docker

    3.2.3 阿里云镜像安装

    # 1. 安装必要工具
    yum install -y yum-utils

    # 2. 添加软件源信息
    yum-config-manager –add-repo https://mirrors.aliyun.com/docker-ce/linux/rhel/docker-ce.repo

    # 3. 安装 Docker
    yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    # 4. 启动 Docker
    systemctl enable –now docker

    3.2.4 清华镜像安装

    yum install -y yum-utils
    yum-config-manager –add-repo https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/rhel/docker-ce.repo
    yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    systemctl enable –now docker

    3.2.5 离线安装(RPM 包)

    下载地址:https://download.docker.com/linux/rhel/9/x86_64/stable/Packages/

    # 1. 上传 RPM 包
    # containerd.io-1.7.25-3.1.el9.x86_64.rpm
    # docker-ce-28.0.1-1.el9.x86_64.rpm
    # docker-ce-cli-28.0.1-1.el9.x86_64.rpm

    # 2. 安装
    rpm -ivh containerd.io-*.rpm
    rpm -ivh docker-ce-cli-*.rpm
    rpm -ivh docker-ce-*.rpm

    3.2.6 官方卸载

    # 1. 卸载引擎
    sudo dnf remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras

    # 2. 删除镜像、容器和数据卷
    sudo rm -rf /var/lib/docker
    sudo rm -rf /var/lib/containerd

    3.3 Ubuntu 安装

    3.3.1 官方安装

    # 1. 卸载所有冲突的包
    for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
    sudo apt-get remove $pkg
    done

    # 2. 设置 Docker 的 apt 存储库
    sudo apt-get update
    sudo apt-get install ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc

    echo "deb [arch=$(dpkg –print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update

    # 3. 安装最新版本
    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    3.3.2 阿里云安装

    # 1. 安装必要系统工具
    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg

    # 2. 信任 Docker 的 GPG 公钥
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg –dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg

    # 3. 写入软件源信息
    echo "deb [arch=$(dpkg –print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

    # 4. 安装 Docker
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    3.3.3 离线安装(Deb 包)

    官网下载地址:https://download.docker.com/linux/ubuntu/dists/noble/pool/stable/amd64/

    # 1. 上传并安装
    sudo dpkg -i containerd.io_*.deb
    sudo dpkg -i docker-ce-cli_*.deb
    sudo dpkg -i docker-ce_*.deb
    sudo dpkg -i docker-buildx-plugin_*.deb
    sudo dpkg -i docker-compose-plugin_*.deb

    # 2. 验证
    docker -v

    3.3.4 官方卸载

    # 1. 卸载引擎
    sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras

    # 2. 删除镜像、容器和数据卷
    sudo rm -rf /var/lib/docker
    sudo rm -rf /var/lib/containerd

    # 3. 删除认证
    sudo rm /etc/apt/sources.list.d/docker.list
    sudo rm /etc/apt/keyrings/docker.asc

    3.4 脚本安装

    # 下载安装脚本
    curl -fsSL https://get.docker.com -o get-docker.sh

    # 清理旧版本(Dry Run)
    sh get-docker.sh –dry-run

    # 安装新版本
    sh get-docker.sh

    # 验证
    docker version

    3.5 配置镜像加速

    注意:2025 年开始,各大厂商都不支持 docker 镜像拉取,需要配置镜像加速器。

    # 1. 配置 Docker 镜像加速
    cat > /etc/docker/daemon.json <<EOF
    {
    "default-ipc-mode": "shareable",
    "data-root": "/data/docker",
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "100m",
    "max-file": "50"
    },
    "registry-mirrors": [
    "https://docker.1ms.run",
    "https://func.ink",
    "https://proxy.1panel.live",
    "https://docker-0.unsee.tech",
    "https://docker.zhai.cm",
    "https://a.ussh.net",
    "https://docker.melikeme.cn",
    "https://docker.hlmirror.com",
    "https://docker.xiaogenban1993.com",
    "https://docker.1panel.top",
    "https://docker.kejilion.pro",
    "https://dockerpull.cn",
    "https://docker.xuanyuan.me",
    "https://docker.anye.in",
    "https://hub.fast360.xyz"
    ]
    }
    EOF

    # 2. 重启 Docker 服务
    sudo systemctl daemon-reload
    sudo systemctl restart docker

    # 3. 查看是否生效
    docker info | grep "Registry Mirrors" -A 5


    四、Docker 核心原理

    4.1 Docker 内部结构

    Docker Engine 是具有以下主要组件的客户端-服务器应用程序:

    • 服务器是一种长期运行的程序,称为守护进程(dockerd)
    • REST API,指定程序可以用来与守护程序进行通信并指示其操作的接口
    • 命令行界面(CLI)客户端(docker 命令)

    【多份笔记存在不同记录】部分笔记中 Docker 引擎组件的流程图中包含客户端、REST API、守护进程三层架构;另有笔记补充说明守护进程还可以与其他守护进程通信以管理 Docker 服务。

    4.2 容器生命周期

    4.2.1 状态与命令对应表
    状态说明命令
    created 初创建 docker create
    running 运行状态 docker run、docker start、docker restart、docker unpause
    stopped 停止状态 docker stop、docker kill
    paused 暂停状态 docker pause
    4.2.2 状态转换说明

    需要根据实际情况选择的操作:

    • killed by out-of-memory(因内存不足被终止):宿主机内存被耗尽,也被称为 OOM,这时需要杀死最吃内存的容器,然后进行选择操作
    • container process exited(异常终止):出现容器被终止后,将进入 Should restart? 选择操作:
      • yes:需要重启,容器执行 start 命令,转为运行状态
      • no:不需要重启,容器转为停止状态

    4.3 命名空间(Namespace)

    命名空间(namespace)是 Linux 内核的一个强大特性,为容器虚拟化的实现带来极大便利。命名空间用于实现内存、CPU、网络 IO、硬盘 IO、存储空间、文件系统、网络、PID、UID、IPC 等的相互隔离。

    4.3.1 进程命名空间(PID namespace)

    PID namespace 对进程 PID 重新编号,即两个不同的 namespace 下的进程可以用相同的 PID。内核为所有的 PID namespace 维护了一个树状结构,最顶层的是系统初始时创建的,被称作 root namespace(进程号 1)。父节点可以看到子节点中的进程,反过来,子节点却看不到父节点 PID namespace 的任何内容。

    # 查看进程示例
    [root@localhost ~]# ps -ef | grep docker
    root 2335 1 0 21:01 ? 00:00:00 /usr/bin/dockerd
    root 2896 2881 0 21:05 ? 00:00:00 nginx: master process nginx -g daemon off;
    101 2933 2896 0 21:05 ? 00:00:00 nginx: worker process

    4.3.2 网络命名空间(network namespace)

    通过网络命名空间,可以实现网络隔离。网络命名空间为进程提供了一个完全独立的网络协议栈的视图,包括网络设备接口、IPv4 和 IPv6 协议栈、IP 路由表、防火墙规则、sockets 等。Docker 采用虚拟网络设备(Virtual Network Device)的方式,将不同命名空间的网络设备连接到一起。默认情况下,容器中的虚拟网卡将同本地主机上的 docker0 网桥连接在一起。

    4.3.3 IPC 命名空间(IPC namespace)

    进程间通信(Inter-Process Communication,IPC)涉及的 IPC 资源包括常见的信号量、消息队列和共享内存。PID Namespace 和 IPC Namespace 可以组合起来一起使用,在同一个 IPC namespace 下的进程彼此可见,不同 IPC namespace 下的进程则互相不可见。

    4.3.4 挂载命名空间(Mount namespace)

    类似于 chroot,将一个进程放到一个特定的目录执行。挂载命名空间允许不同命名空间的进程看到的文件结构不同,这样每个命名空间中的进程所看到的文件目录彼此被隔离。可以通过 /proc/[pid]/mounts 查看到所有挂载在当前 namespace 中的文件系统。

    4.3.5 UTS 命名空间(UTS namespace)

    UTS(UNIX Time-sharing System)命名空间允许每个容器拥有独立的主机名和域名。Docker 中,每个镜像基本上都以自身提供的服务名来命名镜像的 hostname,其原理就是利用了 UTS namespace。默认情况下,Docker 容器的主机名就是返回的容器 ID。

    4.3.6 用户命名空间(User namespace)

    每个容器可以有不同的用户和组 ID,也就是说可以在容器内使用特定的内部用户执行程序,而非本地系统上存在的用户。每个容器内部都可以有 root 帐号,但跟宿主机不在一个命名空间。

    命名空间汇总表:

    Namespace系统参数调用隔离内容
    UTS CLONE_NEWUTS 主机名和域名
    IPC CLONE_NEWIPC 信号量、消息队列和共享内存
    PID CLONE_NEWPID 进程编号
    Network CLONE_NEWNET 网络设备、网络栈、端口等
    Mount CLONE_NEWNS 挂载点(文件系统)
    User CLONE_NEWUSER 用户和用户组

    4.4 控制组(Cgroups)

    控制组(Cgroups)是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。默认情况下,容器没有资源限制,可以使用 docker stats 容器ID 查看容器状态。Docker 提供了一些方法来控制容器可以使用多少内存或 CPU。

    4.4.1 CPU 限制
    选项描述
    –cpus 指定一个容器可以使用多少可用的 CPU 资源。例如 –cpus="1.5"
    –cpu-period 指定 CPU CFS 调度程序周期,与 –cpu-quota 一起使用
    –cpu-quota 在容器上设置 CPU CFS 配额
    –cpuset-cpus 限制容器可以使用的特定 CPU 或内核,如 0-3 或 1,3
    –cpu-shares 设置 CPU 权重(默认 1024),这是一个软限制

    docker run –cpus 1.5 –rm -d –network host nginx:1.28.1

    4.4.2 内存限制
    选项描述
    -m, –memory 容器可以使用的最大内存量,最小允许值为 4m
    –memory-swap 允许此容器交换到磁盘的内存量
    –memory-swappiness 调整内存交换倾向(0-100)
    –memory-reservation 软限制,低于 –memory
    –oom-kill-disable 禁用 OOM 杀手

    docker run –rm -d –network host -m 100m nginx:1.28.1

    4.4.3 磁盘读写限制

    BlockIO 指的是磁盘的读写,docker 可通过设置权重、限制 bps 和 iops 的方式控制容器读写磁盘的带宽。

    docker run -it –device-write-bps /dev/sda:30MB ubuntu

    4.5 联合文件系统(UnionFS)

    联合文件系统(UnionFS)是一种轻量级的高性能分层文件系统,它支持将文件系统中的修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。UnionFS 是实现 Docker 镜像的技术基础。

    4.5.1 Docker 存储

    Docker 目前通过插件化方式支持多种文件系统后端。当 Docker 利用镜像启动一个容器时,将在镜像文件系统的最顶端再挂载一个新的可读写的层给容器。容器中的内容更新将会发生在可读写层。

    # 查看镜像分层
    docker history nginx:1.28.1

    4.5.2 多种文件系统比较
    文件系统说明
    AUFS 最早支持的文件系统,对 Debian/Ubuntu 支持好,成熟度很高
    OverlayFS 类似于 AUFS,性能更好,已合并到内核,未来会取代 AUFS
    Device Mapper Redhat 公司和 Docker 团队一起开发,内核支持,性能略慢
    btrfs 参考 zfs 等特性设计,试图未来取代 Device Mapper
    vfs 基于普通文件系统的中间层抽象,性能差,比较占用空间
    zfs 最初设计为 Solaris 10 上的写时文件系统,对 Linux 支持不够成熟

    通过 docker info 的 Storage Driver 可以查看当前使用的文件系统。


    五、Docker 基本操作

    5.1 镜像管理

    5.1.1 搜索镜像

    docker search 镜像名称[:TAG]

    注意:只能搜索 Docker Hub 仓库镜像,私有仓库无法搜索到。

    [root@localhost ~]# docker search mysql
    NAME DESCRIPTION STARS
    mysql MySQL is a widely used... 9760
    mariadb MariaDB is a community-developed... 3564
    mysql/mysql-server Optimized MySQL Server Docker... 717

    5.1.2 拉取镜像

    docker pull 镜像名称[:TAG]

    如果不显式指定 TAG,则默认会选择 latest 标签。镜像的仓库名称中还应添加仓库地址(registry)作为前缀,默认使用的是 Docker Hub 服务,该前缀可以忽略。

    [root@localhost ~]# docker pull mysql:8.4.4
    8.4.4: Pulling from library/mysql
    8559a31e96f4: Pull complete
    d51ce1c2e575: Pull complete
    ...

    5.1.3 查看本地镜像

    docker images
    # 或
    docker image ls

    [root@localhost ~]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    mysql 8.4.4 9cfcce23593a 6 weeks ago 448MB

    5.1.4 添加镜像标签

    docker tag 原镜像名[:TAG] 目标镜像名[:TAG]

    如果 TAG 缺省,默认 latest。

    5.1.5 查看镜像信息

    docker inspect 镜像名称[:TAG]
    docker history 镜像名称[:TAG]

    返回的是一个 JSON 格式的消息,如果只要其中一项内容时,可以使用 -f 参数来指定:

    docker inspect mysql:8.4.4 -f {{".Architecture"}}

    5.1.6 导出镜像

    docker save -o 本地路径/文件名称 镜像名称[:TAG] [...]

    # 导出单个镜像
    docker image save busybox > docker-busybox.tar.gz

    # 导出多个镜像
    docker image save busybox:latest nginx:1.28.1 -o /opt/busybox_nginx.tar.gz

    5.1.7 导入镜像

    docker load -i 本地路径/文件名称

    [root@localhost ~]# docker image load -i docker-busybox.tar.gz
    23bc2b70b201: Loading layer 1.37 MB/1.37 MB
    Loaded image: busybox:latest

    5.1.8 查看悬空镜像

    悬虚镜像(Dangling Images)是指那些没有标签且没有被任何容器使用的镜像。

    docker images -f "dangling=true"

    5.1.9 删除悬空镜像

    # 删除所有悬空镜像
    docker image prune -f

    # 删除所有未被标签引用的镜像(包括悬空镜像和未使用的中间层镜像)
    docker image prune -a -f

    # 或者使用 docker rmi
    docker rmi $(docker images -f "dangling=true" -q)

    5.1.10 删除镜像

    docker rmi 镜像名称[:TAG] [...]

    当同一个镜像拥有多个标签的时候,docker rmi 命令只是删除该镜像多个标签中的指定标签而已,并不影响镜像文件。如果镜像只剩下一个标签,使用 docker rmi 会彻底删除镜像。如果有容器正在运行该镜像,则不能删除,可使用 -f 强行删除(不推荐)。

    # 删除单个标签
    docker rmi mysql:8.4.4

    # 彻底删除镜像(只剩一个标签时)
    docker rmi mysql8:latest

    5.2 容器管理

    以下以 Nginx 镜像为例进行演示:

    [root@localhost ~]# docker pull nginx:1.28.1
    1.28.1: Pulling from library/nginx
    ae9b786964d0: Pull complete
    ...
    Status: Downloaded newer image for nginx:1.28.1

    5.2.1 查看容器

    # 查看正在运行的容器
    docker ps

    # 查看所有容器(包括停止的)
    docker ps -a

    5.2.2 创建容器

    docker create [OPTIONS] IMAGE [COMMAND] [ARG...]

    [root@localhost ~]# docker create -it nginx:1.28.1
    6242066cddcadcd51777900a290f885be1752ff65e567e5b8af4b7a6ab0da3ea

    # 创建停止后自动删除的容器
    [root@localhost ~]# docker create –rm nginx:1.28.1
    c6109c3eccbbce0e190c403a8df2f44ccacc8158b2cc6cd5da4833ce15b0a284

    5.2.3 启动容器

    docker start 容器名/ID

    5.2.4 创建并启动容器

    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

    常用选项:

    选项说明
    -t 打开一个终端
    -i 交互式运行
    -d 后台运行
    -p 端口映射,格式:<hostPort>:<containerPort>
    –name 指定容器名称
    –rm 容器停止后自动删除
    –network 指定容器使用的网络
    5.2.5 停止容器

    # 优雅停止(发送 SIGTERM,默认等待 10 秒)
    docker stop 容器名/ID [-t 时间]

    # 强制停止(发送 SIGKILL)
    docker kill 容器名/ID

    # 重启容器
    docker restart 容器名/ID

    # 停止所有容器
    docker stop $(docker ps -qa)

    5.2.6 进入容器

    docker exec -it 容器名/ID /bin/bash

    [root@localhost ~]# docker exec -it strange_wescoff /bin/bash
    root@6242066cddca:/# curl localhost
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    ...
    </html>
    root@6242066cddca:/# exit
    exit

    5.2.7 暂停与恢复

    # 暂停容器
    docker pause 容器名/ID

    # 恢复暂停的容器
    docker unpause 容器名/ID

    5.2.8 查看容器信息

    # 查看容器详细信息(JSON 格式)
    docker inspect 容器名/ID

    # 查看容器资源使用情况
    docker stats 容器名/ID

    # 查看容器进程
    docker top 容器名/ID

    # 查看容器日志
    docker logs 容器名/ID

    5.2.9 复制容器文件

    # 将文件从容器复制出来
    docker cp 容器名:容器内路径 宿主机路径

    # 将文件复制到容器内部
    docker cp 宿主机路径 容器名:容器内路径

    # 复制文件到容器
    docker cp /root/index2.html nginx:/usr/share/nginx/html/

    # 从容器复制文件到宿主机
    docker cp nginx:/usr/share/nginx/html/50x.html .

    5.2.10 删除容器

    # 删除指定容器(只能删除停止状态的容器)
    docker rm 容器名/ID

    # 强制删除运行中的容器
    docker rm -f 容器名/ID

    # 删除所有容器
    docker rm -f $(docker ps -qa)

    5.2.11 通过容器创建镜像

    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

    # 修改容器内容
    docker exec -it nginx /bin/bash
    echo "welcome to nginx!" > /usr/share/nginx/html/index.html

    # 创建新镜像
    docker commit nginx nginx1:1.28.1

    # 使用新镜像运行容器
    docker run –name nginx1 -d -p 80:80 nginx1:1.28.1

    5.2.12 重命名容器

    docker rename 旧容器名 新容器名

    5.2.13 查看容器暴露端口

    docker port 容器名

    [root@localhost ~]# docker port nginx
    80/tcp –> 0.0.0.0:80
    80/tcp –> [::]:80

    5.2.14 导出与导入容器

    # 导出容器为归档文件
    docker export -o 文件.tar 容器名

    # 导入归档文件为镜像
    docker import 文件.tar 镜像名[:TAG]

    # 导出容器
    docker export -o nginx-1.28.1.tar.gz nginx

    # 导入为镜像
    docker import /root/nginx-1.28.1.tar.gz nginx2:1.28.1

    5.2.15 事件监听

    docker events [OPTIONS]

    # 监听容器停止事件
    docker events -f 'event=stop'

    5.2.16 检查文件变更

    docker diff 容器名

    [root@localhost ~]# docker diff nginx
    C /run
    D /run/nginx.pid
    C /etc
    C /etc/nginx
    ...

    5.2.17 连接容器

    docker attach [OPTIONS] CONTAINER

    # 连接到正在运行的容器
    docker attach nginx

    # 在连接到容器后执行命令
    docker attach –sig-proxy=false nginx

    5.3 仓库管理

    5.3.1 登录仓库

    docker login -u 用户名 -p 密码 [SERVER]

    [root@localhost ~]# docker login -u haha -p 123465
    Login Succeeded

    5.3.2 登出仓库

    docker logout [SERVER]

    5.3.3 认证文件

    Mac/Win 机器上的是隐藏密码的,但是在 Linux 下是显示密码的,只不过进行了 base64 编码,只要拷贝此文件到其他机器指定目录下(/root/.docker/config.json)即可免登录。


    六、容器网络管理

    6.1 网络模式概览

    Docker 的网络定义:

    模式说明
    bridge 默认值,在 Docker 网桥 docker0 上为容器创建新的网络
    host 容器直接使用宿主机的网络(不隔离网络命名空间)
    container 与指定容器共享网络命名空间
    none 禁用所有网络,只有 lo 接口
    overlay 覆盖网络,用于 Swarm 集群中跨主机通信
    macvlan 为容器分配 MAC 地址,使其在网络上显示为物理设备

    查看已安装的网络驱动:

    [root@localhost ~]# docker network ls
    NETWORK ID NAME DRIVER SCOPE
    f23b4899add1 bridge bridge local
    65520497f693 host host local
    a0c5f18e0f04 none null local

    6.2 Bridge 网络模式

    6.2.1 模式介绍

    当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,默认地址 172.17.0.0/16。从 docker0 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair 设备,一端放在容器中(eth0),另一端放在主机中(vethxxx),并加入到 docker0 网桥中。

    # 查看网桥
    [root@localhost ~]# brctl show
    bridge name bridge id STP enabled interfaces
    docker0 8000.920bf364e96c no veth4fc6117
    veth645d9ec

    前置工具安装:

    dnf install -y https://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpm
    dnf install -y bridge-utils

    6.2.2 模式演示

    docker run –name bx1 -it –network bridge –rm busybox:latest
    / # ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> ...
    2: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0

    / # route -n
    Kernel IP routing table
    Destination Gateway Genmask Flags Metric Ref Use Iface
    0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
    172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0

    / # ping 192.168.72.169
    64 bytes from 192.168.72.169: seq=0 ttl=64 time=0.194 ms

    6.3 Host 网络模式

    6.3.1 模式介绍

    如果启动容器的时候使用 host 模式,容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器不会虚拟出自己的网卡,而是使用宿主机的 IP 和端口。

    6.3.2 模式演示

    docker run –name bx2 -it –rm –network host busybox:latest
    / # ip a
    # 输出与宿主机一致,包含 ens160、docker0 等

    6.4 Container 网络模式

    6.4.1 模式介绍

    新创建的容器和已经存在的一个容器共享一个 Network Namespace。两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。

    6.4.2 模式演示

    # 终端1:创建容器 bx1
    docker run –name bx1 -it –rm busybox:latest
    / # echo "hello world bx1" >> /tmp/index.html
    / # httpd -h /tmp/
    / # netstat -lntup
    tcp 0 0 :::80 :::* LISTEN 9/httpd

    # 终端2:创建容器 bx2,共享 bx1 的网络
    docker run –name bx2 -it –rm –network container:bx1 busybox:latest
    / # ip a
    # IP 与 bx1 相同
    / # wget -O – -q 127.0.0.1
    hello world bx1
    / # ls /tmp/
    # 文件系统不共享,目录为空

    6.5 None 网络模式

    6.5.1 模式介绍

    使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是并不进行任何网络配置。没有网卡、IP、路由等信息,只有 lo 网络接口。

    6.5.2 模式演示

    docker run –name bx3 –rm -it –network none busybox:latest
    / # ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> ...
    / # route -n
    Kernel IP routing table
    Destination Gateway Genmask Flags Metric Ref Use Iface
    # 路由表为空
    / # ping 192.168.72.169
    ping: sendto: Network is unreachable

    6.6 端口映射与外部访问

    6.6.1 随机映射(-P)

    docker run –name nginx -P -d nginx:1.28.1
    docker ps
    PORTS: 0.0.0.0:32768->80/tcp, [::]:32768->80/tcp

    6.6.2 映射所有端口地址

    格式:hostPort:containerPort

    docker run –name nginx -d –network bridge -p 80:80 nginx:1.28.1

    6.6.3 映射到指定地址的指定端口

    格式:IP:hostPort:containerPort

    docker run –name nginx -d -p 127.0.0.1:8080:80 nginx:1.28.1
    # 只能通过 127.0.0.1:8080 访问

    6.6.4 映射指定地址的任意端口

    格式:IP::containerPort

    docker run –rm -d -p 127.0.0.1::80 nginx:1.28.1

    6.6.5 查看端口映射

    docker port nginx

    【多份笔记存在不同记录】部分笔记示例中使用 nostalgi_c_morse 作为容器名,另一些使用 nginx。两者均为示例容器名,实际使用时替换为具体容器名即可。

    6.7 自定义网络与容器互联

    6.7.1 新建网络

    # 创建 bridge 类型网络
    docker network create -d bridge my-net

    # 查看网络列表
    docker network ls

    # 查看网络详细信息
    docker network inspect my-net

    6.7.2 连接容器

    # 在 my-net 网络中创建容器
    docker run –name bx1 -it –rm –network my-net busybox:latest sh
    docker run –name bx2 -it –rm –network my-net busybox:latest sh

    # 通过容器名互相访问(DNS 自动解析)
    # 在 bx1 中:
    / # ping bx2
    PING bx2 (172.18.0.3): 56 data bytes
    64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.257 ms

    # 在 bx2 中:
    / # ping bx1
    PING bx1 (172.18.0.2): 56 data bytes
    64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.087 ms

    6.7.3 不同网络隔离测试

    # 在默认 bridge 网络中创建容器
    docker run -it –name bx3 –network bridge –rm busybox:latest sh
    / # ping bx1
    ping: bad address 'bx1'
    # 无法通信,因为不在同一个网络

    6.7.4 删除网络

    docker network rm my-net

    ⚠️ 注意:不要去删除原生的三个网络类型(bridge、host、none)。

    6.8 DNS 配置

    6.8.1 全局 DNS 配置

    在 /etc/docker/daemon.json 文件中配置 DNS 信息:

    {
    "dns": [
    "223.5.5.5",
    "8.8.8.8"
    ]
    }

    systemctl daemon-reload
    systemctl restart docker

    验证:

    docker run -it –rm busybox:latest cat /etc/resolv.conf
    # Generated by Docker Engine.
    nameserver 223.5.5.5
    nameserver 8.8.8.8

    6.8.2 自定义主机名

    docker run –name bx -it –rm –hostname busybox busybox:latest
    / # cat /etc/hostname
    busybox

    # 或使用 -h 简写
    docker run –name bx -it –rm -h busybox busybox:latest

    6.8.3 自定义 DNS

    docker run –name bx -it –rm –hostname busybox –dns 172.17.0.9 busybox:latest
    / # cat /etc/resolv.conf
    nameserver 172.17.0.9

    6.8.4 自定义搜索域

    docker run –name bx -it –rm –hostname busybox –dns 172.17.0.9 –dns-search www.example.com busybox:latest
    / # cat /etc/resolv.conf
    nameserver 172.17.0.9
    search www.example.com


    七、容器数据管理

    默认情况下,在容器内创建的所有文件都存储在可写容器层上。这样做的问题有:

    • 当容器不再存在时,数据不会持久保存
    • 容器的可写层与运行容器的主机紧密耦合
    • 写入容器的可写层需要存储驱动程序来管理文件系统,性能比直接写入主机要低

    Docker 为容器提供了两种选项来持久存储数据:数据卷(Data Volumes)和数据卷容器(Data Volume Containers),也称为 bind mounts(绑定挂载)。如果在 Linux 上运行 Docker,还可以使用 tmpfs 挂载。

    Volume、Bind 和 tmpfs 的异同:

    • 相同之处:无论选择使用哪种类型,数据在容器内看起来都是相同的,被视为容器文件系统中的目录或单个文件。
    • 不同之处:
      • 卷(Volume):存储在由 Docker 管理的主机文件系统中(/var/lib/docker/volumes/),非 Docker 进程不应该修改这部分文件系统。
      • 绑定挂载(Bind Mount):把主机的本地目录挂载到容器中某个挂载点,可以存储在主机系统的任何位置。
      • tmpfs 挂载:仅存储在主机系统的内存中,而不会写入主机系统的文件系统。

    7.1 数据管理命令

    docker volume –help
    # Commands:
    # create Create a volume
    # inspect Display detailed information on one or more volumes
    # ls List volumes
    # prune Remove unused local volumes
    # rm Remove one or more volumes

    7.2 数据卷(Volume)操作

    7.2.1 创建数据卷

    docker volume create myvol

    7.2.2 查看数据卷

    docker volume ls
    docker volume inspect myvol
    # 输出包含 Mountpoint: /var/lib/docker/volumes/myvol/_data

    7.2.3 使用数据卷

    # 使用创建好的数据卷
    docker run –name nginx -d -p 80:80 -v myvol:/usr/share/nginx/html nginx:1.28.1

    # 挂载宿主机目录
    docker run –name nginx -d -p 80:80 -v /opt/nginx/html:/usr/share/nginx/html nginx:1.28.1

    # 只读挂载
    docker run –name nginx -d -p 80:80 -v /opt/nginx/html:/usr/share/nginx/html:ro nginx:1.28.1

    7.2.4 验证数据共享

    # 在宿主机修改数据
    echo 1111 > /var/lib/docker/volumes/myvol/_data/index.html

    # 进入容器查看
    docker exec -it nginx bash
    cat /usr/share/nginx/html/index.html # 1111

    # 在容器内修改
    echo 2222 > /usr/share/nginx/html/index.html

    # 在宿主机查看
    cat /var/lib/docker/volumes/myvol/_data/index.html # 2222

    7.2.5 删除数据卷

    # 必须先停止并删除关联的容器
    docker stop nginx && docker rm nginx

    # 删除数据卷
    docker volume rm myvol

    # 清理未使用的数据卷
    docker volume prune

    7.3 数据卷容器(Data Volume Containers)

    7.3.1 创建数据卷容器

    # 创建宿主机目录
    mkdir /data/nginx

    # 创建数据卷容器
    docker create -v /data/nginx:/data –name voldata nginx:1.28.1

    # 验证挂载
    docker inspect voldata
    # "Mounts": [{"Type": "bind", "Source": "/data/nginx", "Destination": "/data"}]

    7.3.2 挂载数据卷容器

    docker run –name n1 –volumes-from voldata –rm -d nginx:1.28.1
    docker run –name n2 –volumes-from voldata –rm -d nginx:1.28.1

    7.3.3 验证数据共享

    # 在 n1 中创建文件
    docker exec -it n1 bash
    cd /data
    echo haha > n1.txt

    # 在 n2 中查看
    docker exec -it n2 bash
    cat /data/n1.txt # haha

    # 在宿主机修改
    echo 22222 >> /data/nginx/n1.txt

    # n1 和 n2 中都能看到更新

    7.3.4 只读绑定安装

    # 使用 ro 选项
    docker run -d –name devtest -v "$(pwd)"/target:/app:ro nginx:1.28.1

    # 验证
    docker inspect devtest
    # "Mounts": [{"Type":"bind","Source":"/root/target","Destination":"/app","Mode":"ro","RW":false}]

    7.4 tmpfs 挂载

    # 使用 –tmpfs 标志
    docker run -d –name tmptest –tmpfs /app nginx:1.28.1

    # 使用 –mount 标志(支持更多选项)
    docker run -d –name tmptest \\
    –mount type=tmpfs,destination=/app,tmpfs-mode=1770 \\
    nginx:1.28.1

    7.5 数据卷备份与恢复

    7.5.1 备份

    # 创建备份目录
    mkdir /root/backup

    # 备份数据卷容器
    docker run –rm –volumes-from voldata \\
    -v /root/backup:/backup \\
    nginx:1.28.1 \\
    tar -zcf /backup/data.tar.gz /data

    # 查看备份文件
    ls /backup/data.tar.gz
    tar -tf /backup/data.tar.gz

    注意:tar 命令是在容器内部执行的,路径应该是容器内部的路径。

    7.5.2 恢复

    # 删除测试数据
    docker exec -it n1 bash
    rm -rf /data/*

    # 恢复数据
    docker run –rm –volumes-from voldata \\
    -v /root/backup:/backup \\
    nginx:1.28.1 \\
    tar -zxf /backup/data.tar.gz -C /


    八、Dockerfile 镜像构建

    8.1 什么是 Dockerfile

    Dockerfile 是一个纯文本文件,包含一系列用于构建 Docker 镜像的指令。Dockerfile 中的每一行都代表镜像构建过程中的一个步骤。

    Dockerfile 的关键组件:

  • 基础镜像:构建起点
  • 应用程序代码与依赖项:添加代码并安装依赖
  • 命令与配置项:执行命令、设置环境变量、暴露端口
  • 为什么 Dockerfile 很重要?

    • 标准化应用程序的构建和部署方式
    • 确保在不同环境(开发、测试、生产)中的一致性
    • 使应用程序具有可移植性且更易于管理
    • 实现 CI/CD 自动化
    • 基础设施版本控制

    8.2 常用指令详解

    8.2.1 FROM

    指定基础镜像,必须是 Dockerfile 中非注释行的第一个指令。

    FROM python:3.14-slim

    8.2.2 COPY

    从宿主机复制文件或目录到镜像中。

    COPY <src>… <dest>
    # 或
    COPY ["<src>",… "<dest>"]

    COPY requirements.txt /app/
    COPY . /app/

    如果目标路径不存在,会自动创建。

    8.2.3 RUN

    在构建过程中执行命令,常用于安装软件包。

    RUN <command>
    # 或
    RUN ["<executable>", "<param1>", "<param2>"]

    RUN apt-get update \\
    && apt-get install -y –no-install-recommends gcc \\
    && rm -rf /var/lib/apt/lists/*

    8.2.4 CMD

    指定容器启动时运行的默认命令。Dockerfile 中可以有多个 CMD 指令,但仅最后一个会生效。

    CMD <command>
    CMD ["<executable>","<param1>","<param2>"]
    CMD ["<param1>","<param2>"]

    CMD ["flask", "run", "–host=0.0.0.0"]

    8.2.5 WORKDIR

    为后续指令设置工作目录。

    WORKDIR /app

    8.2.6 ADD

    类似于 COPY,但支持 TAR 文件和 URL 路径。

    ADD <src>… <dest>
    ADD ["<src>",… "<dest>"]

    与 COPY 的区别:

  • 都可以将主机上的资源复制到镜像中
  • COPY 只能从本地读取资源;ADD 还支持从远程 URL 获取资源
  • 满足同等功能的情况下,推荐使用 COPY 指令
  • ADD 更擅长读取本地 tar 文件并解压缩
  • 当要读取 URL 远程资源时,建议使用 RUN 指令中的 wget 或 curl
  • ADD http://nginx.org/download/nginx-1.28.1.tar.gz .
    ADD nginx-1.27.4.tar.gz .

    8.2.7 EXPOSE

    声明容器监听的端口,用于文档化和端口映射。

    EXPOSE <port>[/<protocol>] [<port>[/<protocol>]]…

    EXPOSE 5000
    EXPOSE 80 443
    EXPOSE 11211/udp 11211/tcp

    8.2.8 ENV

    定义环境变量,可被后续指令调用。

    ENV <key> <value>
    ENV <key>=<value> [<key>=<value>…]

    ENV NGINX_VERSION=1.28.1
    ENV FLASK_APP=app.py FLASK_ENV=production

    8.2.9 VOLUME

    声明数据卷挂载点。

    VOLUME <mountpoint>
    VOLUME ["<mountpoint>"]

    VOLUME /app/nginx-1.27.4

    如果挂载点目录路径下此前有文件存在,docker run 命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中。

    8.2.10 ENTRYPOINT

    与 CMD 类似,但不会被 docker run 命令行参数覆盖。命令行参数会作为参数传递给 ENTRYPOINT。

    ENTRYPOINT <command>
    ENTRYPOINT ["<executable>", "<param1>", "<param2>"]

    ENTRYPOINT ["flask", "run", "–host=0.0.0.0"]

    8.2.11 ARG

    构建参数,可在构建时动态配置。

    ARG version="1.0"

    docker build –build-arg version=2.0 -t myapp:2.0 .

    8.2.12 LABEL

    添加元数据。

    LABEL maintainer="1062080730@qq.com"
    LABEL author="jock"

    8.2.13 HEALTHCHECK

    设置健康检查。

    HEALTHCHECK –interval=30s –timeout=3s \\
    CMD curl -f http://localhost:5000/ || exit 1

    8.2.14 USER

    切换用户。

    USER appuser

    8.3 中级概念

    8.3.1 多阶段构建

    通过分离构建和运行时环境来创建精简的生产镜像。

    # 第一阶段:构建
    FROM golang:1.21-alpine AS builder

    WORKDIR /app
    COPY go.mod go.sum ./
    RUN go mod download
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -o app

    # 第二阶段:运行时(更小镜像)
    FROM alpine:3.23
    COPY –from=builder /app/app /usr/local/bin/
    EXPOSE 443
    CMD ["app"]

    优势:

    • 更小的生产环境镜像
    • 将构建工具排除在运行时环境之外,提升安全性
    8.3.2 环境变量使用

    ENV APP_ENV=production
    CMD ["node", "server.js", "–env", "${APP_ENV}"]

    运行时覆盖:

    docker run -e APP_ENV=development myapp

    8.4 高级技巧

    8.4.1 优化镜像大小

    1. 使用更小体积的基础镜像

    FROM python:3.14-alpine
    # 或
    FROM python:3.14-slim

    2. 最小化层数

    # 不推荐(多层)
    RUN apt-get update
    RUN apt-get install -y curl
    RUN apt-get clean

    # 推荐(一层)
    RUN apt-get update && apt-get install -y curl && apt-get clean

    8.4.2 安全最佳实践

    1. 避免使用 root 用户

    RUN adduser –disabled-password appuser
    USER appuser

    2. 使用可信的基础镜像

    FROM nginx:stable

    3. 扫描镜像漏洞

    trivy image myimage

    8.5 调试与故障排除

    # 增量构建特定阶段
    docker build –target builder -t debug-image

    # 检查镜像层
    docker history <image_id>

    # 查看容器日志
    docker logs <container_id>

    # 使用 .dockerignore 过滤不必要文件
    # .dockerignore 内容:
    Dockerfile
    node_modules
    *.log

    8.6 编写最佳实践

  • 固定镜像版本:避免使用 latest 标签
  • 优化分层:合并指令以减少层数
  • 使用 .dockerignore 文件:防止不必要文件被包含
  • 保持镜像轻量:使用 alpine 或 slim 版本
  • 添加元数据:使用 LABEL 添加版本、作者等信息
  • 使用非 root 用户:增强安全性
  • 清理临时文件:减少镜像大小
  • 8.7 常见错误避免

    错误解决方案
    使用大型基础镜像 使用 alpine 或 slim 版本
    未能利用多阶段构建 分离构建和运行环境
    硬编码敏感信息 使用环境变量或密钥管理工具
    安装后未清理 在同一条 RUN 中清理缓存
    未添加注释 添加有意义的注释

    8.8 镜像构建与管理

    # 构建镜像
    docker build -t myapp:1.0 .

    # 指定 Dockerfile
    docker build -f Dockerfile.prod -t myapp:1.0 .

    # 使用构建参数
    docker build –build-arg VERSION=2.0 -t myapp:2.0 .

    # 不缓存构建
    docker build –no-cache -t myapp:1.0 .

    # 多阶段构建指定目标阶段
    docker build –target builder -t myapp:builder .

    # 查看镜像分层
    docker history myapp:1.0


    九、Dockerfile 案例实战

    9.1 基于 CentOS 构建 Nginx 镜像

    1. 创建项目目录

    mkdir demo1 && cd demo1

    2. 编写 Dockerfile

    FROM centos:7 AS builder

    RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak

    RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \\
    curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo

    RUN yum install -y wget make gcc gcc-c++ pcre-devel zlib-devel openssl-devel && yum clean all

    RUN wget https://nginx.org/download/nginx-1.28.1.tar.gz && \\
    tar -zxf nginx-1.28.1.tar.gz && \\
    rm nginx-1.28.1.tar.gz

    WORKDIR /nginx-1.28.1

    ARG version="1.0"

    RUN ./configure –prefix=/usr/local/nginx –with-http_ssl_module && \\
    make && \\
    make install

    RUN mkdir -p /usr/local/nginx/html && \\
    echo "hello jock | welcome to nginx! | version ${version}" > /usr/local/nginx/html/index.html

    FROM centos:7

    LABEL maintainer="1062080730@qq.com"
    LABEL author="jock"

    COPY –from=builder /usr/local/nginx /usr/local/nginx

    RUN echo '#!/bin/bash' > /start.sh && \\
    echo 'hostname > /usr/local/nginx/html/hostname.html' >> /start.sh && \\
    echo '/usr/local/nginx/sbin/nginx -g "daemon off;"' >> /start.sh && \\
    chmod +x /start.sh

    EXPOSE 80 443

    ENTRYPOINT ["/start.sh"]

    3. 构建镜像

    docker build -t myapp:1.0 .

    4. 运行容器并测试

    docker run –rm -d –name myapp -p 80:80 myapp:1.0
    curl localhost
    # hello jock | welcome to nginx! | version 1.0
    curl localhost/hostname.html
    # c245dd948565

    9.2 基于 Debian 构建 Nginx 镜像

    1. 创建项目目录并上传依赖库

    mkdir demo2 && cd demo2
    ls
    # openssl-3.0.16.tar.gz pcre2-10.45.tar.gz zlib-1.3.1.tar.gz

    2. 编写 Dockerfile

    FROM debian:bullseye-slim AS builder

    ENV NGINX_VERSION=1.28.1 \\
    OPENSSL_VERSION=3.0.16 \\
    PCRE_VERSION=10.45 \\
    ZLIB_VERSION=1.3.1

    RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \\
    sed -i 's|security.debian.org|mirrors.aliyun.com/debian-security|g' /etc/apt/sources.list

    RUN apt-get update && \\
    apt-get install -y \\
    build-essential \\
    wget \\
    libpcre3 \\
    libpcre3-dev \\
    zlib1g-dev \\
    libssl-dev \\
    libgd-dev \\
    && rm -rf /var/lib/apt/lists/*

    COPY ./openssl-3.0.16.tar.gz /usr/local/src
    COPY ./pcre2-10.45.tar.gz /usr/local/src
    COPY ./zlib-1.3.1.tar.gz /usr/local/src

    WORKDIR /usr/local/src

    RUN wget https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \\
    tar -xzf nginx-${NGINX_VERSION}.tar.gz && \\
    tar -xzf openssl-${OPENSSL_VERSION}.tar.gz && \\
    tar -xzf pcre2-${PCRE_VERSION}.tar.gz && \\
    tar -xzf zlib-${ZLIB_VERSION}.tar.gz && \\
    rm -f *.tar.gz

    WORKDIR /usr/local/src/nginx-${NGINX_VERSION}

    RUN ./configure –prefix=/usr/local/nginx \\
    –sbin-path=/usr/sbin/nginx \\
    –modules-path=/usr/lib/nginx/modules \\
    –conf-path=/etc/nginx/nginx.conf \\
    –error-log-path=/var/log/nginx/error.log \\
    –http-log-path=/var/log/nginx/access.log \\
    –pid-path=/var/run/nginx.pid \\
    –lock-path=/var/run/nginx.lock \\
    –user=nginx \\
    –group=nginx \\
    –with-http_ssl_module \\
    –with-http_v2_module \\
    –with-http_realip_module \\
    –with-http_gzip_static_module \\
    –with-http_stub_status_module \\
    –with-threads \\
    –with-stream \\
    –with-openssl=../openssl-${OPENSSL_VERSION} \\
    –with-pcre=../pcre2-${PCRE_VERSION} \\
    –with-zlib=../zlib-${ZLIB_VERSION} && \\
    make -j $(nproc) && \\
    make install

    FROM debian:bullseye-slim

    LABEL maintainer="1062080730@qq.com"
    LABEL author="jock"

    RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \\
    sed -i 's|security.debian.org|mirrors.aliyun.com/debian-security|g' /etc/apt/sources.list

    RUN apt-get update && \\
    apt-get install -y \\
    libpcre3 \\
    zlib1g \\
    openssl \\
    && rm -rf /var/lib/apt/lists/*

    RUN groupadd -r nginx && \\
    useradd -r -g nginx -s /sbin/nologin -d /nonexistent -c "nginx user" nginx

    COPY –from=builder /usr/local/nginx /usr/local/nginx
    COPY –from=builder /usr/sbin/nginx /usr/sbin/nginx
    COPY –from=builder /etc/nginx /etc/nginx
    COPY –from=builder /var/log/nginx /var/log/nginx

    RUN mkdir -p /usr/local/nginx/html && \\
    echo "hello jock | welcome to nginx! | version 1.0" > /usr/local/nginx/html/index.html

    RUN echo '#!/bin/bash' > /start.sh && \\
    echo 'hostname > /usr/local/nginx/html/hostname.html' >> /start.sh && \\
    echo '/usr/sbin/nginx -g "daemon off;"' >> /start.sh && \\
    chmod +x /start.sh

    WORKDIR /usr/local/nginx

    EXPOSE 80 443

    ENTRYPOINT ["/start.sh"]

    3. 构建并运行

    docker build -t myapp:2.0 .
    docker run –rm –name myapp -d -p 80:80 myapp:2.0
    curl localhost
    # hello jock | welcome to nginx! | version 1.0

    9.3 基于 Alpine 构建 Nginx 镜像

    FROM alpine:3.23 AS builder

    RUN apk add –no-cache \\
    build-base \\
    pcre-dev \\
    zlib-dev \\
    openssl-dev \\
    linux-headers \\
    wget \\
    tar

    ARG version=1.0
    ENV NGINX_VERSION=1.28.1

    RUN wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \\
    tar -xzf nginx-${NGINX_VERSION}.tar.gz && \\
    rm nginx-${NGINX_VERSION}.tar.gz

    WORKDIR /nginx-${NGINX_VERSION}

    RUN ./configure –prefix=/usr/local/nginx \\
    –sbin-path=/usr/sbin/nginx \\
    –modules-path=/usr/lib/nginx/modules \\
    –conf-path=/etc/nginx/nginx.conf \\
    –error-log-path=/var/log/nginx/error.log \\
    –http-log-path=/var/log/nginx/access.log \\
    –pid-path=/var/run/nginx.pid \\
    –lock-path=/var/run/nginx.lock \\
    –user=nginx \\
    –group=nginx \\
    –with-threads \\
    –with-file-aio && \\
    make && \\
    make install

    FROM alpine:3.23

    COPY –from=builder /usr/local/nginx /usr/local/nginx
    COPY –from=builder /usr/sbin/nginx /usr/sbin/nginx
    COPY –from=builder /etc/nginx /etc/nginx
    COPY –from=builder /var/log/nginx /var/log/nginx

    RUN addgroup -S nginx && \\
    adduser -S -G nginx -s /sbin/nologin -D -H nginx

    RUN mkdir -p /usr/local/nginx/html && \\
    echo "hello jock | welcome to nginx! | version ${version}" > /usr/local/nginx/html/index.html

    RUN echo '#!/bin/sh' > /start.sh && \\
    echo 'hostname > /usr/local/nginx/html/hostname.html' >> /start.sh && \\
    echo '/usr/sbin/nginx -g "daemon off;"' >> /start.sh && \\
    chmod +x /start.sh

    RUN apk add –no-cache pcre zlib openssl && \\
    mkdir -p /var/cache/nginx && \\
    chown -R nginx:nginx /var/cache/nginx && \\
    chown -R nginx:nginx /var/log/nginx && \\
    ln -sf /dev/stdout /var/log/nginx/access.log && \\
    ln -sf /dev/stderr /var/log/nginx/error.log

    WORKDIR /usr/local/nginx

    EXPOSE 80 443

    ENTRYPOINT ["/start.sh"]

    docker build -t myapp:1.0 .
    docker run –rm –name myapp -d -p 80:80 myapp:1.0
    docker images
    # myapp:1.0 20.7MB 6.33MB

    9.4 基于 Alpine 构建错误页面镜像

    1. 创建目录并编写 Dockerfile

    FROM alpine:3.23 AS builder

    RUN apk add –no-cache \\
    build-base \\
    pcre-dev \\
    zlib-dev \\
    openssl-dev \\
    linux-headers \\
    wget \\
    tar

    ENV NGINX_VERSION=1.28.1

    RUN wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \\
    tar -xzf nginx-${NGINX_VERSION}.tar.gz && \\
    rm nginx-${NGINX_VERSION}.tar.gz

    WORKDIR /nginx-${NGINX_VERSION}

    RUN ./configure \\
    –prefix=/usr/local/nginx \\
    –with-http_ssl_module \\
    –with-http_realip_module \\
    –with-http_stub_status_module \\
    –with-threads \\
    –with-file-aio && \\
    make && \\
    make install

    FROM alpine:3.23

    COPY –from=builder /usr/local/nginx /usr/local/nginx
    COPY error.html /usr/local/nginx/html/error.html

    RUN apk add –no-cache pcre zlib openssl && \\
    ln -sf /dev/stdout /usr/local/nginx/logs/access.log && \\
    ln -sf /dev/stderr /usr/local/nginx/logs/error.log

    RUN echo "index.html" > /usr/local/nginx/html/index.html

    RUN echo 'server { error_page 404 /error.html; location = /error.html { root /usr/local/nginx/html; } }' > /usr/local/nginx/conf/default.conf

    EXPOSE 80 443

    ENTRYPOINT ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

    2. 编写 error.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自定义错误页面</title>
    <style>
    body {
    font-family: Arial, sans-serif;
    text-align: center;
    padding: 50px;
    }
    h1 { color: #333; }
    p { color: #666; }
    </style>
    </head>
    <body>
    <h1>哎呀!页面未找到</h1>
    <p>你所请求的页面可能已经被移除或者地址错误。</p>
    </body>
    </html>

    3. 构建并运行

    docker build -t error:1.0 .
    docker run –rm –name error -d -p 8080:80 error:1.0
    curl localhost:8080/error.html

    9.5 构建 HTTPS 服务镜像

    1. 创建目录并编写 main.go

    package main

    import (
    "log"
    "net/http"
    )

    func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, HTTPS!\\n"))
    })
    log.Println("Server running on https://localhost:443")
    err := http.ListenAndServeTLS(":443", "/etc/ssl/certs/server.crt",
    "/etc/ssl/private/server.key", nil)
    if err != nil {
    log.Fatal("ListenAndServeTLS: ", err)
    }
    }

    2. 编写 go.mod

    module github.com/yourusername/go–https–server

    go 1.21

    require (
    golang.org/x/crypto v0.14.0 // indirect
    golang.org/x/net v0.17.0 // indirect
    golang.org/x/sys v0.13.0 // indirect
    )

    3. 编写 Dockerfile

    FROM golang:1.21-alpine AS builder

    RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
    ENV GOPROXY=https://goproxy.cn,direct

    RUN apk add –no-cache git make openssl

    WORKDIR /app

    COPY go.mod go.sum ./
    RUN go mod download

    COPY . .

    RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o app

    RUN openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \\
    -keyout server.key -out server.crt -subj "/CN=localhost" \\
    -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

    FROM alpine:3.23

    RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
    RUN apk add –no-cache ca-certificates tzdata

    RUN addgroup -S appgroup && adduser -S appuser -G appgroup

    COPY –from=builder /app/app /usr/local/bin/app
    COPY –from=builder /app/server.crt /etc/ssl/certs/
    COPY –from=builder /app/server.key /etc/ssl/private/

    RUN chown appuser:appgroup /usr/local/bin/app && \\
    chmod 755 /usr/local/bin/app && \\
    chmod 644 /etc/ssl/certs/server.crt && \\
    chmod 644 /etc/ssl/private/server.key

    WORKDIR /home/appuser
    USER appuser

    EXPOSE 443

    HEALTHCHECK –interval=30s –timeout=3s \\
    CMD wget –no-check-certificate -qO- https://localhost/healthz || exit 1

    ENTRYPOINT ["app", "–cert", "/etc/ssl/certs/server.crt", "–key", "/etc/ssl/private/server.key"]

    4. 构建并运行

    docker build -t https-server:1.0 .
    docker run –rm –name hs -d -p 443:443 https-server:1.0
    curl -k https://localhost
    # Hello, HTTPS!

    9.6 构建 Python 计算镜像(马青公式)

    1. 编写 main.py

    # -*- coding: utf-8 -*-
    from __future__ import division
    import time

    time1 = time.time()
    number = 1000
    number1 = number + 10
    b = 10 ** number1
    x1 = b * 4 // 5
    x2 = b // –239
    he = x1 + x2
    number *= 2

    for i in range(3, number, 2):
    x1 //= –25
    x2 //= –57121
    x = (x1 + x2) // i
    he += x

    pai = he * 4
    pai //= 10 ** 10
    paistring = str(pai)
    result = paistring[0] + '.' + paistring[1:len(paistring)]
    print(result)
    time2 = time.time()
    print('Total time:' + str(time2 – time1) + 's')

    2. 编写 Dockerfile

    FROM python:2.7-slim
    ADD main.py /root
    CMD ["/usr/bin/python", "/root/main.py"]

    3. 构建并运行

    docker build -t maqing:1.0 .
    docker run –name maqing -d maqing:1.0
    docker logs maqing
    # 3.141592653589793238462…
    # Total time:0.000882s


    十、Swarm 集群管理

    10.1 Swarm 核心概念

    Docker Swarm 是 Docker 官方提供的一套容器编排系统。

    核心概念:

    概念说明
    集群(Cluster) 由多个 Docker 主机组成,以集群模式运行
    节点(Node) 集群中的一台机器,可以是 Manager 或 Worker
    Manager 节点 管理成员资格和委派,使用 Raft 协议协同工作
    Worker 节点 运行实际应用服务的容器
    服务(Service) 对运行在集群上的应用服务的期望状态描述
    任务(Task) 部署的最小单元,与容器一一对应
    栈(Stack) 描述一系列相关服务的集合(YAML 文件)

    10.2 Swarm 安装

    # 拉取镜像
    docker pull swarm

    # 查看版本
    docker run –rm swarm:latest -v
    # swarm version 1.2.9 (527a849)

    10.3 Swarm 集群搭建

    10.3.1 主机规划
    主机名IP 地址角色
    manager1 192.168.72.47 管理节点
    worker1 192.168.72.48 工作节点
    worker2 192.168.72.49 工作节点
    10.3.2 环境准备

    所有节点配置 hosts:

    cat >> /etc/hosts <<EOF
    192.168.72.47 manager1
    192.168.72.48 worker1
    192.168.72.49 worker2
    EOF

    10.3.3 初始化集群

    # 在管理节点执行
    docker swarm init –advertise-addr 192.168.72.47

    # 输出示例:
    # Swarm initialized: current node (ny9sbiscw1dax5y92nzzwvhk5) is now a manager.
    # To add a worker to this swarm, run the following command:
    # docker swarm join –token SWMTKN-xxx 192.168.72.47:2377

    # 查看节点
    docker node ls

    10.3.4 加入工作节点

    # 在工作节点执行(使用 init 输出的 token)
    docker swarm join –token SWMTKN-xxx 192.168.72.47:2377

    # 如果忘记 token,在管理节点查看
    docker swarm join-token worker

    # 如果 token 过期,重新生成
    docker swarm join-token –rotate worker

    10.3.5 查看集群状态

    # 查看节点列表
    docker node ls

    # 查看节点详细信息
    docker node inspect self

    # 查看集群状态
    docker info | grep Swarm

    10.4 服务管理

    10.4.1 创建服务

    # 创建服务
    docker service create –replicas 3 –name nginx -p 80:80 nginx:1.28.1

    # 查看服务列表
    docker service ls

    # 查看服务任务
    docker service ps nginx

    # 查看服务详情
    docker service inspect –pretty nginx

    10.4.2 扩展服务

    # 扩展到 5 个副本
    docker service scale nginx=5

    10.4.3 删除服务

    docker service rm nginx

    10.5 滚动更新与回滚

    10.5.1 发布服务

    # 创建 Redis 服务
    docker service create –replicas 3 –name redis –update-delay 10s redis:8.2

    10.5.2 滚动更新

    # 更新到 8.4 版本
    docker service update –image redis:8.4 redis

    # 查看更新状态
    docker service ps redis

    10.5.3 回滚

    # 回滚到上一个版本
    docker service update –rollback redis

    10.6 节点管理(污染与激活)

    10.6.1 污染节点(Drain)

    # 将节点设置为 Drain 状态(维护模式)
    docker node update –availability drain worker1

    # 查看节点状态
    docker node ls
    # worker1 的 AVAILABILITY 变为 Drain

    # 查看任务迁移
    docker service ps redis
    # 任务已从 worker1 迁移到其他节点

    10.6.2 激活节点

    # 恢复到 Active 状态
    docker node update –availability active worker1

    注意:drain 状态只会影响 Swarm 服务工作负载,不会影响独立容器。

    10.6.3 节点管理命令
    命令说明
    docker node demote 降级管理节点为工作节点
    docker node inspect 查看节点详细信息
    docker node ls 列出所有节点
    docker node promote 升级工作节点为管理节点
    docker node ps 查看节点上的任务
    docker node rm 删除节点
    docker node update 更新节点

    10.7 路由网格

    10.7.1 发布服务端口

    docker service create –name my-web \\
    –publish published=8080,target=80 \\
    –replicas 2 \\
    nginx:1.28.1

    10.7.2 TCP 和 UDP 端口

    # 仅 TCP
    docker service create –name dns-cache -p 53:53 dns-cache

    # TCP 和 UDP
    docker service create –name dns-cache \\
    –publish published=53,target=53 \\
    –publish published=53,target=53,protocol=udp \\
    dns-cache

    # 仅 UDP
    docker service create –name dns-cache \\
    –publish published=53,target=53,protocol=udp \\
    dns-cache

    10.7.3 绕过路由网格(Host 模式)

    docker service create –name dns-cache \\
    –publish published=53,target=53,protocol=udp,mode=host \\
    –mode global \\
    dns-cache


    十一、Docker Compose 编排

    11.1 Compose 概念

    Docker Compose 定位是定义和运行多个 Docker 容器的应用。它将所管理的容器分为三层:

    层级说明
    项目(Project) 由一组关联的应用容器组成的一个完整业务单元
    服务(Service) 一个应用的容器,可包括若干运行相同镜像的容器实例
    容器(Container) Docker 容器

    11.2 Compose 安装

    # 下载 Docker Compose
    curl -L https://github.com/docker/compose/releases/download/v5.0.2/docker-compose-$(uname -s)–$(uname -m) -o /usr/bin/docker-compose

    # 或者使用 wget
    wget https://github.com/docker/compose/releases/download/v5.0.2/docker-compose-linux-x86_64
    mv docker-compose-linux-x86_64 /usr/bin/docker-compose

    # 添加执行权限
    chmod +x /usr/bin/docker-compose

    # 验证
    docker-compose –version

    11.3 docker-compose.yml 详解

    11.3.1 基本示例

    services:
    nginx:
    image: nginx:1.28.1
    restart: always
    container_name: nginx
    environment:
    – TZ=Asia/Shanghai
    ports:
    – "80:80"
    – "443:443"
    volumes:
    – /opt/nginx/log:/var/log/nginx
    – /opt/nginx/www:/usr/share/nginx/html
    depends_on:
    – mysql
    – redis

    mysql:
    image: mysql:8.4.4
    container_name: mysql
    ports:
    – "3306:3306"
    command:
    ––character–set–server=utf8mb4
    ––collation–server=utf8mb4_general_ci
    environment:
    MYSQL_ROOT_PASSWORD: "123456"
    volumes:
    – /opt/mysql/db:/var/lib/mysql

    redis:
    image: redis:8.4
    container_name: redis
    environment:
    – TZ=Asia/Shanghai
    ports:
    – "6379:6379"
    volumes:
    – /opt/redis/data:/data
    depends_on:
    – mysql

    11.3.2 常见指令
    指令说明
    services 定义服务
    image 指定服务的镜像名称或 ID
    ports 端口映射 HOST:CONTAINER
    build 指定 Dockerfile 路径,自动构建镜像
    command 覆盖容器启动后默认执行的命令
    depends_on 确定容器的启动顺序
    environment 设置环境变量
    volumes 挂载数据卷
    network_mode 网络模式
    networks 定义网络

    11.4 常用命令

    命令说明
    docker-compose up -d 启动所有服务(后台运行)
    docker-compose down 停止并删除所有容器
    docker-compose down -v 同时删除数据卷
    docker-compose ps 查看运行状态
    docker-compose logs 查看日志
    docker-compose stop 停止服务
    docker-compose start 启动服务
    docker-compose restart 重启服务
    docker-compose exec 服务名 bash 进入容器
    docker-compose build 重新构建镜像
    docker-compose pull 拉取最新镜像
    docker-compose scale 服务名=3 扩展服务副本
    docker-compose ls 查看运行的项目
    docker-compose events 查看容器事件
    docker-compose pause 暂停服务
    docker-compose unpause 恢复暂停的服务
    docker-compose port 服务名 端口 显示暴露的端口
    docker-compose run 服务名 命令 运行一次性命令

    11.5 使用案例:Flask + Redis

    11.5.1 编写应用程序

    app.py:

    import time
    import redis
    from flask import Flask

    app = Flask(__name__)
    cache = redis.Redis(host='redis', port=6379)

    def get_hit_count():
    retries = 5
    while True:
    try:
    return cache.incr('hits')
    except redis.exceptions.ConnectionError as exc:
    if retries == 0:
    raise exc
    retries -= 1
    time.sleep(0.5)

    @app.route('/')
    def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\\n'.format(count)

    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

    requirements.txt:

    Flask==3.1.2
    redis==7.1.0

    Dockerfile:

    FROM python:3.14-alpine

    WORKDIR /code
    COPY . .

    RUN pip install –no-cache-dir -r requirements.txt

    EXPOSE 5000
    CMD ["python", "app.py"]

    docker-compose.yml:

    services:
    web:
    build: .
    ports:
    – "5000:5000"
    depends_on:
    – redis
    volumes:
    – .:/code # 动态修改代码无需重建
    redis:
    image: redis:alpine

    11.5.2 运行与测试

    docker-compose up -d
    docker-compose ps

    curl localhost:5000
    # Hello World! I have been seen 1 times.
    curl localhost:5000
    # Hello World! I have been seen 2 times.

    # 修改代码后无需重建
    vim app.py
    # 访问立即生效

    11.6 与 Swarm 集成

    services:
    nginx:
    image: nginx:1.28.1
    environment:
    – TZ=Asia/Shanghai
    ports:
    – "80:80"
    – "443:443"
    volumes:
    – /docker/nginx/log:/var/log/nginx
    – /docker/nginx/www:/etc/nginx/html
    deploy:
    mode: replicated
    replicas: 2

    mysql:
    image: mysql:8.4.4
    ports:
    – "3306:3306"
    command:
    ––character–set–server=utf8mb4
    ––collation–server=utf8mb4_general_ci
    environment:
    MYSQL_ROOT_PASSWORD: "123456"
    volumes:
    – "/docker/mysql/db:/var/lib/mysql"
    deploy:
    mode: replicated
    replicas: 2

    # 部署 Stack
    docker stack deploy -c docker-compose.yml web

    # 查看服务
    docker stack services web

    # 删除 Stack
    docker stack rm web


    十二、Harbor 私有仓库

    12.1 Harbor 概述

    Harbor(港湾)是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器。由 VMware 在 Docker Registry 的基础之上进行了二次封装。

    主要组件:

    • proxy:nginx 前端代理,分发前端页面 UI 访问和镜像上传下载流量
    • ui:Web 管理页面,包含前端页面和后端 API,使用 MySQL 数据库
    • registry:镜像仓库,存储镜像文件
    • adminserver:系统配置管理中心
    • jobservice:镜像复制工作
    • log:日志汇总组件

    12.2 环境准备

    # 修改主机名
    hostnamectl hostname harbor

    # 修改 IP(仅主机模式网络)
    nmcli c m ens160 ipv4.method manual ipv4.address 192.168.10.20/24 \\
    ipv4.gateway 192.168.10.200 ipv4.dns "223.5.5.5 8.8.8.8" \\
    connection.autoconnect yes
    nmcli c up ens160

    # 开启路由转发
    echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
    sysctl -p

    # 配置主机映射
    cat > /etc/hosts <<EOF
    192.168.10.20 hb.reg.com harbor
    EOF

    12.3 安装 Docker 与 Compose

    # 添加 Docker 源
    dnf install yum-utils -y
    yum-config-manager –add-repo https://mirrors.aliyun.com/docker-ce/linux/rhel/docker-ce.repo

    # 安装 Docker
    dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

    # 配置 Docker
    cat > /etc/docker/daemon.json <<EOF
    {
    "default-ipc-mode": "shareable",
    "data-root": "/data/docker",
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "100m",
    "max-file": "50"
    },
    "insecure-registries": ["https://hb.reg.com"],
    "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.imgdb.de",
    "https://docker-0.unsee.tech",
    "https://docker.hlmirror.com",
    "https://func.ink"
    ]
    }
    EOF

    # 启动 Docker
    systemctl enable –now docker

    # 安装 Docker Compose
    wget https://github.com/docker/compose/releases/download/v2.35.1/docker-compose-linux-x86_64
    mv docker-compose-linux-x86_64 /usr/bin/docker-compose
    chmod +x /usr/bin/docker-compose

    12.4 Harbor 安装部署

    # 创建数据目录
    mkdir -p /data

    # 下载 Harbor
    cd /data
    wget https://github.com/goharbor/harbor/releases/download/v2.13.2/harbor-offline-installer-v2.13.2.tgz

    # 解压
    tar -xzf harbor-offline-installer-v2.13.2.tgz
    cd harbor

    # 复制配置文件
    cp harbor.yml.tmp1 harbor.yml

    # 修改配置文件
    vim harbor.yml
    # hostname: hb.reg.com
    # https:
    # port: 443
    # certificate: /data/cert/hb.reg.com.crt
    # private_key: /data/cert/hb.reg.com.key

    12.5 证书配置

    生成 CA 证书:

    mkdir ssl && cd ssl

    # 生成 CA 私钥
    openssl genrsa -out ca.key 4096

    # 生成 CA 证书
    openssl req -x509 -new -nodes -sha512 -days 3650 \\
    -subj "/C=CN/ST=Chongqing/L=Banan/O=Example/OU=Personal/CN=MyPersonal Root CA" \\
    -key ca.key -out ca.crt

    生成服务器证书:

    # 生成私钥
    openssl genrsa -out hb.reg.com.key 4096

    # 生成证书签名请求
    openssl req -sha512 -new \\
    -subj "/C=CN/ST=Chongqing/L=Banan/O=Example/OU=Personal/CN=hb.reg.com" \\
    -key hb.reg.com.key -out hb.reg.com.csr

    # 创建 v3 扩展文件
    cat > v3.ext <<EOF
    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
    extendedKeyUsage=serverAuth
    subjectAltName=alt_names
    [alt_names]
    DNS.1=hb.reg.com
    DNS.2=hb.reg
    DNS.3=hb
    EOF

    # 生成证书
    openssl x509 -req -sha512 -days 3650 -extfile v3.ext \\
    -CA ca.crt -CAkey ca.key -CAcreateserial \\
    -in hb.reg.com.csr -out hb.reg.com.crt

    # 复制证书到 Harbor 目录
    mkdir /data/cert
    cp hb.reg.com.crt /data/cert/
    cp hb.reg.com.key /data/cert/

    # 转换证书供 Docker 使用
    openssl x509 -inform PEM -in hb.reg.com.crt -out hb.reg.com.cert

    # 复制到 Docker 证书目录
    mkdir -p /etc/docker/certs.d/hb.reg.com:443
    cp hb.reg.com.cert /etc/docker/certs.d/hb.reg.com:443/
    cp hb.reg.com.key /etc/docker/certs.d/hb.reg.com:443/
    cp ca.crt /etc/docker/certs.d/hb.reg.com:443/

    # 重启 Docker
    systemctl restart docker

    12.6 启动与配置服务

    cd /data/harbor

    # 加载镜像并安装
    docker load -i harbor.v2.13.2.tar.gz
    ./install.sh

    # 查看容器
    docker-compose ps

    # 配置系统服务
    cat > /usr/lib/systemd/system/harbor.service <<EOF
    [Unit]
    Description=Harbor
    After=docker.service network-online.target
    Requires=docker.service

    [Service]
    Type=simple
    Restart=on-failure
    RestartSec=5
    ExecStart=/usr/bin/docker-compose –file /data/harbor/docker-compose.yml up
    ExecStop=/usr/bin/docker-compose –file /data/harbor/docker-compose.yml down

    [Install]
    WantedBy=multi-user.target
    EOF

    systemctl daemon-reload
    systemctl enable –now harbor

    12.7 测试本地仓库

    # 拉取镜像
    docker pull nginx:1.28.0
    docker pull mysql:8.4.4

    # 打标签
    docker tag nginx:1.28.0 hb.reg.com/library/nginx:1.28.0
    docker tag mysql:8.4.4 hb.reg.com/library/mysql:8.4.4

    # 登录 Harbor
    docker login hb.reg.com
    # 用户名: admin
    # 密码: Harbor12345

    # 推送镜像
    docker push hb.reg.com/library/nginx:1.28.0
    docker push hb.reg.com/library/mysql:8.4.4

    # 从 Harbor 拉取镜像
    docker rmi hb.reg.com/library/nginx:1.28.0
    docker pull hb.reg.com/library/nginx:1.28.0

    # API 查询
    curl -k -u 'admin:Harbor12345' 'https://hb.reg.com/api/v2.0/projects/library/repositories'


    十三、案例实战:中间件容器化

    13.1 MySQL 安装

    13.1.1 拉取镜像

    docker pull mysql:8.4.8

    13.1.2 创建挂载目录

    mkdir -p /opt/mysql/{conf,data,logs}

    13.1.3 创建配置文件

    # 创建临时容器获取配置文件
    docker run –name mysql_temp -d –rm -e MYSQL_ROOT_PASSWORD=12345 mysql:8.4.8
    docker cp mysql_temp:/etc/my.cnf /opt/mysql/conf/
    docker cp mysql_temp:/etc/mysql/conf.d /opt/mysql/conf/
    docker stop mysql_temp

    13.1.4 安装 MySQL

    docker run –name mysql -d \\
    -e MYSQL_ROOT_PASSWORD=123456 \\
    -v /opt/mysql/conf/my.cnf:/etc/my.cnf \\
    -v /opt/mysql/conf/conf.d:/etc/mysql/conf.d \\
    -v /opt/mysql/data:/var/lib/mysql \\
    -v /opt/mysql/logs:/var/log/mysql \\
    -p 3306:3306 \\
    –privileged=true \\
    mysql:8.4.8 \\
    –character-set-server=utf8mb4 \\
    –collation-server=utf8mb4_unicode_ci

    13.2 Redis 安装

    # 拉取镜像
    docker pull redis:8.4

    # 创建目录和配置
    mkdir -p /opt/redis/{data,conf}
    cat > /opt/redis/conf/redis.conf <<EOF
    appendonly yes
    requirepass redis123
    EOF

    # 启动容器
    docker run –name redis -d \\
    -p 6379:6379 \\
    -v /opt/redis/data:/data \\
    -v /opt/redis/conf/redis.conf:/etc/redis/redis.conf \\
    redis:8.4 redis-server /etc/redis/redis.conf

    13.3 Elasticsearch 安装

    # 拉取镜像
    docker pull elasticsearch:8.19.5

    # 修改内核参数
    echo "vm.max_map_count=262144" >> /etc/sysctl.conf
    sysctl -p

    # 创建网络
    docker network create es-net

    # 启动容器
    docker run –name es -d \\
    –restart=always \\
    –network es-net \\
    -p 9200:9200 \\
    -p 9300:9300 \\
    –privileged=true \\
    -e discovery.type=single-node \\
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \\
    elasticsearch:8.19.5

    # 修改配置(关闭安全认证)
    docker cp -a es:/usr/share/elasticsearch/config/elasticsearch.yml .
    vim elasticsearch.yml
    # xpack.security.enabled: false
    # xpack.security.enrollment.enabled: false
    # xpack.security.http.ssl.enabled: false
    # xpack.security.transport.ssl.enabled: false
    docker cp -a ./elasticsearch.yml es:/usr/share/elasticsearch/config/
    docker restart es

    # 访问验证
    curl http://localhost:9200

    13.4 Kibana 安装

    # 拉取镜像(版本必须与 ES 一致)
    docker pull kibana:8.19.5

    # 启动容器
    docker run –name kibana \\
    –network es-net \\
    -d -p 5601:5601 \\
    -e ELASTICSEARCH_HOSTS=http://es:9200 \\
    kibana:8.19.5

    # 浏览器访问 http://IP:5601

    13.5 MySQL 主从复制

    13.5.1 主从复制原理
  • 主库更新事件写入二进制日志(binlog)
  • 主库开启 binlog dump 线程,将日志事件发送给从库
  • 从库 IO 线程接收 binlog,写入中继日志(relay log)
  • 从库 SQL 线程读取并执行 relay log 中的 SQL 语句
  • 13.5.2 配置主服务器

    # 创建配置
    mkdir -p /data/master/conf
    cat > /data/master/conf/my.cnf <<EOF
    [mysqld]
    server-id=1
    read-only=0
    datadir=/var/lib/mysql
    socket=/var/run/mysqld/mysqld.sock
    [client]
    socket=/var/run/mysqld/mysqld.sock
    EOF

    # 启动主服务器
    docker run -d –name mysql-master \\
    -e MYSQL_ROOT_PASSWORD=123456 \\
    -v /data/master/conf/my.cnf:/etc/my.cnf \\
    -p 3306:3306 \\
    mysql:9.3.0 \\
    –character-set-server=utf8mb4 \\
    –collation-server=utf8mb4_unicode_ci

    # 创建复制用户
    docker exec -it mysql-master mysql -uroot -p123456
    mysql> CREATE USER 'backups'@'%' IDENTIFIED BY '123456';
    mysql> GRANT REPLICATION SLAVE ON *.* TO 'backups'@'%';
    mysql> FLUSH PRIVILEGES;
    mysql> SHOW BINARY LOG STATUS;
    # 记录 File 和 Position

    13.5.3 配置从服务器

    # 创建配置
    mkdir -p /data/slave/conf
    cat > /data/slave/conf/my.cnf <<EOF
    [mysqld]
    server-id=2
    read-only=1
    datadir=/var/lib/mysql
    socket=/var/run/mysqld/mysqld.sock
    [client]
    socket=/var/run/mysqld/mysqld.sock
    EOF

    # 启动从服务器
    docker run -d –name mysql-slave \\
    -e MYSQL_ROOT_PASSWORD=123456 \\
    -v /data/slave/conf/my.cnf:/etc/my.cnf \\
    -p 3307:3306 \\
    mysql:9.3.0 \\
    –character-set-server=utf8mb4 \\
    –collation-server=utf8mb4_unicode_ci

    # 配置同步
    docker exec -it mysql-slave mysql -uroot -p123456
    mysql> CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='主服务器IP',
    SOURCE_USER='backups',
    SOURCE_PASSWORD='123456',
    SOURCE_LOG_FILE='binlog.000003',
    SOURCE_LOG_POS=864,
    GET_SOURCE_PUBLIC_KEY=1;
    mysql> START REPLICA;
    mysql> SHOW REPLICA STATUS\\G;
    # 确认 Slave_IO_Running: Yes, Slave_SQL_Running: Yes

    13.5.4 验证

    # 在主库创建数据
    mysql> CREATE DATABASE mydb;
    mysql> USE mydb;
    mysql> CREATE TABLE t1(id INT, name VARCHAR(20));
    mysql> INSERT INTO t1 VALUES(1, 'zhangsan');

    # 在从库查询
    mysql> SHOW DATABASES;
    mysql> SELECT * FROM mydb.t1;

    13.6 MySQL 双主双从

    13.6.1 创建网络

    docker network create mysql-replica-net

    13.6.2 配置文件

    # master1.cnf
    [mysqld]
    server-id=1
    log_bin=mysql-bin
    auto_increment_increment=2
    auto_increment_offset=1

    # master2.cnf
    [mysqld]
    server-id=2
    log_bin=mysql-bin
    auto_increment_increment=2
    auto_increment_offset=2

    # slave1.cnf
    [mysqld]
    server-id=3
    log_bin=mysql-bin
    relay_log=mysql-relay-bin
    read_only=1

    # slave2.cnf
    [mysqld]
    server-id=4
    log_bin=mysql-bin
    relay_log=mysql-relay-bin
    read_only=1

    13.6.3 创建容器

    # Master1
    docker run -d –name master1 \\
    –network mysql-replica-net \\
    -e MYSQL_ROOT_PASSWORD=123456 \\
    -v /data/master1.cnf:/etc/my.cnf \\
    -p 3306:3306 \\
    mysql:9.3.0 \\
    –character-set-server=utf8mb4 \\
    –collation-server=utf8mb4_unicode_ci

    # Master2
    docker run -d –name master2 \\
    –network mysql-replica-net \\
    -e MYSQL_ROOT_PASSWORD=123456 \\
    -v /data/master2.cnf:/etc/my.cnf \\
    -p 3307:3306 \\
    mysql:9.3.0 \\
    –character-set-server=utf8mb4 \\
    –collation-server=utf8mb4_unicode_ci

    13.6.4 配置复制

    # 在 master1 和 master2 分别创建复制用户
    CREATE USER 'backups'@'%' IDENTIFIED BY '123456';
    GRANT REPLICATION SLAVE ON *.* TO 'backups'@'%';
    FLUSH PRIVILEGES;
    SHOW BINARY LOG STATUS;

    # Master1 复制 Master2
    CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='master2',
    SOURCE_USER='backups',
    SOURCE_PASSWORD='123456',
    SOURCE_LOG_FILE='binlog.000003',
    SOURCE_LOG_POS=864,
    GET_SOURCE_PUBLIC_KEY=1;
    START REPLICA;

    # Master2 复制 Master1
    CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='master1',
    SOURCE_USER='backups',
    SOURCE_PASSWORD='123456',
    SOURCE_LOG_FILE='binlog.000003',
    SOURCE_LOG_POS=864,
    GET_SOURCE_PUBLIC_KEY=1;
    START REPLICA;

    13.7 Nginx 高可用(Keepalived)

    13.7.1 主机规划
    主机名IP 地址角色
    kp-master 192.168.72.135 Nginx + Keepalived MASTER
    kp-slave 192.168.72.136 Nginx + Keepalived BACKUP
    VIP 192.168.72.100 虚拟 IP
    13.7.2 部署 Nginx

    # 创建配置目录
    mkdir -p /opt/nginxdir

    # 创建 Nginx 配置
    cat > /opt/nginxdir/default.conf <<EOF
    server {
    listen 80;
    server_name localhost;
    location / {
    root /usr/share/nginx/html;
    index index.html;
    }
    }
    EOF

    # 创建首页
    echo "Nginx on $(hostname)" > /opt/nginxdir/index.html

    # 运行 Nginx 容器
    docker run -d –name my-nginx -p 80:80 \\
    -v /opt/nginxdir/default.conf:/etc/nginx/conf.d/default.conf \\
    -v /opt/nginxdir/index.html:/usr/share/nginx/html/index.html \\
    nginx:1.28.1

    13.7.3 部署 Keepalived(主节点)

    # 创建配置文件
    mkdir -p /opt/keepalived/conf
    cat > /opt/keepalived/conf/keepalived.conf <<EOF
    global_defs {
    router_id nginx1
    }

    vrrp_script check_nginx {
    script "/check_nginx.sh"
    interval 2
    weight -20
    }

    vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
    auth_type PASS
    auth_pass 1111
    }

    virtual_ipaddress {
    192.168.72.100
    }

    track_script {
    check_nginx
    }
    }
    EOF

    # 创建检查脚本
    cat > /opt/keepalived/check_nginx.sh <<'EOF'
    #!/bin/bash
    count=$(ps -C nginx –no-header | wc -l)
    if [ $count -eq 0 ]; then
    docker start my-nginx 2>/dev/null || docker run -d –name my-nginx -p 80:80 \\
    -v /opt/nginxdir/default.conf:/etc/nginx/conf.d/default.conf \\
    -v /opt/nginxdir/index.html:/usr/share/nginx/html/index.html \\
    nginx:1.28.1
    sleep 2
    if [ $(ps -C nginx –no-header | wc -l) -eq 0 ]; then
    systemctl stop keepalived
    fi
    fi
    EOF

    chmod +x /opt/keepalived/check_nginx.sh

    # 运行 Keepalived 容器
    docker run –cap-add=NET_ADMIN –cap-add=NET_BROADCAST –cap-add=NET_RAW \\
    –net=host -d –name kp-master \\
    -v /opt/keepalived/conf/keepalived.conf:/container/service/keepalived/assets/keepalived.conf \\
    -v /opt/keepalived/check_nginx.sh:/check_nginx.sh \\
    -v /etc/localtime:/etc/localtime \\
    osixia/keepalived:2.0.20

    13.7.4 部署 Keepalived(备节点)

    # 配置类似,修改 state 为 BACKUP,priority 为 90
    docker run –cap-add=NET_ADMIN –cap-add=NET_BROADCAST –cap-add=NET_RAW \\
    –net=host -d –name kp-backup \\
    -v /opt/keepalived/conf/keepalived.conf:/container/service/keepalived/assets/keepalived.conf \\
    -v /opt/keepalived/check_nginx.sh:/check_nginx.sh \\
    -v /etc/localtime:/etc/localtime \\
    osixia/keepalived:2.0.20


    附录:常用命令速查表

    Docker 基础命令

    分类命令说明
    系统 docker info 查看 Docker 系统信息
    系统 docker version 查看 Docker 版本
    镜像 docker images 列出本地镜像
    镜像 docker pull 拉取镜像
    镜像 docker push 推送镜像
    镜像 docker build 构建镜像
    镜像 docker rmi 删除镜像
    镜像 docker save 导出镜像
    镜像 docker load 导入镜像
    镜像 docker tag 添加镜像标签
    镜像 docker inspect 查看镜像详情
    镜像 docker history 查看镜像历史
    容器 docker ps [-a] 列出容器
    容器 docker run 创建并启动容器
    容器 docker create 创建容器
    容器 docker start/stop/restart 启动/停止/重启容器
    容器 docker exec 在容器中执行命令
    容器 docker logs 查看容器日志
    容器 docker rm 删除容器
    容器 docker cp 复制文件
    容器 docker commit 通过容器创建镜像
    容器 docker rename 重命名容器
    容器 docker port 查看端口映射
    容器 docker export/import 导出/导入容器

    网络命令

    命令说明
    docker network ls 列出所有网络
    docker network create 创建网络
    docker network inspect 查看网络详情
    docker network rm 删除网络
    docker network connect 连接容器到网络
    docker network disconnect 断开容器网络

    数据卷命令

    命令说明
    docker volume ls 列出数据卷
    docker volume create 创建数据卷
    docker volume inspect 查看数据卷详情
    docker volume rm 删除数据卷
    docker volume prune 清理未使用的数据卷

    Swarm 命令

    命令说明
    docker swarm init 初始化集群
    docker swarm join 加入集群
    docker node ls 列出节点
    docker service create 创建服务
    docker service ls 列出服务
    docker service scale 扩展服务
    docker service update 更新服务
    docker stack deploy 部署 Stack

    Compose 命令

    命令说明
    docker-compose up -d 启动服务(后台)
    docker-compose down 停止并删除
    docker-compose ps 查看状态
    docker-compose logs 查看日志
    docker-compose exec 进入容器
    docker-compose build 构建镜像
    docker-compose stop/start 停止/启动服务
    docker-compose pause/unpause 暂停/恢复服务
    docker-compose ls 查看运行项目
    docker-compose port 显示暴露端口
    docker-compose events 查看容器事件

    持续更新中… 本笔记将随着 Docker 技术的发展不断完善。如有错误或建议,欢迎指正。

    赞(0)
    未经允许不得转载:171主机测评 » Docker容器从入门到精通
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址