前言
本人 Ghost 博客以及自建私有云 Nextcloud 均已经稳定运行了一年有余,期间经历过两次服务器迁移和多次版本升级,均未发生过数据丢失和其他问题,在迁移过程中也曾分享过如何将 Docker Volumes 安全的跨服务器迁移。目前博客和网盘服务分别搭建于两台服务器,并统一使用另一台服务器作反代。
在反代软件上,一直使用的都是 Nginx,最近在研究 K8s,也对比较流行的云原生反向代理工具 Traefik 产生了兴趣,于是便花了一点时间将反代服务器上的 Nginx 换成了 Traefik。一定要吐槽的一点是,Traefik 的官方文档写得实在太糟糕了,初次接触的用户,想通过只看官方文档把事情搞定,那是相当困难,所以我觉得非常有必要分享一下,让其他初次使用的用户避免踩坑。
目前 Traefik 已经更新到了 2.1
版本,其 2.x
版本和 1.x
版本差异较大,本文自然将基于最新版本,新版本增加的自动配置 HTTPS 功能和 TCP 代理功能都十分有价值。
主要目标
反向代理服务器的工作,自然就是截获服务器流量,并将流量转发至目标服务或地址,在这一基础上,如果转发的目标服务或地址是多个,就是负载均衡。Traefik 官方文档中的图片都是萌萌的,下面这张图就比较清晰的说明了 Traefik 或者说一般反代软件的功能:
本人目前的需求比较简单,就是将来自于pbeta.me
和www.pbeta.me
的访问流量转发至 博客IP:博客端口
,将来自于cloud.pbeta.me
的访问流量转发至 网盘IP:端口
,另外,考虑到演示需要,本文将完成以下目标:
- 域名访问 Traefik Dashboard
- 将域名访问转发至 外部IP:端口
- 将域名访问转发至 Docker 服务
- 配置 HTTPS 访问(使用 LetsEncrypt)
- 使用 Middlewares 实现 HTTP 访问自动跳转 HTTPS
- 使用 Middlewares 为 Traefik Dashboard 增加密码验证
Traefik 配置说明
在安装之前,我觉得有必要讲一下 Traefik 这款工具的配置方式,搞清楚了基本的配置方式,在下面安装和配置的过程中才能有清晰的思路,以下内容主要参考了官方文档中的Configuration Introduction 页面。
配置类型
简单的说,Traefik 的配置包括静态配置和动态配置两种,前者是 Traefik 自身的配置,需要重启才能生效,后者则可以理解为被代理服务的配置,可以通过配置实现为即时生效。
如果配置内容不存在服务差异性,那就可以统一在静态配置中,否则就需要在动态配置中为每一个服务中单独添加,动态配置中的多个服务也可以共用同一配置内容,比如可以配置一个basicAuth
的Middlewares
,由多个服务共用。
配置内容位置
无论静态配置还是动态配置,都有两种配置方式:CLI
形式或者独立文件形式。
对于静态配置,一个是 Traefik 镜像启动时的启动参数,另一个是单独的配置文件(如 traefik.yml
),官方文档提供示例时,也同时包括这两种形式,分别对应的是 CLI
和 File(YAML)
,不过在查看官方的配置示例时,你会发现还包括 File(TOML)
,TOML 文件是对 YAML 的一种改进,本文暂时都使用 YAML,读者可以自行转换。另外,官方文档中也说明了静态配置可以通过环境变量实现,本文暂不使用此方式。
配置项的优先级为配置文件 > 命令行参数 > 环境变量,请注意配置文件与命令行参数是互斥的,如果你选择使用配置文件,就不能再使用命令行参数,最终的配置并非二者的叠加。
而对于动态配置,可以选择直接在服务的 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
- traefik.yml(可选)
- dynamic.yml
再次重复一次,如果使用独立配置文件来存放静态配置,那么
docker-compose.yml
文件中的command
部分将不会生效。
有了以上的文件,如何加载呢?docker-compose.yml
中的配置自然不必考虑这个问题,对于其他两个文件的加载则必须要绑定至容器。
traefik.yml 文件的加载
当 Traefik 启动时,将会在以下位置搜索配置文件,名称可以是 traefik.toml、traefik.yml 或者 traefik.yaml:
- /etc/traefik/
- $XDG_CONFIG_HOME/
- $HOME/.config/
- . (the working directory).
另外,可以通过添加形式如 --configFile=foo/bar/myconfigfile.toml
的启动参数覆盖默认行为。
根据官方文档的以上描述,考虑到我们是在 Docker 环境中运行 Traefik,所以建议将放置配置文件的目录绑定到容器的 /etc/traefik
目录即可。
dynamic.yml 文件的加载
动态配置文件的加载,则需要使用 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 整个配置的运作方式,更加高级的用法可以自行研究官方文档。
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
配置静态配置的方式,但其提供的这一示例主要存在以下几个问题:
- 缺少 80 端口绑定,只能使用 HTTPS
- 没有开启 Dashboard
- 没有绑定动态配置文件目录
下面我们对其针对性的修改,另外为了清晰,我们将示例中提供的 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
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 服务
当我们启动一个 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 网站:
配置 HTTPS 访问
前面我们一直使用的是 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
中也可以自行根据文档说明自行添加配置内容。
使用 Middlewares
Traefik 提供了非常多的中间件,这些中间件能实现你需要的大部分功能,这里分别以简单权限认证和 HTTP 自动跳转 HTTPS 为例进行介绍。
为了避免配置文件过长,下面只以 Dashboard 进行示例。
实现自动跳转 HTTPS
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
,安装方式如下:
- CentOS
yum -y install httpd-tools
- Ubuntu
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 实现各种高级功能应该并非难事。
在配置过程中遇到任何问题,可以在评论区中提问,本人将尽力协助。
参考文档
今天的文章更好的反向代理工具 Traefik 配置入门——Docker 篇分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16842.html