Why can't docker compose find uvicorn module

Question:

I am new to docker and was trying to dockerize my fastapi application.
I built a Dockerfile shown below

# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster

WORKDIR /app

COPY requirements.txt requirements.txt

RUN apt-get update
RUN apt-get -y install libpq-dev gcc
RUN apt-get -y install libnss3-tools
RUN apt-get -y install curl
RUN curl -LJO https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64
RUN mv mkcert-v1.4.4-linux-amd64 mkcert
RUN chmod +x mkcert
RUN ./mkcert -install
RUN ./mkcert -cert-file cert.pem -key-file key.pem 0.0.0.0 localhost 127.0.0.1 ::1

RUN pip3 install -r requirements.txt

COPY . .

CMD ["python3.8", "-m", "uvicorn", "main:app", "--host=0.0.0.0", "--ssl-keyfile=./key.pem",  "--ssl-certfile=./cert.pem"]

and ran the containers and they all worked. But when I try to combine the containers with docker compose its tells me can’t find uvicorn module even when it’s in the requirements.txt file .
Here is a snippet of my docker compose file containing the server service.

services:

  server:
    container_name: server
    image: python:3.8-slim-buster
    command: ["python3.8", "-m", "uvicorn", "main:app", "--host=0.0.0.0", "--ssl-keyfile=./key.pem",  "--ssl-certfile=./cert.pem"]
    ports:
      - 8000:8000
    working_dir: /app

I have tried using changing the command part of the server service in docker compose to

command: bash "python3.8 -m uvicorn main:app --host=0.0.0.0 --ssl-keyfile=./key.pem  --ssl-certfile=./cert.pem"

didn’t work.
changed it to

command: sh -c "python3.8 -m uvicorn main:app --host=0.0.0.0 --ssl-keyfile=./key.pem  --ssl-certfile=./cert.pem"

didn’t work.

I removed the command totally it still didn’t work, keeps showing

server | /usr/local/bin/python3.8: No module named uvicorn
server exited with code 1

Asked By: redd

||

Answers:

The image you use in the docker compose is not the one previously built in the Dockerfile but a basic Python image.
You could build the image from your Dockerfile

docker build .  -t fastapi

then modify your docker-compose.yml file with something like this

services:
  api:
    image: fastapi
    ports:
      - "8000:8000"

then run docker compose

docker-compose -f docker-compose.yml up
Answered By: Vincent Lagache

Yes, that’s correct. Running the pip install command in a separate container as a long-running service is not ideal as the packages will not be available in the other containers. It’s better to include the pip install command in the Dockerfile for your application and build an image that includes all the required packages. This way, you can use the same image for both development and production environments and ensure consistency.

Here’s an updated Dockerfile:

FROM python:3.8-slim-buster

WORKDIR /app

COPY requirements.txt requirements.txt

RUN apt-get update 
    && apt-get -y install libpq-dev gcc 
    && apt-get -y install libnss3-tools 
    && apt-get -y install curl 
    && curl -LJO https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64 
    && mv mkcert-v1.4.4-linux-amd64 mkcert 
    && chmod +x mkcert 
    && ./mkcert -install 
    && ./mkcert -cert-file cert.pem -key-file key.pem 0.0.0.0 localhost 127.0.0.1 ::1

RUN pip3 install -r requirements.txt

COPY . .

CMD ["python3.8", "-m", "uvicorn", "main:app", "--host=0.0.0.0", "--ssl-keyfile=./key.pem",  "--ssl-certfile=./cert.pem"] 

And here’s the updated Docker Compose file:

version: '3'
services:
  server:
    build: .
    command: sh -c "python3.8 -m uvicorn main:app --host=0.0.0.0 --ssl-keyfile=./key.pem  --ssl-certfile=./cert.pem"
Answered By: S M Rifat