nginx load balancer - Docker compose - docker

I have a simple flask app running on port 5000 inside the container , and i'm trying to add nginx load balance to scale the app(3 instances)
Here is my docker-compose file :
version: "3.7"
services:
chat-server:
image: chat-server
build:
context: .
dockerfile: Dockerfile
volumes:
- './chat_history:/src/app/chat_history'
networks:
- "chat_net"
ngnix-server:
image: nginx:1.13
ports:
- "8080:80"
volumes:
- './ngnix.conf:/etc/ngnix/nginx.conf'
networks:
- "chat_net"
depends_on:
- chat-server
networks:
chat_net:
And here is my nginx.conf file :
events { worker_connections 1024;}
http {
upstream app {
server chat-server_1:5000;
server chat-server_2:5000;
server chat-server_3:5000;
}
}
server {
listen 80;
location / {
proxy_pass http://app;
}
}
both services are on the same chat_net network , but when i hit localhost:8080 on my browser im getting the nginx default page , why is that? what am i missing ?

You have a typo and are not mounting in your nginx.conf file correctly.
You spell it ngnix in a couple of places in your volumes section and the container runs with the default config (hence default home page).
Once you fix that, you will probably hit the error mentioned by #Federkun (nginx won't be able to resolve the 3 domain names you're proxying).
You also have your server directive in the wrong place (it needs to be within the http section).
This should be the modified version of your file:
events { worker_connections 1024;}
http {
upstream app {
server chat-server:5000;
}
server {
listen 80;
location / {
proxy_pass http://app;
}
}
}
Notice this is better than needing nginx to be aware of the replica count. You can run docker-compose up with --scale chat-server=N and resize at anytime by running the same command with a different N without downtime.

#Jedi
shouldn't be at least below?
events { worker_connections 1024;}
http {
upstream app {
least_conn;
server chat-server_1:5000;
server chat-server_2:5000;
}
server {
listen 80;
location / {
proxy_pass http://app;
}
}
}

Related

How to fix 502 Bad Gateway error in nginx?

I have a server running docker-compose. Docker-compose has 2 services: nginx (as a reverse proxy) and back (as an api that handles 2 requests). In addition, there is a database that is not located on the server, but separately (database as a service).
Requests processed by back:
get('/api') - the back service simply replies "API is running" to it
get('/db') - the back service sends a simple query to an external database ('SELECT random() as random, current_database() as db')
request 1 - works fine, request 2 - the back service crashes, nginx continues to work and a 502 Bad Gateway error appears in the console.
An error occurs in the nginx service Logs: upstream prematurely
closed connection while reading response header from upstream.
The back service Logs: connection terminated due to connection timeout.
These are both rather vague errors. And I don’t know how else to get close to them, given that the code is not in a container, without Nginx and with the same database, it works as it should.
What I have tried:
increase the number of cores and RAM (now 2 cores and 4 GB of Ram);
add/remove/change proxy_read_timeout, proxy_send_timeout and proxy_connect_timeout parameters;
test the www.test.com/db request via postman and curl (fails with the same error);
run the code on your local machine without a container and compose and connect to the same database using the same pool and the same ip (everything is ok, both requests work and send what you need);
change the parameter worker_processes (tested with a value of 1 and auto);
add/remove attribute proxy_set_header Host $http_host, replace $http_host with "www.test.com".
Question:
What else can I try to fix the error and make the db request work?
My nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http{
upstream back-stream {
server back:8080;
}
server {
listen 80;
listen [::]:80;
server_name test.com www.test.com;
location / {
root /usr/share/nginx/html;
resolver 121.0.0.11;
proxy_pass http://back-stream;
}
}
}
My docker-compose.yml:
version: '3.9'
services:
nginx-proxy:
image: nginx:stable-alpine
container_name: nginx-proxy
ports:
- 80:80
- 443:443
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- network
back:
image: "mycustomimage"
container_name: back
restart: unless-stopped
ports:
- '81:8080'
networks:
- network
networks:
network:
driver: bridge
I can upload other files if needed. Just taking into account the fact that the code does not work correctly in the container, the problem is rather in setting up the container.
I will be grateful for any help.
Code of the back: here
The reason for the error is this: I forgot to add my server's ip to the list of allowed addresses in the database cluster.

How to use service name as URL in Docker?

