Docker Swarm + Portainer + Traefik搭建应用环境

3,869 阅读6分钟

操作系统均为centos8

介绍

基于docker swarm构建一套可以快速伸缩的应用系统。我们的系统并非是微服务架构,考虑到微服务需要的面对的挑战(分布式事务等)太多了,我们仅仅是多个单体服务,服务间的调用很少,服务间均衡负载使用docker的service实现。

构建目标

可视化管理集群,网关统一输出API,日志统一处理,存储统一处理,网关流量监控,故障转移。

准备工作

准备工作的内容需要为每台机器都执行一遍。

关闭防火墙

systemctl stop firewalld
systemctl disable firewalld

安全起见,生产环境建议保留防火墙,只开放需要的端口。

修改DNS

vi /etc/resolv.conf 

nameserver修改为114.114.114.114

修改Hostname

给每台机器重新设置一下hostname,node-1、node-2、…..node8
hostnamectl set-hostname node-1 --static

关闭selinux

vim /etc/selinux/config

1427DD6E-D3E2-4511-881D-E4BB30382788.png

#重启服务器
reboot 

安装docker-ce

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y yum-utils device-mapper-persistent-data lvm2
dnf makecache
dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
# centos8默认自带podman,因此会冲突,需要加上参数自动替换
dnf install docker-ce docker-ce-cli --allowerasing
# 验证一下是否安装成功
docker version
# 开机自启
systemctl enable docker

修改docker配置文件

vim /etc/docker/daemon.json 

配置内容:

{
    "registry-mirrors": [
        "https://docker.mirrors.ustc.edu.cn"
    ],
    "dns":["114.114.114.114"]
}

主要是加速docker镜像拉取。

资源划分

管理节点

管理节点必须是奇数个

  • 172.16.113.4
  • 172.16.113.5
  • 172.16.113.6

工作节点

  • 172.16.113.7
  • 172.16.113.8
  • 172.16.113.9

网关节点

  • 172.16.113.10
  • 172.16.113.11

运维节点

  • 172.16.113.12

初始化swarm集群

我们在172.16.113.4上执行初始化命令

docker swarm init --listen-addr 0.0.0.0:2377 --cert-expiry 87600h0m0s --task-history-limit 1

然后我们在每个工作节点、运维节点、网关节点上运行

# 该命令在初始化完成后会打印在控制台中,后续也可以在管理节点上执行docker swarm join-token worker来获取
docker swarm join --token SWMTKN-1-5ua3tzuqsglxry0kwb7tg3b2mtiqfg40dwt3na0zwa322tkdfn-03essdmekuv68m4s9l7kv6rud 172.16.113.4:2377

然后我们在剩下的每个管理节点上运行

# 在管理节点上运行docker swarm join-token manager来获取
docker swarm join --token SWMTKN-1-5ua3tzuqsglxry0kwb7tg3b2mtiqfg40dwt3na0zwa322tkdfn-c25ey7vpenvhz4glf8vegnj26 172.16.113.4:2377

验证集群

# 在管理节点上,应该列出6个节点
docker node ls

部署Portainer-ce

Portainer我们不需要安装成集群,我们安装到运维节点上。

创建网络

在运维节点上

docker network create \
 --driver overlay \
 --attachable \
 --subnet 10.12.0.0/24 \
 portainer_agent_network

安装portainer-ce

docker run -d \
-p 8000:8000 \
-p 9000:9000 \
--name=portainer \
--network=portainer_agent_network \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /data/portainer:/data \
portainer/portainer-ce

安装portainer-agent

docker service create \
    --name portainer_agent \
    --network portainer_agent_network \
    --mode global \
    --constraint 'node.platform.os == linux' \
    --mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
    --mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
    portainer/agent

配置portainer-ce

用浏览器打开运维节点IP:9000,登录完成后,如下配置即可。

8C6D4664-B7D5-4989-B14B-3D6F813A03FB.png

部署traefik网关

创建应用网络

在管理节点上运行

docker network create \
 --driver overlay \
 --attachable \
 --subnet 10.100.0.0/24 \
 application_net

创建配置文件

################################################################
#
# Configuration sample for Traefik v2.
#
# For Traefik v1: https://github.com/traefik/traefik/blob/v1.7/traefik.sample.toml
#
################################################################

################################################################
# Global configuration
################################################################
[global]
  checkNewVersion = true
  sendAnonymousUsage = true

################################################################
# Entrypoints configuration
################################################################

# Entrypoints definition
#
# Optional
# Default:
[entryPoints]
  [entryPoints.web]
    address = ":80"

  [entryPoints.websecure]
    address = ":443"

################################################################
# Traefik logs configuration
################################################################

# Traefik logs
# Enabled by default and log to stdout
#
# Optional
#
[log]

  # Log level
  #
  # Optional
  # Default: "ERROR"
  #
  # level = "DEBUG"

  # Sets the filepath for the traefik log. If not specified, stdout will be used.
  # Intermediate directories are created if necessary.
  #
  # Optional
  # Default: os.Stdout
  #
  filePath = "log/traefik.log"

  # Format is either "json" or "common".
  #
  # Optional
  # Default: "common"
  #
  # format = "json"

