Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Docker 如何正确设置基本traefik反向代理?_Docker_Docker Compose_Reverse Proxy_Traefik_Fastapi - Fatal编程技术网

Docker 如何正确设置基本traefik反向代理?

Docker 如何正确设置基本traefik反向代理?,docker,docker-compose,reverse-proxy,traefik,fastapi,Docker,Docker Compose,Reverse Proxy,Traefik,Fastapi,假设我当前的公共IP是101.15.14.71,我有一个名为example.com的域,我使用cloudflare配置了该域,并创建了多个指向我的公共IP的DNS条目 例如: 下面是我的示例项目结构 ├── myapp │   ├── app │   │   └── main.py │   ├── docker-compose.yml │   └── Dockerfile ├── myapp1 │   ├── app │   │   └── main.py │   ├── docker-comp

假设我当前的公共IP是
101.15.14.71
,我有一个名为
example.com
的域,我使用cloudflare配置了该域,并创建了多个指向我的公共IP的DNS条目

例如:

下面是我的示例项目结构

├── 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 on
7777
和myapp1 on
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文件,这里我也有完全相同的,但唯一的区别是我更改了端口

现在来看traefik文件夹

  • acme.json#我使用
    nano-acme.json
    命令创建了它,其中没有任何内容, 但是没有
    chmod 600 acme.json
    以获得适当的权限

  • traefik_dynamic.toml

  • 特拉菲克
  • docker-compose.yml
  • 这些是关于我的文件的细节,我想在这里实现的是

    我想用基本身份验证设置traefik和traefik dashboard,并部署两个fastapi服务

    • myapp7777,我需要通过
      new2.example.com
    • myapp17778,我需要通过
      new3.example.com
    • traefik dashboard,我需要通过
      new1.example.com
    所有这些都应该是https,并且还启用了证书自动重新登录

    我从最新版本traefik的在线文章中获得了所有这些。但问题是这不起作用。我使用docker compose构建和部署traefik,并打开api仪表板。它要求输入密码和用户(
    basic auth I setup
    )我在
    traefik\u 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

    不确定是否将其用于开发或生产目的,但也可以使用卷在容器中装入应用程序目录(如果将其用于开发,则特别有用),并且仅将一个Dockerfile用于
    myapp
    myapp1
    ,通过环境变量对其进行自定义

    由于您已经在使用traefik的动态配置,我将通过
    docker compose.yml
    文件中的docker标签来完成容器配置的大部分设置

    此时,
    myapp
    myapp1
    的dockerfile将非常相似,但我将它们作为单独的文件保存,因为将来可能需要根据应用程序的要求对它们进行更改。我为端口使用了一个环境变量,它允许您从
    docker compose.yml
    文件中更改端口

    您可以使用以下
    Dockerfile
    /myapp/Dockerfile
    /myapp1/Dockerfile
    ):

    注意:对于应用程序依赖项,您确实应该使用类似或文件的内容

    .dockergnore
    文件(
    /myapp/.dockergnore
    /myapp1/.dockergnore
    )应包含:

    Dockerfile
    
    因为整个目录都被复制到容器中,而您不需要
    Dockerfile
    在其中

    您的主traefik配置(
    /traefik/traefik.yml
    )可以是:

    ├── docker-compose.yml
    ├── myapp
    │   ├── .dockerignore
    │   ├── Dockerfile
    │   └── app
    │       └── main.py
    ├── myapp1
    │   ├── .dockerignore
    │   ├── Dockerfile
    │   └── app
    │       └── main.py
    └── traefik
        ├── acme.json
        └── traefik.yml
    
    提供者:
    码头工人:
    exposedByDefault:false
    全球的:
    checkNewVersion:false
    sendAnonymousUsage:false
    api:{}
    访问日志:{}
    入口点:
    网状物:
    地址:“:80”
    http:
    重定向:
    入口点:
    致:“网络安全”
    方案:“https”
    网络安全:
    地址:“:443”
    发出砰的声响:
    入口点:“网络安全”
    证书解决者:
    myresolver:
    顶点:
    caServer:“https://acme-staging-v02.api.letsencrypt.org/directory"
    电子邮件:“example@example.com"
    存储:“/etc/traefik/acme.json”
    httpChallenge:
    入口点:“网络”
    
    注意:上面的acme配置将使用stage-letsencrypt服务器。确保所有详细信息正确无误,并在测试一切正常后删除
    caServer
    ,以便与letsencrypt生产服务器通信

    您的
    /docker compose.yml
    文件应该类似于:

    ├── docker-compose.yml
    ├── myapp
    │   ├── .dockerignore
    │   ├── Dockerfile
    │   └── app
    │       └── main.py
    ├── myapp1
    │   ├── .dockerignore
    │   ├── Dockerfile
    │   └── app
    │       └── main.py
    └── traefik
        ├── acme.json
        └── traefik.yml
    
    版本:“3.9”
    服务:
    myapp:
    建造:
    上下文:./myapp
    dockerfile:./dockerfile
    图片:myapp
    取决于:
    -特拉菲克
    揭露:
    - 7777
    标签:
    -“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:
    建造:
    上下文:./myapp1
    dockerfile:./dockerfile
    图片:myapp1
    取决于:
    -特拉菲克
    揭露:
    - 7778
    标签:
    -“traefik.enable=true”
    -“traefik.http.routers.myapp1.tls=true”
    -“traefik.http.routers.myapp1.tls.certResolver=myresolver”
    
    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.yml
    ├── myapp
    │   ├── .dockerignore
    │   ├── Dockerfile
    │   └── app
    │       └── main.py
    ├── myapp1
    │   ├── .dockerignore
    │   ├── Dockerfile
    │   └── app
    │       └── main.py
    └── traefik
        ├── acme.json
        └── traefik.yml
    
    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
    
    Dockerfile
    
    htpasswd -n admin | sed 's/\$/\$\$/g'