【问题标题】:Using /etc/hosts with docker将 /etc/hosts 与 docker 一起使用
【发布时间】:2019-03-30 21:57:34
【问题描述】:

在我的 Mac 上,我使用运行 Ubuntu 和 apache 的 vagrant,并为我的各种 apache 代码存储库提供虚拟主机条目。在 OSX 方面,我为每个 v-host 条目创建 /etc/hosts 条目。

我正在尝试使用 docker 达到相同的效果,但我很难在访问应用程序时不必指定端口号的情况下解决这个问题,我不想这样做。例如:我的 /etc/hosts 中有 127.0.0.1 dockertest.com,然后我可以通过 http://dockertest.com:8080 访问它。我希望能够在不指定端口的情况下直接转到http://dockertest.com。我怎样才能做到这一点?我知道端口号不能在 /etc/hosts 文件中使用,所以我正在寻找一种可以模拟效果的方法。我需要能够同时运行多个 docker 应用程序,因为一些代码库相互通信并且每个代码库都需要有自己唯一的主机名,所以我不认为在 docker- 中简单地将端口设置为 80:80 compose 文件将起作用,因为每个应用程序都将(尝试)在 127.0.0.1:80 上运行。

对于上下文,我遵循this tutorial 在 docker 上运行 apache、php 和 mysql。我的所有文件都与该站点上显示的完全相同。

更新

以下docker-compose.yml 文件出现502 Bad Gateway nginx 错误。

version: "3.3"
services:
  php:
    build: './php/'
    networks:
      - backend
    volumes:
      - ./public_html/:/var/www/html/
  apache:
    build: './apache/'
    depends_on:
      - php
      - mysql
    networks:
      - frontend
      - backend
    volumes:
      - ./public_html/:/var/www/html/
    environment:
      - VIRTUAL_PORT=3000
      - VIRTUAL_HOST=dockertest.com
  mysql:
    image: mysql:5.6.40
    networks:
      - backend
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
  nginx-proxy:
    image: jwilder/nginx-proxy
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
networks:
  frontend:
  backend:

更新 2

解决了“502 Bad Gateway”错误,这是更新后的docker-compose.yml 文件。我必须将 nginx-proxy 添加到我引用的网络之一。我的问题还没有完全解决,但我确实有一部分工作。对于阅读本文并寻找解决方案的任何人,我创建了另一个问题 here 以防止这个问题变得太长。

version: "3.3"
services:
  php:
    build: './php/'
    networks:
      - backend
    volumes:
      - ./public_html/:/var/www/html/
  apache:
    build: './apache/'
    depends_on:
      - php
      - mysql
    networks:
      - frontend
      - backend
    volumes:
      - ./public_html/:/var/www/html/
    environment:
      - VIRTUAL_HOST=dockertest.com
  mysql:
    image: mysql:5.6.40
    networks:
      - backend
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
  nginx-proxy:
    image: jwilder/nginx-proxy
    networks:
      - backend
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
networks:
  frontend:
  backend:

