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:

  - address:
        port_value: 9901
    - filters:
      - name:
          codec_type: AUTO
          stat_prefix: ingress_http
            name: local_route
            - name: backend
              - "*"
              - match:
                  prefix: "/"
                  cluster: service1
          - name: envoy.filters.http.router
  - name: service1
    type: STRICT_DNS
    connect_timeout: 0.25s
    lb_policy: ROUND_ROBIN
      cluster_name: service1
      - lb_endpoints:
        - endpoint:
                port_value: 8000
  access_log_path: /tmp/admin_access.log
      port_value: 8001
  - name: static_layer_0
              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 (

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

	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")
	http.HandleFunc("/", greet)
	if err := http.ListenAndServe(port, nil); err != nil {

Everything is ready, run the service and start the test


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


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
Log in to the container and verify by ping as follows:

root@eed301853eb6:/# ping docker.for.mac.localhost
PING docker.for.mac.localhost ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=37 time=4.02 ms
64 bytes from icmp_seq=2 ttl=37 time=0.361 ms
--- 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
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=37 time=1.31 ms
64 bytes from icmp_seq=2 ttl=37 time=1.55 ms
--- 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 with docker.for.mac.localhost or to realize the agent's access to the host.

Topics: Go Operation & Maintenance Docker Container