What I want to do:
My docker-composer file contains several services, which each have a service name. All services use the exact same image. I want them to be reachable via the service name (like curl service-one, curl service-two) from the host. The use-case is that these are microservices that should be reachable from a host system.
services:
service-one:
container_name: container-service-one
image: customimage1
service-two:
container_name: container-service-two
image: customimage1
What's the problem
Lots of tutorials say that that's the way to build microservices, but it's usually done by using ports, but I need services names instead of ports.
What I've tried
There are lots of very old answers (5-6 years), but not a single one gives a working answer. There are ideas like parsing the IP of each container and then using that, or just using hostnames internally between docker containers, or complex third party tools like building your own DNS.
It feels weird that I'm the only one who needs several APIs reachable from a host system, this feels like standard use-case, so I think I'm missing something here.
Can somebody tell me where to go from here?
I'll start from basic to advanced as far as I know.
For starter, every service that's part of the docker network (by default everyone that's part of the compose file) so accessing each other by their service name is already there "for free".
If you want to use the service names from the host itself you can set a reverse proxy like nginx and by the server name (in your case would be equal to service name) route the appropriate port on the host running the docker containers.
the basic idea is to intercept all communication to port 80 on the server and send the communication by the incoming DNS name.
Here's an example:
compose file:
version: "3.9"
services:
nginx-router:
image: "nginx:latest"
volumes:
- type: bind
source: ./nginx.conf
target: /nginx/nginx.conf
ports:
- "80:80"
service1:
image: "nginx:latest"
ports:
- "8080:80"
service2:
image: "httpd:latest"
ports:
- "8081:80"
nginx.conf
worker_processes auto;
pid /tmp/nginx.pid;
events {
worker_connections 8000;
multi_accept on;
}
http {
server {
listen 80;
server_name 127.0.0.1;
location / {
proxy_set_header Host $host;
proxy_pass http://service1:80;
}
}
server {
listen 80;
server_name localhost;
location / {
proxy_set_header Host $host;
proxy_pass http://service2:80;
}
}
}
in this example if my server name is localhost I'm routing to service2 which is an httpd image or Apache HTTP and we're getting it works which is the default apache image HTML page:
and when we're accessing through 127.0.0.1 server name we should see nginx and indeed this is what we're getting:
in your case you'd use the service names instead after setting them as a DNS record and using this DNS record to route to the appropriate service.

serving static files from jwilder/nginx-proxy

