do docker container IPs change on restart? - nginx

I am new to docker and I have been dockerizing all my application in a single server. So far, everything is fine and working. However, I don't understand one thing. I am using docker-compose for everything (I haven't created dockerfile for my projects yet) and there is this ports attribute in docker-compose. If I write something like this:
ports:
8085:80
It will listen on 0.0.0.0:8085, which means outside world has access to my server. After some discussions and google-ing, I found that I can take an IP address in my docker bridge network and do port mappings easily:
ports:
172.17.0.1:8085:80
This will listen only on 172.17.0.1:8085, which is great as it is only listens on internally and my nginx proxies the traffic to the necessary ports. (e.g proxy_pass http://172.17.0.1:8085). After knowing more about docker and understanding how they work, I realized that all these containers have their own IP addresses with ports exposed only to those addresses. For example, one of my "web" containers has IPv4 address of 172.17.0.10 and port 80 is exposed. If I do docker inspect on one of these containers, I will see the IP address of the container.
Now, I want to use these IP addresses in my nginx. Instead of proxy_pass http://172.17.0.1:8085, I want to do http://172.17.0.10. I personally think that this is a much elegant interface but there is one thing that concerns me. What happens if I restart my machine? All the containers will start in some kind of order. If I have 5 web containers and they start in random order, can I be sure that the IPs for these containers will be the same? Or will they change? Should I always use ports in docker-compose for use by nginx? If yes, how can I have different IPs per container instead of different ports with the same IP? Will it be okay if I create another docker network interface (let's say in subnet 172.17.1.0), and assign different IPs from that interface to the exposed "public" ports? By this I mean basically using 172.17.1.1:80:80 in one container, 172.17.1.2:80:80 in another etc.

Not an expert in the docker-networking domain but I'll try my best to answer the questions you got there.
Q: What happens if I restart my machine? All the containers will start in some kind of order.
A: Unless you use the links or depends_on keywords, otherwise you cannot guarantee the start sequence.
Q: If I have 5 web containers and they start in random order, can I be sure that the IPs for these containers will be the same?
A: I did a little experiment on my machine by taking note of the ipaddresses of my existing 2 containers (postgresDB and influxDB).
They are running on
Postgres: 172.17.0.2
InfluxDB: 172.17.0.3
Shut it down and boot again. Probably due to them booting up the same order this time, the ip addresses seems to have been maintained. Added the depends_on keyword to force the InfluxDB container to start first before Postgres can, now the IP addresses of both containers are;
Postgres: 172.17.0.3
InfluxDB: 172.17.0.2
I think the IP is distributed based on a first come first serve basis. If you didn't specify an ordering for booting up the containers I think there is a small chance which the ip can be different for the containers. Really depends on who runs first.
Q: Should I always use ports in docker-compose for use by nginx?
A: Yes, if you would like to port forward an nginx instance's port to the outside world. Otherwise no one will be able to hit that web server. E.g. exposing port 443 to let HTTPs traffic come through.
Q: how can I have different IPs per container instead of different ports with the same IP?
A: I don't know whether that is possible or not but after doing some research for you on the docker-compose documentation it seems possible by using the ipam keyword.
See:
https://docs.docker.com/compose/compose-file/#/ipam
That looks scary to me so what I did for my own project was to use the service_name instead.
Example:
container_bbb:
image: banana
my_nginx:
image: apple
environment:
- MOUNT_SRC0=http://container_bbb:80
- MOUNT_DEST0=/
links:
- container_bbb
For this instance in the my_nginx container, the service name container_bbb would be resolved into the hostname of that container.
Then I will have a python script that would dynamically generate the ngix config using this information at the container's entrypoint script area.
Sounds a bit overkill but that gives me more control over what I want to do with my nginx.
So in my /etc/nginx/conf.d/default-locations/ the configs would be something like;
location /container_bbb/ {
proxy_pass http://container_bbb:3000/;
}
Note:
I am using this nginx server instance as a reverse proxy server.
I guess what I am trying to say here is that you can essentially use the hostname instead of the ip address. And to get to the container next-door you would pass in http://CONTAINER_SERVICE_NAME:PORT

You can't rely on the containers' IP addresses. If all your services are on the same docker-compose config, they will automatically be part of the same internal network and you can simply use the service names as the hostnames.
E.g., If your web app was named php, your nginx proxy config would look something like:
location / {
proxy_pass http://php;
proxy_set_header Host $host;
proxy_redirect off;
}
(Also note you might want to enable your firewall, just in case any of the port mappings leaks out to the public IP address of the host.)

Related

How to set up networking for multiple WordPress containers behind an NGINX reverse proxy?

I am trying to use Docker to set up two WordPress containers behind a container running an NGINX reverse-proxy, as illustrated in the following diagram (this is all on an Ubuntu 22.04 VPS):
Ideally, I'd like to have the only connection to the world be via the host's ports 80 and 443 mapped to the NGINX container and then have everything else internal to the Docker network. The issue I am running into is that the official WordPress image wants to expose itself on port 80 as well and that's obviously causing a conflict.
One solution would be to mount the NGINX container on the host's network and map the WordPress containers' ports, but I'd like to keep everything contained. Is there a way to map the WordPress container port to something within itself or create a port mapping on the Docker network? (I am DEFINITELY not a networking person in any way so apologies if I'm missing something obvious)
I ended up moving the apache config files to a directory mounted from the host, then editing the ports.conf and sites-enabled/000-default.conf to get apache to use a different port. There also seemed to be an issue with the reverse-proxy config in NGINX, but that was solved with some copypasta and I'm not quite sure what the problem ended up being there.

