[英]How can I properly setup basic traefik reverse proxy?
Assume my current public IP is 101.15.14.71
, I have a domain called example.com
which I configured using cloudflare and I created multiple DNS entry pointing to my public ip.
例如:
1) new1.example.com - 101.15.14.71
2) new2.example.com - 101.15.14.71
3) new3.example.com - 101.15.14.71
現在,這是我的示例項目結構,
├── myapp
│ ├── app
│ │ └── main.py
│ ├── docker-compose.yml
│ └── Dockerfile
├── myapp1
│ ├── app
│ │ └── main.py
│ ├── docker-compose.yml
│ └── Dockerfile
└── traefik
├── acme.json
├── docker-compose.yml
├── traefik_dynamic.toml
└── traefik.toml
這里我有兩個 fastAPI(即 myapp、myapp1)
這是我在 myapp 和 myapp1 的main.py中的示例代碼,它完全相同,但返回狀態不同,僅此而已
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_main():
return {"message": "Hello world for my project myapp"}
這是 myapp 和 myapp1 的Dockerfile ,這里也完全相同,但唯一的區別是我將 myapp 部署在7777
上,將 myapp1 部署在7778
上的不同容器中
FROM ubuntu:latest
ARG DEBIAN_FRONTEND=noninteractive
RUN apt update && apt upgrade -y
RUN apt install -y -q build-essential python3-pip python3-dev
# python dependencies
RUN pip3 install -U pip setuptools wheel
RUN pip3 install gunicorn fastapi uvloop httptools "uvicorn[standard]"
# copy required files
RUN bash -c 'mkdir -p /app'
COPY ./app /app
ENTRYPOINT /usr/local/bin/gunicorn \
-b 0.0.0.0:7777 \ # this line I use for myapp dockerfile
-b 0.0.0.0:7778 \ # this line I change for myapp1 dockerfile
-w 1 \
-k uvicorn.workers.UvicornWorker app.main:app \
--chdir /app
這是 myapp 和 myapp1 的docker-compose.yml文件,這里我也有完全相同但唯一的區別是我更改了端口,
services: myapp: # I use this line for myapp docker-compose file myapp1: # I use this line for myapp1 docker-compose file build: . restart: always labels: - "traefik.enable=true" - "traefik.docker.network=traefik_public" - "traefik.backend=myapp" # I use this line for myapp docker-compose file - "traefik.backend=myapp1" # I use this line for myapp1 docker-compose file - "traefik.frontend.rule=Host:new2.example.com" # I use this for myapp compose file - "traefik.frontend.rule=Host:new3.example.com" # I use this for myapp1 compose file - "traefik.port=7777" # I use this line for myapp docker-compose file - "traefik.port=7778" # I use this line for myapp1 docker-compose file networks: - traefik_public networks: traefik_public: external: true
現在來到 traefik 文件夾,
acme.json # 我使用nano acme.json
命令創建了它,其中沒有任何內容,但是chmod 600 acme.json
獲得了適當的權限。
traefik_dynamic.toml
[http] [http.routers] [http.routers.route0] entryPoints = ["web"] middlewares = ["my-basic-auth"] service = "api@internal" rule = "Host(`new1.example.com`)" [http.routers.route0.tls] certResolver = "myresolver" [http.middlewares.test-auth.basicAuth] users = [ ["admin:your_encrypted_password"] ]
[entryPoints] [entryPoints.web] address = ":80" [entryPoints.web.http] [entryPoints.web.http.redirections] [entryPoints.web.http.redirections.entryPoint] to = "websecure" scheme = "https" [entryPoints.websecure] address = ":443" [api] dashboard = true [certificatesResolvers.myresolver.acme] email = "reallygoodtraefik@gmail.com" storage= "acme.json" [certificatesResolvers.myresolver.acme.httpChallenge] entryPoint = "web" [providers] [providers.docker] watch = true network = "web" [providers.file] filename = "traefik_dynamic.toml"
services: traefik: image: traefik:latest ports: - 80:80 - 443:443 - 8080:8080 volumes: - /var/run/docker.sock:/var/run/docker.sock -./traefik.toml:/traefik.toml -./acme.json:/acme.json -./traefik_dynamic.toml:/traefik_dynamic.toml networks: - web networks: web:
這些是關於我的文件的詳細信息,我在這里想要實現的是,
我想使用基本身份驗證設置 traefik 和 traefik 儀表板,我部署了兩個我的 fastapi 服務,
new2.example.com
訪問這個應用程序new3.example.com
訪問這個應用程序new1.example.com
訪問它所有這些都應該是 https 並且還啟用了認證自動更新。
我從最新版本的 traefik 的在線文章中獲得了所有這些信息。 但問題是這不起作用。 我使用 docker-compose 構建和部署 traefik,然后打開 api 儀表板。 它要求輸入密碼和用戶( basic auth I setup
)我輸入了我在traefik_dynamic.toml
中設置的用戶詳細信息,但它不起作用。
我哪里做錯了? 請幫助我糾正配置中的錯誤。 我真的很想了解更多關於這方面的信息。
錯誤更新:
traefik_1 | time="2021-06-16T01:51:16Z" level=error msg="Unable to obtain ACME certificate for domains \"new1.example.com\": unable to generate a certificate for the domains [new1.example.com]: error: one or more domains had a problem:\n[new1.example.com] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: Invalid response from http://new1.example.com/.well-known/acme-challenge/mu85LkYEjlvnbDI-wM2xMaRFO1QsPDNjepTDb47dWF0 [2606:4700:3032::6815:55c4]: 404\n" rule="Host(`new1.example.com`)" routerName=api@docker providerName=myresolver.acme
traefik_1 | time="2021-06-16T01:51:19Z" level=error msg="Unable to obtain ACME certificate for domains \"new2.example.com\": unable to generate a certificate for the domains [new2.example.com]: error: one or more domains had a problem:\n[new2.example.com] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: Invalid response from http://new2.example.com/.well-known/acme-challenge/ykiCAEpJeQ1qgVdeFtSRo3q-ATTwgKdRdGHUs2kgIsY [2606:4700:3031::ac43:d1e9]: 404\n" providerName=myresolver.acme routerName=myapp1@docker rule="Host(`new2.example.com`)"
traefik_1 | time="2021-06-16T01:51:20Z" level=error msg="Unable to obtain ACME certificate for domains \"new3.example.com\": unable to generate a certificate for the domains [new3.example.com]: error: one or more domains had a problem:\n[new3.example.com] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: Invalid response from http://new3.example.com/.well-known/acme-challenge/BUZWuWdNd2XAXwXCwkeqe5-PHb8cGV8V6UtzeLaKryE [2606:4700:3031::ac43:d1e9]: 404\n" providerName=myresolver.acme routerName=myapp@docker rule="Host(`new3.example.com`)"
所有服務只需要一個 docker-compose 文件,無需為每個容器定義一個。
您應該使用的項目結構應該類似於:
├── docker-compose.yml
├── myapp
│ ├── .dockerignore
│ ├── Dockerfile
│ └── app
│ └── main.py
├── myapp1
│ ├── .dockerignore
│ ├── Dockerfile
│ └── app
│ └── main.py
└── traefik
├── acme.json
└── traefik.yml
創建容器時,除非它們用於開發目的,否則建議不要使用完整的鏡像,例如 ubuntu。 專門針對您的目的,我建議您使用 python 映像,例如python:3.7-slim
。
不確定您是否將其用於開發或生產目的,但您也可以使用卷將應用程序目錄掛載到容器內(如果您將其用於開發,則特別有用),並且只對myapp
和myapp1
使用一個 Dockerfile ,通過環境變量自定義它。
由於您已經在使用 traefik 的動態配置,我將通過docker-compose.yml
文件中的 docker 標簽來完成容器配置的大部分設置。
此時,您的myapp
和myapp1
的 dockerfile 將非常相似,但我將它們分開保存,因為您可能需要根據未來應用程序的要求對它們進行更改。 我為端口使用了一個環境變量,它可以讓您從docker-compose.yml
文件中更改端口。
您可以使用以下Dockerfile
( ./myapp/Dockerfile
和./myapp1/Dockerfile
):
FROM python:3.7-slim
ARG DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
RUN pip3 install -U pip setuptools wheel && \
pip3 install gunicorn fastapi uvloop httptools "uvicorn[standard]"
COPY . /app
ENV PORT=7777 # and 7778 for myapp1
ENTRYPOINT /usr/local/bin/gunicorn -b 0.0.0.0:$PORT -w 1 -k uvicorn.workers.UvicornWorker app.main:app --chdir /app
注意:你真的應該為你的應用依賴使用詩歌或requirements.txt文件。
.dockerignore
文件( ./myapp/.dockerignore
和./myapp1/.dockerignore
)應包含:
Dockerfile
由於整個目錄都被復制到容器中,並且您不需要Dockerfile
在那里。
您的主要 traefik 配置( ./traefik/traefik.yml
)可能類似於:
providers:
docker:
exposedByDefault: false
global:
checkNewVersion: false
sendAnonymousUsage: false
api: {}
accessLog: {}
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: "websecure"
scheme: "https"
websecure:
address: ":443"
ping:
entryPoint: "websecure"
certificatesResolvers:
myresolver:
acme:
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
email: "example@example.com"
storage: "/etc/traefik/acme.json"
httpChallenge:
entryPoint: "web"
注意:上面的 acme 配置將使用階段 letencrypt 服務器。 確保所有細節都正確,並在測試一切正常后刪除caServer
,以便與letsencrypt生產服務器通信。
您的./docker-compose.yml
文件應該類似於:
version: "3.9"
services:
myapp:
build:
context: ./myapp
dockerfile: ./Dockerfile
image: myapp
depends_on:
- traefik
expose:
- 7777
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.tls=true"
- "traefik.http.routers.myapp.tls.certResolver=myresolver"
- "traefik.http.routers.myapp.entrypoints=websecure"
- "traefik.http.routers.myapp.rule=Host(`new2.example.com`)"
- "traefik.http.services.myapp.loadbalancer.server.port=7777"
myapp1:
build:
context: ./myapp1
dockerfile: ./Dockerfile
image: myapp1
depends_on:
- traefik
expose:
- 7778
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp1.tls=true"
- "traefik.http.routers.myapp1.tls.certResolver=myresolver"
- "traefik.http.routers.myapp1.entrypoints=websecure"
- "traefik.http.routers.myapp1.rule=Host(`new3.example.com`)"
- "traefik.http.services.myapp1.loadbalancer.server.port=7778"
traefik:
image: traefik:v2.4
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
- ./traefik/acme.json:/etc/traefik/acme.json
ports:
- 80:80
- 443:443
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.tls=true"
- "traefik.http.routers.api.tls.certResolver=myresolver"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.rule=Host(`new1.example.com`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=myAuth"
- "traefik.http.middlewares.myAuth.basicAuth.users=admin:$$apr1$$4zjvsq3w$$fLCqJddLvrIZA.CCoGE2E." # generate with htpasswd. replace $ with $$
您可以使用以下命令生成密碼:
htpasswd -n admin | sed 's/\$/\$\$/g'
注意:如果您需要 docker-compose 文件中的文字美元符號,則需要使用此處記錄的$$
。
在目錄中發出docker-compose up
應該會啟動所有服務,並按預期工作。
根據您提供的詳細信息,以上內容應該對您有用,但可以根據您的需要在多個方面進一步改進。
此外,在docker-compose.yml
文件中擁有 traefik 儀表板的憑據可能不是最好的,您可能希望為其使用 docker 機密。 您還可以添加運行狀況檢查並考慮將myapp
和myapp1
放入單獨的內部網絡。
如果您想進一步了解它,我建議您從Get started with Docker Compose 開始,並閱讀: Dockerfile 參考和Compose 文件版本 3 參考
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.