docker-compose expose same port as the service - docker

I have a docker-compose.yml:
services:
backend:
build:
./backend
ports:
- 8100:8100
container_name: "backend"
frontend:
build:
./frontend
ports:
- 4200:4200
container_name: "frontend"
depends_on:
- backend
And i want to get rid of the ports part. I have .env files in the folders /backend and /frontend with the portnumber set in there (e.g PORT=8100). In the dockerfile i can just do Export ${PORT}. But since i cant read the .env from the docker-compose location i am not able to expose the port in the same way. Is it possible to just have a wildcard to expose the port of the containers to the same port on my host like:
ports:
- *:*

No, there's no syntax like this. The ports: syntax always requires you to specify the container-side port, and you must have a ports: block if you want the container to be accessible from outside Docker.
If you weren't using Compose there is a docker run -P (capital P) option, but there the container ports are published on randomly-selected host ports. (This is one of the few contexts where "expose" as a Docker verb does anything useful: docker run -P publishes all exposed ports.)
However: there is no rule that the two port numbers must match. Rather than having the port number configurable in the Dockerfile (requiring a rebuild on any change) it's more common to use a fixed port number in the image and allow the host port number to be configured at deploy time.
For example, assume both images are configured to use the default Express port 3000. You can remap these when you run the containers:
version: '3.8'
services:
backend:
build: ./backend
ports: ['8100:3000']
frontend:
build: ./frontend
depends_on: [backend]
ports: ['4200:3000']

Related

Docker compose service communication

