How to access the host from within the docker container

Posted by craigerjs on Tue, 02 Nov 2021 08:05:43 +0100

Recently, I started envoy proxy, pulled the envoyproxy/envoy:latest image, and conducted a local test. However, when the proxy failed, I recorded the whole process.

Configure agent

Refer to envoyproxy official Front end agent sample configuration As a blueprint, it has changed to its own configuration. The contents are as follows:

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

The meaning of the above configuration is to listen to http requests on port 9901 and forward the requests to port 8000 of this machine, and the upstream host listens to and processes the requests on port 8000.

The container startup command is as follows:

$ 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

Two ports are opened. 9901 is responsible for forwarding service traffic, and 8001 handles the dashboard request of envoy's control plane.

upstream service logic

The request is forwarded to the local port 8000. upstream is implemented with go. The code is very simple. A hello world is echoed and the request header is printed at the same time

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())
	}
}

Everything is ready, run the service and start the test

phenomenon

Through the local curl request, it is found that the prompt cannot connect to the upstream host

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

analysis

It is preliminarily determined that the container is isolated from the network and cannot access the host. So docker exec - it envy / bin / bash, after installing the network package, requested 8000 port, but it was impossible, which verified the guess of network isolation.

I checked it on the Internet. It's on the Internet Stack Overflow Under this answer, different solutions are given for different operating system environments. However, we should first understand the network parameter of docker

network parameters

The common optional values of the network parameter are none, host and bridge
none: as the name suggests, disable the container network. At this time, the container cannot access the external network and the external can not access the container. Your - p parameter will also be ignored
Bridge: bridge, which is also the default mode. The container will bridge with the host and communicate through a bridged docker0 network card
Host: that is to revoke network isolation. In this mode, you do not need to specify the - p parameter. What port the container listens to will be directly bound to the same port of the host. At this time, the container and the host are not isolated

After comprehensive consideration, although the host mode can solve the problem, it is not what I want, and the necessary isolation is still needed, so the bridge mode is preferred.
For the bridge mode, in the linux environment, docker deamon will create a docker0 network card to be used as a bridge to realize the communication between the container and the host, but The isolation technology in mac system is different from that in linux Therefore, this network card will not be created.

Because bridge is the default network option, we do not need to modify the docker startup command.
So how does the mac access the host's services from within the container?

mac system container access host

I have installed Docker desktop for mac locally and brought my own docker daemon. The version is 3.6.0 and the built-in docker engine is 20.10.8.
Before version 17.12, you can access the host through the host name docker.for.mac.localhost. After version 17.12, you can access the host through docker.for.mac.host.internal.
Log in to the container and verify by ping as follows:

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

The resolved IP address is my local address

Adjust envoy configuration

According to the above analysis, adjust the upstream host address under clusters in the envoy configuration and replace 127.0.0.1 with docker.for.mac.localhost or docker.for.mac.host.internal to realize the agent's access to the host.

Topics: Go Operation & Maintenance Docker Container