################################################################
# Access logs configuration
################################################################

# Enable access logs
# By default it will write to stdout and produce logs in the textual
# Common Log Format (CLF), extended with additional fields.
#
# Optional
#
[accessLog]

  # Sets the file path for the access log. If not specified, stdout will be used.
  # Intermediate directories are created if necessary.
  #
  # Optional
  # Default: os.Stdout
  #
  filePath = "/log/log.txt"

  # Format is either "json" or "common".
  #
  # Optional
  # Default: "common"
  #
  # format = "json"

################################################################
# API and dashboard configuration
################################################################

# Enable API and dashboard
[api]

  # Enable the API in insecure mode
  #
  # Optional
  # Default: false
  #
  insecure = true

  # Enabled Dashboard
  #
  # Optional
  # Default: true
  #
  dashboard = true

################################################################
# Ping configuration
################################################################

# Enable ping
[ping]

  # Name of the related entry point
  #
  # Optional
  # Default: "traefik"
  #
  # entryPoint = "traefik"

################################################################
# Docker configuration backend
################################################################

# Enable Docker configuration backend
[providers.docker]

  # Docker server endpoint. Can be a tcp or a unix socket endpoint.
  #
  # Required
  # Default: "unix:///var/run/docker.sock"
  #
  swarmMode = true
  endpoint = "ssh://root@172.16.113.4"
  network = "application_net"
  # Default host rule.
  #
  # Optional
  # Default: "Host(`{{ normalize .Name }}`)"
  #
  # defaultRule = "Host(`{{ normalize .Name }}.docker.localhost`)"

  # Expose containers by default in traefik
  #
  # Optional
  # Default: true
  #
  # exposedByDefault = false
  #
  #
#[metrics]
#  [metrics.influxDB] 
#    address = "influxdb:8089"
#    protocol = "udp"
#    database = "traefik"

注意:配置文件中的endpoint应该任意2个管理节点的ip,这里利用ssh保障docker access api的安全。

SSH免密登录配置

每个管理节点都需要支持ssh免密登录,然后把公钥存放到网关节点上,这样网关节点就不需要密码就能ssh到管理节点上。免密登录的配置请自己查资料了。

创建traefik容器

在2台网关节点上都要运行,创建2个网关入口,以保障高可用(可以使用keepalived来实现vIP漂移)。

docker run -d -p 81:8080 -p 80:80 \
-v /data/traefik/conf/traefik.toml:/etc/traefik/traefik.toml \
--name=traefik \
--network=application_net \
-v /root/.ssh:/root/.ssh \
traefik:v2.4.8

到这一步,portainer上应该可以看到运行traefik的容器了。

这步很关键!(安装ssh)

目前traefik其实还没正确连接到swarm集群。ok! 我们在portainer上进入traefik的容器,然后运行

apk update
apk add openssh

等待安装完成后,traefik就能自动连接上swarm集群,至此集群和网关就搭建完成了。

部署应用

这里使用nginx来充当应用。 在任何一台管理节点上运行

 docker service create \
 --replicas 10 \
 --publish 8080:80 \
 --network=application_net \
 --label="traefik.http.routers.nginx-service.rule=Host(\`nb.io\`)" \
 --label="traefik.http.services.nginx-service.loadbalancer.server.port=80" \
 --name nginx nginx

Host中的nb.io实际应该换成自己的域名,没有域名自己想办法吧,可以使用docker镜像sameersbn/bind搭建一个私有dns服务器。 等待完成后,我们可以在traefik的webUI上看到:

FA864325-45B7-437E-B4E1-427F24D394A4.png 现在你可以访问nb.io来访问nginx服务集群了。

约束应用部署的节点

现在在swarm集群中部署服务,服务的容器会跑到运维节点和网关节点,其实这不是我们想要的。

给节点打标签

在portainer的swarm菜单下为每个节点进行打标签,或者使用命令,该命令需要在管理节点执行

docker node update —label-add role=application node-1
docker node update —label-add role=application node-2
docker node update —label-add role=application node-3
docker node update —label-add role=application node-4
docker node update —label-add role=application node-5
docker node update —label-add role=application node-6
docker node update —label-add role=gateway node-7
docker node update —label-add role=gateway node-8
docker node update —label-add role=sys node-9

调整服务创建命令

 docker service create \
 --replicas 10 \
 --publish 8080:80 \
 --network=application_net \
 --constraint 'node.labels.role == application' \
 --label="traefik.http.routers.nginx-service.rule=Host(\`nb.io\`)" \
 --label="traefik.http.services.nginx-service.loadbalancer.server.port=80" \
 --name nginx nginx

现在应用服务只会部署在node-1到node-6节点了。

总结

部署的方式多种多样,traefik,portainer也可以以service的方式部署,这个还是看实际情况吧,这里是直接启容器的。