Dockerized Flask app is not accessible in localhost - docker

I have been playing around with docker, celery, redis and Flask for the past 2-3 days, after successfully setting up a flask, celery and redis server I decided to go onto to the next point which dockerizing it. I have successfully created a docker image and a composer file which seem to work just fine when building. I am using a local redis server and I am able to access it by using docker.for.mac.localhost as the host name in order to access the redis server from inside the container, but, when I try to access the flask app while it's running from outside of the container it doesn't work.
Having done some research I have tried the following:
Running with server host as 0.0.0.0
Exposing and using a different port other than 5000
This is my Dockerfile:
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python3", "./app.py"]
And this is my docker-compose.yml file
version: "3"
services:
web:
container_name: web
build: ./api
ports:
- "5000:5001"
links:
- redis
depends_on:
- redis
environment:
- FLASK_ENV=development
volumes:
- ./api:/app
redis:
container_name: redis
image: redis:5.0.5
hostname: redis
worker:
build:
context: ./api
hostname: worker
entrypoint: celery
command: -A app.celery worker --loglevel=info
volumes:
- ./api:/app
links:
- redis
depends_on:
- redis
Thanks for any help in advance!

Your port mapping is backwards. It should be external to internal.
ports:
- "5001:5000"

Related

Go backend to redis connection refused after docker compose up

I'm currently trying to introduce docker compose to my project. It includes a golang backend using the redis in-memory database.
version: "3.9"
services:
frontend:
...
backend:
build:
context: ./backend
ports:
- "8080:8080"
environment:
- NODE_ENV=production
env_file:
- ./backend/.env
redis:
image: "redis"
ports:
- "6379:6379"
FROM golang:1.16-alpine
RUN mkdir -p /usr/src/app
ENV PORT 8080
WORKDIR /usr/src/app
COPY go.mod /usr/src/app
COPY . /usr/src/app
RUN go build -o main .
EXPOSE 8080
CMD [ "./main" ]
The build runs successfully, but after starting the services, the go backend immediately exits throwing following error:
Error trying to ping redis: dial tcp 127.0.0.1:6379: connect: connection refused
Error being catched here:
_, err = client.Ping(ctx).Result()
if err != nil {
log.Fatalf("Error trying to ping redis: %v", err)
}
How come the backend docker service isn't able to connect to redis? Important note: when the redis service is running and I start my backend manually using go run *.go, there's no error and the backend starts successfully.
When you run your Go application inside a docker container, the localhost IP 127.0.0.1 is referring to this container. You should use the hostname of your Redis container to connect from your Go container, so your connection string would be:
redis://redis
I found I was having this same issue. Simply changing (in redis.NewClient(&redis.Options{...}) Addr: "localhost:6379"to Addr: "redis:6379" worked.
Faced similar issue with Golang and redis.
version: '3.0'
services:
redisdb:
image: redis:6.0
restart: always
ports:
- "6379:6379"
container_name: redisdb-container
command: ["redis-server", "--bind", "redisdb", "--port", "6379"]
urlshortnerservice:
depends_on:
- redisdb
ports:
- "7777:7777"
restart: always
container_name: url-shortner-container
image: url-shortner-service
In redis configuration use
redisClient := redis.NewClient(&redis.Options{
Addr: "redisdb:6379",
Password: "",
DB: 0,
})

Nuxt.js 500 NuxtServerError under docker-compose

my system contains 3 dockers:
mongodb
api backend, built with Nestjs
web application, build with Nuxt.js
the mongo and the backend seems to be working, because i can access the swagger at localhost:3000/api/.
the Nuxtjs web app is failing, and i'm getting 500 Nuxtserver error.
Dockerfile (for the web app):
FROM node:12.13-alpine
ENV APP_ROOT /src
RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}
ADD . ${APP_ROOT}
RUN npm install
RUN npm run build
ENV HOST 0.0.0.0
EXPOSE 4000
docker-compose.yml:
version: "3"
services:
# backend nestjs app
api:
image: nestjs-api-server
container_name: my-api
depends_on:
- db
restart: unless-stopped
environment:
- NODE_ENV=production
ports:
- 3000:3001
networks:
- mynet
links:
- db
# mongodb
db:
image: mongo
container_name: db_mongo
restart: unless-stopped
volumes:
- ~/data/:/data/db
ports:
- 27017:27017
networks:
- mynet
# front web app, nuxt.js
web:
image: nuxtjs-web-app
container_name: my-web
depends_on:
- api
restart: always
ports:
- 4000:4000
environment:
- BASE_URL=http://localhost:3000/api
command:
"npm run start"
networks:
- mynet
networks:
mynet:
driver: bridge
Looks like the nuxtjs app cannot connect to the api. in the log i see:
ERROR connect ECONNREFUSED 127.0.0.1:3000
But why? the swagger (coming from the same api) works fine on http://localhost:3000/api/#/.
Any idea?
environment:
- BASE_URL=http://localhost:3000/api
localhost in a container means inside that particular container. i.e., it will try to resolve port 3000 in my-web container itself.
Basically from front-end you cannot do container communication. May be you can communicate via public hostname or ip or you can make use of extra_hosts concept in docker-compose to resolve localhost.
Got it. The problem was in nuxtServerInit. This is a very special method on vuex, and it is running in the server. i called $axios from it, and i guess you can't do that.
once i commented that method, it's working fine.

