Map port of container without exposing to host in docker-compose - docker-compose

I have
services:
api:
build: .
ports:
- "8080:8080"
superservice:
image: superservice
ports:
- # ?
superservice is very super, but I simply pulled it from the Docker hub and its port cannot be configured when creating a container. The default port is 8080. But that is already in use. How do I change it to 8081? I do NOT want it to be accessible from the host, that is why - "8081:8080" is not desirable.

In this case you would have to change the port superservice is running on by either changing its configuration, or if possible, change the command or entrypoint it runs on start and pass the new port as an argument.
Although, if superservice does not have to be reachable from the host then you should have no problem referencing it as http://superservice:8080 from inside the api container.

Related

Docker Compose understanding the ports mapping

Docker newbie here. I am trying to understand the meaning of the following:
services:
mongo1:
hostname: mongo1
container_name: mongo1
image: mongo:5.0.6
expose:
- 27017
ports:
- 27011:27017
restart: always
Note the ports: 27011:27017. When the Docker is up and running, I can access the MongoDB server via port 27011, so what is the 27017? And why do I need to expose it like the following?
expose:
- 27017
expose: is a legacy implementation detail of first-generation Docker networking. It does almost nothing in current Docker, and it's always safe to remove it from Compose files. No other changes are required.
ports: describes how to map a port from the host system to a port in the container. The second port number is a fixed property of the image and is typically the "normal" port the container listens on; in your example MongoDB normally listens on port 27017 and the second port number must be exactly that. The first port number can be any otherwise-unused port on the host system.

Docker Compose: Increment environment variable

I am locally deploying a full-stack app via Docker Compose and would like to derive the backend and frontend ports from a single environment variable $PORT. For example, if $PORT = 3000, then the backend port should be 3000 and the frontend port should be 3001. And if $PORT = 4000, then the backend port should be 4000 and the frontend port should be 4001.
For this, I would like to do something like this in my docker-compose.yml:
version: "3"
services:
backend:
...
ports:
- "${PORT}:3000"
frontend:
...
ports:
- "$((PORT + 1)):4200"
This fails with ERROR: Invalid interpolation format for "environment" option in service "frontend". Is there a way to achieve this in Docker Compose?
Compose only supports a limited set of environment variable substitutions: ${VARIABLE}, ${VARIABLE:-default}, ${VARIABLE:?error message}, and the latter two options without colons. You cannot do other substitutions, computation, or shell callouts in Compose.
For this particular case, you can let Docker pick the host port number for you. This is less predictable than the scheme you describe, but it doesn't require any special setup. Instead of using two numbers in ports: just specify the container port number
version: '3.8'
services:
backend:
ports:
- '3000'
frontend:
ports:
- '4200'
To find the corresponding host port number, you need to run docker-compose port
docker-compose port frontend 4200
I don't think it's possible to do that. But why don't you set before in your environment those ports variables? For example run before everything:
export PORT=3000 #or whatever number you want
export PORT_INC=$(($PORT+1))
And then you use like this:
ports:
- "$PORT_INC:4200"

How to get long hostname of a docker container inside a container?