I have a web app (django served by uwsgi) and I am using nginx for proxying requests to specific containers.
Here is a relevant snippet from my default.conf.
upstream web.ubuntu.com {
server 172.18.0.9:8080;
}
server {
server_name web.ubuntu.com;
listen 80 ;
access_log /var/log/nginx/access.log vhost;
location / {
include uwsgi_params;
uwsgi_pass uwsgi://web.ubuntu.com;
}
}
Now I want the static files to be served from nginx rather than uwsgi workers.
So basically I want to add something like:
location /static/ {
autoindex on;
alias /staticfiles/;
}
to the automatically generated server block for the container.
I believe this should make nginx serve all requests to web.ubuntu.com/static/* from /staticfiles folder.
But since the configuration(default.conf) is generated automatically, I don't know how to add the above location to the server block dynamically :(
I think location block can't be outside a server block right and there can be only one server block per server?
so I don't know how to add the location block there unless I add dynamically to default.conf after nginx comes up and then reload it I guess.
I did go through https://github.com/jwilder/nginx-proxy and I only see an example to actually change location settings per-host and default. But nothing about adding a new location altogether.
I already posted this in Q&A for jwilder/nginx-proxy and didn't get a response.
Please help me if there is a way to achieve this.
This answer is based on this comment from the #553 issue discussion on the official nginx-proxy repo. First, you have to create the default_location file with the static location:
location /static/ {
alias /var/www/html/static/;
}
and save it, for example, into nginx-proxy folder in your project's root directory. Then, you have to add this file to /etc/nginx/vhost.d folder of the jwilder/nginx-proxy container. You can build a new image based on jwilder/nginx-proxy with this file being copied or you can mount it using volumes section. Also, you have to share static files between your webapp and nginx-proxy containers using a shared volume. As a result, your docker-compose.yml file will look something like this:
version: "3"
services:
nginx-proxy:
image: jwilder/nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./nginx-proxy/default_location:/etc/nginx/vhost.d/default_location
- static:/var/www/html/static
webapp:
build: ./webapp
expose:
- 8080
volumes:
- static:/path/to/webapp/static
environment:
- VIRTUAL_HOST=webapp.docker.localhost
- VIRTUAL_PORT=8080
- VIRTUAL_PROTO=uwsgi
volumes:
static:
Now, the server block in /etc/nginx/conf.d/default.conf will always include the static location:
server {
server_name webapp.docker.localhost;
listen 80 ;
access_log /var/log/nginx/access.log vhost;
location / {
include uwsgi_params;
uwsgi_pass uwsgi://webapp.docker.localhost;
include /etc/nginx/vhost.d/default_location;
}
}
which will make Nginx serve static files for you.

nginx reverse-proxy simple config not redirecting

To get the hang of nginx with docker, I have a very simple nginx.conf file + docker-compose, running 2 containers for 1 service (service itself+db).
What I want:
localhost --> show static page
localhost/pics --> show another static page
localhost/wekan --> redirect to my container, which is running on port 3001.
the last part (redirect to docker-container) does not work. The app can be reached under localhost:3001, tho.
My nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
server{
listen 80;
location / {
root /home/user/serverTest/up1; #index.html is here
}
location /wekan {
proxy_pass http://localhost:3001;
rewrite ^/wekan(.*)$ $1 break; # this didnt help either
}
location /pics {
proxy_pass http://localhost/example.jpg;
}
location ~ \.(gif|jpg|png)$ {
root /home/user/serverTest/data/images;
}
}
docker-compose.yml:
version: '2'
services:
wekandb:
image: mongo:3.2.21
container_name: wekan-db
restart: always
command: mongod --smallfiles --oplogSize 128
networks:
- wekan-tier
expose:
- 27017
volumes:
- /home/user/wekan/wekan-db:/data/db
- /home/user/wekan/wekan-db-dump:/dump
wekan:
image: quay.io/wekan/wekan
container_name: wekan-app
restart: always
networks:
- wekan-tier
ports:
# Docker outsideport:insideport
- 127.0.0.1:3001:8080
environment:
- MONGO_URL=mongodb://wekandb:27017/wekan
- ROOT_URL=http://localhost
Looking at the nginx-error logs, I get this:
2018/12/17 11:57:16 [error] 9060#9060: *124 open() "/home/user/serverTest/up1/31fb090e9e6464a4d62d3588afc742d2e11dc1f6.js" failed (2: No such file or directory),
client: 127.0.0.1, server: ,
request: "GET /31fb090e9e6464a4d62d3588afc742d2e11dc1f6.js?meteor_js_resource=true HTTP/1.1", host: "localhost",
referrer: "http://localhost/wekan"
So I guess this makes sense because in my understanding, nginx is now adding the redirect to the root given # /, but clearly this is not where the container is running.
How do I prevent that?
Your nginx cannot access the local network interface of your docker composition.
Try to bind wekan's port like this:
wekan:
ports:
- 127.0.0.1:3001:8080
Mind the 127.0.0.1
See https://docs.docker.com/compose/compose-file/#ports
the problem was within the docker-compose configuration.
For anyone wondering, all you need is a proxy pass addr:port or addr:port/ whereas the 2nd option does the same as the rewrite part, so this can be skipped.
Apart from that, i had to add the /wekan into the ROOT_URL inside my docker-compose

Nginx proxy for multibranch environment

I am using nginx as a simple proxy service for my multiple dockerized containers (including image with nginx layer as well). I am trying to create vhost for each branch and this is causing a lot of trouble here. What i want to achieve is:
An nginx proxy service should proxy to containers on paths:
[branch_name].a.xyz.com (frontend container)
some-jenkins.xyz.com (another container)
some other containers not existing yet
nginx.conf inside proxy container:
upstream frontend-branch {
server frontend:80;
}
server {
listen 80;
server_name ~^(?<branch>.*)\.a\.xyz\.com;
location / {
proxy_pass http://frontend-branch;
}
}
nginx.conf inside frontend container:
server {
listen 80;
location / {
root /www/html/branches/some_default_branch
}
}
server {
listen 80;
location ~^/(?<branch>.*)$ {
root /www/html/branches/$branch
}
}
docker-compose for proxy:
version: "2.0"
services:
proxy:
build: .
ports:
- "80:80"
restart: always
networks:
default:
external:
name: nginx-proxy
Inside frontend project it looks pretty much the same, except service name and ofc ports (81:80).
Is there any way to "pass" the branch as a path for frontend container (e.g. some frontend:80/$branch) ?
Is it even possible to create that kind of proxy? I don't want to use the same image based on nginx as a proxy and as a 'frontend keeper' because in the future I will want to use proxy for more than only one container so having configuration for whole site proxy inside frontend project would be weird.
Cheers

Resources