【问题讨论】:

    标签: apache docker containers


    【解决方案1】:

    您可以使用jwilder/nginx-proxy,它是由其他容器的env vars自动配置的反向代理,因此您无需手动编写nginx代理配置。同样根据要求,它允许使用特定端口将请求转发到。

    # docker-compose.yml
    
    version: '3.3'
    
    services:
    
      lamp:
        environment:
          VIRTUAL_HOST: some_domain.dev
          VIRTUAL_PORT: 9999
        image: my_lamp_image
    
      app:
        environment:
          VIRTUAL_HOST: another_domain.dev
          VIRTUAL_PORT: 3000
        image: my_app_image
    
      nginx-proxy:
        image: jwilder/nginx-proxy
        ports:
          - 80:80
        volumes:
          - /var/run/docker.sock:/tmp/docker.sock:ro
    
    # /etc/hosts
    
    127.0.0.1 some_domain.dev
    127.0.0.1 another_domain.dev
    

    jwilder/nginx-proxy 有很多不错的功能,如 ssl、uwsgi、fastcgi,也可以在生产环境中使用。还有像let's encrypt sslman in the middle proxy这样的“伴侣”添加。

    【讨论】:

    • 有没有办法做到这一点,但有多个 docker-compose 文件,一个用于我的每个存储库?我能够让它工作,但我正在处理 20 多个存储库,并非所有存储库都相互关联,而且有些使用不同版本的 PHP,因此将它们全部放在一个 docker-compose 文件中不会对我的情况有意义。一旦运行,端口 80 就已经被阻塞,我无法使用自己的 docker-compose 文件运行第二个应用程序。谢谢。
    • 是的,有。但请打开一个新问题或使用额外要求更新原始问题。这个解释在 cmets 中看起来不太好......
    • 我用我的 docker-compose.yml 文件更新了我的帖子。我以为我让它工作了,但我意识到我把ports 80:80留在了docker-compose.yml的apache服务部分,所以实际上并不是nginx在做代理。删除后,我收到“502 Bad Gateway”错误
    • 您的 apache 位于 2 个网络中 - 前端和后端。您的 nginx 在 1 个网络中 - 默认(因为您没有向其中添加任何网络条目,所以它被添加到“默认”中)。为了让这两个容器进行通信,它们需要在同一个网络中。因此,要么从docker-compose.yml 中删除所有网络引用,要么将nginx-proxy 添加到apache 所在的网络之一。
    • 谢谢,您的两个建议都有效。你建议离开网络还是删除它们?我按照您的建议在这里创建了一个新帖子,谢谢。 stackoverflow.com/questions/55446765/…
    【解决方案2】:

    看起来您的 apache 服务器在容器内的端口 80 上运行。如果你想在 /etc/hosts 条目中使用 dockertest.com 外部,那么你也必须在外部使用端口 80。

    1. 为 dockertest.com 域创建 /etc/hosts 条目
    2. 如果您使用 docker,请使用 -p 80:80 运行它,或者如果您使用 docker-compose
    ports:
      - "80:80"
    

    【讨论】:

    • 我应该提到我需要能够同时运行多个 docker 应用,其中一些是相互交互的微服务。这不会限制我一次只能运行 1 个 docker 应用吗?
    • 如果您的所有服务都应该在端口 80 上运行,那么您实际上一次只能使用 1 个 docker 应用程序。您可以在 docker 服务前使用反向代理来通过 http 或 https 运行多个服务。我会为此推荐你traefik
    • 但我可以指定不同的端口号来运行多个应用程序。例如:8080:808081:80,然后访问 http://dockertest.com:8080http://dockertest2.com:8081。我正在尝试实现该结果,但不必在 url 中指定端口号。如果这不是做事的“码头方式”,我应该如何为我的每个应用程序提供唯一的主机名,而不必在 url 中指定端口?
    • 没有 docker 方式。您有两个选择 - 1. 在不同的端口上运行您的服务 - 2. 使用带有虚拟主机配置的服务器或前面的反向代理。查看 traefik 文档。
    • 当你说“在不同的端口上运行你的服务”时,你的意思是在像http://dockertest2.com:8081这样的url中指定端口号吗?如果是这样,听起来 #2 是我唯一的选择。
    【解决方案3】:

    一种可能性是将所有应用程序设置在各自的容器中,然后通过docker network 连接它们。

    为了访问所有容器,我建议将 nginx webserver 容器添加到网络中作为反向代理,然后您可以将其绑定到计算机的 80 端口。

    然后,您可以为每个应用单独定义一个location,也可以定义一个通用位置,例如

    # sample.conf
    server {
      listen 80 default_server;
      server_name ~ (?<docker_host_name>.+);
      location ~ {
        # for actual request forwarding
        proxy_pass                         http://$docker_host_name$1$is_args$args;
        # some stuff I figured out I have to use in order for service to work properly
        proxy_set_header                   Upgrade $http_upgrade;
        proxy_set_header                   Connection 'upgrade';
        proxy_http_version                 1.1;
        proxy_cache_bypass                 $http_upgrade;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
      }
    }
    
    

    此配置必须内联放置在原始 /etc/nginx/nginx.conf 中或包含在 http 配置块中的单独文件中。

    重启 nginx 服务或容器后(取决于容器设置),您应该能够访问 docker 网络内的所有服务,并且所有服务应该能够毫无问题地相互通信。

    当然,您仍然必须将条目保留在 hosts 文件中,以便您的计算机知道它必须在本地处理请求。

    编辑:

    原始配置(可能)没有做它应该做的事情。 所以,我想出了一个更新的版本,它应该可以完成工作:

    # sample.conf
    server {
      listen 80 default_server;
      location ~ {
        # for actual request forwarding
        proxy_pass                         http://$host$1$is_args$args;
        # some stuff I figured out I have to use in order for service to work properly
        proxy_set_header                   Upgrade $http_upgrade;
        proxy_set_header                   Connection 'upgrade';
        proxy_http_version                 1.1;
        proxy_cache_bypass                 $http_upgrade;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
      }
    }
    
    

    使用此配置,nginx 服务器将侦听端口 80 上的所有传入请求,并将它们转发到网络内的适当容器。 您也不必自己配置主机解析,因为 docker 容器名称也代表容器的主机(-名称)。

    希望这对你有用。

    【讨论】:

    • 我链接的教程为 3 个服务(apache、php、mysql)使用了覆盖网络。这就是您通过连接容器所指的吗?如果是这样,你有什么资源可以让我具体阅读你所指的 nginx 吗?即使只是一些让我查找的术语也会有所帮助。谢谢
    • 没错。通过在 docker 网络中连接容器,它们可以通过与容器名称相对应的主机名进行通信。希望对您有所帮助但是,您不能将多个容器绑定到端口 80,您必须有一个服务来决定将提供什么应用程序。对于这些事情,您使用reverse proxy。可以使用 Apache,但在设置反向代理时,nginx 几乎总是首选的 Web 服务器。
    • 此解决方案是否需要将我的所有代码存储库放入一个 docker-compose 文件中,还是我可以为每个存储库保留单独的 docker-compose 文件?我使用 jwilder/nginx-proxy 服务尝试了 artemkloko 的答案,但它似乎需要将我的所有存储库作为单独的服务放入一个 docker-compose 文件中。我宁愿将它们分开,因为并非所有它们都相互关联,有些甚至使用不同的 php 版本。此外,有些我什至很少使用,因此始终保持该服务运行对我来说并不理想。再次感谢
    • 我刚刚在我的答案中添加了一个新的配置块。该配置实际上应该允许您在单独的容器中运行所有应用程序(使用单独的撰写文件),同时启用容器间通信。因此,您不必更改任何文件,而是使用显示的第二个配置设置一个简单的 nginx 容器。希望有帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多