Skip to Content
Technical Articles

Python with packages depending on NumPy – Part I

Overview

The standard Cloud Foundry python buildpack allows you to deploy your application by specifying your dependencies on the following file

requirements.txt

Flask==1.0.2

You may add numpy here and it will install it without any issues. However, if you enter any packages that depend on numpy as a dependency, the buildpack will fail, like so:

requirements.txt

Flask==1.0.2
numpy
matplotlib
scikit-fuzzy==0.4.0
Downloading https://files.pythonhosted.org/packages/09/36/4938f2...eb5ff/scikit-fuzzy-0.4.0.tar.gz (994kB)
Complete output from command python setup.py egg_info:
To install scikit-fuzzy from source, you will need numpy.
Install numpy with pip:
pip install numpy
Or use your operating system package manager.

Apparently the buildpack isn’t prepared to install pre-requirements such as numpy. The above output is from python buildpack version 1.6.25. As of of this writing the most recent version is 1.6.28. But even by specifying the latest version this behavior is pretty much the same.

Some folks have forked an older version of this buildpack and never bothered to update their forks to incorporate the changes made after.

So my quest was on how do we provide the usage of such dependencies on the standard buildpack.

Solution A – Miniconda to the rescue

After a lot of digging around I came across a documentation that was not know to me regarding the python buildpack. It should be able to deploy your application just like you would with Anaconda or Miniconda. However, all it said was to use the file environment.yml.

So the solution would involve the following steps:

  1. Remove the files ‘requirements.txt’ and ‘runtime.txt’ from your project
  2. Create a new file with the name ‘environment.yml’
  3. Add the following contents:
name: flask-skfuzzy

channels:
- conda-forge

dependencies:
- python=3.6.*
- pip
- pytest
- icu == 56.*
- flask
- numpy
- nomkl
- scipy
- matplotlib
- scikit-fuzzy

NOTE: In my experience I had to add icu to avoid library linking errors during startup. The nomkl is also there in an effort to reduce the disk size occupied by the conda’s environment in the cloud.

This will work just like what you are used to doing with the following conda command:

conda env create -f environment.yml -n py3

This feels less “error-prone” and will probably make your application work just like if it were running on the conda environment created by the above command.

It also feels the correct way to publish python applications, provided that you don’t need to think about the various differences a cloud environment has related to your own local environment.

Once this file is in place, you must change the manifest.yml file to start using the newest buildpack from Cloud Foundry:

---
applications:
- name: flask-skfuzzy
  memory: 512MB
  disk_quota: 2G
  buildpacks:
    - https://github.com/cloudfoundry/python-buildpack
  stack: cflinuxfs3
  env:
    #BP_DEBUG: "True"

NOTE: I’ve included the environment variable BP_DEBUG here for your convenience. If you should face issues deploying your application, un-comment this variable and it will start giving lots of information so you can understand what is going on.

Once you do a cf push, you will start noticing that the buildpack will work differently.

First, it will load miniconda:

Waiting for API to complete processing files...

Staging app and tracing logs...
   Cell 08338ca7-...-42e442150e8a creating container for instance 05553d49-...-8b658c06bdd5
   Cell 08338ca7-...-42e442150e8a successfully created container for instance 05553d49-...-8b658c06bdd5
   Downloading app package...
   Downloaded app package (6.8K)
   -----> Download go 1.11.4
   -----> Running go build supply
   /tmp/buildpackdownloads/c011a0fe8e55069cdbeb0a3d00e21875 ~
   ~
   -----> Python Buildpack version 1.6.28
   -----> Supplying conda
   -----> Installing miniconda2 4.5.12
          Download [https://repo.continuum.io/miniconda/Miniconda2-4.5.12-Linux-x86_64.sh]
   -----> Installing Miniconda
          PREFIX=/tmp/contents148130992/deps/0/conda
          installing: python-2.7.15-h9bab390_6 ...
          installing: ca-certificates-2018.03.07-0 ...
          installing: conda-env-2.6.0-1 ...
          installing: libgcc-ng-8.2.0-hdf63c60_1 ...
...

NOTE: Don’t worry about python here being on version 2.7. Miniconda 2.4.5.12 is built on top of it. And this python version isn’t the one CF will use as runtime for your app.

Miniconda will then figure out what is needed for the environment based on your environment.yml:

   -----> Installing Dependencies
   -----> Installing conda environment from environment.yml
          Solving environment: ...working... done
          Preparing transaction: ...working... done
          Verifying transaction: ...working... done
          Executing transaction: ...working... done

After is builds the environment, it will present a list of tarballs that will be removed from the filesystem. These are the programs that will be available to your environment:

          python-3.6.3-1.tar.bz2                      19.1 MB
...
          numpy-1.12.1-py36_blas_openblash1522bff_1001.tar.bz2     3.8 MB
          scipy-1.2.0-py36_blas_openblash1522bff_1201.tar.bz2    18.2 MB
...
          pip-19.0.2-py36_0.tar.bz2                    1.8 MB
...
          setuptools-40.8.0-py36_0.tar.bz2             626 KB
          flask-1.0.2-py_2.tar.bz2                      66 KB

          ---------------------------------------------------
          Total:                                     217.9 MB

NOTE: Checkout the total file size of each tarball – huge right?. Think about how much disk size this will take after they are uncompressed.

After the software is installed on the conda environment, you will see the buildpack removing files that are no longer needed and prepare to run the start command:

          Proceed ([y]/n)?
          removing conda-env-2.6.0-1
          removing nomkl-3.0-0
          removing blas-1.1-openblas
   -----> Done
   -----> Running go build finalize
   /tmp/buildpackdownloads/c011a0fe8e55069cdbeb0a3d00e21875 ~
   ~
   Exit status 0
   Uploading droplet, build artifacts cache...
   Uploading droplet...
   Uploading build artifacts cache...
   Uploaded build artifacts cache (242.3M)
   Uploaded droplet (293M)
   Uploading complete

Now Cloud Foundry attempts to start your application. When it succeeds it wil show you some statistical data:

Waiting for app to start...

name:              flask-skfuzzy
requested state:   started
routes:            flask-skfuzzy.cfapps.eu10.hana.ondemand.com
last uploaded:     Fri 15 Feb 14:30:53 DST 2019
stack:             cflinuxfs3
buildpacks:        python

type:            web
instances:       1/1
memory usage:    512M
start command:   python app.py
     state     since                  cpu    memory          disk       details
#0   running   2019-02-15T16:31:43Z   1.2%   98.6M of 512M   1G of 2G

NOTE: Check the overall disk size of this application: 1G. That’s the reason, I had to use 2G on my manifest file. This is the reason why I added the nomkl module – I didn’t try to figure out if this was really helping or not. 1G to run a simple python application was simply unacceptable to me.

There has to be another way!

Solution 2 – Fork the Buildpack

Read it on part II of my next blog:

https://blogs.sap.com/2019/02/15/python-with-packages-depending-on-numpy-part-ii

 

Enjoy!

Be the first to leave a comment
You must be Logged on to comment or reply to a post.