Our application is behind traefik reverse proxy. We manage many subdomains and we use the watch-file ability of traefik to dynamically setup new subdomains to proxyfy.
So our application generate a traefik .yaml dynamic config file.
The same traefik will manage many instances of the same application.
For that purprose we need to indicate to traefik how to reach our application inside it own network.
We know we can use the simple hostname, the one which is the container name.
But this only work inside the default docker-compose network of the app instance and not the external network shared with traefik.
This one need the long hostname version so we are sure it reach the right application instance.
(<compose_name>_<container_name>_1 or depending docker-compose version (<compose_name>_<container_name>_1_<hash>)
Do you know a way to get the long version of the hostname of a docker-compose container inside another container of the same docker-compose default network ?
For better context, here a simple docker-compose.yaml file
version: "3"
services:
app:
image: app_image
networks:
- app_network
restart: unless-stopped
nginx:
image: nginx
links:
- app
networks:
- app_network
- traefik_traefik
restart: unless-stopped
networks:
traefik_traefik:
external: true
app_network:
driver: bridge
We want, from inside the app container, to get the nginx long hostname version, so we can use it to generate the dynamic configuration for traefik.
Thanks for your help.
We thought to have found a solution. Querying for the FQDN of the short-named hostname give the needed long hostname.
dig +short -x `dig +short nginx`
Return composename_app_1.composename.app_network.
In our python app we can get the same result with
import socket
socket.getfqdn('nginx')

How to connect Postgresql Docker Container with another Docker Container

I want to connect mysoft docker container to postgresql docker container.
But i have some errors:
ERROR: for mysoft_db_1 Cannot start service db: driver failed programming external connectivity on endpoint mysoft_db_1 (XXX):
Error starting userland proxy: listen tcp 0.0.0.0:5432: bind: address already in use
ERROR: for db Cannot start service db: driver failed programming external connectivity on endpoint mysoft_db_1 (XXX):
Error starting userland proxy: listen tcp 0.0.0.0:5432: bind: address already in use
here is my docker-compose.yml
version: '2'
services:
mysoft:
image: mysoft/mysoft:1.2.3
ports:
- "80:8080"
environment:
- DATABASE_URL=postgres://mysoft:PASSWORD#db/mysoft?sslmode=disable
db:
image: postgresql
environment:
- POSTGRES_USER=mysoft
- POSTGRES_PASSWORD=PASSWORD
- POSTGRES_DB=mysoft
ports:
- 5432:5432
I want use another, already running docker pg server to connect new soft, also one pg docker server, for more projects
Is it possible?
You should add links to the definition of mysoft service in docker-compose.yml. Then your db service will be accessible from mysoft container.
After that your service definition will look like this.
mysoft:
image: mysoft/mysoft:1.2.3
ports:
- "80:8080"
environment:
- DATABASE_URL=postgres://mysoft:PASSWORD#db/mysoft?sslmode=disable
links:
- db
Now about error of binding. Probably, you receive it, because you have a local postgresql running on port 5432 or you already have a running docker container with 5432 port mapped to local machine.
ports:
- 5432:5432
It is used for mapping ports to your local machine. And if you don't need to access container's db from it, just remove it.
I want use another, already running docker pg server to connect new
soft, also one pg docker server, for more projects Is it possible?
Yes, it's possible. Use external_links.
If you choose this option:
Remove the db service and links in mysoft service definition from your docker-compose.yml
Add external_links with correct container name to mysoft service definition.
Update host and port in DATABASE_URL according to the container name and postgresql port in it.
You might want to check of you already have a local postgres running on port 5432? If you do you can not do the ports 5432:5432 but have to expose the inner port to an other outer port e.g. 5555:5432
at least if you are using native docker (running on localhost)...

docker run mongo image on a different port

The short question is can I run mongo from mongo:latest image on a different port than 27017 (for example on 27018?)
If yes, how can I do this inside a docker-compose.yml file in order ro be able to type the following command:
docker-compose run
The longer story:
I have an app running in AWS EC2 instance. The app consists of a mongodb and a web application. Now I decided to separate part of this app into its own microservice running in the same AWS inside docker container (two containers one for another mongo and one for a web app). I think the problem is I can not have mongodb running on port 27017 and at the same time another mongodb running inside a docker container on port 27017. Right? I have this assumption because when I stop the first mongo (my app mongo), my docker mongo works.
So I am trying to make the second mongo (the one that is inside the docker container), to run in a different port and my second web app (the one inside another docker conianter), to listen to mongo on a different port. Here is my attempt to change the docker-compose file:
version: '2'
services:
webapp:
image: myimage
ports:
- 3000:3000
mongo:
image: mongo:latest
ports:
- 27018:27018
And inside my new app, I changed the mongo url to:
monog_url = 'mongodb://mongo:27018'
client = MongoClient(monog_url, 27018)
Well, the same if I say:
monog_url = 'mongodb://mongo:27018'
client = MongoClient(monog_url)
But when I run docker-compose run, it still does not work, and I get the following errors:
ERROR: for mongo driver failed programming external
connectivity on endpoint: Error starting userland proxy:
listen tcp 0.0.0.0:27017: bind: address already in use
Or
pymongo.errors.ServerSelectionTimeoutError:
mongo:27018: [Errno -2] Name or service not known
You can tell MongoDB to listen on a different port in the configuration file, or by using a command-line parameter:
services:
mongo:
image: 'mongo:latest'
command: mongod --port 27018
ports:
- '27018:27018'
You can run processes inside a container and outside on the same port. You can even run multiple containers using the same port internally. What you can't do is map the one port from the host to a container. Or in your case, map a port that is already in use to a container.
For example, this would work on your host:
services:
webapp:
image: myimage
ports:
- '3000:3000'
mongo:
image: 'mongo:latest'
ports:
- '27018:27017'
mongo2:
image: mongo:latest
ports:
- '27019:27017'
The host mongo listens on 27017. The host also maps ports 27018 and 27019 to the container mongo instances, both listening on 27017 inside the container.
Each containers has its own network namespace and has no concept of what is running in another container or on the host.
Networks
The webapp needs to be able to connect to the mongo containers internal port. You can do this over a container network which allows connections between the container and also name resolution for each service
services:
webapp:
image: myimage
ports:
- '3000:3000'
networks:
- myapp
depends_on:
- mongo
mongo:
image: 'mongo:latest'
ports:
- '27018:27017'
networks:
- myapp
networks:
myapp:
driver: bridge
From your app the url mongo://mongo:27017 will then work.
From your host need to use the mapped port and an address on the host, which is normally localhost: mongo://localhost:27018
Default communication between different containers running on the same host
I solved the problem, not by running the container in a different port though, but by learning one new feature in docker-compose version 2 and that is we do not need to specify links or networks. The newly created containers by default will be part of docker0 network and hence they can communicate with each other.
As Matt mentioned, we can run processes inside containers on the same port. They should be isolated. So the problem can not be that the docker container and the host are using the same port. The problem is perhaps there is an attempt to forward a used port in host to another port in container.
Below is a working docker-compose file:
version: '2'
services:
webapp:
image: myimage
ports:
- 3000:3000
mongo:
image: mongo:latest
I looked at the mongo:latest docker file in github, and realized they exposed 27017. So we do not need to change the port or forward host ports to the running mongo container. And the mongo url can stay on the same port:
monog_url = 'mongodb://mongo:27017'
client = MongoClient(monog_url, 27017)
Docker run an image on a different port
So the above solution solved the problem, but as for the question title 'docker run mongo image on a different port', the simplest way is just to change the docker-compose to:
version: '2'
services:
web:
image: myimage
mongo:
image: mongo:latest
command: mongod --port 27018
Mongo is now running on 27018 and the following url is still accessible inside the web:
monog_url = 'mongodb://mongo:27018'
client = MongoClient(monog_url, 27018)
I had the same problem
I changed ports in my docker-compose.yml file and this work for me
In doing so, i don't change port in my connection string
mongo:
image: mongo
ports:
- "27018:27018"