Traefik load balance between Docker provider and server at url - traefik

I currently have a Traefik setup with one nodejs service running locally in a docker container with a docker-compose.yml file like so:
container_name: nestjs-server
build:
context: ./
dockerfile: Dockerfile
networks:
- traefik-global-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.nestjs-server.rule=Host(`mydomain.com`) || Host(`www.mydomain.com`)"
- "traefik.http.routers.nestjs-server.entrypoints=websecure"
- "traefik.http.routers.nestjs-server.tls.certresolver=letsencrypt"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
I am running on a 1vCPU / 2GB cloud instance. Now I would like to add a second node app instance on another VM. I have seen it is possible to add server instances to the load balancer like so:
services:
my-service:
loadBalancer:
servers:
- url: "http://<private-ip-server-1>:<private-port-server-1>/"
- url: "http://<private-ip-server-2>:<private-port-server-2>/"
But I am not sure how to load balance between instances on another service alongside local docker instances. I have read that it is not possible to mix the label based config with the file config, so I assume I'd need to do something like:
my-service:
loadBalancer:
servers:
- url: "http://<private-ip-server-1>:<private-port-server-1>/"
- port: "<local-port-server-2>"
Is this possible? What is the correct way to accomplish this, other than having everything run on the same machine within docker?

Related

How to add a simple routing rule to traefik

I'm trying to get started with traefik in the hopes I can replace my current reverse proxy (pound) with traefik.
How do I add a simple routing rule so that mysubdomain.mydomain.com routes to http://192.168.x.x:8080?
I'm following the quickstart here. I created the following docker compose yml file and started it with docker-compose up -d reverse-proxy
version: '3'
services:
reverse-proxy:
container_name: reverse-proxy
image: traefik #The official Traefik docker image
command: --api --docker #Enables the web UI and tells Træfik to listen to docker
ports:
- "80:80" #The HTTP port
- "8080:8080" #The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock #So that Traefik can listen to the Docker events
Great, the container is running, but now what? How would I go about adding the simply routing rule?
If my backend web service isn't running one of these supported backends will it not work? Surely traefik can simply route http requests to any http backend right?
For example my backend web service is a web interface for my synology NAS at home. Traefik should be able to route this right? If so, how?

Traefik internal only traffic

I have an Ubuntu 16.04 Docker host running Traefik and Free-ipa server, i want to use trafek to block extranal access to free-ips server but allow internal ranges.
is this possible?
Thanks
Mo
You can use docker's network to isolate your environment, for exemple,
services:
traefik:
networks:
- traefik-net
free-ipa:
networks:
- internal-net
others:
networks:
- traefik-net
- internal-net
Here, others can access free-ipa just by using free-ipa as dns name, and it's accessible by traefik as well. traefik can't see free-ipa because they are not in the same network.

Deploying Traefik with LetsEncrypt and multiple Docker backend

I am considering replacing Apache for Traefik for my web project (Kestrel / .Net Core). After reading the documentation, a few things remain unclear to me regarding Traefik:
1/ Does Traefik automatically handle the LetsEncrypt certificate renewal or does it need to be done manually or via an external script? From the doc it's said that this is performed when adding a new host or restart, but what happens after 3 months of Traefik running without any restart/new host added?
2/ When a Docker backend becomes unreachable, how is it possible to serve a custom static HTML page? I can see how to set specific error page from the documentation, but not how to redirect trafic to it when a given backend becomes unavailable.
3/ When a Docker backend needs to be updated, is there some steps that need to be performed on Traefik prior to performing the Docker stop/restart?
4/ It seems I can't get to have 2 docker backend running at the same time, see the configuration file below, if I uncomment the 2nd backend (api.mydomain.io), then the 1st one becomes not available anymore. Am I missing something here?
version: '3'
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --docker # Enables the web UI and tells Træfik to listen to docker
ports:
- "80:80" # The HTTP port
- "443:443" # The HTTPS port
- "8080:8080" # The Web UI (enabled by --api)
networks:
- proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- $PWD/traefik.toml:/etc/traefik/traefik.toml
- $PWD/acme.json:/acme.json
- /root/mydomain_prod/cert/:/certs/
- /root/mydomain_prod/503.html:/503.html
container_name: traefik-reverse-proxy
##############################
# Front - www.mydomain.io
##############################
mydomain-front:
image: mydomain-front
labels:
- traefik.enable=true
- traefik.backend=mydomain-front
- traefik.frontend.rule=Host:traefik.mydomain.io
- traefik.port=8084
networks:
- internal
- proxy
container_name: mydomain-front
##############################
# API - api.mydomain.io
# Note: If I uncomment this one, then www.mydomain.io won't work anymore
##############################
#mydomain-api:
# image: mydomain-api
# labels:
# - traefik.enable=true
# - traefik.backend=mydomain-api
# - traefik.frontend.rule=Host:api.mydomain.io
# - traefik.port=8082
# networks:
# - internal
# - proxy
# container_name: mydomain-api
Many thanks,
Flo
1/ Traefik can handle the LetsEncrypt certificate renewal. Just remember to create a Volume to store the acme.json file. When the certificate expires, Traefik will do the renewal without asking.
2/ I don’t know if it’s possible. If you find a solution, share it.
3/ When you need to update a Docker, just update it. Traefik will be trigger from that change and update is own configuration.
4/ You can have to backend running at the same time. Below you can see a docker-compose.yml configuration :
version: '3'
services:
two-backend-service:
restart: always
image: ……..
labels:
- traefik.enable=true
- traefik.service1.frontend.rule=Host:service1.exemple.com
- traefik.service1.frontend.passHostHeader=true
- traefik.service1.port=8082
- traefik.Service2.backend=service2
- traefik.Service2.frontend.rule=Host:service2.exemple.com
- traefik.Service2.frontend.passHostHeader=true
- traefik.Service2.port=8081
traefik:
build:
context: ./traefik
dockerfile: Dockerfile
restart: always
ports:
- 80:80
- 443:443
labels:
- traefik.enable=false
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_letsencrypt:/etc/traefik/acme/
volumes:
traefik_letsencrypt:
driver: local

