Exposing a port on a live Docker container

2019-01-03 03:57发布

I'm trying to create a Docker container that acts like a full-on virtual machine. I know I can use the EXPOSE instruction inside a Dockerfile to expose a port, and I can use the -p flag with docker run to assign ports, but once a container is actually running, is there a command to open/map additional ports live?

For example, let's say I have a Docker container that is running sshd. Someone else using the container ssh's in and installs httpd. Is there a way to expose port 80 on the container and map it to port 8080 on the host, so that people can visit the web server running in the container, without restarting it?

标签: docker
14条回答
来,给爷笑一个
2楼-- · 2019-01-03 04:16

To add to the accepted answer iptables solution, I had to run two more commands on the host to open it to the outside world.

HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https

Note: I was opening port https (443), my docker internal IP was 172.17.0.2

Note 2: These rules and temporrary and will only last until the container is restarted

查看更多
走好不送
3楼-- · 2019-01-03 04:17

You cannot do this via Docker, but you can access the container's un-exposed port from the host machine.

if you have a container that with something running on its port 8000, you can run

wget http://container_ip:8000

To get the container´s ip address, run the 2 commands:

docker ps

docker inspect container_name | grep IPAddress

Internally, Docker shells out to call iptables when you run an image, so maybe some variation on this will work.

to expose the container's port 8000 on your localhosts port 8001:

 iptables -t nat -A  DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000

One way you can work this out, is to setup another container with the port mapping you want, and compare the output of the iptables-save command (though, I had to remove some of the other options that force traffic to go via the docker proxy).

NOTE: this is subverting docker, so should be done with the awareness that it may well create blue smoke

OR

Another alternative, is to look the (new? post 0.6.6?) -P option - which will use random host ports, and then wire those up.

OR

with 0.6.5, you could use the LINKs feature to bring up a new container that talks to the existing one, with some additional relaying to that container´s -p flags? (I have not used LINKs yet)

OR

with docker 0.11? you can use docker run --net host .. to attach your container directly to the host's network interfaces (ie, net is not name-spaced) and thus all ports you open in the container are exposed.

查看更多
劫难
4楼-- · 2019-01-03 04:20

I had to deal with this same issue and was able to solve it without stopping any of my running containers. This is a solution up-to-date as of February 2016, using Docker 1.9.1. Anyway, this answer is a detailed version of @ricardo-branco's answer, but in more depth for new users.

In my scenario, I wanted to temporarily connect to MySQL running in a container, and since other application containers are linked to it, stopping, reconfiguring, and re-running the database container was a non-starter.

Since I'd like to access the MySQL database externally (from Sequel Pro via SSH tunneling), I'm going to use port 33306 on the host machine. (Not 3306, just in case there is an outer MySQL instance running.)

About an hour of tweaking iptables proved fruitless, even though:

Step by step, here's what I did:

mkdir db-expose-33306
cd db-expose-33306
vim Dockerfile

Edit dockerfile, placing this inside:

# Exposes port 3306 on linked "db" container, to be accessible at host:33306
FROM ubuntu:latest # (Recommended to use the same base as the DB container)

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody
EXPOSE 33306

CMD socat -ffffdd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306

Then build the image:

docker build -t your-namespace/db-expose-33306 .

Then run it, linking to your running container. (Use -d instead of -rm to keep it in the background until explicitly stopped and removed. I only want it running temporarily in this case.)

docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306  your-namespace/db-expose-33306
查看更多
放荡不羁爱自由
5楼-- · 2019-01-03 04:21

You can use an overlay network like Weave Net, which will assign a unique IP address to each container and implicitly expose all the ports to every container part of the network.

Weave also provides host network integration. It is disabled by default but, if you want to also access the container IP addresses (and all its ports) from the host, you can run simply run weave expose.

Full disclosure: I work at Weaveworks.

查看更多
Explosion°爆炸
6楼-- · 2019-01-03 04:22

Here's what I would do:

  • Commit the live container.
  • Run the container again with the new image, with ports open (I'd recommend mounting a shared volume and opening the ssh port as well)
sudo docker ps 
sudo docker commit <containerid> <foo/live>
sudo docker run -i -p 22 -p 8000:80 -m /data:/data -t <foo/live> /bin/bash
查看更多
男人必须洒脱
7楼-- · 2019-01-03 04:27

There is a handy HAProxy wrapper.

docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_HOST=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy

This creates an HAProxy to the target container. easy peasy.

查看更多
登录 后发表回答