ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

如何从docker容器内访问宿主机

2021-11-02 13:58:51  阅读:314  来源: 互联网

标签:容器 http 宿主机 envoy host mac docker


最近搞envoy代理,拉了envoyproxy/envoy:latest的镜像,本地进行了一次测试,但是碰到了代理失败的情况,记录一下整个过程。

配置代理

参考envoyproxy官方前端代理示例配置作为蓝本,改成了自己的配置。内容如下:

static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 9901
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: AUTO
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: service1
          http_filters:
          - name: envoy.filters.http.router
  clusters:
  - name: service1
    type: STRICT_DNS
    connect_timeout: 0.25s
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service1
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8000
admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001
layered_runtime:
  layers:
  - name: static_layer_0
    static_layer:
      envoy:
        resource_limits:
          listener:
            example_listener_name:
              connection_limit: 10000

以上配置内容的含义是,在9901端口上监听http请求,并将请求转发到本机的8000端口上,upstream主机在8000端口上监听并处理请求。

容器启动命令如下:

$ docker run -d --rm --name envoy -p 9901:9901 -p 8001:8001 -v /config/path/in/host/test.yaml:/etc/envoy.yaml envoyproxy/envoy -c /etc/envoy.yaml

其中开放了两个端口,9901负责业务流量转发,8001处理envoy的控制面dashboard请求。

upstream服务逻辑

请求转发到本机的8000端口,upstream用go实现,代码很简单,回显一个hello world,同时打印请求header

package main

import (
	"flag"
	"fmt"
	"net/http"
	"strings"
	"time"
)

func greet(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World! %s", time.Now())

	fmt.Println("[headers]")
	for k, v := range r.Header {
		var header string
		for _, v1 := range v {
			header = header + v1 + ", "
		}
		header = strings.TrimRight(header, ", ")
		fmt.Printf("\t%s: %s\n", k, header)
	}
}

func main() {
	var port string
	flag.StringVar(&port, "port", ":8000", "-port=:8000")
	flag.Parse()
	http.HandleFunc("/", greet)
	if err := http.ListenAndServe(port, nil); err != nil {
		fmt.Println(err.Error())
	}
}

一切就绪,运行服务,开始测试

现象

通过本机curl请求,发现提示无法连接到上游主机

$ curl http://localhost:9901/
upstream connect error or disconnect/reset before headers. reset reason: connection failure

分析

初步判断是由于容器的网络隔离,无法访问宿主机导致的。遂docker exec -it envoy /bin/bash,安装网络包后,请求8000端口,是不通的,验证了网络隔离的猜测。

上网查了一下,在Stack Overflow的这个回答下,针对不同的操作系统环境,给出了不同的解决方案。但是这里首先要理解一下docker的network参数

network参数

network参数常见可选值有none、host、bridge
none:顾名思义,禁用容器网络,这个时候容器无法访问外部网络,外部也无法访问容器,你的-p参数也会被忽略
bridge:桥接,也是默认模式,容器会与宿主进行桥接,通过一个桥接的docker0网卡进行通信
host:即撤销网络隔离,这个模式下,你不需要要指定-p参数,容器内监听什么端口,就直接会绑定到宿主的同一端口上,这时容器和宿主是没有隔离的

在综合考虑之后,host模式虽然可以解决问题,但不是我想要的,必要的隔离还是需要的,所以优选bridge模式。
对于bridge模式,在linux环境下,docker deamon会创建一个docker0的网卡,用作网桥,实现容器和宿主的通信,但mac系统下隔离技术与linux不同,所以并不会创建这个网卡。

因为bridge是默认的网络选项,我们不需要修改docker启动命令。
那么mac上如何从容器内访问宿主的服务呢?

mac系统容器访问宿主

我本机安装了Docker desktop for mac,自带docker deamon。版本是3.6.0,内置docker engine是20.10.8。
在17.12版本之前,可以通过host名docker.for.mac.localhost来访问宿主,17.12版本及以后,可以通过docker.for.mac.host.internal来访问宿主。
登录到容器内通过ping进行验证如下:

root@eed301853eb6:/# ping docker.for.mac.localhost
PING docker.for.mac.localhost (192.168.65.2) 56(84) bytes of data.
64 bytes from 192.168.65.2: icmp_seq=1 ttl=37 time=4.02 ms
64 bytes from 192.168.65.2: icmp_seq=2 ttl=37 time=0.361 ms
^C
--- docker.for.mac.localhost ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.361/2.191/4.022/1.831 ms
root@eed301853eb6:/# ping docker.for.mac.host.internal
PING docker.for.mac.host.internal (192.168.65.2) 56(84) bytes of data.
64 bytes from 192.168.65.2: icmp_seq=1 ttl=37 time=1.31 ms
64 bytes from 192.168.65.2: icmp_seq=2 ttl=37 time=1.55 ms
^C
--- docker.for.mac.host.internal ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 1.310/1.433/1.556/0.123 ms

其中解析IP地址就是我的本机地址

调整envoy配置

根据以上分析,调整envoy配置中clusters下的上游主机地址,将127.0.0.1替换为docker.for.mac.localhost或docker.for.mac.host.internal,即可实现代理对宿主机的访问。

标签:容器,http,宿主机,envoy,host,mac,docker
来源: https://blog.csdn.net/weixin_44446512/article/details/121098733

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有