How to expose ports only within the docker network? - nginx

I have a few apps running in a Docker network with their ports (3000,4200, etc) exposed. I also have an nginx container running within the same Docker network which hosts these apps on port 80 with different domain names (site1.com, site2.com).
But right now if I go directly to the ports the apps are running on (localhost:3000) I can access them that way too.
How do I expose those ports only to the nginx container and not the host system?

But right now if I go directly to the ports the apps are running on
(localhost:3000) I can access them that way too.
Thats because you are using -p aka --publish command in your docker run
Explanation:
If you want to expose ports between containers only, Do Not use -p or --publish just put them on the same docker network.
Example:
Lets create a new user-defined network:
sudo docker network create appnet
Lets create nginx container for reverse proxy, It should be available to outside world so we use publish.
sudo docker run --name nginx -d --network appnet nginx
Now put your apps in the same network but do not expose ports.
sudo docker run --name app1 -d --network appnet <app image name/id>

You have to use Docker networks.
The default network is shared with host, thus accessible from localhost. You can either configure Docker, creating a network manually, or let tools like docker-compose or Kubernetes to do it for you.

Related

How to setup a simple reverse proxy in docker?

I am new in docker. I have of applications running on multiple container. Now, I would like to publish all my apps. What I am planning to do is do make a cluster containning all my application. I want at least 4 containers.
Nginx container that is facing internet like a reverse proxy. He is responsible to redirect traffic to other containers, since there are not directly accessible through internet.
Node_js container that publishes a web in nodejs (http://www.node-app.me).
java_EE container that publishes Java EE application (http://www.java_ee-app.me).
Django container that publishes a Django application(http://www.django-app.me).
This is the idear I have, but I don't no how to set nginx container to play the proxy role and make the request to the correct container so that if user send a request like http://www.node-app.me, the container nginx will return result from Node_js, and so on. Can you please give idear on where to start ?
The setup could look like this (sorry I am not very good at drawing) :
Unless you have a specific need for nginx, I suggest you use Træfik to do the reverse proxy. It can be configured to dynamically pick up reverse proxy rules via labels on your containers. Here's a basic example.
First, create a common network for Træfik and your three containers.
docker network create traefik
Run Træfik with port 80 exposed and the docker backend enabled.
docker run --name traefik \
-p 80:80 \
-v /var/run/docker.sock:/var/run/docker.sock \
--network traefik \
traefik:1.2.3-alpine \
--entryPoints='Name:http Address::80' \
--docker \
--docker.watch
Run your three services with the appropriate labels. Make sure they share a common network with Træfik so that Træfik can reach it. The node_js one might look something like this.
docker run --name node_js \
--network traefik \
--label 'traefik.frontend.rule=Host:www.node-app.me' \
--label 'traefik.frontend.entryPoints=http' \
--label 'traefik.port=80' \
--label 'traefik.protocol=http' \
your_node_js_image
Træfik will dynamically create a frontend rule that matches on the Host header for www.node-app.me when it sees this container running. The traefik.port and traefik.protocol labels let Træfik know how to communicate with your container.
See the documentation for Træfik's Docker backend for more options and details.

How do I find the network ip using docker and travis?

In my local setup, I can run ...
docker run --name myapp -e HOST=$(docker-machine ip default) --user root myapp
... and then use $HOST to connect to any other container (e.g. one running mongodb).
However, in Travis, docker-machine does not exist. Thus, I cannot simply put that line in my .travis.yml.
How do I get the network IP?
The flag --link adds an entry to /etc/hosts with the ip address of the specified running container
docker run --name myapp --link mongodb:mongodb myapp
However please note that:
The default docker0 bridge network supports the use of port mapping
and docker run --link to allow communications between containers in
the docker0 network. These techniques are cumbersome to set up and
prone to error. While they are still available to you as techniques,
it is better to avoid them and define your own bridge networks
instead.
Another option is using the flag --add-host if you want to add a known ip address
docker run --name myapp --add-host mongodb:10.10.10.1 myapp
Option 2
Create a network
docker network create --subnet=172.18.0.0/16 mynet123
Run mongodb container assigning an static ip
docker run --network mynet123 --ip 172.18.0.22 -d mongodb
Add that ip to the other container
docker run --network mynet123 --add-host mongodb:172.18.0.22 -d myapp

My docker container isn't starting on localhost (0.0.0.0) on Docker for Windows (Native using Hyper-V)

I'm following Digital Ocean's tutorial on how to start a nginx docker container (Currently on Step 4). Currently this is their output:
$ docker run --name docker-nginx -p 80:80 -d nginx
d3ccb73a91985651ec61231bca9f9c716f0dec807e354a29eeef2144f883a01c
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b91f3ce26553 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 443/tcp docker-nginx
But when I run it, this is my output (noticed the different IP of the container):
C:\>docker run --name docker-nginx -p 80:80 -d nginx
d3ccb73a91985651ec61231bca9f9c716f0dec807e354a29eeef2144f883a01c
C:\>docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d3ccb73a9198 nginx "nginx -g 'daemon off" 14 hours ago Up 2 seconds 10.0.75.2:80->80/tcp, 443/tcp docker-nginx
Why does this happen? And how can I get the same results as Digital Ocean's? (Getting the server to start on localhost)
Edit: I'm using Docker for windows (recently released) which apparently runs native using Hyper-V. My output for docker-machine ls is this:
C:\>docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
C:\>
But when I run it, this is my output (noticed the different IP of the
container)
Since this a Windows machine, I assume that you're using Docker Toolbox Docker for Windows. 10.0.75.2 is the IP of the boot2docker virtual machine.
If you are using Windows or Mac OS, you will need some form of virtualization in
order to run Docker. The IP you just saw is the IP of that lightweight virtual machine.
And how can I get the same results as Digital Ocean's? (Getting the
server to start on localhost)
Use a Linux distribution! Also you can enable Expose container ports on localhost in Docker For Windows Settings:
Despite you created the containers in your local machine. These are actually running on a different machine (a virtual machine)
First, check what is the IP of your docker machine (the virtual machine)
$docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM
default * virtualbox Running tcp://192.168.99.100
Then run curl command (or open a browser) to view the default web site on your nginx web server inside the container
curl http://192.168.99.100:80
if you are using a virtual machine on windows:
docker-machine ip default
https://docs.docker.com/machine/concepts/
When I ran this command for the first time: docker run -d -p 80:80 --name docker-tutorial docker101tutorial
I got this error:
docker: Error response from daemon: Conflict. The container name
"/docker-tutorial" is already in use by container "LONG_CONTAINER_ID".
You have to remove (or rename) that container to be able to reuse that
name.
so, I tried to remove this container using: docker rm -f LONG_CONTAINER_ID
then I did: docker run -d -p 3080:80 --name docker-tutorial docker101tutorial
note 3080:80 instead of 80:80... Had I run this from the docker desktop, I would see this default option below:

NGINX-Proxy: Running multiple ports tied to different virtual hosts on one container

Using Jason Wilder's NGINX-Proxy, is it possible to tie two or more sets of virtual hosts to individual ports on just one container?
What I'm thinking:
# start the reverse proxy
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy
# start a first container for http://tutum.test.local
docker run -d -e "VIRTUAL_HOST=tutum.test.local" -e "VIRTUAL_HOST=tutum.school.nationwide" -p 80:80 -p 3000:3000 tutum/hello-world
Where the first virtual host could be linked to a socket running on port 3000 in the code, and the second virtual host could be linked to the 8080 port and handle regular API calls.
Is that possible or would I be better served to just break the socket off into a separate docker container?
After further examining the code I realized this is not currently supported. The best method I've found is to break the sockets and API into different containers.

Docker EXPOSE vs command line -p option (boot2docker)

After spending way too long trying to access my node server running from a docker container within a boot2docker instance I realised the issue came down to a difference between expose and docker run -p.
In my Dockerfile I had EXPOSE 3001, and I could not access this via my host machine.
After running "docker run -p 3001:3001 myappinst myapp" I was able to access the port.
Up until now I thought "docker run -p 3001:3001" was essentially the same as EXPOSE 3001 in the dockerfile.
I noticed however, when running docker ps
I get the following for "EXPOSE":
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
16341e2b9968 housemation-crawler:latest "npm start" 2 minutes ago Up 2 minutes 3001/tcp housemation-crawler-inst
(note: 3001/tcp)
vs the below with docker run -p 3001:3001
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0b14f736033c housemation-crawler:latest "npm start" 8 seconds ago Up 2 seconds 0.0.0.0:3001->3001/tcp housemation-crawler-inst
(0.0.0.0:3001->3001/tcp)
Looks like the latter is doing some kind of port forwarding, whereas the former is just opening up the port? Would that be right?
If I wanted to access a non forwarded exposed port how would I go about doing so? Also, if I wanted to have port forwarding within the dockerfile, what would be the correct syntax?
Your assumptions about how EXPOSE in Dockerfile and -p option in docker run are right. As you can read in Docker on line documentation:
EXPOSE <port> [<port>...]
The EXPOSE instructions informs Docker that the container will listen
on the specified network ports at runtime. Docker uses this
information to interconnect containers using links (see the Docker
User Guide) and to determine which ports to expose to the host when
using the -P flag. Note: EXPOSE doesn't define which ports can be
exposed to the host or make ports accessible from the host by default.
To expose ports to the host, at runtime, use the -p flag or the -P
flag.
So the EXPOSE instruction in Dockerfile will indicate Docker which ports have to map to host if you run the container with the -P flag; but the local ports mapped are not deterministic and are chosen by Docker at run time. Apart from this, Docker will use the ports in EXPOSE to export information as environmental variables in linked containers.
If you want to set the local port mapped, you have to use the -p option in docker run.

Resources