Search code examples
pythondockerflaskjenkins-pipelinepytest

Docker run Flask ImportError: No Module Named Flask


I'm trying to complete my school assignment, which is:

  1. fork https://github.com/aaronjolson/flask-pytest-example
  2. Write Jenkinsfile, Dockerfile -> Resulting in a new tag on your dockerhub repo
  3. Pull docker
  4. Build docker
  5. Run docker
  6. curl localhost:5000 to see results

Currently I'm on stage 5 and I am getting this error when trying to run a docker image:

Traceback (most recent call last):

File "app.py", line 1, in <module>

from flask import Flask

ImportError: No module named flask

Config:

  1. Jenkins is working on Debian 9
  2. To pull and run docker images using Docker client for Windows
  3. Jenkinsfile:
it@debian:~/flask-pytest-example$ cat Jenkinsfile
pipeline {
    environment {
        registry = "tslaceo/flask-pytest"
        imageName = 'flask-pytest'
        registryCred = 'tslaceo'
        gitProject = "https://github.com/tslaceo/flask-pytest-example.git"
    }
    agent any
    options {
        timeout(time: 1, unit: 'HOURS')
    }
    stages {
        stage ('preparation') {
            steps {
                deleteDir()
            }
        }
        stage ('get src from git') {
            steps {
                git 'https://github.com/tslaceo/flask-pytest-example.git'
            }
        }
        stage ('build docker') {
            steps {
                script {
                    dockerImage = docker.build registry + ":$BUILD_NUMBER"
                }
            }
        }
        stage ('docker publish') {
            steps {
                script {
                    docker.withRegistry( '', registryCred ) {
                        dockerImage.push()
                    }
                }
            }
        }
        stage ('cleaning') {
            steps {
                sh "docker rmi $registry:$BUILD_NUMBER"
            }
        }
    }
}

  1. Dockerfile:
it@debian:~/flask-pytest-example$ cat Dockerfile
FROM python
WORKDIR /flask-pytest-example
RUN python --version
RUN pip freeze > requirements.txt
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
CMD ["python", "-u", "app.py"]
  1. requirements.txt
it@debian:~/flask-pytest-example$ cat requirements.txt
flask
pytest
  1. ls -la
it@debian:~/flask-pytest-example$ ls -la
total 52
drwxr-xr-x  5 it it 4096 Apr 27 15:28 .
drwxr-xr-x 19 it it 4096 Apr 27 14:42 ..
-rw-r--r--  1 it it  178 Apr 27 10:32 app.py
-rw-r--r--  1 it it  202 Apr 27 15:06 Dockerfile
-rw-r--r--  1 it it  152 Apr 27 12:39 Dockerfile.save
drwxr-xr-x  8 it it 4096 Apr 27 15:06 .git
-rw-r--r--  1 it it   38 Apr 27 10:32 .gitignore
drwxr-xr-x  2 it it 4096 Apr 27 10:32 handlers
-rw-r--r--  1 it it    0 Apr 27 10:32 __init__.py
-rw-r--r--  1 it it 1147 Apr 27 10:48 Jenkinsfile
-rw-r--r--  1 it it 1071 Apr 27 10:32 LICENSE
-rw-r--r--  1 it it  491 Apr 27 10:32 README.md
-rw-r--r--  1 it it   13 Apr 27 10:32 requirements.txt
drwxr-xr-x  2 it it 4096 Apr 27 10:32 tests

Solution

  • Delete the RUN pip freeze ... line; replace it with COPY requirements.txt . to get the copy of that file that's checked in with the rest of your application.

    The flow in the Dockerfile you show is

    1. Start from a clean, empty Python installation;
    2. List all of the packages installed there (that is, nothing) and write into requirements.txt;
    3. Install all of the packages (that is, nothing) listed in requirements.txt.

    The requirements.txt file should be checked in as part of your application's source code, so if you COPY this in instead of regenerating it, it will have packages listed in it and it will be the exact versions of the packages you tested with in your non-Docker virtual environment.


    I might leave a Jenkins-based build setup as the very last thing in this sequence. A better approach could be:

    1. Build your application using a normal Python virtual environment; no Jenkins, no Docker.

      python3 -m venv venv
      . venv/bin/activate
      pip install -r requirements.txt
      pytest
      ./app.py
      curl http://localhost:5000
      
    2. Wrap your built, working, tested Python application in a Docker container, using the Dockerfile you show above.

      docker build -t tslaceo/flask-pytest .
      docker run -p 5000:5000 tslaceo/flask-pytest
      curl http://localhost:5000
      
    3. Wrap this setup in Jenkins.

    If something is wrong with your application (which is the usual case) the virtual-environment setup will be much easier to debug, and you can use ordinary editors, IDEs, debuggers, etc. without any special setup. If something is wrong with your packaging then running docker build locally will again be easier to debug and tweak than trying to reproduce it in a CI environment.