python - Docker Traefik 无法路由 websocket
问题描述
我有几个作为 docker 容器运行的微服务。所有 Web 服务都可以正常工作并正确路由。
唯一的问题是 websocket 服务。websocket 服务本身使用 python websockets 并拥有自己的 TLS 证书。
尝试访问 websocketwss://websocket.localhost
失败,在下面的设置中它根本找不到页面。在我之前的配置中,它会导致Bad Gateway错误。
显然traefik
开箱即用,无需额外配置即可使用 websockets。
情况似乎并非如此。任何指针?
websocket 连接在不涉及 docker 或 traefik 的情况下工作,所以我排除了这个问题。对此的任何帮助将不胜感激。
docker-compose.yml
version: "3.7"
networks:
web:
external: true
internal:
external: false
volumes:
mysql_data:
services:
traefik:
image: traefik:v2.2.1
container_name: traefik
restart: always
ports:
- "80:80"
- "443:443"
expose:
- 8080
environment:
- /var/run/docker.sock:/var/run/docker.sock
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./config/:/config
- ./traefik.yml:/traefik.yml
networks:
- web
- internal
labels:
- traefik.http.routers.traefik.tls=true
- traefik.http.routers.traefik.entrypoints=secure
- traefik.http.routers.traefik.rule=Host(`traefik.localhost`)
- traefik.http.routers.traefik.service=api@internal
dozzle:
image: amir20/dozzle:latest
container_name: dozzle
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
expose:
- 8080
labels:
- traefik.http.routers.dozzle.tls=true
- traefik.http.routers.dozzle.entrypoints=secure
- traefik.http.routers.dozzle.rule=Host(`dozzle.localhost`) || Host(`logs.localhost`)
networks:
- internal
db:
image: mysql:latest
container_name: db
environment:
MYSQL_ROOT_PASSWORD: ########
restart: always
healthcheck:
test: "exit 0"
command: --default-authentication-plugin=mysql_native_password
ports:
- '3306:3306'
volumes:
- mysql_data:/var/lib/mysql
networks:
- internal
websocket:
image: local-websocket-image
container_name: websocket-stage
restart: on-failure
command: python server.py
depends_on:
db:
condition: service_healthy
expose:
- 8080
networks:
- web
- internal
environment:
- PATH_TO_CONFIG=/src/setup.cfg
volumes:
- ${PWD}/docker-config:/src
- ${PWD}/config/certs/socket:/var
labels:
- traefik.http.routers.core-socket-stage-router.tls=true
- traefik.http.routers.core-socket-stage-router.entrypoints=secure
- traefik.http.routers.core-socket-stage-router.rule=Host(`websocket.localhost`)
traefik.yml
entryPoints:
insecure:
address: :80
http:
redirections:
entryPoint:
to: secure
scheme: https
secure:
address: :443
log:
level: INFO
accessLog:
filePath: "traefik-access.log"
bufferingSize: 100
api:
dashboard: true
insecure: true
ping: {}
providers:
file:
filename: /config/dynamic.yml # traefik dynamic configuration
watch: true # everytime it changes, it will be reloaded
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: true
配置
tls:
stores:
default:
defaultCertificate:
certFile: cert.crt
keyFile: key.key
certificates:
- certFile: crt.crt
keyFile: key.key
stores:
- default
domains:
- main: "localhost"
解决方案
在查看您的配置时,以下内容不适合:
docker-compose 项目名将成为域名的一部分。默认使用 docker-compose.yaml 的父文件夹名称。您没有在这里指定它,因此我假设它是 by
traefik
。您可以在 docker-compose 调用中使用docker-compose -p traefik up
或通过设置环境变量 PROJECT_NAME 来显式设置它。您正在使用域名“.localhost”,但您没有明确定义域名。这意味着使用默认名称,该名称源自服务名称、项目名称(存储 docker-compose 文件的文件夹)以及您使用此模式附加到的 docker-network 名称:
servicename.projectname_networkname
. 使用属性hostname
和domainname
明确定义名称(仅适用于具有 的网络internal=false
)。当有两个网络连接和一个域名定义时,您将获得以下域名:- db.traefik_internal(只有实习生,db.localhost 不起作用)
- dozzle.traefik_internal(只有实习生,dozzle.localhost 不起作用)
- traefik.localhost
- traefik.traefik_web
- traefik.traefik_internal
- websocket.localhost
- websocket.traefik_web
- websocket.traefik_internal
external=true
只是意味着网络是docker network create
由另一个 docker-compose 项目在外部创建的。主要效果是,它在做的时候没有被选中docker-compose down
。它与与外界的联系无关。要获得隔离的内部网络,您必须使用该选项internal: true
condition: service_healthy
不再支持该选项version: "3.7"
,因此请删除该选项(但它不会像您期望的那样工作)或将版本更改为2.4
这是我当前版本的 docker-compose.yaml:
version: "2.4"
networks:
web:
internal:
internal: true
volumes:
mysql_data:
services:
traefik:
image: traefik:v2.2.1
container_name: traefik
hostname: traefik
domainname: localhost
restart: always
ports:
- "80:80"
- "443:443"
expose:
- 8080
environment:
- /var/run/docker.sock:/var/run/docker.sock
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./config/:/config
- ./traefik.yml:/traefik.yml
networks:
- web
- internal
labels:
- traefik.http.routers.traefik.tls=true
- traefik.http.routers.traefik.entrypoints=secure
- traefik.http.routers.traefik.rule=Host(`traefik.localhost`)
- traefik.http.routers.traefik.service=api@internal
dozzle:
image: amir20/dozzle:latest
container_name: dozzle
hostname: dozzle
domainname: localhost
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
expose:
- 8080
labels:
- traefik.http.routers.dozzle.tls=true
- traefik.http.routers.dozzle.entrypoints=secure
- traefik.http.routers.dozzle.rule=Host(`dozzle.traefik_internal`) || Host(`logs.localhost`)
networks:
- internal
db:
image: mysql:latest
container_name: db
hostname: db
domainname: localhost
environment:
MYSQL_ROOT_PASSWORD: ########
restart: always
healthcheck:
test: "exit 0"
command: --default-authentication-plugin=mysql_native_password
ports:
- '3306:3306'
volumes:
- mysql_data:/var/lib/mysql
networks:
- internal
websocket:
image: local-websocket-image
container_name: websocket-stage
hostname: websocket
domainname: localhost
restart: on-failure
command: python server.py
depends_on:
db:
condition: service_healthy
expose:
- 8080
networks:
- web
- internal
environment:
- PATH_TO_CONFIG=/src/setup.cfg
volumes:
- ${PWD}/docker-config:/src
- ${PWD}/config/certs/socket:/var
labels:
- traefik.http.routers.core-socket-stage-router.tls=true
- traefik.http.routers.core-socket-stage-router.entrypoints=secure
- traefik.http.routers.core-socket-stage-router.rule=Host(`websocket.localhost`)
推荐阅读
- php - PHP CURL 没有得到响应,但 CLI curl 有
- typescript - NestJS 不会在任何地方打印日志消息
- python - 给定具有列表的变量,如何输出函数数组
- html - 根据其他元素的高度设置margin-top
- pandas - 给定列的行中值的每个条目的熊猫频率
- svn - 用SVN将分支推入主干
- windows - 在管理文件夹上使用 TortoiseGit
- c# - Xamarin - 在 WebView 中请求相机权限
- jquery - jquery ajax jsonp 和 angularjs $http json 的区别
- apache-kafka - kafka消费者机器是否需要运行zookeeper?