How to build multi tenant application using docker

I am pretty much new to the docker concept and know basics of it.
I just wanted to know how can we build multi tenant application using docker.
Where the containers will use the local hosted database with different schema.With the nginx we can do reverse proxy but how we can achieve it?
because every container will be accessed by localhost:8080 and how we can add upstream and server part.
It will be very helpful if some one explains it to me.
If I understand correctly you want processes in containers to connect to resources on the host.
From you containers perspective in bridge mode (the default), the host's IP is the gateway. Unfortunate the gateway IP address may vary and can only be determinate at runtime.
Here are a few ways to get it:
From the host using docker inspect: docker inspect <container name or ID>. The gateway will be available under NetworkSettings.Networks.Gateway.
From the container you can execute route | awk '/^default/ { print $2 }'
One other possibility is to use --net=host when running your container.
This will run you processes on the same network as your processes on your host. Doing so will make your database accessible from the container on localhost.
Note that using --net=host will not work on Docker for mac/windows.

Best software for dynamic dns proxying to docker containers

Currently i am using haproxy with manual updating backends which points to separate docker nginx containers for different apps.
What is best software to proxying request to different local nginx containers based on hostname?
I would have a simple map file or even /etc/hosts/ which my script would update when docker containers change, for example:
domain1 1.1.1.1
domain2 1.1.1.2
domain3 1.1.1.3
So ideal will be haproxy -> some software proxy or dns -> docker nginx
and software would use map file in fly, not reloading and point request to local ip address.
Maybe i would put varnish cache in front so it would need to be compatible with that too (and why wouldn't) so flow would be:
request -> haproxy (for load balancing in multiple servers)
-> varnish on public server ip ( for in memory caching based on host and route, so if there is cache return response immediately )
-> SOME PROXY OR DNS BASED ON SIMPLE MAP FILE which will further proxy to local ip of one of multiple docker nginx containers
-> docker nginx inside custom network
-> some app in container
What is best practice for this flow, should i put varnish somewhere else, and what is a software i am seeking for?
I am currently using one extra nginx and mapping $host to custom ip address in custom maps.conf file and gracefully reloading nginx on change, but i got feeling that there is better solution for this.
Also i forgot to mention that i dont need only http proxying based on map file, but tcp (ssh, smtp, ftp..) too, just in those cases i will not have haproxy and varnish in front and this app would be public faced on those port.
for example:
port:22
domain1 1.1.1.1
domain2 1.1.1.2
domain3 1.1.1.3
port:25
domain1 1.1.1.4
domain2 1.1.1.5
domain3 1.1.1.6
I think something like Muguet might solve your issue.
From their github repo:
When using Docker, it's sometimes a pain to access your containers
using specific IPs/ports.
Muguet provides you with a DNS Server that resolves auto-generated
hostnames to your containers IPs, plus a Reverse Proxy to access all
your web apps on port 80.
I think what you want is dnsmasq. This basically is a lightweight DNS service you run on your host running docker containers and it allows you to use hostnames instead of IP addresses. It's a pretty common way to solve this issue.
A nice guide to setting up dnsmasq can be found at:
http://docs.blowb.org/setup-host/dnsmasq.html
and searching dnsmasq and docker will point you to many more resources.
One thing to remember is on your haproxy host, make sure you modify the /etc/resolv.conf to include your dnsmasq server.

Looking up a container's address via its hostname dynamically in Nginx

I'm currently trying to run two containers on a single host, one being an application (Ruby on Rails) and the other Nginx as a reverse proxy and cache. The app is running on TCP port 80. What I want to be able to do is bring down my application container, remove it and then bring it up again without having to restart nginx. The problem is that Nginx only seems to look up the IP of the container once, so if it goes down then back up at a different address then Nginx will just complain that there's nothing there.
I've tried a few things:
Using resolver 127.0.0.11 valid=5 to use Docker's DNS
Using an upstream block
Using a variable to try to get nginx to resolve at runtime.
I'm not sure where else to look but none of these options work if the application is brought up on a different IP address. Is there something I'm missing making this impossible?
Thanks.
Ended up reading through the 12 factor app which inspired me to remove the Nginx proxying to Rails upstream altogether, and instead used it as a proxy cache which has an upstream of the external DNS name.

Docker DNS setup on VPS

I have a VPS with static IP address (108.1.2.3 for ex). On this server I have a two docker containers with separate IP (10.1.2.3 and 10.1.2.4 for ex). And I have two domains: domain1.com and domain2.com.
My question is: how I can setup a DNS server for this two domains?
I need to point domain1.com to 10.1.2.3, domain2.com to 10.1.2.4 and have an access through browser for each domain.
I found a solution, but it doesn't work for me.
Unless you add network interfaces to the VPS and give it multiple static IPs and bind the container ports to these IPs (using docker run -p with ip:port:c_port value), you will need some kind of reverse proxy.
When using a reverse proxy such as nginx, your issue with nginx seems to be the need to reload. Please note that, you won't only need to reload every time a new container is launched, but also every time a container is restarted (if you use an nginx container internally linked to the other containers..)
What you need is service discovery and configuration listeners to reload your reverse proxy automatically such as: etcd+confd or https://consul.io/

Resources