This is a simple tutorial on how to run Tensorflow 2.0 example jupyter notebooks in a docker container environment. If you are new to Docker, it is a fantastic tool for developing reproducible applications. This post will not be an indepth tutorial to Docker, if you are interested in an introduction, see https://docs.docker.com/get-started/—I will do a tutorial post soon.
One major benefit of Docker is the ability to share and replicate your development environment with collaborators (and to avoid getting stuck in dependency hell). Assuming your collaborators have Docker (and Docker Compose, if required), standing up an identical and isolated development environment only requires running a few commands!
As data scientists, it is common for us to exclusively live in Jupyter notebooks (for better, or for worse) to perform a variety of tasks—from exploratory data analysis, preprocessing, training, etc. Additionally, we want to ensure our Jupyter environment has the proper dependencies to perform our analysis.
Note: None of these Tensorflow tutorials are my own, they are all available on Tensorflow. The goal of this repository is to replicate these tutorials in a dockerized environment for educational purposes. Any modifications to the content will be indicated accordingly.
Docker Compose Configuration File
In this tutorial, we are keeping things simple. We will first start by creating a
docker-compose.yml file. Generally, these files are used to specify the various services you would like for Docker to stand up—if you are dealing with a multi-container environment. In this example, our
docker-compose.yml will only contain a single service, however this serves as an example of how to include a simple jupyter server to another docker stack.
version: "3.7" services: tf-jupyter: image: jupyter/tensorflow-notebook:latest environment: - JUPYTER_TOKEN=jupyter volumes: - ./tutorials:/tf/tutorials working_dir: /tf/tutorials/ ports: # Jupyter port - "8888:8888" # Tensorboard port - "6006:6006"
Let’s break things down line-by-line.
version: "3.7" specifies the version of docker-compose to use. At a high level, different versions of docker-compose have different parameters you can specify.
Second, we define the various
services to stand up, however since we only have a single service, we only see a single entry. If wanted multiple services, your file may look like:
version: ... services: service-a: ... service-b: ... service-c: ... ...
Next, we define our service Jupyter notebook service. We start by defining the “image” to start from.
As a reminder, an image contains a frozen copy of a development environment. In this example, we are starting from an environment created by the Jupyter team that comes pre-installed with a lot of useful tools for running Tensorflow code. What this line is saying is start from the
tensorflow-notebook image made by
jupyter, and specifically, grab the
latest version of this environment—you can also specify specific versions.
Optionally, we can define environment variables for the container.
environment: - JUPYTER_TOKEN=jupyter
In this example, we defining a single environment variable called
JUPYTER_TOKEN. If you aren’t familiar with Jupyter, this is essentially a password to access the server. So here, we are setting the password to
jupyter—in another post I show you a tip for securing your environment variables. Again, this is optional. If you remove this section of the config, Jupyter will start with no password required.
volumes: - ./tutorials:/tf/tutorials
Here we “mount” a
volume, which essentially means “copy” files from your local machine to a specific directory in the container (whether or not it exists). Above, we mount the entire tutorials folder into a directory called
/tf/tutorials. Note, this directory does not exist in the container, we are instructing docker-compose to make this directory and copy the contents to it. This way, we can access our notebooks from the container and our changes persist upon spinning down the container.
This tells docker-compose to
cd us into the
/tf/tutorials/ directory upon entering it.
ports: # Jupyter port - "8888:8888" # Tensorboard port - "6006:6006"
For this container, we would like to start up two servers, one for Jupyter notebook and another for Tensorboard (if we elect to use it). In order for our local computer to actually access these servers, we must specify the port(s) to expose. Here we tell Jupyter to be accessible on port
8888 by the host (our local computer) and run on port
8888 within the container. What this implies is that we can forward the port to another, if there are port conflicts. Simiarly, for tensorboard, we expose
And that’s it for the configuration file!
How to Run Your Container(s)
Now here is the time to show the power of Docker. Assuming you are
cd‘d into the proper directory, if you run from a terminal/command prompt:
Docker will start up a service called
Creating network "tf_tutorials_default" with the default driver Creating tf_tutorials_tf-jupyter_1 ...
If this is your first time running the command, it will take a while to execute as it is downloading all of the required dependencies. Note, the next time you run this command, you will not have to wait as long.
After everything downloads, you should finally see the following in your terminal:
tf-jupyter_1 | [I 2021-04-09 04:01:24.038 LabApp] JupyterLab application directory is /opt/conda/share/jupyter/lab tf-jupyter_1 | [I 04:01:24.043 NotebookApp] Serving notebooks from local directory: /tf/tutorials tf-jupyter_1 | [I 04:01:24.043 NotebookApp] Jupyter Notebook 6.2.0 is running at: tf-jupyter_1 | [I 04:01:24.043 NotebookApp] http://23b09491f9c6:8888/?token=... tf-jupyter_1 | [I 04:01:24.043 NotebookApp] or http://127.0.0.1:8888/?token=... tf-jupyter_1 | [I 04:01:24.043 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
You now have a Jupyter notebook server running! If you visit
localhost:8888 in your browser, you will arrive on this page:
Recall, the password/token for this Jupyter server is
jupyter (defined in the environment variables). Upon logging in, you’ll arrive at the usual Jupyter notebook screen.
Running the Tensorflow Example Notebooks
Additionally, you can see we already have tensorflow installed. As of 2021-04-09, the following dependencies are included in the
(base) jovyan@53e0be54cffe:/tf/tutorials$ pip list Package Version ----------------------------- ------------------- absl-py 0.11.0 alembic 1.5.5 anyio 2.2.0 appdirs 1.4.4 argon2-cffi 20.1.0 astunparse 1.6.3 async-generator 1.10 attrs 20.3.0 Babel 2.9.0 backcall 0.2.0 backports.functools-lru-cache 1.6.1 beautifulsoup4 4.9.3 bleach 3.3.0 blinker 1.4 bokeh 2.2.3 Bottleneck 1.3.2 brotlipy 0.7.0 cached-property 1.5.1 cachetools 4.2.1 certifi 2020.12.5 certipy 0.1.3 cffi 1.14.5 chardet 4.0.0 click 7.1.2 cloudpickle 1.6.0 conda 4.9.2 conda-package-handling 1.7.2 cryptography 3.4.4 cycler 0.10.0 Cython 0.29.22 cytoolz 0.11.0 dask 2021.2.0 decorator 4.4.2 defusedxml 0.6.0 dill 0.3.3 distributed 2021.2.0 entrypoints 0.3 flatbuffers 1.12 fsspec 0.8.7 gast 0.3.3 gmpy2 2.1.0b1 google-auth 1.27.1 google-auth-oauthlib 0.4.3 google-pasta 0.2.0 grpcio 1.32.0 h5py 2.10.0 HeapDict 1.0.1 idna 2.10 imagecodecs 2021.1.28 imageio 2.9.0 importlib-metadata 3.7.0 ipykernel 5.5.0 ipympl 0.6.3 ipython 7.21.0 ipython-genutils 0.2.0 ipywidgets 7.6.3 jedi 0.18.0 Jinja2 2.11.3 joblib 1.0.1 json5 0.9.5 jsonschema 3.2.0 jupyter-client 6.1.11 jupyter-core 4.7.1 jupyter-packaging 0.7.12 jupyter-server 1.4.1 jupyter-telemetry 0.1.0 jupyterhub 1.3.0 jupyterlab 3.0.9 jupyterlab-pygments 0.1.2 jupyterlab-server 2.3.0 jupyterlab-widgets 1.0.0 Keras-Preprocessing 1.1.2 kiwisolver 1.3.1 llvmlite 0.35.0 locket 0.2.0 Mako 1.1.4 mamba 0.7.14 Markdown 3.3.4 MarkupSafe 1.1.1 matplotlib 3.3.4 mistune 0.8.4 mock 4.0.3 mpmath 1.2.1 msgpack 1.0.2 nbclassic 0.2.6 nbclient 0.5.3 nbconvert 6.0.7 nbformat 5.1.2 nest-asyncio 1.4.3 networkx 2.5 notebook 6.2.0 numba 0.52.0 numexpr 2.7.2 numpy 1.19.5 oauthlib 3.0.1 olefile 0.46 opt-einsum 3.3.0 packaging 20.9 pamela 1.0.0 pandas 1.2.3 pandocfilters 1.4.2 parso 0.8.1 partd 1.1.0 patsy 0.5.1 pexpect 4.8.0 pickleshare 0.7.5 Pillow 8.1.1 pip 21.0.1 pooch 1.3.0 prometheus-client 0.9.0 prompt-toolkit 3.0.16 protobuf 3.15.4 psutil 5.8.0 ptyprocess 0.7.0 pyasn1 0.4.8 pyasn1-modules 0.2.8 pycosat 0.6.3 pycparser 2.20 pycurl 188.8.131.52 Pygments 2.8.0 PyJWT 2.0.1 pyOpenSSL 20.0.1 pyparsing 2.4.7 pyrsistent 0.17.3 PySocks 1.7.1 python-dateutil 2.8.1 python-editor 1.0.4 python-json-logger 2.0.1 pytz 2021.1 PyWavelets 1.1.1 PyYAML 5.4.1 pyzmq 22.0.3 requests 2.25.1 requests-oauthlib 1.3.0 rsa 4.7.2 ruamel-yaml-conda 0.15.80 ruamel.yaml 0.16.12 ruamel.yaml.clib 0.2.2 scikit-image 0.18.1 scikit-learn 0.24.1 scipy 1.6.0 seaborn 0.11.1 Send2Trash 1.5.0 setuptools 49.6.0.post20210108 six 1.15.0 sniffio 1.2.0 sortedcontainers 2.3.0 soupsieve 2.0.1 SQLAlchemy 1.3.23 statsmodels 0.12.2 sympy 1.7.1 tables 3.6.1 tblib 1.6.0 tensorboard 2.4.1 tensorboard-plugin-wit 1.8.0 tensorflow 2.4.1 tensorflow-estimator 2.4.0 termcolor 1.1.0 terminado 0.9.2 testpath 0.4.4 threadpoolctl 2.1.0 tifffile 2021.2.26 toolz 0.11.1 tornado 6.1 tqdm 4.58.0 traitlets 5.0.5 typing-extensions 184.108.40.206 urllib3 1.26.3 vincent 0.4.4 wcwidth 0.2.5 webencodings 0.5.1 Werkzeug 1.0.1 wheel 0.36.2 widgetsnbextension 3.5.1 wrapt 1.12.1 xlrd 2.0.1 zict 2.0.0 zipp 3.4.0
Note, you can do this a few ways, but here are a couple of options:
- Create a terminal in the Jupyter server and execute
- From your command prompt, run
docker-compose run tf-jupyter pip list
Additionally, since you mounted your notebook directory, all changes made within the container should presist to your local copies. However, warning, if you write to unmounted directories, your changes will disappear when you exit the container.
Spinning Down Your Container
When you are done with your jupyter container,
ctrl+c the terminal where you ran the
docker-compose up, and you’ll see the following prompt.
Gracefully stopping... (press Ctrl+C again to force) Stopping tf_tutorials_tf-jupyter_1 ... Killing tf_tutorials_tf-jupyter_1 ... done
To ensure the containers fully stop gracefully, execute:
Link to Repository
For the full code for this tutorial see: