skip to Main Content

I am new to Docker and trying to Dockerize my FastAPI application.
First I created a Dockerfile:

FROM python:3.9.9

WORKDIR /usr/src/app

COPY requirements.txt ./

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Then ran the following command:

docker build -t fastapi .

The command ran successfully.

After that I created the following docker-compose.yml:

version: "3"
services: 
  api:
    build: .
    ports:
      - 8000:8000
    env_file:
         ./.env

Then ran the following command:

docker-compose up -d

Ran successfully:

    Network fastapi_default  Created                              0.7s 
 - Container fastapi_api_1  Started 

Then to check if its running properly I ran the following command:

docker ps -a

And it showed that Container exited few seconds after it was created.

Then I ran this command:

docker logs fastapi_api_1

And it says:

/bin/sh: 1: [uvicorn,: not found

Not sure what is the reason. Tried some solutions that I found online but nothing worked out. I do have uvicorn in my requirements.txt file.

Help will be appriciated. Please let me know if additional information is required.

4

Answers


  1. Chosen as BEST ANSWER

    So, basically there was something wrong with the docker. I had created mulitple images. I removed all of them and ran the same commands again and it worked. I don't know the exact reason but its working now.

    What I think was happening is that instead of deleting the old images and creating new one. I was just doing

    docker-compose down
    

    and then

    docker-compose up -t
    

    I think that command was not taking the changes into consideration.

    then i ran:

    docker-compose up --build
    

    and I think that created a new image and it worked.

    Then I noticed that there were atleast 10 images created. I deleted all of them and ran the same commands:

    docker build .
    docker-compose up -t
    

    and it worked fine again.

    So basically instead of using creating new image it was using the old one which was not created correctly:

    docker-compose up --build
    

    In short you should use docker-compose up --build whenever you make changes in your dockerfile or docker-compose.yml instead of docker-compose up -t

    It might be confusing but I am also very new to Docker.

    Thanks for the help everyone!


  2. Note: You don’t need to do docker build -t fastapi . manually. Docker-compose will do it for you (because you set build: .) But! You must run up command with --build parameter (docker-compose up --build) to force rebuild image even if it exists.

    And about your problem:

    Here is a very good article (and one more) about RUN, ENTRYPOINT and CMD

    Here is three forms for CMD:

    • CMD ["executable","param1","param2"] (exec form, preferred)
    • CMD ["param1","param2"] (sets additional default parameters for ENTRYPOINT in exec form)
    • CMD command param1 param2 (shell form)

    According error, looks like Docker interpreting CMD as a shell form or additional parameters for default ENTRYPOINT

    Actually still not sure why it happens, but changing CMD to

    CMD uvicorn app.main:app --host 0.0.0.0 --port 8000
    

    or

    ENTRYPOINT ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
    

    should solve your problem

    Also it will be better to use full path to uvicorn executable (/usr/bin/uvicorn or where it installed by default?). It is just my opinion but, that is may be a reason why CMD is interpreted as parameters instead of command.

    PS In addition here is note from docker docs:

    Note
    The exec form is parsed as a JSON array, which means that you must use double-quotes (“) around words not single-quotes (‘).

    So exec form syntax must meet the conditions of JSON syntax.

    Login or Signup to reply.
  3. I’ve had the same issue with a Dockerfile in my docker-compose environment containing

    COPY ./requirements.txt /app/requirements.txt
    RUN pip install -r /app/requirements.txt
    RUN pip install uvicorn==0.20.0
    CMD ["uvicorn", "--host", "0.0.0.0", "--port", "6000", "app:app"]
    

    So I don’t need an extra command:line in my docker-compose.yml
    It turned out that if you install uvicorn in your requirements.txt, as I like to do for testing purposes
    then it gets installed locally, and
    RUN pip install uvicorn==0.20.0 is skipped, which means,
    there is no /usr/bin/uvicorn ‘executable’ available, just somewhere in site-packages and CMD will fail.
    So, if you use uvicorn in your requirements.txt, and in Dockerfile as well, you can maybe
    force the reinstallation

    RUN pip install --ignore-installed uvicorn==0.20.0
    

    in the Dockerfile,
    or set the PATH to find it somewhere in the guts of python,
    or – what I find is a better solution to keep the image size small –
    is to remove uvicorn from requirements.txt

    Login or Signup to reply.
  4. Check your CMD in Dockerfile. Please give as

    CMD python3 -m uvicorn app:app --reload --host 0.0.0.0 --port 80
    

    The docs says you can use like this in CMD rather than CMD ["uvicorn", ....]

    https://docker-fastapi-projects.readthedocs.io/en/latest/uvicorn.html

    Hope this works for you.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search