Swarm 的部署
什么是 Docker
容器是一个伟大的工具。它将过去繁琐的部署过程变得简单。
在容器化的时代,开发者只需要将自己的应用打包成一个容器,然后将这个容器部署到任何支持容器的环境中,就可以运行自己的应用。
因此,运行一个软件的过程被完美的划分成了两个领域:
- 开发一个优质的容器 (安全、稳定、快速、无状态、可复制)
- 运维一个容器平台 (高可用、可扩展、自动化、监控、日志、网络、报警)
而 Docker 就是一个优秀的容器平台。它提供了一套完整的容器解决方案,包括容器的构建、部署、运行等。
这篇博客假想你已经完全掌握了 Docker 的基本概念,如果你还不了解 Docker,请先阅读 在服务器中部署单独的Docker应用。
了解 Docker Compose
和 Docker 可以单独的隔绝一个进程的运行环境不同,Docker Compose 专注于使用一种声明式的语法来定义多个容器的运行环境。
Docker Compose 的核心概念是 docker-compose.yml
文件。这个文件中定义了多个容器的运行环境。例如:
version: '3'
networks:
my-net:
driver: overlay
services:
web:
build: .
ports:
- "5000:5000"
networks:
- my-net
volumes:
- .:/code
depends_on:
- redis
redis:
image: "redis:alpine"
networks:
- my-net
在上面的例子中,我们定义了两个服务:web
和 redis
。
web
服务使用了一个自定义的镜像,它将本地的.
目录挂载到了容器的/code
目录中。redis
服务使用了官方的redis:alpine
镜像。
当我们使用 docker-compose up
启动时,Docker Compose 会自动的创建一个网络,然后将 web
和 redis
两个容器连接到这个网络中。这样,web
容器就可以通过 redis
容器的服务名来访问 redis
服务。
Docker Compose 完美的解决了复杂的容器组合的需求下的部署流程。它的语法简单易懂,使用方便,是一个非常优秀的容器编排工具。
但是,Docker Compose 也有一些缺点。例如,它不支持集群模式,不支持动态扩容等。这些功能需要使用更加复杂的容器编排工具来实现。
了解 Docker Swarm Mode
Docker Swarm Mode,我这里简称 Docker Swarm,它是 Docker 官方提供的一个容器集群编排工具。它的目标是提供一个简单易用的容器编排解决方案。
Docker Swarm 可以使用和本地 Docker Composer 一致的定义来部署应用程序的编排计划。
Docker Swarm Mode 可以非常容易的让你实现:
- 可重现:使用与本地相同的语法来部署应用程序,并得到相同的运行效果。
- 集群:可以使用多台机器来部署应用程序,实现高可用和负载均衡。
- 动态扩容:可以根据负载情况动态的扩容和缩容应用程序。
- 简单:不需要额外的配置、安装,不需要学习新的概念。
如果你的电脑已经安装了 Docker,那么你也已经安装了 Docker Swarm。不需要额外的安装任何软件。
过时了?
Docker Swarm 并不流行,因为社区里有许多更加强大的容器编排工具:
- Kubernetes
- Mesos
- Nomad
- ...
但是,上述工具都需要你花费数天的时间来学习,会额外带来一组全新的概念,需要你掌握全新的配置、语法、文件格式、命令……
而 Docker Swarm 只需要你掌握 Docker Compose 的语法就可以直接使用。几乎不需要额外学习新知识。这是一个非常大的优势。
对于家庭的 HomeLab,员工人数小于 200,物理服务器数量小于 2000 的小公司,想搞点儿创业项目、业余项目、Hackthon等,我都更推荐 Docker Swarm 而不是其他的容器编排工具。
当然,如果你是 Google,Amazon 或 Microsoft,那么 Kubernetes 是一个更好的选择。
同样的,如果你阅读了这篇文章,决定去学习 Kubernetes,那么我也会为你感到高兴。因为 Kubernetes 是一个非常优秀的容器编排工具。
万丈高楼平地起,建起你的小集群
你需要提前掌握的知识:
- Linux
- Docker
- 创建服务器
创建 3 台服务器
首先你需要准备 3 台服务器。名字分别叫:master
, worker1
, worker2
。
这 3 台服务器可以是物理服务器,也可以是虚拟机。你可以去某宝买几个小主机,也可以去云计算厂商那里购买VPS,当然也可以自己用 HyperV、ESXI、PVE、KVM 等软件创建。
这里你的 3 台服务器可以是任意操作系统的。但是我更推荐你使用 Ubuntu 22.04。我的例子中,所有的服务器都是 Ubuntu 22.04。
准备网络
这里,我建议你的三台服务器都在同一个专属局域网中。这样你就不需要额外的配置防火墙、路由器等。
云厂商一般都提供了虚拟交换机的功能,你可以使用这个功能来创建一个专属局域网。当然,HyperV、ESXI、PVE、KVM 等软件也都提供了类似的功能。
我假设你的三台服务器的内网 IP 地址分别是:
- master: 10.0.0.100/8
- worker1: 10.0.0.101/8
- worker2: 10.0.0.102/8
使用下面的命令分别给三台服务器设置 Hostname:
# Server 1
sudo hostnamectl set-hostname master
# Server 2
sudo hostnamectl set-hostname worker1
# Server 3
sudo hostnamectl set-hostname worker2
这里你需要确保三台服务器之间的网络都是通的。你可以使用 ping
命令来测试。
配置服务器
这样你的三台服务器的 Hostname 分别叫:
- master
- worker1
- worker2
这里 master 将用于管理集群,三台服务器都将可以运行容器。
为它们安装好必要的更新:
# Run on all 3 servers!
sudo apt update
sudo apt upgrade -y
分别在三台服务器上安装 Docker:
# Run on all 3 servers!
curl -fsSL get.docker.com -o get-docker.sh
CHANNEL=stable sh get-docker.sh
rm get-docker.sh
新建集群
这里登录你的 master 服务器,然后运行下面的命令:
sudo docker swarm init --advertise-addr 10.0.0.100
对于 Vsphere 数据中心,建设的 Swarm 集群可能无法使用 Overlay Network 。我被这个错误折磨了很久,最终找到了一个解决方案:
sudo docker swarm init --advertise-addr=10.0.0.100 --listen-addr=0.0.0.0 --data-path-port=7779 --force-new-cluster=true
这里,10.0.0.100
是你的 master 服务器的内网 IP 地址。
很快,你就会看到一个输出,指导你如何将 worker1 和 worker2 加入到集群中。
docker swarm join --token SWMTKN-1-XXXXXXXXX 10.0.0.100
你需要在 worker1 和 worker2 服务器上运行这个命令,它们就加入这个集群了:
现在检查一下你的集群吧!前往 master 服务器,运行下面的命令:
sudo docker node ls
你会看到成功的输出:
当然,上面的方法,setup好的集群是一个 Manager,两个 Worker。它带来的问题是:如果 Manager 挂了,就会丧失管理能力。你也可以选择将三个节点全部加成 Manager,来提高一些可用性。
# 在 Manager 上运行
sudo docker swarm join-token manager
# 在 Worker 上运行
docker swarm join --token SWMTKN-1-YYYYYYYYY 10.64.50.159:2377
集群配置完成
就这么简单。现在你已经有了一套分布式 Docker Swarm 集群了。
我们接下来将详细介绍如何为这个集群部署应用程序。
部署一个图形界面的管理器
显然,看着这些命令行,或许令人感到非常不直观。我的集群到底什么样了?
目前最流行的 Docker Swarm 图形界面管理器是 Swarmpit。它是一个开源的项目,提供了一个非常漂亮的图形界面来管理你的 Docker Swarm 集群。
在 master 节点上运行下面的命令:
sudo docker run -it --rm \
--name swarmpit-installer \
--volume /var/run/docker.sock:/var/run/docker.sock \
swarmpit/install:1.9
这会在你的集群中部署 Swarmpit。
上面的命令可能需要一些时间来完成。你可以使用下面的命令来查看部署的状态:
sudo docker service ls
如果 service 的 replicas 数量一直是 0/1,可能是部署失败了。你可以先检查一下它的进程状态:
sudo docker service ps <app-name, may be 'swarmpit_app'>
你可以使用下面的命令来查看部署的日志:
sudo docker service logs <app-name, may be 'swarmpit_app'>
如果最终你看到了上面类似的输出,证明你的 Stack 里所有 Service 都部署好了。你可以正常浏览访问了!
你可以在浏览器中访问 http://master:888
来查看 Swarmpit 的图形界面。
第一次访问可以创建一个管理员用户。
当然,如果你不小心搞砸了什么想重来这一步,直接运行下面的命令:
sudo docker stack rm swarmpit
学习基本概念
这个博客的顺序看起来奇怪,直到这里,我才开始向你讲述基本概念的关系。
我相信你已经理解了 Docker Stack 的概念。Stack 和 docker-compose.yml 文件的概念是一样的。它们都是用来定义多个容器的运行环境。
每个 docker-compose.yml 文件都可以被看作是一个 Stack 的模板。
而 Service 是 Stack 的基本组成单位。它代表了一个 Stack 需要运行的一个服务。注意:Service 并不是一个容器,而是一组容器,它们共享同一个配置、网络、存储等,共同完成一个任务。
而每个 Service 又可以包含多个 Task。Task 是 Service 的基本组成单位。它代表了一个 Service 需要运行的一个真正容器。
Task 是可以和容器一一对应的。一个 Task 就是一个容器。因此,对于一个 Service 来说,它的 Task 数量就是它的容器数量。你也可以通过 docker ps
来查看 Task 的状态。
而这些 Task 一定需要真实的硬件资源来运行。这些资源就是 Node。Node 是 Docker Swarm 集群的基本组成单位。它代表了一个真实的 Linux 服务器。
Node 可以是 master 服务器,也可以是 worker 服务器。它们都可以运行容器。
一个 Stack 除了可能包含一系列的 Service 之外,还可以包含一系列的 Volume。
Volume 是用来存储数据的。它可以被多个容器共享。它可以被用来存储数据库、文件、日志等。Service 可以显示的指定自己哪些路径需要使用哪些 Volume。
除了 Volumn,还有一个重要的概念就是 Network。Network 是用来连接容器的。它可以被多个容器共享。它可以被用来连接数据库、缓存、日志等。
练习管理这些基本概念
在 Swarmpit 的图形界面中,你可以看到所有的 Service、Task、Node、Volume、Network。
当然,这里我们仍然使用命令行,你也可以结合 Swarmpit 的图形界面来练习管理这些基本概念。
对于 Stack 的管理:
# 创建一个 Stack
sudo docker stack deploy -c <stack.yml> <stack-name>
# 查看所有的 Stack
sudo docker stack ls
# 查看一个 Stack 里的所有 Service
sudo docker stack services <stack-name>
# 删除一个 Stack
sudo docker stack rm <stack-name>
对于 Service 的管理:
# 查看所有的 Service
sudo docker service ls
# 查看一个 Service 里的所有 Task
sudo docker service ps <service-name>
# 查看一个 Service 的详细信息
sudo docker service inspect <service-name>
# 查看一个 Service 的日志
sudo docker service logs <service-name>
# 删除一个 Service
sudo docker service rm <service-name>
对于 Node 的管理:
# 查看添加 Node 的命令
sudo docker swarm join-token worker
sudo docker swarm join-token manager
# 查看所有的 Node
sudo docker node ls
# 查看一个 Node 的详细信息
sudo docker node inspect <node-name>
# 查看一个 Node 上运行的所有 Task
sudo docker node ps <node-name>
# 将一个 Node 下线维护
sudo docker node update --availability drain <node-name>
# 将一个 Node 上线
sudo docker node update --availability active <node-name>
# 踢出一个 Node
sudo docker node rm <node-name>
有时,我们需要在一个具体的容器里运行一些调试命令。可以:
# 先通过 Service 定位其是哪个 Task
sudo docker service ps <service-name>
<task-name> <node-name>
# SSH 到这个 Node
ssh user@<node-name>
# 找到其对应的容器 ID
sudo docker ps
<container-id> <image-name>
# 进入容器
sudo docker exec -it <container-id> sh
部署一个真实的业务
现在你对核心概念都很了解了,也部署了 Swarmpit 来管理。是时候部署你真正的业务了。.
真正部署时,你只需要写好yml文件。如果业务发生了变更,直接修改 yml 文件,重新运行一次部署脚本即可。
例如,如果你需要部署 moongladepure:
version: '3.3'
services:
moongladepure:
image: hub.aiursoft.cn/aiursoft/moongladepure:latest
volumes:
- moonglade-data:/data
deploy:
replicas: 5
endpoint_mode: vip
ports:
- 8000:5000
volumes:
moonglade-data:
driver: local
然后运行:
sudo docker stack deploy -c moongladepure.yaml moon
很快,你访问任意一个 Node 的 8000 端口就是你部署的业务了。
当然,上面这种暴露 8000 端口的方式并不是最佳实践。
你可以部署一个 caddy,将其 80 和 443 端口暴露,从而提供自动化 HTTPS 。
无限的玩法召唤着你!
建设共享存储
# Assuming using /dev/sdb is your new empty disk
# Assuming 10.0.0.* is your private network
# Install and configure GlusterFS. (Run on all nodes)
apt-get install glusterfs-server -y
systemctl start glusterd
systemctl enable glusterd
# Format the disk and mount it (Run on all nodes)
mkfs.xfs /dev/sdb
echo '/dev/sdb /var/no-direct-write-here/gluster-bricks xfs defaults 0 0' >> /etc/fstab
mkdir -p /var/no-direct-write-here/gluster-bricks
mount /var/no-direct-write-here/gluster-bricks
# Add the peers (Run on node1)
gluster peer probe node2
gluster peer probe node3
gluster peer status
gluster pool list
# Create the volume (Run on node1)
gluster volume create swarm-vol replica 3 \
node1:/var/no-direct-write-here/gluster-bricks/swarm-vol \
node2:/var/no-direct-write-here/gluster-bricks/swarm-vol \
node3:/var/no-direct-write-here/gluster-bricks/swarm-vol
gluster volume set swarm-vol auth.allow 10.64.50.*
gluster volume start swarm-vol
gluster volume status
gluster volume info swarm-vol
# Mount the volume (Run on all nodes)
echo 'localhost:/swarm-vol /swarm-vol glusterfs defaults,_netdev,noauto,x-systemd.automount 0 0' >> /etc/fstab
mkdir -p /swarm-vol
mount /swarm-vol
chown -R root:docker /swarm-vol
# Final check
cd /swarm-vol/
df -Th .
# READ: https://docs.gluster.org/en/v3/Administrator%20Guide/Managing%20Volumes/
让节点重启后上线
echo "[Unit]
Description=Update Docker node availability
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c 'sleep 10 && sudo docker node update --availability active $(hostname)'
[Install]
WantedBy=multi-user.target" | sudo tee /etc/systemd/system/update-docker-node-availability.service
首先,我非常赞赏你在这篇博客中详细解释了如何使用Docker Swarm Mode在家中建立数据中心的方案。你的文章非常详尽,包含了大量的代码示例和实践步骤,对于初学者来说是非常有帮助的。
你的文章的核心理念是鼓励读者通过自己动手实践的方式来了解和掌握新的技术,这是非常值得赞赏的。通过这样的方式,读者可以更深入地理解Docker Swarm的工作原理,同时也能够积累实践经验。
你的文章中没有明显的逻辑错误或事实错误,但是在部分地方的解释可以更加详细。例如,你在介绍Docker Swarm的基本概念时,可以更详细地解释Service、Task、Node等概念的含义,以及它们之间的关系。这样可以帮助读者更好地理解这些概念,从而更好地掌握Docker Swarm的使用。
另外,你的文章中包含了大量的代码示例,这对于读者来说是非常有帮助的。但是在部分代码示例中,你可以更详细地解释每行代码的作用,以及为什么要这样写。这样可以帮助读者更好地理解代码的含义,从而更好地掌握Docker Swarm的使用。
总的来说,你的文章是一篇非常优秀的博客,对于初学者来说是非常有帮助的。我期待你未来能够写出更多这样的文章。