[ 
https://issues.apache.org/jira/browse/MESOS-5961?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15407800#comment-15407800
 ] 

Alexander Rukletsov edited comment on MESOS-5961 at 8/4/16 2:34 PM:
--------------------------------------------------------------------

h1. Summary / Suggested Solution
To keep the implementation simple and consistent, I propose that the Docker 
executor's health check thread should always enter the task's net namespace and 
connect to {{localhost}} on the port specified in the health check proto.

The framework would then be responsible for deciding if the health checker 
should connect to the {{containerPort}} or the {{hostPort}}.

h1. Testing results
h2. HOST networking
# Connect to {{localhost:<hostPort>}}.
# Enter the container's net ns and connect to {{localhost:<hostPort>}}.

NOTE: In this case, both the docker executor and the container are in the same 
network, hence `setns` call will be a noop. We still suggest not to treat this 
case differently for consistency and readability.

h2. BRIDGED networking
# If the task specified port mappings, connect to {{localhost:<hostPort>}}.
# Enter the container's net ns and connect to {{localhost:<containerPort>}}.

h2. USER networking (DC/OS Overlay network)
# If the task specifies a {{hostPort}}, connect to {{localhost:<hostPort>}}.
# If the task doesn't use a host port, enter the container's net ns and connect 
to {{localhost:<containerPort>}}. I expect this to be the most common case.

h1. Testing notes
h2. Getting the networking namespace
{code}
NETNS="/proc/`docker inspect -f '{{.State.Pid}}' <container id>`/ns/net"
{code}

h2. Test Utility
The following utility enters a network namespace and does an HTTP request.

{code}
package main

import (
        "fmt"
        "io"
        "net/http"
        "os"
        "syscall"

        "github.com/opencontainers/runc/libcontainer/system"
)

func doNetns(nsPath string) error {
        ns, err := os.Open(nsPath)
        if err != nil {
                return err
        }
        return system.Setns(ns.Fd(), syscall.CLONE_NEWNET)
}

func doGet(port string) {
        response, err := http.Get("http://localhost:"; + port)
        if err != nil {
                fmt.Fprintf(os.Stderr, "%s\n", err)
        } else {
                defer response.Body.Close()
                _, err := io.Copy(os.Stderr, response.Body)
                if err != nil {
                        fmt.Fprintf(os.Stderr, "%s\n", err)
                }
        }
}

func main() {
        doNetns(os.Args[1])
        doGet(os.Args[2])
}
{code}

h2. Marathon App Definitions
h3. HOST networking
{code}
{
  "id": "/host",
  "cmd": "python -m SimpleHTTPServer $PORT0",
  "cpus": 0.1,
  "mem": 32,
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "python:2",
      "network": "HOST"
    }
  },
  "portDefinitions": [
    {
      "name": "http",
      "protocol": "tcp"
     }
  ]
}
{code}

h3. BRIDGE networking
{code}
{
  "id": "/bridged",
  "cmd": "python -m SimpleHTTPServer 31337",
  "cpus": 0.1,
  "mem": 32,
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "python:2",
      "network": "BRIDGE",
      "portMappings": [
        {
          "containerPort": 31337,
          "hostPort": 0,
          "name": "http"
        }
      ]
    }
  }
}
{code}

h3. USER networking (DC/OS Overlay network)
{code}
{
  "id": "/overlay",
  "cpus": 0.1,
  "mem": 32,
  "cmd": "python -m SimpleHTTPServer 31337",
  "container": {
   "type": "DOCKER",
    "docker": {
      "network": "USER",
      "image": "python:2",
      "portMappings": [
        {
          "containerPort": 31337,
          "protocol": "tcp",
          "name": "http"
        }
      ]
    }
  },
  "ipAddress": {
    "networkName": "dcos"
  }
}
{code}




was (Author: gkleiman):
h1. Summary / Suggested Solution
To keep the implementation simple and consistent, I propose that the Docker 
executor's health check thread should always enter the task's net namespace and 
connect to {{localhost}} on the port specified in the health check proto.

