本人 Ghost 博客以及自建私有云 Nextcloud 均已经稳定运行了一年有余,期间经历过两次服务器迁移和屡次版本升级,均未发生过数据丢失和其余问题,在迁移过程当中也曾分享过如何将 Docker Volumes 安全的跨服务器迁移。目前博客和网盘服务分别搭建于两台服务器,并统一使用另外一台服务器做反代。web
在反代软件上,一直使用的都是 Nginx,最近在研究 K8s,也对比较流行的云原生反向代理工具 Traefik 产生了兴趣,因而便花了一点时间将反代服务器上的 Nginx 换成了 Traefik。必定要吐槽的一点是,Traefik 的官方文档写得实在太糟糕了,初次接触的用户,想经过只看官方文档把事情搞定,那是至关困难,因此我以为很是有必要分享一下,让其余初次使用的用户避免踩坑。docker
目前 Traefik 已经更新到了 2.1
版本,其 2.x
版本和 1.x
版本差别较大,本文天然将基于最新版本,新版本增长的自动配置 HTTPS 功能和 TCP 代理功能都十分有价值。apache
反向代理服务器的工做,天然就是截获服务器流量,并将流量转发至目标服务或地址,在这一基础上,若是转发的目标服务或地址是多个,就是负载均衡。Traefik 官方文档中的图片都是萌萌的,下面这张图就比较清晰的说明了 Traefik 或者说通常反代软件的功能:json
本人目前的需求比较简单,就是未来自于pbeta.me
和www.pbeta.me
的访问流量转发至 博客IP:博客端口
,未来自于cloud.pbeta.me
的访问流量转发至 网盘IP:端口
,另外,考虑到演示须要,本文将完成如下目标:api
在安装以前,我以为有必要讲一下 Traefik 这款工具的配置方式,搞清楚了基本的配置方式,在下面安装和配置的过程当中才能有清晰的思路,如下内容主要参考了官方文档中的Configuration Introduction 页面。安全
简单的说,Traefik 的配置包括静态配置和动态配置两种,前者是 Traefik 自身的配置,须要重启才能生效,后者则能够理解为被代理服务的配置,能够经过配置实现为即时生效。bash
若是配置内容不存在服务差别性,那就能够统一在静态配置中,不然就须要在动态配置中为每个服务中单独添加,动态配置中的多个服务也能够共用同一配置内容,好比能够配置一个basicAuth
的Middlewares
,由多个服务共用。服务器
不管静态配置仍是动态配置,都有两种配置方式:CLI
形式或者独立文件形式。网络
对于静态配置,一个是 Traefik 镜像启动时的启动参数,另外一个是单独的配置文件(如 traefik.yml
),官方文档提供示例时,也同时包括这两种形式,分别对应的是 CLI
和 File(YAML)
,不过在查看官方的配置示例时,你会发现还包括 File(TOML)
,TOML 文件是对 YAML 的一种改进,本文暂时都使用 YAML,读者能够自行转换。另外,官方文档中也说明了静态配置能够经过环境变量实现,本文暂不使用此方式。hexo
配置项的优先级为配置文件 > 命令行参数 > 环境变量,请注意配置文件与命令行参数是互斥的,若是你选择使用配置文件,就不能再使用命令行参数,最终的配置并不是两者的叠加。
而对于动态配置,能够选择直接在服务的 docker-compose
文件最下方经过 labels
实现,好比这样:
# yaml
whoami:
# A container that exposes an API to show its IP address
image: containous/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
复制代码
也能够写在单独的配置文件中,这一文件在 Traefik 中通常命名为 dynamic.yml
,你能够将全部路由配置写在此文件中,为了清晰起见,本文统一使用后一种方式。
经过上面的说明,咱们能够知道,在 Docker 中使用 Traefik 大体可能会涉及到三个文件:
再次重复一次,若是使用独立配置文件来存放静态配置,那么
docker-compose.yml
文件中的command
部分将不会生效。
有了以上的文件,如何加载呢?docker-compose.yml
中的配置天然没必要考虑这个问题,对于其余两个文件的加载则必需要绑定至容器。
当 Traefik 启动时,将会在如下位置搜索配置文件,名称能够是 traefik.toml、traefik.yml 或者 traefik.yaml:
另外,能够经过添加形式如 --configFile=foo/bar/myconfigfile.toml
的启动参数覆盖默认行为。
根据官方文档的以上描述,考虑到咱们是在 Docker 环境中运行 Traefik,因此建议将放置配置文件的目录绑定到容器的 /etc/traefik
目录便可。
动态配置文件的加载,则须要使用 Traefik 的 providers 启动参数,形式以下:
CLI
形式--providers.file.directory=/etc/traefik
--providers.file.filename=dynamic.yml
--providers.file.watch=true
复制代码
providers:
file:
directory: "/etc/traefik"
filename: "dynamic.yml"
watch: true
复制代码
这三行启动参数的含义很是容易理解,在官方文档中我没有注意到有默认目录,因此咱们必定须要指定目录,指定配置文件名,最后一行的watch=true
将开启动态配置项的即时生效,再也不须要重启容器。
与 traefik.yml
文件的加载相似,在 Docker 环境运行 Traefik 的状况下,咱们须要将存放 dynamic.yml
的目录绑定至容器的 /etc/traefik
目录,这里咱们使用了同一目录,这样就没必要分别绑定两个目录了。
经过以上的描述,读者应该基本明白了 Traefik 整个配置的运做方式,更加高级的用法能够自行研究官方文档。
咱们使用 Docker 安装 Traefik,下文将以官方文档中的相关示例为模板,修正其错误,完成初步配置及安装。
咱们使用的配置文件来自于官方文档中Docker-compose with let's encrypt: TLS Challenge,内容以下:
version: "3.3"
services:
traefik:
image: "traefik:v2.0.0-rc3"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
#- "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.mytlschallenge.acme.email=postmaster@mydomain.com"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
image: "containous/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.mydomain.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=mytlschallenge"
复制代码
官方文档中的这一示例,使用了 CLI
配置静态配置的方式,但其提供的这一示例主要存在如下几个问题:
下面咱们对其针对性的修改,另外为了清晰,咱们将示例中提供的 whoami
应用在后面做为单独应用运行。
根据前文对 Traefik 配置方式的讲解,咱们知道咱们既能够选择在 docker-compose.yml
文件中配置,也可使用独立的 traefik.yml
配置,本人建议使用独立的 traefik.yml
配置,下文也只提供这一种方式,熟悉了之后,读者能够自行切换。
静态配置里能够有哪些内容,能够参考官方文档
咱们的配置文件内容以下:
docker-compose.yml
文件version: "3.3"
services:
traefik:
image: "traefik:latest" # 咱们直接部署最新版本,可自行调整
container_name: "traefik"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
# 自动申请的证书存放位置,咱们须要在当前目录建立 letsencrypt 目录
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# 绑定咱们的配置目录
- "./config:/etc/traefik"
复制代码
./config/traefik.yml
文件providers:
docker: {}
file:
directory: "/etc/traefik"
filename: "dynamic.yml"
watch: true
log:
level: DEBUG
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
mytlschallenge:
acme:
email: "yourname@domain"
storage: "/letsencrypt/acme.json"
tlsChallenge: {}
api:
dashboard: true
复制代码
./config/dynamic.yml
文件因为咱们暂时不转发任何服务,此文件暂时为空。
启动咱们的 docker-compose.yml
文件:
docker-compose up -d
复制代码
稍等片刻,就能看到服务建立成功,使用 docker ps
查看,能够看到容器正常运行。
Traefik 的 Dashboard 其实是其 API 功能的图形化展现,因此咱们须要开启配置中的 API 参数和 Dashboard 参数,参考官方文档:
If you enable the API, a new special service named api@internal is created and can then be referenced in a router. And then define a routing configuration on Traefik itself with the dynamic configuration.
若是开启了 api
,就会建立一个叫作 api@internal
的服务,咱们上面所使用的 traefik.yml
配置中,已经打开了 api
,也打开了 dashboard
。
官方配置中有一行
- "--api.insecure=true"
被咱们无视掉了,有兴趣的朋友阅读这里。
而后按官方文档说明,为 Traefik 自身添加这一动态路由,因此咱们修改 dynamic.yml
文件:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.domain.com`)"
service: api@internal
复制代码
Rule 的配置除了
Host
还有Path
、PathPrefix
等,配置逻辑运算符来实现配置,具体能够查看这里。另外,记得将域名提早解析到服务器 IP,若是是本地虚拟机测试,请自行修改hosts
文件。
以后从新运行 docker-compose up -d
便可,此时访问绑定的域名就能看到 Traefik 的 Dashboard 了:
当咱们启动一个 Docker 服务后,Traefik 就能发现服务并为其建立默认路由,须要注意的一点是,若是 Traefik 要可以与新的 Docker 服务进行通讯,必须将其加入到同一网络,咱们使用 docker-compose.yml
启动 Traefik 时,就建立了 traefik_default
网络,新加入的容器须要手动加入该网络。
加入网络的方式不少,能够自行搜索,使用 docker run
时经过 --network traefik_default
,或者使用docker-compose.yml
时添加:
networks:
- traefik_default
复制代码
下面咱们使用 Traefik 提供的 whoami
应用进行测试,使用 docker run
启动应用:
docker run -d -P --name whoami --net traefik_default containous/whoami
复制代码
以后咱们查看 Dashboard,就会发现 Traefik 已经自动发现了服务,服务名为 whoami@docker
。下面咱们为该服务配置路由,打开咱们的 ./config/dynamic.yml
文件,在下方增长 whoami
路由配置内容:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
whoami:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
复制代码
配置完成并保存后,在 Dashboard 就能够看到新添加的路由了,此时咱们访问 http://traefik.pbeta.cn/whoami
就能访问到咱们的服务了:
你会发现咱们并无告诉要转发服务的哪一个端口,这是由于 Traefik 智能的进行了处理,若是服务只暴露一个端口,Traefik 就会自动选择该端口,但若是服务暴露多个端口,你必须手动指定,具体请参考官方文档。
咱们使用本机来模拟这一需求,在咱们的服务器上运行一个 Ghost 服务,可是并不加入 traefik_default
网络,而是在 Traefik 中经过 服务器互联网IP : 服务端口 来转发。
启动一个 Ghost 容器:
docker run -d -p 2368:2368 --name ghost ghost
复制代码
咱们暴露了服务器的 2368 端口,此时直接在外部访问 服务器IP:端口 就能访问到网站(若是你防火墙开放了 2368 端口的话)
下面咱们就配置 Traefik 将 traefik.pbeta.cn/ghost
转发至该地址,继续修改咱们的 dynamic.yml
,分别添加一个服务和一个路由,完整的 dynamic.yml
文件以下:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
whoami:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
ghost:
entryPoints:
- "web"
rule: "Host(`ghost.pbeta.cn`) "
service: ghost
services:
ghost:
loadBalancer:
servers:
- url: "http://47.74.154.202:2368/"
复制代码
保存以后访问 http://ghost.pbeta.cn
便可打开咱们刚启动的 Ghost 网站:
前面咱们一直使用的是 web
这一入口,经过简单配置便可实现 HTTPS 访问服务。官方文相关页面有较多示例,可供参考。本文将只讲解使用 Let's Encrypt 自动配置 HTTPS。
前面提供的 traefik.yml
中已经包括了相关的配置:
certificatesResolvers:
mytlschallenge:
acme:
email: "yourname@domain"
storage: "/letsencrypt/acme.json"
tlsChallenge: {}
复制代码
咱们为这一 certificatesRsolver
命名为了 mytlschallenge
,以后在路由配置中添加 tls
部分使用该 resolver
便可,因此咱们打开 dynamic.yml
,进行编辑,为服务额外添加一条路由配置:
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
tls:
certResolver: "mytlschallenge"
复制代码
保存以后稍等片刻,就已经配置好了 HTTPS:
能够在多个网站使用同一个 certificatesResolver
,但为了不冲突,支持经过 option
来进行区分,一个完整的配置示例以下:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
tls:
certResolver: "mytlschallenge"
options: traefik
whoami:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
whoami-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
tls:
certResolver: "mytlschallenge"
options: traefik
ghost:
entryPoints:
- "web"
rule: "Host(`ghost.pbeta.cn`)"
service: ghost
ghost-tls:
entryPoints:
- "websecure"
rule: "Host(`ghost.pbeta.cn`)"
service: ghost
tls:
certResolver: "mytlschallenge"
options: ghost
services:
ghost:
loadBalancer:
servers:
- url: "http://47.74.154.202:2368/"
tls:
options:
traefik: {}
ghost: {}
复制代码
这样咱们的三个路由的 HTTPS 访问都就配置好了,你能够注意到咱们使用了2个 options
,由于 traefik.pbeta.cn
和 ghost.pbeta.cn
须要不一样的证书,因此必须以此进行区分,options
中也能够自行根据文档说明自行添加配置内容。
Traefik 提供了很是多的中间件,这些中间件能实现你须要的大部分功能,这里分别以简单权限认证和 HTTP 自动跳转 HTTPS 为例进行介绍。
为了不配置文件过长,下面只以 Dashboard 进行示例。
Middlewares 的使用很是简单,在动态配置文件中的 http
(或tcp
)下添加 middlewares
,以后在每个路由中使用便可,咱们添加一个自动跳转 HTTPS 的 Middleware:
middlewares:
redirect:
redirectScheme:
scheme: https
复制代码
以后咱们在以 web
为入口的服务添加这一 middleware
:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
middlewares:
- redirect
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
tls:
certResolver: "mytlschallenge"
options: traefik
middlewares:
redirect:
redirectScheme:
scheme: https
tls:
options:
traefik: {}
复制代码
保存文件以后,访问 http://traefik.pbeta.cn
将会自动跳转至 https://traefik.pbeta.cn
。
这里须要使用的中间件是 BasicAuth,具体的使用方式能够参阅官方文档。
在 K8s 中咱们使用 Secret 资源来管理密码等,但在 Docker 中没法经过这种方式,须要使用 users
或者 usersFile
参数管理密码,这里咱们使用 users
。
密码的建立须要借助于 htpasswd
,安装方式以下:
yum -y install httpd-tools
复制代码
apt install apache2-utils
复制代码
咱们使用 htpasswd
命令来生成一用户名为test 密码 为test1234 的密码对:
echo $(htpasswd -nb test test1234)
复制代码
获得的信息是 test:$apr1$k.xiBHjv$VdavfNvly69vNZvkKpB2j0
。
须要注意一点,因为咱们是在单独配置文件中使用,因此无须进行转义,若是是以
CLI
形式使用的话,全部$
符号必须写两次,可使用官方文档中的命令来生成转义后的密码echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
下面咱们就使用此密码对来建立咱们的 BasicAuth Middleware,打开 dynamic.yml
文件进行修改,在上面建立的 redirect
下添加以下内容:
test-auth:
basicAuth:
users:
- "test:$apr1$k.xiBHjv$VdavfNvly69vNZvkKpB2j0"
复制代码
以后在前面的路由下的 middlewares
下添加 test-auth
,完整的 dynamic.yml
文件以下:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
middlewares:
- redirect
- test-auth
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
middlewares:
- test-auth
tls:
certResolver: "mytlschallenge"
options: traefik
middlewares:
redirect:
redirectScheme:
scheme: https
test-auth:
basicAuth:
users:
- "test:$apr1$k.xiBHjv$VdavfNvly69vNZvkKpB2j0"
tls:
options:
traefik: {}
复制代码
保存文件后,再次访问 http://traefik.pbeta.cn
,就会发现须要密码登陆了:
输入密码后便可正常访问。
经过以上内容,咱们对 Traefik 的配置方式有了比较深刻的了解,并实现了咱们的目标,Traefik 的官方文档虽然杂乱,但不失详尽,有了本文提供的基础知识,再结合官方文档,使用 Traefik 实现各类高级功能应该并不是难事。
在配置过程当中遇到任何问题,能够在评论区中提问,本人将尽力协助。