如何正确设置基本的 traefik 反向代理?
How can I properly setup basic traefik reverse proxy?
假设我当前的 public IP 是 101.15.14.71
,我有一个名为 example.com
的域,我使用 cloudflare 配置了它,并且我创建了多个指向我的 public 的 DNS 条目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 中的示例代码,它完全相同,但 return 状态不同,仅此而已
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_main():
return {"message": "Hello world for my project myapp"}
这是我的 Dockerfile,用于 myapp 和 myapp1,两者也完全相同,但唯一的区别是我在 7777
上部署 myapp,在 [=22= 上部署 myapp1 ] 在不同的容器中
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
这是我的 docker-compose.yml 文件,用于 myapp 和 myapp1,这里我也完全一样,但唯一不同的是我更改了端口,
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"]
]
- traefik.toml
[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"
- docker-compose.yml
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 仪表板,我部署了两个快速api 服务,
- myapp 7777,我需要通过
new2.example.com
访问此应用
- myapp1 7778,我需要通过
new3.example.com
访问此应用
- traefik 仪表板,我需要通过
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
.
不确定您是将其用于开发还是生产目的,但您也可以使用卷将应用程序目录挂载到容器内(如果您将其用于开发则特别有用),并且只使用一个 Dockerfile myapp
和 myapp1
,通过环境变量自定义它。
由于您已经在使用 traefik 的动态配置,我将通过 docker-compose.yml
文件中的 docker 标签完成容器配置的大部分设置。
您的 myapp
和 myapp1
的 docker 文件在这一点上将非常相似,但我将它们作为单独的文件保存,因为您可能需要更改它们取决于您将来应用程序的要求。我为端口使用了一个环境变量,它允许您从 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
注意:您真的应该为您的应用程序依赖项使用 poetry or a 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配置将使用stage letsencrypt server。确保所有细节都正确,并在测试一切正常后删除 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$zjvsq3w$$fLCqJddLvrIZA.CCoGE2E." # generate with htpasswd. replace $ with $$
您可以使用以下命令生成密码:
htpasswd -n admin | sed 's/$/$$/g'
注意:如果您需要在 docker-compose 文件中使用文字美元符号,您需要使用 $$
作为记录 here.
在目录中发出 docker-compose up
应该会启动所有服务,并按预期工作。
根据您提供的详细信息,以上内容应该适合您,但可以根据您的需要在多个方面进一步改进。
此外,在 docker-compose.yml
文件中拥有 traefik 仪表板的凭据可能不是最好的,您可能希望为此使用 docker 秘密。您还可以添加健康检查并考虑将 myapp
和 myapp1
放入单独的内部网络。
如果你想深入了解,我建议你从Get started with Docker Compose and also read: Dockerfile reference and Compose file version 3 reference
开始
假设我当前的 public IP 是 101.15.14.71
,我有一个名为 example.com
的域,我使用 cloudflare 配置了它,并且我创建了多个指向我的 public 的 DNS 条目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 中的示例代码,它完全相同,但 return 状态不同,仅此而已
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_main():
return {"message": "Hello world for my project myapp"}
这是我的 Dockerfile,用于 myapp 和 myapp1,两者也完全相同,但唯一的区别是我在 7777
上部署 myapp,在 [=22= 上部署 myapp1 ] 在不同的容器中
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
这是我的 docker-compose.yml 文件,用于 myapp 和 myapp1,这里我也完全一样,但唯一不同的是我更改了端口,
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"] ]
- traefik.toml
[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"
- docker-compose.yml
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 仪表板,我部署了两个快速api 服务,
- myapp 7777,我需要通过
new2.example.com
访问此应用
- myapp1 7778,我需要通过
new3.example.com
访问此应用
- traefik 仪表板,我需要通过
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
.
不确定您是将其用于开发还是生产目的,但您也可以使用卷将应用程序目录挂载到容器内(如果您将其用于开发则特别有用),并且只使用一个 Dockerfile myapp
和 myapp1
,通过环境变量自定义它。
由于您已经在使用 traefik 的动态配置,我将通过 docker-compose.yml
文件中的 docker 标签完成容器配置的大部分设置。
您的 myapp
和 myapp1
的 docker 文件在这一点上将非常相似,但我将它们作为单独的文件保存,因为您可能需要更改它们取决于您将来应用程序的要求。我为端口使用了一个环境变量,它允许您从 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
注意:您真的应该为您的应用程序依赖项使用 poetry or a 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配置将使用stage letsencrypt server。确保所有细节都正确,并在测试一切正常后删除 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$zjvsq3w$$fLCqJddLvrIZA.CCoGE2E." # generate with htpasswd. replace $ with $$
您可以使用以下命令生成密码:
htpasswd -n admin | sed 's/$/$$/g'
注意:如果您需要在 docker-compose 文件中使用文字美元符号,您需要使用 $$
作为记录 here.
在目录中发出 docker-compose up
应该会启动所有服务,并按预期工作。
根据您提供的详细信息,以上内容应该适合您,但可以根据您的需要在多个方面进一步改进。
此外,在 docker-compose.yml
文件中拥有 traefik 仪表板的凭据可能不是最好的,您可能希望为此使用 docker 秘密。您还可以添加健康检查并考虑将 myapp
和 myapp1
放入单独的内部网络。
如果你想深入了解,我建议你从Get started with Docker Compose and also read: Dockerfile reference and Compose file version 3 reference
开始