gpt4 book ai didi

Docker 服务仅对本地主机可用

转载 作者:行者123 更新时间:2023-12-02 18:20:36 25 4
gpt4 key购买 nike

简单用例:运行 Nginx 的生产服务器(监听 0.0.0.0:80 和 443),负责读取 SSL 证书,如果有效,则重定向到 Docker 容器中的“隐藏”服务。该服务运行 Gunicorn(所以是一个 Django 网站)并在端口 8000 上进行监听。这听起来很标准、简单、经过测试,几乎美得令人难以置信……但当然,它并没有像我想要的那样工作。

因为 Gunicorn 在其小型 Docker 容器中运行,可以通过 Internet 访问。如果你访问我的主机名,端口 8000,你会得到 Gunicorn 网站。显然,它很丑,但最糟糕的是它完全绕过了 Nginx 和 SSL 证书。那么,为什么 Docker 容器可以通过 Internet 访问呢?我知道有一段时间它与 Docker 正好相反。我们需要适当的平衡!

在进一步检查问题时:我确实有防火墙,并且它的配置非常有限。它只允许端口 22(用于 ssh,等待重新映射)、80 和 443。因此绝对不允许使用 8000。但是 ufw 使用 iptables,如果容器在该端口上运行,Docker 添加了一些 iptables 规则来绕过配置。

我尝试了很多愚蠢的事情(这是工作的一部分):在我的 docker-compose.yml 文件中指定要绑定(bind)的端口,我试图删除它们('当然如果我这样做,nginx 无法访问我的隐藏服务) .我试图添加一个指定绑定(bind)的IP(似乎是允许的):

ports:
- "127.0.0.1:8000:8000"

这产生了一个奇怪的结果,因为 Nginx 无法连接,但 Gunicorn 仍然可以通过 Internet 看到。所以我会说,与我想要的完全相反。我尝试手动更改Docker服务以添加标志(不好)并尝试在 etc/docker/daemon.json中添加配置文件(再次将“ip”设置更改为“127.0.0.1”)。我没有想法。如果有人有指点...毕竟,我认为这不是 Docker 极为罕见的用法。

细节:我不使用 docker run 运行容器直接地。我有一个 docker-compose.yml使用 docker stack 归档和运行服务,所以成群结队(虽然我当时只有一台机器)。可能是相关的,但我认为不是。
  • 系统:Debian 9。
  • Docker 版本:18.09。
  • docker-compose 版本:1.22

  • nginx (/etc/nginx/sites-available/example.com)
    upstream gunicorn {
    server localhost:8000;
    }

    server {
    server_name example.com www.example.com;
    location / {
    proxy_pass http://gunicorn;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_redirect off;
    }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate ...;
    ssl_certificate_key ...;
    include ...;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }

    server {
    if ($host = www.example.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 404; # managed by Certbot
    }

    docker -compose.yml
    version: '3.7'

    services:
    gunicorn:
    image: gunicorn:latest
    command: gunicorn mysite.wsgi:application --bind 0.0.0.0:8000
    volumes:
    - ./:/usr/src/app/
    ports:
    - "8000:8000"
    depends_on:
    - db
    networks:
    - webnet
    db:
    image: postgres:10.5-alpine
    volumes:
    - postgres_data:/var/lib/postgresql/data/
    networks:
    - webnet

    networks:
    webnet:

    volumes:
    postgres_data:

    Note: the gunicorn image has been built beforehand, but there's no trick, just a Python-3.7:slim image with all set for gunicorn and a Django website under mysite/. It doesn't expose any port (not that I think makes any difference here).

    最佳答案

    好的,经过一番挖掘,这是我发现的:docker 将确保创建 iptables 规则以从网络外部访问容器。让 Docker 完全不关心 iptables 并不是一个好策略,因为它将需要它来转发从容器到外部世界的连接。所以documentation建议在 docker-user 链中创建一个 iptables 规则,以防止外部访问 Docker 守护进程。这就是我所做的。当然,给定的命令(稍作修改以完全禁止外部访问)并没有持续存在,所以我不得不创建一个服务来添加这个规则。可能不是最好的选择,所以如果您有更好的选择,请随时发表评论。这是我添加的 iptables 规则:

    iptables -I DOCKER-USER -i ext_if ! -s 127.0.0.1 -j DROP

    此规则禁止外部访问 Docker 守护程序,但仍允许连接到单个容器。这条规则似乎没有为我解决任何问题,因为这个解决方案并不完全是我问题的答案。为了禁止从 Internet 访问我在 8000 端口上运行的 Docker 容器,我在同一个脚本中添加了另一个规则:
    iptables -I DOCKER-USER -p tcp --destination-port 8000 -j DROP

    这个规则有点极端:它完全禁止 Docker 网络上的 8000 端口上的网络流量。主机(localhost)被排除在此规则之外,因为之前的规则无论如何都应该允许本地流量(如果您手动进行 iptables 配置,则必须添加此规则,这不是给定的,这是我切换的原因到更简单的解决方案,如 ufw )。如果您使用 iptables -L 查看防火墙规则,你会看到链 DOCKER-USER在任何 Docker 规则之前调用。您可能会发现另一条规则允许同一端口上的流量。但是,因为我们在更高优先级的规则中禁止流量,所以端口 8000 将有效地隐藏在外部。

    这个解决方案虽然看起来解决了问题,但并不完全优雅和直观。同样,我不禁想知道我是否是第一个使用 Docker 来托管我的“隐藏”服务同时在前面维护不同服务的人。我想通常的方法是将 nginx 放在 docker 容器本身中,但这给我带来了其他问题,坦率地说,我决定超越优势。

    关于Docker 服务仅对本地主机可用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54261105/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com