The framework would then be responsible for deciding if the health checker 
should connect to the {{containerPort}} or the {{hostPort}}.

h1. Testing results
h2. HOST networking
# Connect to {{localhost:<hostPort>}}.
# Enter the container's net ns and connect to {{localhost:<hostPort>}}.

NOTE: In this case, both the docker executor and the container are in the same 
network, hence `setns` call will be a noop. We still suggest not to treat this 
case differently for consistency and readability.

h2. BRIDGED networking
# Connect to {{localhost:<hostPort>}}.
# Enter the container's net ns and connect to {{localhost:<containerPort>}}.

h2. USER networking (DC/OS Overlay network)
# If the task specifies a {{hostPort}}, connect to {{localhost:<hostPort>}}.
# If the task doesn't use a host port, enter the container's net ns and connect 
to {{localhost:<containerPort>}}. I expect this to be the most common case.

h1. Testing notes
h2. Getting the networking namespace
{code}
NETNS="/proc/`docker inspect -f '{{.State.Pid}}' <container id>`/ns/net"
{code}

h2. Test Utility
The following utility enters a network namespace and does an HTTP request.

{code}
package main

import (
        "fmt"
        "io"
        "net/http"
        "os"
        "syscall"

        "github.com/opencontainers/runc/libcontainer/system"
)

func doNetns(nsPath string) error {
        ns, err := os.Open(nsPath)
        if err != nil {
                return err
        }
        return system.Setns(ns.Fd(), syscall.CLONE_NEWNET)
}

func doGet(port string) {
        response, err := http.Get("http://localhost:"; + port)
        if err != nil {
                fmt.Fprintf(os.Stderr, "%s\n", err)
        } else {
                defer response.Body.Close()
                _, err := io.Copy(os.Stderr, response.Body)
                if err != nil {
                        fmt.Fprintf(os.Stderr, "%s\n", err)
                }
        }
}

func main() {
        doNetns(os.Args[1])
        doGet(os.Args[2])
}
{code}

h2. Marathon App Definitions
h3. HOST networking
{code}
{
  "id": "/host",
  "cmd": "python -m SimpleHTTPServer $PORT0",
  "cpus": 0.1,
  "mem": 32,
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "python:2",
      "network": "HOST"
    }
  },
  "portDefinitions": [
    {
      "name": "http",
      "protocol": "tcp"
     }
  ]
}
{code}

h3. BRIDGE networking
{code}
{
  "id": "/bridged",
  "cmd": "python -m SimpleHTTPServer 31337",
  "cpus": 0.1,
  "mem": 32,
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "python:2",
      "network": "BRIDGE",
      "portMappings": [
        {
          "containerPort": 31337,
          "hostPort": 0,
          "name": "http"
        }
      ]
    }
  }
}
{code}

h3. USER networking (DC/OS Overlay network)
{code}
{
  "id": "/overlay",
  "cpus": 0.1,
  "mem": 32,
  "cmd": "python -m SimpleHTTPServer 31337",
  "container": {
   "type": "DOCKER",
    "docker": {
      "network": "USER",
      "image": "python:2",
      "portMappings": [
        {
          "containerPort": 31337,
          "protocol": "tcp",
          "name": "http"
        }
      ]
    }
  },
  "ipAddress": {
    "networkName": "dcos"
  }
}
{code}



> HTTP and TCP health checks should support docker executor and bridged mode.
> ---------------------------------------------------------------------------
>
>                 Key: MESOS-5961
>                 URL: https://issues.apache.org/jira/browse/MESOS-5961
>             Project: Mesos
>          Issue Type: Improvement
>            Reporter: Alexander Rukletsov
>            Assignee: haosdent
>              Labels: health-check, mesosphere
>
> If an executor and a task, e.g. the docker executor and docker container in 
> bridged mode, exist in different network namespaces, HTTP and TCP health 
> checks using {{localhost}} may not work properly. One solution would be to 
> enter the container's network in the health check binary.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to