Fail to obtain connection between two Docker containers

I have an application that is divided in 2 parts: Frontend and Backend. My Frontend is a React JS application and my backend is a Java Spring boot application. This project is running in Docker, and there's 3 containers: frontend, backend and db (database). My problem is that I can't make my front and send any request to my backend container. Below is my Docker configuration files:
Docker-compose:
version: "3"
services:
db:
image: postgres:9.6
container_name: db
ports:
- "5433:5432"
environment:
- POSTGRES_PASSWORD=123
- POSTGRES_USER=postgres
- POSTGRES_DB=test
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: backend
ports:
- "8085:8085"
depends_on:
- db
frontend:
container_name: frontend
build:
context: ./frontend
dockerfile: Dockerfile
expose:
- "80"
ports:
- "80:80"
links:
- backend
depends_on:
- backend
Dockerfile frontend:
# Stage 0, "build-stage", based on Node.js, to build and compile the frontend
FROM node:8.12.0 as build-stage
WORKDIR /app
COPY package*.json /app/
RUN yarn
COPY ./ /app/
RUN yarn run build
# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
FROM nginx
RUN rm -rf /usr/share/nginx/html/*
COPY --from=build-stage /app/build/ /usr/share/nginx/html
# Copy the default nginx.conf provided by tiangolo/node-frontend
COPY --from=build-stage /app/nginx.conf /etc/nginx/conf.d/default.conf
Dockerfile backend:
FROM openjdk:8
ADD /build/libs/reurb-sj-13-11-19.jar reurb-sj-13-11-19.jar
EXPOSE 8085
ENTRYPOINT ["java", "-jar", "reurb-sj-13-11-19.jar", "--app.db.host=
Is Frontend I've tried to send requests to these Ip's:
localhost:8085
172.18.0.3:8085
172.18.0.3
0.0.0.0:8085
When I try to send a request from Frontend, it "starts" and waits for about 10 seconds, then it returns with an error. The weird part is that my request doesn't return with any status.
PS.: I've read all internet and everyone said to put EXPOSE, PORTS and the LINKS (inside docker-compose), I've tried but still doesn't work.
You need to connect to backend:8085.
--
You shouldn't be using IP's to connect to your services but rather the service name listed in your docker-compose file.
Note: If using localhost, that refers to frontend container itself. Usually 0.0.0.0 is used to bind to all IP's or represent any IP address rather than connecting to a specific IP.
So in your front-end code, you need to use backend as the hostname (E.g., backend:8085).
It looks like you have already linked your services so networking shouldn't be an issue. My advice is to always test within the container using something such as:
docker-compose exec frontend bash
# You may need to install packages
ping backend
telnet backend 8085
I think it is worth mentioning that link is legacy and eventually will be removed.
Source: https://docs.docker.com/network/links/
Unless you really need it, you should create custom network for your app. Good documentation is here: https://docs.docker.com/compose/compose-file/#networks
And example:
version: "3"
services:
db:
image: postgres:9.6
container_name: db
ports:
- "5433:5432"
environment:
- POSTGRES_PASSWORD=123
- POSTGRES_USER=postgres
- POSTGRES_DB=test
networks:
- new
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: backend
ports:
- "8085:8085"
depends_on:
- db
networks:
- new
frontend:
container_name: frontend
build:
context: ./frontend
dockerfile: Dockerfile
expose:
- "80"
ports:
- "80:80"
networks:
- new
depends_on:
- backend
networks:
new:

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

Exposing localhost ports in several local services

I'm currently attempting to use Docker to make our local dev experience involving two services easier, but I'm struggling to use host and container ports in the right way. Here's the situation:
One repo containing a Rails API, running on 127.0.0.1:3000 (lets call this backend)
One repo containing an isomorphic React/Redux frontend app, running on 127.0.0.1:8080 (lets call this frontend)
Both have their own Dockerfile and docker-compose.yml files as they are in separate repos, and both start with docker-compose up fine.
Currently not using Docker at all for CI or deployment, planning to in the future.
The issue I'm having is that in local development the frontend app is looking for the API backend on 127.0.0.1:3000 from within the frontend container, which isn't there - it's only available to the host and the backend container actually running the Rails app.
Is it possible to forward the backend container's 3000 port to the frontend container? Or at the very least the host's 3000 port as I can see the Rails app on localhost on my computer. I've tried 127.0.0.1:3000:3000 within the frontend docker-compose but I can't do that while running the Rails app as the port is in use and fails to connect. I'm thinking maybe I've misunderstood the point or am missing something obvious?
Files:
frontend Dockerfile
FROM node:8.7.0
RUN npm install --global --silent webpack yarn
RUN mkdir /app
WORKDIR /app
COPY package.json /app/package.json
COPY yarn.lock /app/yarn.lock
RUN yarn install
COPY . /app
frontend docker-compose.yml
version: '3'
services:
web:
build: .
command: yarn start:dev
volumes:
- .:/app
ports:
- '8080:8080'
- '127.0.0.1:3000:3000' # rails backend exposed to localhost within container
backend Dockerfile
FROM ruby:2.4.2
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app
backend docker-compose.yml
version: '3'
volumes:
postgres-data:
driver: local
services:
postgres:
image: postgres:9.6
volumes:
- postgres-data:/var/lib/postgresql/data
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/app
ports:
- '3000:3000'
depends_on:
- postgres
You have to unite the containers in one network. Do it in your docker-compose.yml files.
Check this docs to learn about networks in docker.
frontend docker-compose.yml
version: '3'
services:
gui:
build: .
command: yarn start:dev
volumes:
- .:/app
ports:
- '8080:8080'
- '127.0.0.1:3000:3000'
networks:
- webnet
networks:
webnet:
backend docker-compose.yml
version: '3'
volumes:
postgres-data:
driver: local
services:
postgres:
image: postgres:9.6
volumes:
- postgres-data:/var/lib/postgresql/data
back:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/app
ports:
- '3000:3000'
depends_on:
- postgres
networks:
- webnet
networks:
webnet:
Docker has its own DNS resolution, so after you do this you will be able to connect to your backend by setting the address to: http://back:3000
Managed to solve this using external links in the frontend app to link to the default network of the backend app like so:
version: '3'
services:
web:
build: .
command: yarn start:dev
environment:
- API_HOST=http://backend_web_1:3000
external_links:
- backend_default
networks:
- default
- backend_default
ports:
- '8080:8080'
volumes:
- .:/app
networks:
backend_default: # share with backend app
external: true

Resources