一、docker compose Kafka 单机docker-compose.yml： version: "3.8" services: kafka: image: bitnami/kafka:4.0.0 container_name: kafka ports: - "9092:9092" environment: - KAFKA_ENABLE_KRAFT=yes - KAFKA_KRAFT_CLUSTER_ID=4L6g3nShT-eMCtK--X86sw - KAFKA_CFG_NODE_ID=1 - KAFKA_CFG_PROCESS_ROLES=broker,controller - KAFKA_CFG_LISTENERS=PLAINTEXT://0.0.0.0:9092,CONTROLLER://:9093 - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.10.200:9092 - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@kafka:9093 - KAFKA_CFG_LOG_DIRS=/bitnami/kafka/data volumes: - kafka-data:/bitnami/kafka volumes: kafka-data: 启动： docker compose up -d docker compose logs -f kafka version: "3.8": 使用 Compose 文件规范 3.8 版本。 services: 定义要运行的服务集合。 kafka: 服务名（同时也是默认的内部 DNS 名称）。 image: bitnami/kafka:4.0.0: 使用 Bitnami 的 Kafka 4.0.0 镜像（KRaft 模式支持）。 container_name: kafka: 指定容器名为 kafka（便于管理）。 ports: "9092:9092": 将宿主机 9092 暴露到容器 9092（客户端用 9092 连接 Kafka）。未暴露 9093，因为控制面只在容器网络内通信。 environment: Kafka 配置（通过环境变量注入） KAFKA_ENABLE_KRAFT=yes: 启用 KRaft 模式（不使用 Zookeeper）。 KAFKA_KRAFT_CLUSTER_ID=...: KRaft 集群 ID，需固定不变（初始化生成一次即可复用）。 KAFKA_CFG_NODE_ID=1: 当前节点 ID（单节点可为 1）。 KAFKA_CFG_PROCESS_ROLES=broker,controller: 同一进程同时扮演 broker 与 controller。 KAFKA_CFG_LISTENERS=PLAINTEXT://0.0.0.0:9092,CONTROLLER://:9093: 定义监听端口 PLAINTEXT://0.0.0.0:9092：客户端监听在所有网卡 9092。 CONTROLLER://:9093：控制面监听在 9093（对容器网络可见）。 KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.10.200:9092: 对客户端“宣告”的地址，客户端拿到元数据后按此地址回连；需填宿主机可达的 IP/域名与端口。 KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT: 将自定义监听名映射到安全协议（此处均为明文，无 TLS/SASL）。 KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER: 控制面使用名为 CONTROLLER 的监听器。 KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@kafka:9093: KRaft 控制器投票者列表（节点 ID@地址）；单节点为 1@kafka:9093，其中 kafka 为 Compose 内部主机名。 KAFKA_CFG_LOG_DIRS=/bitnami/kafka/data: Kafka 数据目录（分区/段文件等）在容器内的路径。 volumes: kafka-data:/bitnami/kafka: 将命名卷 kafka-data 挂载到容器路径 /bitnami/kafka，持久化数据与配置。 volumes: kafka-data: 定义命名卷 kafka-data（使用默认本地驱动）。 补充要点： 外部客户端应使用 bootstrap.servers=192.168.10.200:9092。 确认宿主机防火墙放行 TCP 9092；若 IP/域名变更，记得同步更新 KAFKA_CFG_ADVERTISED_LISTENERS。 二、docker run（Kafka 单容器） docker run -d --name kafka \ -p 9092:9092 \ -e KAFKA_ENABLE_KRAFT=yes \ -e KAFKA_KRAFT_CLUSTER_ID=4L6g3nShT-eMCtK--X86sw \ -e KAFKA_CFG_NODE_ID=1 \ -e KAFKA_CFG_PROCESS_ROLES=broker,controller \ -e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \ -e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ -e KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER \ -e KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@127.0.0.1:9093 \ -e KAFKA_CFG_LOG_DIRS=/bitnami/kafka/data \ -v kafka-data:/bitnami/kafka \ bitnami/kafka:4.0.0 创建主题： docker exec -it kafka /opt/bitnami/kafka/bin/kafka-topics.sh \ --create --topic test --bootstrap-server localhost:9092 \ --replication-factor 1 --partitions 1 生产者： docker exec -it kafka /opt/bitnami/kafka/bin/kafka-console-producer.sh \ --bootstrap-server localhost:9092 --topic test 消费者： docker exec -it kafka /opt/bitnami/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server localhost:9092 --topic test --from-beginning 列出主题： docker exec -it kafka /opt/bitnami/kafka/bin/kafka-topics.sh \ --bootstrap-server localhost:9092 --list
一、简介 Docker Machine 是Docker官方编排项目之一，使用go语言编写的，使用不同引擎在多种平台上快速的安装Docker环境。 Docker Machine 是一个工具，它允许你在虚拟宿主机上安装Docker，并使用docker-machine命令管理这个宿主机，可以使用Docker Machine在本地的MAC或者windows box、公司网络，数据中心或者AWS这样的云提供商上创建docker。 使用docker-machine命令，可以启动、审查、停止、重启托管的docker 也可以升级Docker客户端和守护程序并配置docker客户端和宿主机通信。 Docker Machine 也可以集中管理所以得docker主机。 二、为什么要使用 Docker Machine Docker Machine 使你能够在各种 Linux 上配置多个远程 Docker 宿主机。 此外，Machine 允许你在较早的 Mac 或 Windows 系统上运行 Docker，如上一主题所述。 Docker Engine Linux 系统上原生地运行。如果你有一个 Linux 作为你的主系统，并且想要运行 docker 命令，所有你需要做的就是下载并安装 Docker Engine 。然而，如果你想要在网络上、云中甚至本地配置多个 Docker 宿主机有一个有效的方式，你需要 Docker Machine。 无论你的主系统是 Mac、Windows 还是 Linux，你都可以在其上安装 Docker Machine，并使用 docker-machine 命令来配置和管理大量的 Docker 宿主机。它会自动创建宿主机、在其上安装 Docker Engine 、然后配置 docker 客户端。每个被管理的宿主机（“machine”）是 Docker 宿主机和配置好的客户端的结合 三、Docker和Docker Machine之间的区别 当人们说“Docker”时，他们通常是指 Docker Engine，它是一个客户端 - 服务器应用程序，由 Docker 守护进程、一个REST API指定与守护进程交互的接口、和一个命令行接口（CLI）与守护进程通信（通过封装REST API）。Docker Engine 从 CLI 中接受docker 命令，例如 docker run 、docker ps 来列出正在运行的容器、docker images 来列出镜像，等等。 Docker Machine 是一个用于配置和管理你的宿主机（上面具有 Docker Engine 的主机）的工具。通常，你在你的本地系统上安装 Docker Machine。Docker Machine有自己的命令行客户端 docker-machine 和 Docker Engine 客户端 docker。你可以使用 Machine 在一个或多个虚拟系统上安装 Docker Engine。 这些虚拟系统可以是本地的（就像你在 Mac 或 Windows 上使用 Machine 在 VirtualBox 中安装和运行 Docker Engine 一样）或远程的（就像你使用 Machine 在云提供商上 provision Dockerized 宿主机一样）。Dockerized 宿主机本身可以认为是，且有时就称为，被管理的“machines”。 四、安装 Docker Mechine 可以在多种平台上安装使用，包括Linux 、MacOS已经windows Docker Mechine 安装非常的简单：GitHub 地址:Releases。 安装 Docker Mechine： curl -L https://github.com/docker/machine/releases/download/v0.15.0/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine && chmod +x /tmp/docker-machine && sudo cp /tmp/docker-machine /usr/local/bin/docker-machine 查看版本确认是否安装成功： docker-machine -v 五、常用命令参数 active 查看当前激活状态的Docker主机 config 查看当前激活状态Docker主机的连接信息 creat 创建Docker主机 env 显示连接到某个主机需要的环境变量 inspect 以json格式输出指定Docker的详细信息 ip 获取指定Docker主机的地址 kill 直接杀死指定的Docker主机 ls 列出所有的管理主机 provision 重新配置指定主机 regenerate-certs 为某个主机重新生成TLS信息 restart 重启指定的主机 rm 删除某台Docker主机，对应的虚拟机也会被删除 ssh 通过SSH连接到主机上，执行命令 scp 在Docker主机之间以及Docker主机和本地主机之间通过scp远程复制数据 mount 使用SSHFS从计算机装载或卸载目录 start 启动一个指定的Docker主机，如果对象是个虚拟机，该虚拟机将被启动 status 获取指定Docker主机的状态(包括：Running、Paused、Saved、Stopped、Stopping、Starting、Error)等 stop 停止一个指定的Docker主机 upgrade 将一个指定主机的Docker版本更新为最新 url 获取指定Docker主机的监听URL version 显示Docker Machine的版本或者主机Docker版本 help 显示帮助信息 参考： Docker三剑客之Docker Machine
一、前言 Swarm 是 Docker 公司推出的用来管理 docker 集群的平台，几乎全部用 GO 语言来完成的开发的，代码开源：https://github.com/docker/swarm Docker Swarm 和 Docker Compose 一样，都是 Docker 官方容器编排项目，但不同的是，Docker Compose 是一个在单个服务器或主机上创建多个容器的工具，而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务，对于微服务的部署，显然 Docker Swarm 会更加适合。从 Docker 1.12.0 版本开始，Docker Swarm 已经包含在 Docker 引擎中（docker swarm），并且已经内置了服务发现工具，就不需要像之前一样，再配置 Etcd 或者 Consul 来进行服务发现配置了。 上图可以看出，Swarm 是典型的 master-slave 结构，通过发现服务来选举 manager。manager 是中心管理节点，各个 node 上运行 agent 接受 manager 的统一管理，集群会自动通过 Raft 协议分布式选举出 manager 节点，无需额外的发现服务支持，避免了单点的瓶颈问题，同时也内置了 DNS 的负载均衡和对外部负载均衡机制的集成支持。 二、Docker Swarm 工作原理 2.1、Docker Engine client 通过 docker service create 命令去创建一个服务。 2.2、swarm manager API 这个请求直接由 Swarm manager 的 API 进行接收，接收命令并创建服务对象。 orchestrator 为服务创建一个任务。 allocater 为这个任务分配 IP 地址。 dispatcher 将任务分配到指定的节点。 scheduler 再该节点中下发指定命令。 2.3、worker node：接收manager任务后去运行这个任务 container 创建相应的容器。 worker 连接到调度程序以检查分配的任务。 executor 执行分配给工作节点的任务。 三、Swarm 重要概念 Swarm 集群的管理和编排是使用嵌入 docker 引擎的 SwarmKit，可以在 docker 初始化时启动 swarm 模式或者加入已存在的 swarm。 Node 每一个 docker engin 都是一个node（节点），分为 manager 和worker。Manager节点还执行维护所需群集状态所需的编排和集群管理功能。Work节点接收并执行从管理器节点分派的任务。 Service 一个服务是任务的定义，管理机或工作节点上执行。它是群体系统的中心结构，是用户与群体交互的主要根源。创建服务时，需要指定要使用的容器镜像。 Task 任务是在 docekr 容器中执行的命令，Manager 节点根据指定数量的任务副本分配任务给 worker 节点。一个任务包含了一个容器及其运行的命令。task 是 service 的执行实体，task 启动 docker 容器并在容器中执行任务。 3.1、Swarm 命令行说明 docker swarm 集群管理，子命令有 init, join, leave, update。（docker swarm --help查看帮助）； 执行集群的管理功能，维护集群的状态，选举一个 leader 节点去执行调度任务。 init #初始化集群 join #将节点加入集群 join-token #管理加入令牌 leave #从集群中删除某个节点，强制删除加参数--force update #更新集群 unlock #解锁集群 docker node 节点管理，子命令有 accept, promote, demote, inspect, update, tasks, ls, rm。（docker node --help 查看帮助） 接收和执行任务。参与容器集群负载调度，仅用于承载 task。 demote #将集群中一个或多个节点降级 inspect #显示一个或多个节点的详细信息 ls #列出集群中的节点 promote #将一个或多个节点提升为管理节点 rm #从集群中删除停止的节点，--force强制删除参数 ps #列出一个或多个节点上运行的任务 update #更新节点 docker service 服务创建，子命令有 create, inspect, update, remove, tasks。（docker service--help 查看帮助） 一个服务是 work 节点上执行任务的定义。创建一个服务，指定了容器所使用的镜像和容器运行的命令。 create #创建一个新的服务 inspect #列出一个或多个服务的详细信息 ps #列出一个或多个服务中的任务信息 ls #列出服务 rm #删除一个或多个服务 scale #扩展一个或多个服务 update #更新服务 四、Swarm 的调度策略 Swarm在调度(scheduler)节点（leader节点）运行容器的时候，会根据指定的策略来计算最适合运行容器的节点，目前支持的策略有：spread, binpack, random。 4.1、Random 顾名思义，就是随机选择一个 Node 来运行容器，一般用作调试用，spread 和 binpack 策略会根据各个节点的可用的 CPU, RAM 以及正在运行的容器的数量来计算应该运行容器的节点。 4.2、Spread 在同等条件下，Spread 策略会选择运行容器最少的那台节点来运行新的容器，binpack策略会选择运行容器最集中的那台机器来运行新的节点。使用 Spread 策略会使得容器会均衡的分布在集群中的各个节点上运行，一旦一个节点挂掉了只会损失少部分的容器。 4.3、Binpack Binpack 策略最大化的避免容器碎片化，就是说 binpack 策略尽可能的把还未使用的节点留给需要更大空间的容器运行，尽可能的把容器运行在一个节点上面。 五、Swarm Cluster 模式特性 批量创建服务：建立容器之前先创建一个 overlay 的网络，用来保证在不同主机上的容器网络互通的网络模式。 强大的集群的容错性：Swarm Cluster 不光只是提供了优秀的高可用性，同时也提供了节点弹性扩展或缩减的功能。当容器组想动态扩展时，只需通过 scale 参数即可复制出新的副本出来。如果有需求想在每台节点上都 run 一个相同的副本，方法其实很简单，只需要在命令中将 --replicas n 更换成 --mode=global 即可。 复制服务（--replicas n）：将一系列复制任务分发至各节点当中，具体取决于您所需要的设置状态，例如 --replicas 3 。 全局服务（--mode=global）：适用于集群内全部可用节点上的服务任务，例如 --mode global 。如果大家在 Swarm 集群中设有 7 台 Docker 节点，则全部节点之上都将存在对应容器。 调度机制：所谓的调度其主要功能是cluster的server端去选择在哪个服务器节点上创建并启动一个容器实例的动作。它是由一个装箱算法和过滤器组合而成。每次通过过滤器（constraint）启动容器的时候，swarm cluster 都会调用调度机制筛选出匹配约束条件的服务器，并在这上面运行容器。 六、Dcoker Swarm 集群部署 6.1、环境准备(三台 linux 机器，centos 系统) IP：192.168.10.130 主机名：manager130 担任角色：swarm manager IP：192.168.10.131 主机名：node131 担任角色：swarm node IP：192.168.10.132 主机名：node132 担任角色：swarm node 6.2、创建 Swarm cluster 1、准备工作 1、修改主机名 # 192.168.10.130执行 hostnamectl set-hostname manager130 # 192.168.10.131执行 hostnamectl set-hostname node131 # 192.168.10.132执行 hostnamectl set-hostname node132 2、在所有节点上配置 /etc/hosts 文件 192.168.10.130 manager130 192.168.10.131 node131 192.168.10.132 node132 3、设置防火墙 关闭三台机器上的防火墙，不建议直接关闭防火墙，一般生成环境上不允许直接关闭防火墙。如果开启防火墙，则需要在所有节点的防火墙上依次放行 2377/tcp（管理端口）、7946/tcp/udp（节点间通信端口）、4789/udp（overlay 网络端口）端口。 # 放开2377/tcp，7946/udp，4789/udp端口 firewall-cmd --zone=public --add-port=2377/tcp --permanent firewall-cmd --zone=public --add-port=7946/tcp --permanent firewall-cmd --zone=public --add-port=7946/udp --permanent firewall-cmd --zone=public --add-port=4789/udp --permanent # 重新加载生效 firewall-cmd --reload # 查看 firewall-cmd --list-ports 4、安装 Docker Docker 安装 2、创建 Swarm 并添加节点 1、创建Swarm集群（manager110） docker swarm init --advertise-addr 192.168.10.130 Swarm initialized: current node (sxwaiyl5j64dbxeanxw7wgj8e) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4ev72f2jax5vhkhc7bjx6gfb61m8w99ctscpc84p96gdp1xrcz-9mwpr765ca0fdunc94j09wlzf 192.168.10.130:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. 上面命令执行后，该机器自动加入到 swarm 集群。这个会创建一个集群 token，作为集群唯一标识。记住这个 token 值，后续将其他节点加入集群都会用到这个 token 值。其中，--advertise-addr 参数表示其它 swarm 中的 worker 节点使用此ip地址与 manager 联系。命令的输出包含了其它节点如何加入集群的命令。再次执行会报如下错误。 解决方法： # 这里的leave就是在集群中删除节点，-f参数强制删除，执行完在重新执行OK docker swarm leave -f docker swarm init --advertise-addr 192.168.10.130 2、查看集群的相关信息 docker info 发现 swarm 状态 active，且是 manager 节点。 docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION sxwaiyl5j64dbxeanxw7wgj8e * manager130 Ready Active Leader 20.10.22 3、添加 node 节点主机到 Swarm 集群 在创建 Swarm 集群的时候就已经给出了添加节点的方法。如果忘记了，可以通过以下命令查看 token 和添加方法。 docker swarm join-token worker node131 & node132 主机上执行： docker swarm join --token SWMTKN-1-4ev72f2jax5vhkhc7bjx6gfb61m8w99ctscpc84p96gdp1xrcz-9mwpr765ca0fdunc94j09wlzf 192.168.10.130:2377 在 manager130 节点上查看 node 信息： docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION sxwaiyl5j64dbxeanxw7wgj8e * manager130 Ready Active Leader 20.10.22 zk6jluzkwevz73yzxu9za8h55 node131 Ready Active 20.10.22 owzfehdo3p0mc807n2328gb9k node132 Ready Active 20.10.22 MANAGER STATUS 的三种状态： Leader 为群体做出所有群管理和编排决策的主要管理者节点。 Reachable 如果 Leader 节点变为不可用，该节点有资格被选举为新的 Leader。 Unavailable 该节点不能和其他 Manager 节点产生任何联系，这种情况下，应该添加一个新的 Manager 节点到集群，或者将一个 Worker 节点提升为 Manager 节点。 升级/降级节点，示例： # 升级 docker node promote node131 # 降级 docker node demote node131 七、在 Swarm 中部署服务 7.1、Nginx 为例 Docker 1.12 版本提供服务的 Scaling、health check、滚动升级等功能，并提供了内置的 dns、vip 机制，实现 service 的服务发现和负载均衡能力。 1、创建网络（overlay） docker node ls docker network create -d overlay nginx_net docker network ls | grep nginx_net 2、部署服务 # 就创建了一个具有一个副本（--replicas 1 ）的nginx服务，使用镜像 nginx docker service create --replicas 1 --network nginx_net --name my_nginx -p 80:80 nginx # 查看 docker service ls 3、查询 Swarm 中服务的信息 --pretty 使命令输出格式化为可读的格式，不加 --pretty 可以输出更详细的信息： docker service inspect --pretty my_nginx 查询到哪个节点正在运行该服务： docker service ps my_nginx 如下该容器被调度到 manager-node 节点上启动了，然后访问 http://192.168.10.130 即可访问这个容器应用（如果调度到其他节点，访问也是如此）。 登陆该节点，可以查看到 nginx 容器在运行中 docker ps 4、在 Swarm 中动态扩展服务(scale) 当然，如果只是通过 service 启动容器，swarm 也算不上什么新鲜东西了。Service 还提供了复制（类似 kubernetes 里的副本）功能。可以通过 docker service scale 命令来设置服务中容器的副本数比如将上面的 my_nginx 容器动态扩展到 4 个。 docker service scale my_nginx=4 和创建服务一样，增加 scale 数之后，将会创建新的容器，这些新启动的容器也会经历从准备到运行的过程，过一分钟左右，服务应该就会启动完成，这时候可以再来看一下 nginx 服务中的容器。 docker service ps my_nginx 可以看到，之前 my_nginx 容器只在 manager-node 节点上有一个实例，而现在又增加了 3 个实例。 5、模拟宕机 node 节点 如果一个节点宕机了（即该节点就会从swarm集群中被踢出），则Docker应该会将在该节点运行的容器，调度到其他节点，以满足指定数量的副本保持运行状态。 将 node131 宕机后或将 node131 的 docker 服务关闭，那么它上面的 task 实例就会转移到别的节点上。当 node131 节点恢复后，它转移出去的 task 实例不会主动转移回来，只能等别的节点出现故障后转移 task 实例到它的上面。使用命令 docker node ls，发现 node131 节点已不在 swarm 集群中了(状态为：Down)。然后过一会查询服务的状态列表。 6、Swarm 动态缩容服务(scale) 同理，swarm 还可以缩容，同样是使用 scale 命令。将 my_nginx 容器变为 1 个 docker service scale my_nginx=1 7、docker service update 除了上面使用 scale 进行容器的扩容或缩容之外，还可以使用 docker service update 命令。 可对服务的启动参数进行更新/修改。 docker service update --replicas 3 my_nginx docker service ps my_nginx 8、删除服务 docker service rm my_nginx 7.2、Swarm 中使用 Volume(挂载目录，mount 命令) 1、查看 volume 的帮助信息 docker volume --help 2、创建一个 volume docker volume create --name testvolume docker volume ls docker volume inspect testvolume 3、创建新的服务并挂载 testvolume(nginx 为例) docker service create --replicas 3 --mount type=volume,src=testvolume,dst=/usr/share/nginx/html --name test_nginx nginx tip：参数 src 写成 source 也可以；dst 表示容器内的路径，也可以写成 target。查看 docker service ls docker service ps test_nginx 7.3、多服务 Swarm 集群部署 这里部署的服务有三个 (nginx服务，visualizer 服务，portainer 服务) 除了 nginx 服务作为示例之外，visualizer（官方地址）和 portainer（官方地址）都是集群 GUI 管理服务。docker service 部署的是单个服务，我们可以使用 docker stack 进行多服务编排部署。 1、编写 docker-compose.yml 文件 version: "3" services: nginx: image: nginx ports: - 8888:80 deploy: mode: replicated replicas: 3 visualizer: image: dockersamples/visualizer ports: - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock" deploy: replicas: 1 placement: constraints: [node.role == manager] portainer: image: portainer/portainer ports: - "9000:9000" volumes: - "/var/run/docker.sock:/var/run/docker.sock" deploy: replicas: 1 placement: constraints: [node.role == manager] 2、通过这个 yml 文件部署服务 docker stack deploy -c docker-compose.yml deploy_deamon 2、测试验证 第一个服务：deploy_deamon_nginx，先查看调度到哪个节点上 docker service ps deploy_deamon_nginx 看调度到 manager130 和 node132 节点上。访问：http://192.168.10.130:8888、http://192.168.10.132:8888。 八、Docker Swarm 网络管理 8.1、Swarm 集群产生两种不同类型的流量 控制和管理层面：包括 Swarm 消息管理等，例如请求加入或离开 Swarm，这种类型的流量总是被加密的。(涉及到集群内部的 hostname、ip-address、subnet、gateway 等) 应用数据层面：包括容器与客户端的通信等。（涉及到防火墙、端口映射、网口映射、VIP 等） 8.2、在 Swarm Service 中有三个重要的网络概念 Overlay networks 覆盖物网络，顾名思义是附着在主机底层网络之上的网络， 这个网络保证了不同主机之间容器通信，手动创建。 ingress network 进入网络，顾名思义是外部客户端访问服务时，服务节点间负载均衡（节点在开放端口上收到请求，上交给 IPVS，选择容器），是一种特殊的 overlay 网络，创建集群的时候自动创建。初始化或加入 Swarm 集群时会自动创建 ingress 网络，大多数情况下，用户不需要自定义配置，但是 docker 17.05 和更高版本可以自定义网络 docker_gwbridge 是一种桥接网络，将 overlay 网络（包括 ingress 网络）连接到一个单独的 Docker 守护进程的物理网络。默认情况下，服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络。docker_gwbridge 网络在初始化或加入 Swarm 时自动创建。大多数情况下，用户不需要自定义配置，但是 Docker 允许自定义。 在初始化或刚加入 Swarm 集群时，会自动创建一个 Ingress 和 docker-gwbridge 网络 九、docker-machine、docker swarm、docker node、docker service 和 docker stack 常用命令 9.1、docker-machine 常用命令 docker-machine create 创建一个 Docker 主机（常用-d virtualbox） docker-machine ls 查看所有的 Docker 主机 docker-machine ssh SSH 到主机上执行命令 docker-machine env 显示连接到某个主机需要的环境变量 docker-machine inspect 输出主机更多信息 docker-machine kill 停止某个主机 docker-machine restart 重启某台主机 docker-machine rm 删除某台主机 docker-machine scp 在主机之间复制文件 docker-machine start 启动一个主机 docker-machine status 查看主机状态 docker-machine stop 停止一个主机 9.2、docker swarm 常用命令 docker swarm init 初始化集群 docker swarm join-token worker 查看工作节点的 token docker swarm join-token manager 查看管理节点的 token docker swarm join 加入集群中 9.3、docker node 常用命令 docker node ls 查看所有集群节点 docker node rm 删除某个节点（-f强制删除） docker node inspect 查看节点详情 docker node demote 节点降级，由管理节点降级为工作节点 docker node promote 节点升级，由工作节点升级为管理节点 docker node update 更新节点 docker node ps 查看节点中的 Task 任务 9.4、docker service 常用命令 docker service create 部署服务 docker service inspect 查看服务详情 docker service logs 查看某个服务日志 docker service ls 查看所有服务详情 docker service rm 删除某个服务（-f强制删除） docker service scale 设置某个服务个数 docker service update 更新某个服务 9.5、docker stack 常用命令 docker stack deploy 部署新的堆栈或更新现有堆栈 docker stack ls 列出现有堆栈 docker stack ps 列出堆栈中的任务 docker stack rm 删除堆栈 docker stack services 列出堆栈中的服务 docker stack down 移除某个堆栈（不会删除数据） 十、Docker 组件 docker-compose 主要是解决本地 docker 容器编排问题。 docker-machine 是解决 docker 运行环境问题。 docker-swarm 是解决多主机多个容器调度部署问题。
一、Harbor 简介 1.1、简介 Harbor 是 VMware 公司开源的企业级 Docker Registry 项目，其目标是帮助用户迅速搭建一个企业级的 Docker Registry 服务。 Harbor 以 Docker 公司开源的 Registry 为基础，提供了图形管理 UI 、基于角色的访问控制(Role Based AccessControl) 、AD/LDAP 集成、以及审计日志(Auditlogging) 等企业用户需求的功能，同时还原生支持中文。 Harbor 的每个组件都是以 Docker 容器的形式构建的，使用 docker-compose 来对它进行部署。用于部署 Harbor 的 docker-compose 模板位于 harbor/docker-compose.yml。 1.2、Harbor 的特性 1、基于角色控制：用户和仓库都是基于项目进行组织的，而用户在项目中可以拥有不同的权限。 2、基于镜像的复制策略：镜像可以在多个 Harbor 实例之间进行复制（同步）。 3、支持 LDAP/AD：Harbor 可以集成企业内部已有的 AD/LDAP（类似数据库的一张表），用于对已经存在的用户认证和管理。 4、镜像删除和垃圾回收：镜像可以被删除，也可以回收镜像占用的空间。 5、图形化用户界面：用户可以通过浏览器来浏览，搜索镜像仓库以及对项目进行管理。 6、审计管理：所有针对镜 像仓库的操作都可以被记录追溯，用于审计管理。 7、支持 RESTful API：RESTful API 提供给管理员对于 Harbor 更多的操控, 使得与其它管理软件集成变得更容易。 8、Harbor 和 docker registry 的关系：Harbor 实质上是对 docker registry 做了封装，扩展了自己的业务模板。 1.3、Harbor的构成 Harbor 在架构上主要有 Proxy、Registry、Core services、Database（Harbor-db）、Log collector（Harbor-log）、Job services 六个组件。 Docker Harbor 私有仓库操作的过程： 1、所有的请求或认为的操作都会首先交给 proxy（反向代理）。 2、proxy 会先将请求转发给后端Core services，Core services 中包含 UI、token（身份验证服务）、webhook（网站的一些服务功能）。 3、转发给registry（镜像存储），若需要下载镜像等权限操作，需要通过 Core services 中的 token 令牌的身份验证服务才行。 4、每一次下载和上传都产生操作记录，生成日志，保存至 database 中。 5、database 记录保存镜像的元信息及用户与组的身份信息，通过验证授权才能允许相关操作。 Proxy: 是一个 nginx 的前端代理，Harbor 的 Registry、UI、Token 服务等组件，都处在 nginx 反向代理后边。 该代理将来自浏览器、docker clients 的请求转发到后端不同的服务上。 Registry: 负责储存 Docker 镜像，并处理 Docker push/pull 命令。由于要对用户进行访问控制，即不同用户对 Docker 镜像 有不同的读写权限，Registry 会指向一个 Token 服务，强制用户的每次 Docker pull/push 请求都要携带一个合法的 Token， Registry 会通过公钥对 Token 进行解密验证。 Core services: Harbor的核心功能， UI（harbor-ui）: 提供图形化界面，帮助用户管理 Registry 上的镜像（image）, 并对用户进行授权。 WebHook：为了及时获取Registry上image 状态变化的情况，在Registry 上配置 Webhook，把状态变化传递给 UI 模块。 Token 服务：负责根据用户权限给每个 Docker push/pull 命令签发 Token。Docker 客户端向 Registry 服务发起的请求， 如果不包含 Token，会被重定向到 Token 服务，获得 Token 后再重新向 Registry 进行请求。 Database（harbor-db）：为core services提供数据库服务，负责储存用户权限、审计日志、Docker 镜像分组信息等数据。 Job services: 主要用于镜像复制，本地镜像可以被同步到远程 Harbor 实例上。 Log collector（harbor-log）: 负责收集其他组件的日志到一个地方。 二、部署Harbor 2.1、部署 Docker-Compose 服务 Docker-Compose 容器编排 2.2、部署 Harbor 服务 2.2.1下载或上传 Harbor 安装程序 # 下载harbor离线安装包 wget -c https://github.com/goharbor/harbor/releases/download/v2.8.1/harbor-offline-installer-v2.8.1.tgz # 解压 tar -zxvf harbor-offline-installer-v2.8.1.tgz -C /opt/module 2.3、修改Habor配置文件 harbor.cfg cp harbor.yml.tmpl harbor.yml //修改配置文件中hostname内容 vim harbor.yml .... hostname: 192.168.10.130 #修改为当前主机的IP或域名 # http related config http: port: 80 #https: #注释掉https服务 # port: 443 # certificate: /your/certificate/path # private_key: /your/private/key/path # internal_tls: # enabled: true # dir: /etc/harbor/tls/internal harbor_admin_password: Harbor12345 --指定密码 2.4、安装 Harbor ./install.sh 2.5、登录harbor的web平台 默认用户名：admin，默认密码：Harbor12345 2.6、登录成功界面 2.7、推送镜像至 Harbor docker login -u admin -p Harbor12345 http://127.0.0.1 或者： docker login 192.168.10.130 Username: admin Password: Error response from daemon: Get "https://192.168.10.130/v2/": dial tcp 192.168.2.50:443: connect: connection refused 解决登录失败方法如下： 默认访问 Docker 仓库使用 443 端口，要修改为 80 端口仓库地址。 # 重启harbor服务： docker-compose stop && docker-compose start 下载镜像并修改 tag： docker pull nginx docker tag nginx:latest 192.168.10.130/library/nginx:v1 推送镜像到 library 项目： docker push 192.168.10.130/library/nginx:v1 2.8、Harbor 启停 # 进入 Harbor 安装目录 cd harbor # 关闭 Harbor docker-compose down # 开启 Harbor docker-compose up -d # 查看服务状态 docker-compose ps # 重启 Harbor docker-compose restart # 查看服务日志 docker-compose logs # 查看某个具体服务的日志，例如 nginx docker-compose logs nginx # 停止某个具体服务 docker-compose stop nginx # 启动某个具体服务 docker-compose start nginx
一、原生命令 docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS c1e2abb01b8c portainer 0.00% 14.42MiB / 3.842GiB 0.37% 322kB / 4.77MB 0B / 1.63MB 8 ddb92363b45d fervent_lederberg 0.17% 287.5MiB / 3.842GiB 7.31% 3.6kB / 2.06kB 0B / 0B 28 通过 docker stats 命令可以很方便的看到当前宿主机上所有容器的 CPU，内存以及网络流量等数据，一般小公司够用了。 但是，docker stats 统计结果只能是当前宿主机的全部容器，数据资料是实时的，没有地方存储、没有健康指标过线预警等功能。 二、CIG简介 容器监控 3 剑客 CAdvisor 监控收集 + InfluxDB 存储数据 + Granfana 展示图表。 2.1、CAdvisor CAdvisor 是一个容器资源监控工具，包括容器的内存，CPU，网络IO，磁盘IO 等监控，同时提供了一个 WEB 页面用于查看容器的实时运行状态。CAdvisor 默认存储 2 分钟的数据，而且只是针对单物理机。不过, CAdvisor 提供了很多数据集成接口，支持 InfluxDB，Redis，Kafka，Elasticsearch 等集成，可以加上对应配置将监控数据发往这些数据库存储起来。 CAdvisor功能主要有两点： 展示 Host 和容器两个层次的监控数据。 展示历史变化数据。 2.2、InfluxDB InfluxDB 是用 Go 语言编写的一个开源分布式时序、事件和指标数据库，无需外部依赖。CAdvisor 默认只在本机保存最近 2 分钟的数据，为了持久化存储数据和统一收集展示监控数据，需要将数据存储到 InfluxDB 中。InfluxDB 是一个时序数据库，专门用于存储时序相关数据，很适合存储 CAdvisor 的数据。而且，CAdvisor 本身已经提供了 InfluxDB 的集成方法，启动容器时指定配置即可。 InfluxDB主要功能: 基于时间序列：支持与时间有关的相关函数(如最大、最小、求和等)。 可度量性：你可以实时对大量数据进行计算。 基于事件：它支持任意的事件数据。 2.3、Granfana Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置(支持的数据源包括 InfluxDB，MySQL，Elasticsearch，OpenTSDB，Graphite 等)和丰富的插件及模板功能，支持图表权限控制和报警。 Grafan主要特性： 灵活丰富的图形化选项。 可以混合多种风格。 支持白天和夜间模式。 多个数据源。 总结： 三、实践 1、新建目录 [root@docker130 ~]# cd /mydocker/ [root@docker130 mydocker]# mkdir cig 2、新建 3 件套组合的 docker-compose.yml version: '3.1' volumes: grafana_data: {} services: influxdb: image: tutum/influxdb:0.9 restart: always environment: - PRE_CREATE_DB=cadvisor ports: - "8083:8083" - "8086:8086" volumes: - ./data/influxdb:/data cadvisor: image: google/cadvisor links: - influxdb:influxsrv command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086 restart: always ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:rw - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro grafana: user: "104" image: grafana/grafana user: "104" restart: always links: - influxdb:influxsrv ports: - "3000:3000" volumes: - grafana_data:/var/lib/grafana environment: - HTTP_USER=admin - HTTP_PASS=admin - INFLUXDB_HOST=influxsrv - INFLUXDB_PORT=8086 - INFLUXDB_NAME=cadvisor - INFLUXDB_USER=root - INFLUXDB_PASS=root 3、启动docker-compose文件 docker-compose up 4、查看三个服务容器是否启动 5、测试 浏览 cAdvisor 收集服务，http://ip:8080/。 第一次访问慢，请稍等 cadvisor 也有基础的图形展现功能，这里主要用它来作数据采集。 浏览 influxdb 存储服务，http://ip:8083/。 浏览 grafana 展现服务，http://ip:3000。默认帐户密码admin/admin。 6、配置步骤 配置数据源 选择 influxdb 数据源 配置细节 配置面板 panel 到这里 cAdvisor + InfluxDB + Grafana 容器监控系统就部署完成了。
一、简介 Portainer 是一款轻量级的应用，它提供了图形化界面，用于方便地管理 Docker 环境，包括单机环境和集群环境。 二、安装 portainer.io Portainer Documentation 步骤： 1、docker 命令安装 docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer -v /var/run/docker.sock:/var/run/docker.sock： 这个选项将主机的 Docker 套接字文件挂载到容器内。这使得 Portainer 能够与 Docker 引擎进行通信，从而管理 Docker 容器和服务。 -v portainer_data:/data： 这个选项创建一个名为 portainer_data 的 Docker 卷，并将其挂载到容器的 /data 目录。这个卷用于持久化 Portainer 的数据，以便在容器重启或重新创建时保留数据。 2、第一次登录需创建 admin，访问地址：xxx.xxx.xxx.xxx:9000。 用户名，直接用默认 admin，密码记得 8 位，随便写。 设置 admin 用户和密码后首次登陆。 选择 local 选项卡后本地 docker 详细信息展示。
一、简介 Compose 是 Docker 公司推出的一个工具软件，可以管理多个 Docker 容器组成一个应用。需要定义一个 YAML 格式的配置文件 docker-compose.yml，写好多个容器之间的调用关系。然后，只要一个命令，就能同时启动 / 关闭这些容器。 Docker-Compose 是 Docker 官方的开源项目，负责实现对 Docker 容器集群的快速编排。 二、作用 docker 建议我们每一个容器中只运行一个服务，因为 docker 容器本身占用资源极少，所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题？ 如果我需要同时部署好多个服务，难道要每个服务单独写 Dockerfile 然后在构建镜像，构建容器。所以 docker 官方给我们提供了 docker-compose 多服务部署的工具。 Compose 允许用户通过一个单独的 docker-compose.yml 模板文件（YAML 格式）来定义一组相关联的应用容器为一个项目（project）。 可以很容易地用一个配置文件定义一个多容器的应用，然后使用一条指令安装这个应用的所有依赖，完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。 三、下载安装 官网：https://docs.docker.com/compose/compose-file/compose-file-v3/ 官网下载：https://docs.docker.com/compose/install/ curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose docker-compose --version CentOS/RHEL/Rocky/Alma（官方源）： sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker docker compose version 卸载步骤： 如果是使用 curl 以下方式安装，则卸载 docker-compose: sudo rm /usr/local/bin/docker-compose 四、Compose 核心概念 一文件：docker-compose.yml 两要素 服务（service） 一个个应用容器实例，比如订单微服务、库存微服务、mysql 容器、nginx 容器或者 redis 容器。 工程（project） 由一组关联的应用容器组成的一个完整业务单元，在 docker-compose.yml 文件中定义。 五、Compose 使用的三个步骤 编写 Dockerfile 定义各个微服务应用并构建出对应的镜像文件。 使用 docker-compose.yml 定义一个完整业务单元，安排好整体应用中的各个容器服务。 最后，执行 docker-compose up 命令来启动并运行整个应用程序，完成一键部署上线。 六、Compose 常用命令 docker compose -h 查看帮助。 docker compose up 启动所有 docker compose 服务。 docker compose up -d 启动所有 docker compose 服务并后台运行。指定文件：docker compose -f docker compose.yml up -d。 docker compose down 停止并删除容器、网络、卷、镜像。 docker compose exec yml 里面的服务 id 进入容器实例内部。 docker compose exec docker compose.yml 文件中写的服务 id /bin/bash 。 docker compose ps 展示当前 docker compose 编排过的运行的所有容器。 docker compose top 展示当前 docker compose 编排过的容器进程。 docker compose logs yml 里面的服务 id 查看容器输出日志。 docker compose config 检查配置。 docker compose config -q 检查配置，有问题才有输出。 docker compose restart 重启服务。 docker compose start 启动服务。 docker compose stop 停止服务。 七、Compose 编排微服务 改造升级微服务工程 docker_boot 。 mvn package 命令将微服务形成新的 jar 包 并上传到 Linux 服务器 /mydocker 目录下。 编写 Dockerfile： # 基础镜像使用 java FROM java:8 # 作者 MAINTAINER zhuangpf # VOLUME 指定临时文件目录为 /tmp，在主机 /var/lib/docker 目录下创建了一个临时文件并链接到容器的 /tmp VOLUME /tmp # 将 jar 包添加到容器中并更名为 docker_boot.jar ADD docker_boot-1.0-SNAPSHOT.jar docker_boot.jar # 运行 jar 包 RUN bash -c 'touch /docker_boot.jar' ENTRYPOINT ["java","-jar","/docker_boot.jar"] # 暴露 6001 端口作为微服务 EXPOSE 6001 构建镜像： docker build -t docker_boot:1.0 . 7.1、不用 Compose 新建 mysql 容器实例： docker run -p 3306:3306 --name mysql57 --privileged=true -v /zzyyuse/mysql/conf:/etc/mysql/conf.d -v /zzyyuse/mysql/logs:/logs -v /zzyyuse/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 进入 mysql 容器实例并新建库 db2021 + 新建表 t_user： docker exec -it mysql57 /bin/bash mysql -uroot -p create database db2021; use db2021; CREATE TABLE `t_user` ( `id` INT (10) UNSIGNED NOT NULL AUTO_INCREMENT, `username` VARCHAR (50) NOT NULL DEFAULT '' COMMENT ' 用户名 ', `password` VARCHAR (50) NOT NULL DEFAULT '' COMMENT ' 密码 ', `sex` TINYINT (4) NOT NULL DEFAULT '0' COMMENT ' 性别 0 = 女 1 = 男 ', `deleted` TINYINT (4) UNSIGNED NOT NULL DEFAULT '0' COMMENT ' 删除标志，默认 0 不删除，1 删除 ', `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ' 更新时间 ', `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ' 创建时间 ', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT=' 用户表 '; 单独的 redis 容器实例： docker run -p 6379:6379 --name redis608 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf 微服务工程： docker run -d -p 6001:6001 docker_boot:1.6 上面三个容器实例依次顺序启动成功： swagger 测试： http://localhost: 你的微服务端口 /swagger-ui.html#/ 上面成功了，有哪些问题？ 先后顺序要求固定，先 mysql + redis 才能微服务访问成功。 多个 run 命令...... 容器间的启停或宕机，有可能导致 IP 地址对应的容器实例变化，映射出错，要么生产 IP 写死 (可以但是不推荐)，要么通过服务调用。 7.2、使用 Compose docker-compose.yml version: "3" services: microService: image: docker_boot:1.0 container_name: ms01 ports: - "6001:6001" volumes: - /app/microService:/data networks: - atguigu_net depends_on: - redis - mysql redis: image: redis:6.0.8 ports: - "6379:6379" volumes: - /app/redis/redis.conf:/etc/redis/redis.conf - /app/redis/data:/data networks: - atguigu_net command: redis-server /etc/redis/redis.conf mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: '123456' MYSQL_ALLOW_EMPTY_PASSWORD: 'no' MYSQL_DATABASE: 'db2021' MYSQL_USER: 'zzyy' MYSQL_PASSWORD: 'zzyy123' ports: - "3306:3306" volumes: - /app/mysql/db:/var/lib/mysql - /app/mysql/conf/my.cnf:/etc/my.cnf - /app/mysql/init:/docker-entrypoint-initdb.d networks: - atguigu_net command: --default-authentication-plugin=mysql_native_password #解决外部无法访问 networks: atguigu_net: 通过服务名访问，IP 无关。 mvn package 命令将微服务形成新的 jar 包 并上传到 Linux 服务器 /mydocker 目录下。 根据 Dockerfile 构建镜像： docker build -t docker_boot:1.0 . 执行： docker compose up 或者执行 docker compose up -d 关停：
一、简介 docker不启动，默认网络情况。 即：ens33、lo、virbr0 在 CentOS7 的安装过程中如果有选择相关虚拟化的的服务安装系统后，启动网卡时会发现有一个以网桥连接的私网地址的 virbr0 网卡(virbr0 网卡：它还有一个固定的默认 IP 地址192.168.122.1)，是做虚拟机网桥的使用的，其作用是为连接其上的虚机网卡提供 NAT 访问外网的功能。 Linux 安装，勾选安装系统的时候附带了 libvirt 服务才会生成的一个东西，如果不需要可以直接将 libvirtd 服务卸载，yum remove libvirt-libs.x86_64。 docker 启动后，网络情况。 会产生一个名为docker0的虚拟网桥 查看 docker 网络模式命令。 默认创建3大网络模式 二、常用基本命令 1、All 命令 2、查看网络 docker network ls 3、查看网络源数据 docker network inspect XXX网络名字 4、删除网络 docker network rm XXX网络名字 5、案例 三、作用 容器间的互联和通信以及端口映射。 容器 IP 变动时候可以通过服务名直接网络通信而不受到影响。 四、网络模式 4.1、总体介绍 bridge模式：使用--network bridge指定，默认使用docker0。 host模式：使用--network host指定。 none模式：使用--network none指定。 container模式：使用--network container:NAME或者容器ID指定。 4.2、容器实例内默认网络 IP 生产规则 1、先启动两个 ubuntu 容器实例。 2、docker inspect 容器ID or 容器名字。 3、关闭 u2 实例，新建 u3，查看 ip 变化 结论： docker 容器内部的 ip 是有可能会发生改变的。 4.3、案例说明 4.3.1、bridge Docker 服务默认会创建一个 docker0 网桥（其上有一个 docker0 内部接口），该桥接网络的名称为 docker0，它在内核层连通了其他的物理或虚拟网卡，这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口的 IP 地址和子网掩码，让主机和容器之间可以通过网桥相互通信。 查看 bridge 网络的详细信息，并通过 grep 获取名称项 docker network inspect bridge | grep name [root@docker130 ~]# docker network inspect bridge | grep name "com.docker.network.bridge.name": "docker0", ifconfig [root@docker130 ~]# ifconfig | grep docker docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 说明： 1、Docker 使用 Linux 桥接，在宿主机虚拟一个Docker容器网桥(docker0)，Docker 启动一个容器时会根据 Docker 网桥的网段分配给容器一个 IP 地址，称为Container-IP，同时 Docker 网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥，这样容器之间就能够通过容器的Container-IP直接通信。 2、docker run 的时候，没有指定 network 的话默认使用的网桥模式就是 bridge，使用的就是docker0。在宿主机 ifconfig，就可以看到 docker0 和自己 create 的 network eth0，eth1，eth2……代表网卡一，网卡二，网卡三……，lo代表127.0.0.1，即 localhost，inet addr 用来表示网卡的IP地址。 3、网桥 docker0 创建一对对等虚拟设备接口一个叫 veth，另一个叫 eth0，成对匹配。 3.1、整个宿主机的网桥模式都是 docker0 ，类似一个交换机有一堆接口，每个接口叫 veth，在本地主机和容器内分别创建一个虚拟接口，并让他们彼此联通（这样一对接口叫 veth pair）； 3.2、每个容器实例内部也有一块网卡，每个接口叫 eth0； 3.3、docker0 上面的每个 veth 匹配某个容器实例内部的 eth0，两两配对，一一匹配。 通过上述，将宿主机上的所有容器都连接到这个内部网络上，两个容器在同一个网络下,会从这个网关下各自拿到分配的 ip，此时两个容器的网络是互通 代码 docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8 docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8 两两匹配验证 4.3.2、host 直接使用宿主机的 IP 地址与外界进行通信，不再需要额外进行 NAT 转换。 说明： 容器将不会获得一个独立的Network Namespace，而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的 IP 和端口。 警告： docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8 问题： docker 启动时总是遇见标题中的警告。 原因： docker 启动时指定--network=host或-net=host，如果还指定了-p映射端口，那这个时候就会有此警告，并且通过-p设置的参数将不会起到任何作用，端口号会以主机端口号为主，重复时则递增。 解决： 解决的办法就是使用 docker 的其他网络模式，例如--network=bridge，这样就可以解决问题，或者直接无视。 正确： docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8 无之前的配对显示了，看容器实例内部 没有设置-p的端口映射了，如何访问启动的 tomcat83？ http://宿主机IP:8080/ 在 CentOS 里面用默认的火狐浏览器访问容器内的 tomcat83 看到访问成功，因为此时容器的 IP 借用主机的，所以容器共享宿主机网络 IP，这样的好处是外部主机与容器可以直接通信。 4.3.3、none 在none模式下，并不为 Docker 容器进行任何网络配置。 也就是说，这个 Docker 容器没有网卡、IP、路由等信息，只有一个 lo 需要我们自己为 Docker 容器添加网卡、配置 IP 等。 禁用网络功能，只有 lo 标识(就是 127.0.0.1 表示本地回环)。 案例： docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8 进入容器内部查看： 在容器外部查看： 4.3.4、container container ⽹络模式。 新建的容器和已经存在的一个容器共享一个网络 ip 配置而不是和宿主机共享。新创建的容器不会创建自己的网卡，配置自己的 IP，而是和一个指定的容器共享 IP、端口范围等。同样，两个容器除了网络方面，其他的如文件系统、进程列表等还是隔离的。 案例： docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8 docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8 运行结果： 相当于 tomcat86 和 tomcat85 公用同一个 ip 同一个端口，导致端口冲突本案例用 tomcat 演示不合适。 案例2： Alpine 操作系统是一个面向安全的轻型 Linux 发行版 Alpine Linux 是一款独立的、非商业的通用 Linux 发行版，专为追求安全性、简单性和资源效率的用户而设计。可能很多人没听说过这个 Linux 发行版本，但是经常用 Docker 的朋友可能都用过，因为他小，简单，安全而著称，所以作为基础镜像是非常好的一个选择，可谓是麻雀虽小但五脏俱全，镜像非常小巧，不到 6M 的大小，所以特别适合容器打包。 docker run -it --name alpine1 alpine /bin/sh docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh 运行结果，验证共用搭桥： 假如此时关闭 alpine1，再看看 alpine2。 4.3.5、自定义网络 过时的 link： 案例： before docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8 docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8 上述成功启动并用 docker exec 进入各自容器实例内部。 问题： 按照 IP 地址 ping 是 OK 的。 按照服务名 ping 结果？ after 自定义桥接网络，自定义网络默认使用的是桥接网络 bridge。 新建自定义网络： docker network create test_network 新建容器加入上一步新建的自定义网络： docker run -d -p 8081:8080 --network test_network --name tomcat81 billygoo/tomcat8-jdk8 docker run -d -p 8082:8080 --network test_network --name tomcat82 billygoo/tomcat8-jdk8 互相 ping 测试 问题结论： 自定义网络本身就维护好了主机名和 ip 的对应关系（ip和域名都能通）。 五、Docker平台架构图解 整体说明： 从其架构和运行流程来看，Docker 是一个 C/S 模式的架构，后端是一个松耦合架构，众多模块各司其职。 Docker 运行的基本流程为： 1、用户是使用 Docker Client 与 Docker Daemon 建立通信，并发送请求给后者。 2、Docker Daemon 作为 Docker 架构中的主体部分，首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。 3、Docker Engine 执行 Docker 内部的一系列工作，每一项工作都是以一个 Job 的形式的存在。 4、Job 的运行过程中，当需要容器镜像时，则从 Docker Registry 中下载镜像，并通过镜像管理驱动 Graph driver 将下载镜像以 Graph 的形式存储。 5、当需要为 Docker 创建网络环境时，通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。 6、当需要限制 Docker 容器运行资源或执行用户指令等操作时，则通过 Execdriver 来完成。 7、Libcontainer是一项独立的容器管理包，Network driver 以及 Exec driver 都是通过 Libcontainer 来实现具体对容器进行的操作。 整体架构：
一、简介 Dockerfile是用来构建 Docker 镜像的文本文件，是由一条条构建镜像所需的指令和参数构成的脚本。 官网：https://docs.docker.com/engine/reference/builder/ 构建三步骤： 编写 Dockerfile 文件。 docker build命令构建镜像。 docker run依镜像运行容器实例。 二、DockerFile 构建过程解析 Dockerfile 内容基础知识： 1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数。 2、指令按照从上到下，顺序执行。 3、#表示注释。 4、每条指令都会创建一个新的镜像层并对镜像进行提交。 Docker 执行 Dockerfile 的大致流程： 1、docker 从基础镜像运行一个容器 2、执行一条指令并对容器作出修改。 3、执行类似 docker commit 的操作提交一个新的镜像层。 4、docker 再基于刚提交的镜像运行一个新容器。 5、执行 dockerfile 中的下一条指令直到所有指令都执行完成。 总结： 从应用软件的角度来看，Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段。 Dockerfile 是软件的原材料。 Docker 镜像是软件的交付品。 Docker 容器则可以认为是软件镜像的运行态，也即依照镜像运行的容器实例。 Dockerfile面向开发，Docker 镜像成为交付标准，Docker 容器则涉及部署与运维，三者缺一不可，合力充当 Docker体系的基石。 1、Dockerfile，需要定义一个 Dockerfile，Dockerfile 定义了进程需要的一切东西。Dockerfile 涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道，这时需要考虑如何设计 namespace 的权限控制)等等; 2、Docker 镜像，在用 Dockerfile 定义一个文件之后，docker build 时会产生一个 Docker 镜像，当运行 Docker 镜像时会真正开始提供服务; 3、Docker 容器，容器是直接提供服务的。 三、DockerFile常用保留字指令 参考 tomcat8 的 dockerfile 入门：https://github.com/docker-library/tomcat 3.1、FROM 基础镜像，当前新镜像是基于哪个镜像的，指定一个已经存在的镜像作为模板，第一条必须是 from 。 3.2、MAINTAINER 镜像维护者的姓名和邮箱地址 3.3、RUN 容器构建时需要运行的命令。 两种格式： shell格式 RUN <命令行命令> # <命令行命令>等同于，在终端操作的shell命令。 RUN yum -y install vim exec格式 RUN ["可执行文件","参数1","参数2"] # 例如 # RUN ["./test.php","dev","offline"] 等价于 RUN ./test.php dev offline RUN是在 docker build 时运行。 3.4、EXPOSE 当前容器对外暴露出的端口。 3.5、WORKDIR 指定在创建容器后，终端默认登陆的进来工作目录，一个落脚点。 3.6、USER 指定该镜像以什么样的用户去执行，如果都不指定，默认是root。 3.7、ENV 用来在构建镜像过程中设置环境变量。 ENV MY_PATH /usr/mytest 这个环境变量可以在后续的任何 RUN 指令中使用，这就如同在命令前面指定了环境变量前缀一样； 也可以在其它指令中直接使用这些环境变量，比如：WORKDIR $MY_PATH。 3.8、ADD 将宿主机目录下的文件拷贝进镜像且会自动处理 URL 和解压 tar 压缩包。 3.9、COPY 类似 ADD，拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置 COPY src dest COPY ["src", "dest"] <src源路径>：源文件或者源目录 <dest目标路径>：容器内的指定路径，该路径不用事先建好，路径不存在的话，会自动创建。 3.10、VOLUME 容器数据卷，用于数据保存和持久化工作。 3.11、CMD 指定容器启动后的要干的事情。 CMD 容器启动命令 CMD 指令的格式和 RUN 相似，也是两种格式: shell 格式：CMD <命令> exec格式：CMD ["可执行文件"，"参数1"，"参数2"...] 参数列表格式：CMD ["参数1”，“参数2”..]。在指定了 ENTRYPOINT 指令后，用 CMD 指定具体的参数。 注意： Dockerfile 中可以有多个 CMD 指令，但只有最后一个生效，CMD 会被 docker run 之后的参数替换。 参考官网 Tomcat 的 dockerfile。 EXPOSE 8080 CMD ["catalina.sh", "run"] 演示自己的覆盖操作： docker run it -p 8080:8080 57800e5b1cbf /bin/bash 它和前面 RUN 命令的区别： CMD 是在 docker run 时运行。 RUN 是在 docker build 时运行。 3.12、ENTRYPOINT 也是用来指定一个容器启动时要运行的命令。 类似于 CMD 指令，但是 ENTRYPOINT 不会被 docker run 后面的命令覆盖， 而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。 命令格式和案例说明 命令格式： ENTRYPOINT ["<executeable>","<paraml>","<param2>",...] ENTRYPOINT 可以和 CMD 一起用，一般是变参才会使用 CMD ，这里的 CMD 等于是在给 ENTRYPOINT 传参。 当指定了 ENTRYPOINT 后，CMD 的含义就发生了变化，不再是直接运行其命令而是将 CMD 的内容作为参数传递给 ENTRYPOINT指令，他两个组合会变成： <ENTRYPOINT>"<CM>" 案例如下：假设已通过 Dockerfile 构建了 nginx:test 镜像： FROM nginx ENTRYPOINT ["nginx”, "-c"] #定参 CMD ["/etc/nginx/nginx.conf"] #变参 是否传参 按照dockerfile编写执行 传参运行 Docker命令 docker run nginx:test docker run nginx:test -c /etc/nginx/new.conf 衍生出的实际命令 nginx -c /etc/nginx/nginx.conf nginx -c /etc/nginx/new.conf 优点： 在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。 注意： 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令，仅最后一个生效。 总结： 四、案例 4.1、要求 Centos7 镜像具备 vim + ifconfig + jdk8 JDK 的下载镜像地址 官网： 下载地址： https://www.oracle.com/java/technologies/downloads/#java8 https://mirrors.yangxingzhen.com/jdk/ 4.2、编写 准备编写 Dockerfile 文件： vim Dockerfile 如下： FROM centos MAINTAINER zhuangpf<809566095@qq.com> ENV MYPATH /usr/local WORKDIR $MYPATH #安装vim编辑器 RUN yum -y install vim #安装ifconfig命令查看网络IP RUN yum -y install net-tools #安装java8及lib库 RUN yum -y install glibc.i686 RUN mkdir /usr/local/java #ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置 ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/ #配置java环境变量 ENV JAVA_HOME /usr/local/java/jdk1.8.0_171 ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH ENV PATH $JAVA_HOME/bin:$PATH EXPOSE 80 CMD echo $MYPATH CMD echo ">>>>> success ok" CMD /bin/bash 4.3、构建 docker build -t 新镜像名字:TAG . docker build -t centosjava8:1.5 . 注意，上面TAG后面有个空格，有个点 4.4、运行 docker run -it 新镜像名字:TAG docker run -it centosjava8:1.5 /bin/bash 4.5、再体会下UnionFS（联合文件系统） UnionFS（联合文件系统）：Union文件系统（UnionFS）是一种分层、轻量级并且高性能的文件系统，它支持对文件系统的修改作为一次提交来一层层的叠加，同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承，基于基础镜像（没有父镜像），可以制作各种具体的应用镜像。 4.6、虚悬镜像 仓库名、标签都是<none>的镜像，俗称 dangling image。 vim Dockerfile from ubuntu CMD echo 'action is success' 然后构建 docker build . 查看 docker image ls -f dangling=true 删除 docker image prune 删除所有未使用的镜像，是指当前未被任何容器使用的镜像。这包括： 悬空镜像：这些镜像没有任何标签（tag），并且没有被任何容器引用。 未被运行的容器使用的镜像：如果某个镜像没有被任何正在运行或已停止的容器使用，它将被视为未使用。 五、通过 IDEA 新建一个普通微服务模块 详见 docker_boot。 六、通过 dockerfile 发布微服务部署到 docker 容器 Dockerfile # 基础镜像使用java FROM java:8 # 作者 MAINTAINER zhuangpf # VOLUME 指定临时文件目录为/tmp，在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为docker_boot.jar ADD docker_boot-1.0-SNAPSHOT.jar docker_boot.jar # 运行jar包 RUN bash -c 'touch /docker_boot.jar' ENTRYPOINT ["java","-jar","/docker_boot.jar"] #暴露6001端口作为微服务 EXPOSE 6001 将微服务 jar 包和 Dockerfile 文件上传到同一个目录下。 构建镜像： docker build -t docker_boot:1.0 . 运行容器： docker run -d -p 6001:6001 docker_boot:1.0
一、问题 Docker 挂载主机目录访问如果出现 cannot open directory .: Permission denied 解决办法： 在挂载目录后多加一个 --privileged=true 参数即可。 如果是 CentOS7 安全模块会比之前系统版本加强，不安全的会先禁止，所以目录挂载的情况被默认为不安全的行为。 在 SELinux 里面挂载目录被禁止掉了，如果要开启，一般使用 --privileged=true 命令，扩大容器的权限解决挂载目录没有权限的问题，也即使用该参数，container 内的 root 拥有真正的 root 权限，否则，container 内的 root 只是外部的一个普通用户权限。 二、参数 -v docker run -d -p 5000:5000 -v /deploy/registry/:/var/lib/registry --privileged=true registry 默认情况下，仓库被创建再容器的 /var/lib/registry 目录下，建议自行用容器卷映射，方便于主机联调。 三、容器数据卷 卷就是目录或文件，存在于一个或多个容器中，由 docker 挂载到容器，但不属于联合文件系统，因此能够绕过 Union File System 提供一些用于持续存储或共享数据的特性： 卷的设计目的就是数据的持久化，完全独立于容器的生存周期，因此 Docker 不会在容器删除时删除其挂载的数据卷。 将 docker 容器内的数据保存进宿主机的磁盘中： 运行一个带有容器卷存储功能的容器实例 docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名 四、作用 将运用与运行的环境打包镜像，run 后形成容器实例运行，但是我们对数据的要求希望是持久化的。 Docker 容器产生的数据，如果不备份，那么当容器实例删除后，容器内的数据自然也就没有了。 为了能保存数据在 docker 中我们使用卷。 特点： 数据卷可在容器之间共享或重用数据。 卷中的更改可以直接实时生效。 数据卷中的更改不会包含在镜像的更新中。 数据卷的生命周期一直持续到没有容器使用它为止。 五、案例 5.1、宿主 vs 容器之间映射添加容器卷 命令： docker run -it -v /宿主机目录:/容器内目录 镜像名 /bin/bash docker run -it --name myu3 --privileged=true -v /tmp/myHostData:/tmp/myDockerData ubuntu /bin/bash 查看数据卷是否挂载成功： docker inspect 容器ID [root@docker130 ~]# docker inspect 99890896222b "Mounts": [ { "Type": "bind", "Source": "/tmp/myHostData", "Destination": "/tmp/myDockerData", "Mode": "", "RW": true, "Propagation": "rprivate" } ] 容器和宿主机之间数据共享 docker 修改，主机同步获得。 主机修改，docker 同步获得。 docker 容器stop，主机修改，docker 容器重启数据同步。 5.2、读写规则映射添加说明 读写(默认)rw rw = read + write ro = read only：此时如果宿主机写入内容，可以同步给容器内，容器可以读取到。 docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名 docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名 docker run -it --name myu3 --privileged=true -v /tmp/myHostData:/tmp/myDockerData:rw ubuntu /bin/bash 5.3、卷的继承和共享 1、容器1完成和宿主机的映射 docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu 2、容器2继承容器1的卷规则 docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu 六、Docker 卷 Docker 卷是一种用于持久化和共享容器数据的机制。它允许您将数据存储在宿主机的文件系统中，而不是仅仅存储在容器内部。这样，即使容器被删除或重新创建，数据仍然可以保留。 6.1、特点 持久性：卷的数据在容器生命周期之外存在，容器删除后数据仍然保留。 共享：多个容器可以挂载同一个卷，从而实现数据共享。 性能：卷的读写性能通常优于容器内部的文件系统，因为它们直接使用宿主机的文件系统。 管理：Docker 提供了命令来创建、列出、删除和管理卷，使得数据管理更加方便。 6.2、位置 在 Linux 系统上，Docker 卷默认存储在宿主机的以下位置： /var/lib/docker/volumes/ 在这个目录下，每个卷都有一个以卷名命名的子目录，实际的数据存储在该子目录的 _data 目录中。例如，如果您创建了一个名为 portainer_data 的卷，您可以在以下路径找到它： /var/lib/docker/volumes/portainer_data/_data/ 七、区别 7.1、Docker 卷 定义： Docker 卷是 Docker 提供的一种持久化存储机制，允许您将数据存储在宿主机的文件系统中。卷可以在多个容器之间共享，并且在容器删除后仍然存在。 管理： 卷是独立于容器的，可以通过 Docker 命令（如 docker volume create、docker volume ls 等）进行管理。 位置： 默认情况下，Docker 卷存储在宿主机的 /var/lib/docker/volumes/ 目录中。 用途： 适用于需要持久化和共享数据的场景，例如数据库、应用程序配置文件等。 7.2、容器数据卷 定义： 容器数据卷是指在创建容器时使用的卷，通常是通过 -v 或 --mount 选项将宿主机的目录或 Docker 卷挂载到容器内的特定路径。 管理： 容器数据卷的生命周期与容器相关联。如果容器被删除，挂载的容器数据卷（如果是匿名卷）可能会被删除，但如果是命名卷，则数据仍然保留。 位置： 容器数据卷可以是宿主机的目录（绑定挂载）或 Docker 卷（命名卷），具体取决于创建容器时的配置。 用途： 主要用于在容器内持久化数据，确保容器重启或更新时数据不会丢失。 7.3、-v 在 Docker 中，使用 -v 选项可以进行两种类型的挂载：绑定挂载（bind mount）和 命名卷（named volume）。这两种方式都可以使用 -v 选项，但它们的用法和目的有所不同。 1、绑定挂载（Bind Mount） 绑定挂载将宿主机的特定目录挂载到容器内的目录。使用 -v 选项时，需要指定宿主机的路径和容器内的路径，格式如下： docker run -v /宿主机路径:/容器路径 <镜像名> 例如： docker run -v /host/data:/container/data my-image 2、命名卷（Named Volume） 命名卷是 Docker 管理的卷，存储在 Docker 的默认位置（通常是 /var/lib/docker/volumes/）。使用 -v 选项时，只需指定卷的名称和容器内的路径，格式如下： docker run -v <卷名>:/容器路径 <镜像名> 例如： docker run -v my-volume:/container/data my-image