So I have a docker-compose file with 3 services: backend, react frontend and mongo.
backend Dockerfile:
FROM ubuntu:latest
WORKDIR /backend-server
COPY ./static/ ./static
COPY ./config.yml ./config.yml
COPY ./builds/backend-server_linux ./backend-server
EXPOSE 8080
CMD ["./backend-server"]
frontend Dockerfile:
FROM nginx:stable
WORKDIR /usr/share/nginx/html
COPY ./build .
COPY ./.env .env
EXPOSE 80
CMD ["sh", "-c", "nginx -g \"daemon off;\""]
So nothing unusual, I guess.
docker-compose.yml:
version: "3"
services:
mongo-db:
image: mongo:4.2.0-bionic
container_name: mongo-db
volumes:
- mongo-data:/data
network_mode: bridge
backend:
image: backend-linux:latest
container_name: backend
depends_on:
- mongo-db
environment:
- DATABASE_URL=mongodb://mongo-db:27017
..etc
network_mode: bridge
# networks:
# - mynetwork
expose:
- "8080"
ports:
- 8080:8080
links:
- mongo-db:mongo-db
restart: always
frontend:
image: frontend-linux:latest
container_name: frontend
depends_on:
- backend
network_mode: bridge
links:
- backend:backend
ports:
- 80:80
restart: always
volumes:
mongo-data:
driver: local
This is working. My problem is that by adding ports: - 8080:8080 to the backend part, that server becomes available to the host machine. Theoretically the network should work without these lines, as I read it in the docker docs and this question, but if I remove it, the API calls just stop working (but curl calls written in the docker-compose under the frontend service will still work).
Your react frontend is making requests from the browser.
Hence the endpoint, in this case, your API needs to be accessible to the browser, not the container that is handing out static js, css and html files.
Hope this image makes some sense.
P.S. If you wanted to specifically not expose the API you can get the Web Server to proxy Requests to /api/ to the API container, that will happen at the network level and mean you only need to expose the one server.
I do this by serving my Angular apps out of Nginx and then proxy traffic for /app1/api/* to one container and /app2/api/* to another container etc

docker-compose up not listening on specified port

When I run docker-compose up, it tells me its listening on localhost port 5000, despite port 80 configuration in my docker-compose.override.yml file, and despite exposing port 80 in the Dockerfile.
I've also tried setting the port in docker-compose.yml but it still defaults to port 5000
docker-compose.yml
version: '3'
services:
myapp:
image: me/myapp
environment:
- ASPNETCORE_ENVIRONMENT=Production
build:
context: .
dockerfile: MyApp.API/Dockerfile
docker-compose.override.yml
version: '3'
services:
myapp:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "80:80"
Dockerfile:
...
EXPOSE 80
...
What am I missing that would force docker-compose up to listen on the port specified in the yml?
Its important with what kind of configuration you start the ASP.NET application. You can do that by putting it into the environment like that:
Dockerfile
ENV ASPNETCORE_URLS=http://*:80
Alternatively you an also define it in your docker-compose.yml:
version: '3'
services:
myapp:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://*:80
ports:
- "80:80"
The EXPOSE instruction in Dockerfile does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.
In your case all control is done via docker compose and I would not worry about seeing port 5000 as it is still going to be inaccessible.

Specifying ports both for the docker and compose file

I've built a Docker compose file to run database and a nodejs microservice in their own containers.
The database seems to stops working if I don't specify the EXPOSE ports, even though I've specified them in the compose file. Do we have to specify ports in both places?
database/Dockerfile
FROM mysql
ENV MYSQL_DATABASE=test
ENV MYSQL_ROOT_PASSWORD=password
EXPOSE 6603:3306
COPY ./schema.sql /docker-entrypoint-initdb.d/
docker-compose.yml
version: '3'
services:
database:
build:
./database
ports:
- "6603:3306"
image: "test-mysql"
container_name: "test-mysql"
web:
build:
./service
ports:
- "8080:8080"
depends_on:
- database
image: "test-nodejs"
container_name: "test-nodejs"
restart: on-failure
Do I've to specify ports 6603:3306 in both Database/Dockerfile and docker-compose.yml file?
On modern Docker, EXPOSE statements are almost purely documentation. You also can't un-expose a port once it's been exposed in a Dockerfile, and the standard mysql image will already EXPOSE 3306, so you don't need an EXPOSE line in your own Dockerfile.
(In any case a Dockerfile can never specify a specific host port it wants to use, only a container-side port that should be made visible.)
only EXPOSE 3306 - In dockerfile which tells inside container DB running on that port.
ports:
- "6603:3306"
This is perfect which tells outside container you can access DB with 6603 Port.
Yes it's necessary to specify the ports in file without it one will not able to expose the container port and in docker compose if you will not specify port it will not be able to make connection.
But in docker file you can do
EXPOSE 3360

docker-compose.yml container_name and hostname

What is the use of container_name in docker-compose.yml file? Can I use it as hostname which is nothing but the service name in docker-compose.yml file.
Also when I explicitly write hostname under services does it override the hostname represented by service name?
hostname: just sets what the container believes its own hostname is. In the unusual event you got a shell inside the container, it might show up in the prompt. It has no effect on anything outside, and there’s usually no point in setting it. (It has basically the same effect as hostname(1): that command doesn’t cause anything outside your host to know the name you set.)
container_name: sets the actual name of the container when it runs, rather than letting Docker Compose generate it. If this name is different from the name of the block in services:, both names will be usable as DNS names for inter-container communication. Unless you need to use docker to manage a container that Compose started, you usually don’t need to set this either.
If you omit both of these settings, one container can reach another (provided they’re in the same Docker Compose file and have compatible networks: settings) using the name of the services: block and the port the service inside the container is listening in.
version: '3'
services:
redis:
image: redis
db:
image: mysql
ports: [6033:3306]
app:
build: .
ports: [12345:8990]
env:
REDIS_HOST: redis
REDIS_PORT: 6379
MYSQL_HOST: db
MYSQL_PORT: 3306
The easiest answer is the following:
container_name: This is the container name that you see from the host machine when listing the running containers with the docker container ls command.
hostname: The hostname of the container. Actually, the name that you define here is going to the /etc/hosts file:
$ exec -it myserver /bin/bash
bash-4.2# cat /etc/hosts
127.0.0.1 localhost
172.18.0.2 myserver
That means you can ping machines by that names within a Docker network.
I highly suggest set these two parameters the same to avoid confusion.
An example docker-compose.yml file:
version: '3'
services:
database-server:
image: ...
container_name: database-server
hostname: database-server
ports:
- "xxxx:yyyy"
web-server:
image: ...
container_name: web-server
hostname: web-server
ports:
- "xxxx:xxxx"
- "5101:4001" # debug port
you can customize the image name to build & container name during docker-compose up for this, you need to mention like below in docker-compose.yml file.
It will create an image & container with custom names.
version: '3'
services:
frontend_dev:
stdin_open: true
environment:
- CHOKIDAR_USEPOLLING=true
build:
context: .
dockerfile: Dockerfile.dev
image: "mycustomname/sample:v1"
container_name: mycustomname_sample_v1
ports:
- '3000:3000'
volumes:
- /app/node_modules
- .:/app

Is it possible to bind port XXXX on a docker container A to port XXXX or YYYY on docker container B

Let's say I have a docker-compose file as below:
version: '2'
services:
# The php-fpm container
app:
build:
context: ./
dockerfile: app.dev.dockerfile
working_dir: /var/www
volumes:
- ./:/var/www
expose:
- 8003
# The Web Server
web:
build:
context: ./
dockerfile: web.dockerfile
working_dir: /var/www
volumes_from:
- app
links:
- app:app
ports:
- 80:80
- 8004:8003
So I like to serve the port 8003 on App container from port 8004 in Web container.
But I am not able to get the result.
So my guess is that Web port mapping of 8004:8003 on Web container is limited to Web container only.
Or is it actually mapped to exposed 8003 port on the App container?
If so how do I test that Web port 8004 is in fact mapped to port 8003 on App container?
Is there a way for me to create a one directional binding (or even better bidirectional binding) or mapping of port 8003 on App container to port 8004 on Web container ?
If my host is running some App and docker services (that includes these two container), and App is trying to listen on port 8004 in Web container he is actually communicating to the App container.
Containers are designed to keep each process seperate. Each process/container has it's own seperate network stack
The only way "mapping" as you describe from one container to another is achieved is if there is a user space process that forwards requests. Like Apache http or Nginx does to forward HTTP requests to a FastCGI PHP process.
For debug, map the port directly to the app container. If you are not able to connect there is likely a problem with the debug setup in the app container.
# The php-fpm container
app:
build:
context: ./
dockerfile: app.dev.dockerfile
working_dir: /var/www
volumes:
- './:/var/www'
ports:
- '8003:8003'
# The Web Server
web:
build:
context: ./
dockerfile: web.dockerfile
working_dir: /var/www
volumes_from:
- app
ports:
- 80:80
By the way, links are not required for version 2+ connectivity. Compose will create a user defined network by default which allows access between your containers.

Resources