How to make REST calls between Frontend and Backend using Docker containers

I have 3 docker containers:
Backend (Spring boot rest api)
Frontend (Js and html in the apache image)
Mongodb
I'm orchestrating them through docker-compose and works nicely.
However I don't know how to let my frontend javascript client know the backend container's host/ip in order to reach it.
This is my docker-compose.yml:
version: '3.1'
services:
project-server:
build: .
restart: always
container_name: project-server
ports:
- 8200:8200
working_dir: /opt/app
depends_on:
- mongo
httpd:
image: project-ui
container_name: project-ui
ports:
- 8201:80
mongo:
image: project-mongo
container_name: project-mongo
ports:
- 27018:27017
volumes:
- $HOME/data/mongo-data:/data/db
- $HOME/data/mongo-bkp:/data/bkp
restart: always
So i've tried with this in my js client app:
export default {
REMOTE_HOST: 'http://project-server:8200'
}
But it doesn't work. (Failed to load resource: net::ERR_NAME_NOT_RESOLVED)
And i'm pretty sure it's because JS runs locally on the browser so it has no way to resolve that.
What's the right way to do this? There is any way for the frontend service (apache) to pass/render the real host to Javascript and get it somehow?
Thanks a lot
project-server can be resolved only within the network created by docker-compose. As you mentioned, to connect from the outside world you need to export the IP of your host instead of project-server. The problem is the guest container doesn't know the IP of the guest. Here is a detailed discussion about that: How to get the IP address of the docker host from inside a docker container
What you probably need in your situation is to run the container passing the IP of the host as an environment variable:
run --env <IP>=<value>
Then in node you can just read that variable.
Hope it helps

Redis connection refused when using traefik

I'm having a hard time trying to configure one redis container for all my applications using traefik. This is my configuration:
1 - Docker compose for Traefik and Redis:
version: '2'
services:
proxy:
container_name: traefik
image: traefik:1.3.6-alpine
command: --docker
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
networks:
- proxy
labels:
- traefik.frontend.rule=Host:monitor.company.dev
- traefik.port=8080
redis:
container_name: main_redis
image: redis:3.2
restart: always
volumes:
- ./data/redis:/data
networks:
- proxy
labels:
- traefik.backend=main-redis
- traefik.default.protocol=http
- traefik.frontend.rule=Host:main-redis.company.dev
- traefik.docker.network=proxy
- traefik.port=6379
networks:
proxy:
external: true
2 - Docker compose for my PHP Application.
version: '2'
services:
...
php:
container_name: myapp_php
build: ./docker/php # php:7.1-fpm base image
networks:
- internal
- proxy
labels:
- traefik.enable=false
- traefik.docker.network=proxy
expose:
- 9000
networks:
proxy:
external: true
internal:
external: false
I tried to connect my php application to main-redis.company.dev on both ports 6379 and 80 but I get a Redis::connect(): connect() failed: Connection refused message.
I also changed these stuff in my redis.conf:
Commented the line with bind 127.0.0.1
And changed protected-mode to no
My docker containers are staying in the same network, so I think it should work. Anyone knows why am I having this problem?
2022 UPDATE to #djeeg answer
For some time now you can use TCP mode for your routers. To do that you need to define the labels with TCP instead of HTTP
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.redis.rule=HostSNI(`redis.example.com`)"
- "traefik.tcp.routers.redis.entrypoints=redis" //6379 entrypoint
- "traefik.tcp.routers.redis.tls.certresolver=myresolver" //let's encrypt resolver
- "traefik.tcp.routers.redis.service=redis"
- "traefik.tcp.services.redis.loadbalancer.server.port=6379"
once you got that working in order to connect assuming you are using TSL you will get error Error: Protocol error, got "H" as reply type byte.
To prevent this you need to do things.
Allow for tls connection in the connection string
Setup SNI for your DNS name or provide public certificate file via cert pr cacert
redis-cli -u redis://redis.example.com:6379 --tls --sni redis.example.com
First off, remove the traefik labels from your redis service definition, traefik is currently (Nov 2017) a HTTP proxy, so you can't expose the endpoint like that
See here:
https://github.com/containous/traefik/issues/10
https://github.com/containous/traefik/issues/1611
Then to connect the php service to the redis service, that looks like you are trying to do that within the same docker instance (rather than externally)
Instead of main-redis.company.dev:6379, it should be like on of these:
redis:6379
main_redis:6379
%PROJECT_NAME%_redis:6379
depending upon how you are deploying the container