简体   繁体   中英

Error connecting to python server running in boot2docker (centos container | Windows 7.1 host)

My use case :
We need to run a watir-webdriver script in headless mode and our dev machines run Windows.

The gist of our problem :

I can stand up the python server inside the container, but I can't connect to it at its expected location from the host: http://192.168.59.103:8084.

The architecture :

A ruby script that "does something useful and prints the output to the console" and a basic python server that imports os and then executes os.system('ruby ourrubyscript.rb') inside our index route. We also brought in flask for api routing and flask.cors to eliminate potential cross origin issues.

Local test (on Host) :

running "python server.py" in our host workspace stands up a python server on port 5000. Routing to it from a browser executes our route and prints the expected output to the console.

server.py

from flask import Flask
from flask import request
from flask.ext.cors import CORS

import os

app = Flask(__name__)
CORS(app, resources={r'/': {"origins": "*"}}, headers='Content-Type')
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route('/')
def index():
    return "<h1>Hello Stupid</h1>"

@app.route('/ruby/test', methods=['GET'])
def runRubyScript():
    return os.system("ruby script.rb")

if __name__ == "__main__":
    app.run()

When I nav to localhost:5000, "Hello Stupid" prints to my screen.
When I route to localhost:5000/ruby/test, our script runs and that script prints to my console.


Procedure to move this to docker

We pulled latest centos and installed wget, xvfb, git, ruby, python, pip, flask, flask-cors, and firefox; committed that to a local image named "webdev." Then gem installed headless and installed phantomjs to $PATH We then cloned our src repository to "/opt/testapp" in the container. This repository contains our "server.py" file and a "script.rb" file.

docker@boot2docker:~$ docker run -d -p 5000:5000 --name wd webdev python /opt/testapp/server.py

So, I left my boot2docker-vm bound to private ip 192.168.59.103 , and I can confirm that this ip is valid by navigating to a different port that is running a different container; however, when I navigate to 5000, I get an ERR_CONNECTION_REFUSED. I had an almost "AHA!!" moment thinking that iptables had the port locked down by default and we needed to go open internal port 5000 in order to map it out to the vm but then I found that the centos image does not have iptables (or firewalld since this is CentOS7) installed by default. When that approach turned out to be incorrect, I decided to post to see if anyone might be able to assist here because I am out of ideas.

So I have figured out why this is not exposed to the host environment and this makes perfect sense.

In NAT mode, the virtual machine gets assigned a private static ip address: 192.168.59.103 (that is...the virtual machine gets assigned that IP)

Each container stands up with 2 adapters: a loopback and an externally facing virtual private bridge accessible to the vm.

When I stand up my server on port 5000, it binds directly to loopback inside the container and is inaccessible to the virtual machine.

Removing the localhost binding from the service and allowing it to bind to the default gateway 0.0.0.0:5000

causes the service to listen on all adapters and allows communications between the vm and the container's external adapter through the virtual private bridge that gets created when the container stands.

For some reason, switching my virtual machine to run in Bridged mode against my NIC is causing the boot2docker-vm to crash on start....so I'm relegated to NAT for the time being until I can figure out how to switch it properly.

[Edit 1 (related to bridging)]

Bridge mode seems to currently be unsupported in boot2docker as of at least October 8, 2014. b2d expects a NAT adapter for ssh bootstrapping and the host adapter for container<->container socket access.

The current, unsupported, undocumented workaround to expose a container to hosts on a network is to add a third network interface to VirtualBox and bridge with it.


[Edit 2 (example server running against default gateway)]

Here is an example of a flask server that attaches to all interfaces: Note that the only Δ between the server above and the server below is the final line of the configuration.

app.run() needs to become app.run(host='0.0.0.0')

from flask import Flask
from flask import request
from flask.ext.cors import CORS

import os

app = Flask(__name__)
CORS(app, resources={r'/': {"origins": "*"}}, headers='Content-Type')
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route('/')
def index():
    return "<h1>Hello Stupid</h1>"

@app.route('/ruby/test', methods=['GET'])
def runRubyScript():
    return os.system("ruby script.rb")

if __name__ == "__main__":
    app.run(host='0.0.0.0')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM