├── Dockerfile ├── Dockerfile.Bonus ├── Pipfile ├── Pipfile.lock ├── README.md ├── conf └── jupyter.py ├── nbs ├── Load_Unload.ipynb └── notebook.tar.gz └── scripts ├── build.sh ├── d_build.sh ├── d_build_and_run.sh ├── d_run.sh ├── deploy.sh └── entrypoint.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8.2-slim 2 | 3 | ENV APP_HOME /app 4 | WORKDIR ${APP_HOME} 5 | 6 | COPY . ./ 7 | 8 | RUN pip install pip pipenv --upgrade 9 | RUN pipenv install --skip-lock --system --dev 10 | 11 | CMD ["./scripts/entrypoint.sh"] -------------------------------------------------------------------------------- /Dockerfile.Bonus: -------------------------------------------------------------------------------- 1 | FROM python:3.8.2-slim 2 | 3 | ENV APP_HOME /app 4 | WORKDIR ${APP_HOME} 5 | 6 | COPY . ./ 7 | 8 | # Install Ubuntu dependencies 9 | # libopencv-dev = opencv dependencies 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ 11 | tzdata \ 12 | libopencv-dev \ 13 | build-essential \ 14 | libssl-dev \ 15 | libpq-dev \ 16 | libcurl4-gnutls-dev \ 17 | libexpat1-dev \ 18 | gettext \ 19 | unzip \ 20 | supervisor \ 21 | python3-setuptools \ 22 | python3-pip \ 23 | python3-dev \ 24 | python3-venv \ 25 | python3-urllib3 \ 26 | git \ 27 | && \ 28 | apt-get clean && \ 29 | rm -rf /var/lib/apt/lists/* 30 | 31 | # Upgrade PIP 32 | RUN pip install pip pipenv --upgrade 33 | 34 | # sklearn opencv, numpy, and pandas 35 | RUN pip install scikit-learn opencv-contrib-python numpy pandas 36 | 37 | # tensorflow (including Keras) 38 | RUN pip install tensorflow keras 39 | 40 | # pytorch (cpu) 41 | RUN apt-get update && apt-get -y install gcc mono-mcs && rm -rf /var/lib/apt/lists/* 42 | RUN pip install torch==1.5.0+cpu torchvision==0.6.0+cpu -f https://download.pytorch.org/whl/torch_stable.html 43 | 44 | # fastai 45 | RUN pip install fastai 46 | 47 | # Project installs 48 | RUN pipenv install --skip-lock --system --dev 49 | 50 | CMD ["./scripts/entrypoint.sh"] -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | jupyter = "*" 10 | 11 | [requires] 12 | python_version = "3.8" 13 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "48fd0902485d39635357a936436891db877ce762c3217183dff442e4b185b5da" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "appnope": { 20 | "hashes": [ 21 | "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", 22 | "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71" 23 | ], 24 | "markers": "sys_platform == 'darwin'", 25 | "version": "==0.1.0" 26 | }, 27 | "attrs": { 28 | "hashes": [ 29 | "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", 30 | "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" 31 | ], 32 | "version": "==19.3.0" 33 | }, 34 | "backcall": { 35 | "hashes": [ 36 | "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", 37 | "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" 38 | ], 39 | "version": "==0.2.0" 40 | }, 41 | "bleach": { 42 | "hashes": [ 43 | "sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f", 44 | "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b" 45 | ], 46 | "version": "==3.1.5" 47 | }, 48 | "decorator": { 49 | "hashes": [ 50 | "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", 51 | "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7" 52 | ], 53 | "version": "==4.4.2" 54 | }, 55 | "defusedxml": { 56 | "hashes": [ 57 | "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", 58 | "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5" 59 | ], 60 | "version": "==0.6.0" 61 | }, 62 | "entrypoints": { 63 | "hashes": [ 64 | "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", 65 | "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" 66 | ], 67 | "version": "==0.3" 68 | }, 69 | "ipykernel": { 70 | "hashes": [ 71 | "sha256:09bac6473a593f61a3ae036035b81a2d30457ff157163562796560516a2f67d8", 72 | "sha256:d718d5f717e0818329d371313f99aabba1bf4ca13f1e9f80cc3c5f866ee8a9ad" 73 | ], 74 | "version": "==5.3.3" 75 | }, 76 | "ipython": { 77 | "hashes": [ 78 | "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64", 79 | "sha256:9f4fcb31d3b2c533333893b9172264e4821c1ac91839500f31bd43f2c59b3ccf" 80 | ], 81 | "markers": "python_version >= '3.3'", 82 | "version": "==7.16.1" 83 | }, 84 | "ipython-genutils": { 85 | "hashes": [ 86 | "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", 87 | "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" 88 | ], 89 | "version": "==0.2.0" 90 | }, 91 | "ipywidgets": { 92 | "hashes": [ 93 | "sha256:13ffeca438e0c0f91ae583dc22f50379b9d6b28390ac7be8b757140e9a771516", 94 | "sha256:e945f6e02854a74994c596d9db83444a1850c01648f1574adf144fbbabe05c97" 95 | ], 96 | "version": "==7.5.1" 97 | }, 98 | "jedi": { 99 | "hashes": [ 100 | "sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20", 101 | "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5" 102 | ], 103 | "version": "==0.17.2" 104 | }, 105 | "jinja2": { 106 | "hashes": [ 107 | "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", 108 | "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" 109 | ], 110 | "version": "==2.11.2" 111 | }, 112 | "jsonschema": { 113 | "hashes": [ 114 | "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", 115 | "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" 116 | ], 117 | "version": "==3.2.0" 118 | }, 119 | "jupyter": { 120 | "hashes": [ 121 | "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7", 122 | "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78", 123 | "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f" 124 | ], 125 | "index": "pypi", 126 | "version": "==1.0.0" 127 | }, 128 | "jupyter-client": { 129 | "hashes": [ 130 | "sha256:7ad9aa91505786420d77edc5f9fb170d51050c007338ba8d196f603223fd3b3a", 131 | "sha256:b360f8d4638bc577a4656e93f86298db755f915098dc763f6fc05da0c5d7a595" 132 | ], 133 | "version": "==6.1.6" 134 | }, 135 | "jupyter-console": { 136 | "hashes": [ 137 | "sha256:6f6ead433b0534909df789ea64f0a14cdf9b6b2360757756f08182be4b9e431b", 138 | "sha256:b392155112ec86a329df03b225749a0fa903aa80811e8eda55796a40b5e470d8" 139 | ], 140 | "version": "==6.1.0" 141 | }, 142 | "jupyter-core": { 143 | "hashes": [ 144 | "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e", 145 | "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21" 146 | ], 147 | "version": "==4.6.3" 148 | }, 149 | "markupsafe": { 150 | "hashes": [ 151 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", 152 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", 153 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", 154 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", 155 | "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", 156 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", 157 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", 158 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", 159 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", 160 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", 161 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", 162 | "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", 163 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", 164 | "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", 165 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", 166 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", 167 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", 168 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", 169 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", 170 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", 171 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", 172 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", 173 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", 174 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", 175 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", 176 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", 177 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", 178 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", 179 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", 180 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", 181 | "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", 182 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", 183 | "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" 184 | ], 185 | "version": "==1.1.1" 186 | }, 187 | "mistune": { 188 | "hashes": [ 189 | "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", 190 | "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4" 191 | ], 192 | "version": "==0.8.4" 193 | }, 194 | "nbconvert": { 195 | "hashes": [ 196 | "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523", 197 | "sha256:f0d6ec03875f96df45aa13e21fd9b8450c42d7e1830418cccc008c0df725fcee" 198 | ], 199 | "version": "==5.6.1" 200 | }, 201 | "nbformat": { 202 | "hashes": [ 203 | "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340", 204 | "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f" 205 | ], 206 | "version": "==5.0.7" 207 | }, 208 | "notebook": { 209 | "hashes": [ 210 | "sha256:3edc616c684214292994a3af05eaea4cc043f6b4247d830f3a2f209fa7639a80", 211 | "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48" 212 | ], 213 | "version": "==6.0.3" 214 | }, 215 | "packaging": { 216 | "hashes": [ 217 | "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", 218 | "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" 219 | ], 220 | "version": "==20.4" 221 | }, 222 | "pandocfilters": { 223 | "hashes": [ 224 | "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9" 225 | ], 226 | "version": "==1.4.2" 227 | }, 228 | "parso": { 229 | "hashes": [ 230 | "sha256:158c140fc04112dc45bca311633ae5033c2c2a7b732fa33d0955bad8152a8dd0", 231 | "sha256:908e9fae2144a076d72ae4e25539143d40b8e3eafbaeae03c1bfe226f4cdf12c" 232 | ], 233 | "version": "==0.7.0" 234 | }, 235 | "pexpect": { 236 | "hashes": [ 237 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 238 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 239 | ], 240 | "markers": "sys_platform != 'win32'", 241 | "version": "==4.8.0" 242 | }, 243 | "pickleshare": { 244 | "hashes": [ 245 | "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", 246 | "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" 247 | ], 248 | "version": "==0.7.5" 249 | }, 250 | "prometheus-client": { 251 | "hashes": [ 252 | "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c", 253 | "sha256:c6e6b706833a6bd1fd51711299edee907857be10ece535126a158f911ee80915" 254 | ], 255 | "version": "==0.8.0" 256 | }, 257 | "prompt-toolkit": { 258 | "hashes": [ 259 | "sha256:563d1a4140b63ff9dd587bda9557cffb2fe73650205ab6f4383092fb882e7dc8", 260 | "sha256:df7e9e63aea609b1da3a65641ceaf5bc7d05e0a04de5bd45d05dbeffbabf9e04" 261 | ], 262 | "version": "==3.0.5" 263 | }, 264 | "ptyprocess": { 265 | "hashes": [ 266 | "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", 267 | "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f" 268 | ], 269 | "markers": "os_name != 'nt'", 270 | "version": "==0.6.0" 271 | }, 272 | "pygments": { 273 | "hashes": [ 274 | "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44", 275 | "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324" 276 | ], 277 | "version": "==2.6.1" 278 | }, 279 | "pyparsing": { 280 | "hashes": [ 281 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", 282 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" 283 | ], 284 | "version": "==2.4.7" 285 | }, 286 | "pyrsistent": { 287 | "hashes": [ 288 | "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3" 289 | ], 290 | "version": "==0.16.0" 291 | }, 292 | "python-dateutil": { 293 | "hashes": [ 294 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", 295 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" 296 | ], 297 | "version": "==2.8.1" 298 | }, 299 | "pyzmq": { 300 | "hashes": [ 301 | "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98", 302 | "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0", 303 | "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f", 304 | "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c", 305 | "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421", 306 | "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112", 307 | "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448", 308 | "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960", 309 | "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891", 310 | "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6", 311 | "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85", 312 | "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2", 313 | "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234", 314 | "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7", 315 | "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea", 316 | "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087", 317 | "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9", 318 | "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a", 319 | "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10", 320 | "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6", 321 | "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd", 322 | "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217", 323 | "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230", 324 | "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec", 325 | "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054", 326 | "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566", 327 | "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec", 328 | "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e" 329 | ], 330 | "version": "==19.0.1" 331 | }, 332 | "qtconsole": { 333 | "hashes": [ 334 | "sha256:4f43d0b049eacb7d723772847f0c465feccce0ccb398871a6e146001a22bad23", 335 | "sha256:f5cb275d30fc8085e2d1d18bc363e5ba0ce6e559bf37d7d6727b773134298754" 336 | ], 337 | "version": "==4.7.5" 338 | }, 339 | "qtpy": { 340 | "hashes": [ 341 | "sha256:2db72c44b55d0fe1407be8fba35c838ad0d6d3bb81f23007886dc1fc0f459c8d", 342 | "sha256:fa0b8363b363e89b2a6f49eddc162a04c0699ae95e109a6be3bb145a913190ea" 343 | ], 344 | "version": "==1.9.0" 345 | }, 346 | "send2trash": { 347 | "hashes": [ 348 | "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", 349 | "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b" 350 | ], 351 | "version": "==1.5.0" 352 | }, 353 | "six": { 354 | "hashes": [ 355 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 356 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 357 | ], 358 | "version": "==1.15.0" 359 | }, 360 | "terminado": { 361 | "hashes": [ 362 | "sha256:4804a774f802306a7d9af7322193c5390f1da0abb429e082a10ef1d46e6fb2c2", 363 | "sha256:a43dcb3e353bc680dd0783b1d9c3fc28d529f190bc54ba9a229f72fe6e7a54d7" 364 | ], 365 | "version": "==0.8.3" 366 | }, 367 | "testpath": { 368 | "hashes": [ 369 | "sha256:60e0a3261c149755f4399a1fff7d37523179a70fdc3abdf78de9fc2604aeec7e", 370 | "sha256:bfcf9411ef4bf3db7579063e0546938b1edda3d69f4e1fb8756991f5951f85d4" 371 | ], 372 | "version": "==0.4.4" 373 | }, 374 | "tornado": { 375 | "hashes": [ 376 | "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc", 377 | "sha256:22aed82c2ea340c3771e3babc5ef220272f6fd06b5108a53b4976d0d722bcd52", 378 | "sha256:2c027eb2a393d964b22b5c154d1a23a5f8727db6fda837118a776b29e2b8ebc6", 379 | "sha256:5217e601700f24e966ddab689f90b7ea4bd91ff3357c3600fa1045e26d68e55d", 380 | "sha256:5618f72e947533832cbc3dec54e1dffc1747a5cb17d1fd91577ed14fa0dc081b", 381 | "sha256:5f6a07e62e799be5d2330e68d808c8ac41d4a259b9cea61da4101b83cb5dc673", 382 | "sha256:c58d56003daf1b616336781b26d184023ea4af13ae143d9dda65e31e534940b9", 383 | "sha256:c952975c8ba74f546ae6de2e226ab3cc3cc11ae47baf607459a6728585bb542a", 384 | "sha256:c98232a3ac391f5faea6821b53db8db461157baa788f5d6222a193e9456e1740" 385 | ], 386 | "version": "==6.0.4" 387 | }, 388 | "traitlets": { 389 | "hashes": [ 390 | "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44", 391 | "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7" 392 | ], 393 | "version": "==4.3.3" 394 | }, 395 | "wcwidth": { 396 | "hashes": [ 397 | "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", 398 | "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" 399 | ], 400 | "version": "==0.2.5" 401 | }, 402 | "webencodings": { 403 | "hashes": [ 404 | "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", 405 | "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" 406 | ], 407 | "version": "==0.5.1" 408 | }, 409 | "widgetsnbextension": { 410 | "hashes": [ 411 | "sha256:079f87d87270bce047512400efd70238820751a11d2d8cb137a5a5bdbaf255c7", 412 | "sha256:bd314f8ceb488571a5ffea6cc5b9fc6cba0adaf88a9d2386b93a489751938bcd" 413 | ], 414 | "version": "==3.5.1" 415 | } 416 | }, 417 | "develop": {} 418 | } 419 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [Original Post](https://www.codingforentrepreneurs.com/blog/jupyter-production-server-on-docker-heroku) 2 | 3 | [![Jupyter x Docker on Heroku Post](https://static.codingforentrepreneurs.com/media/cfe-blog/jupyter-production-server-on-docker-heroku/Jupyter_x_Docker_to_Heroku.jpg)](https://www.codingforentrepreneurs.com/blog/jupyter-production-server-on-docker-heroku) 4 | 5 | Jupyter is a tool for running interactive notebooks; basically add Python with Markdown and you've got Jupyter. if you haven't used it before, I recommend you do. 6 | 7 | In this post, I'm going to show you how to deploy a Jupyter Notebook server on Heroku using Docker. 8 | 9 | ## The big caveat 10 | Jupyter has the ability to create new notebooks and they will 100% save on your deployed docker-based Jupyter server... but they will **disappear** as soon as you deploy a new version. That's because containers, by their very nature, are ephemeral by default. 11 | 12 | This caveat doesn't mean we shouldn't do this... it just means it is a HUGE consideration when using this guide over something like http://colab.research.google.com. 13 | 14 | Near the bottom, I'll show you how to package all your Jupyter contents, download it, and unpackage it again when you deploy. 15 | 16 | 17 | ### Final Project Structure 18 | 19 | ``` 20 | cfe_jupyter 21 | | Dockerfile 22 | │ Pipfile 23 | │ Pipfile.lock 24 | │ 25 | └───conf 26 | │ │ jupyter.py 27 | | 28 | └───nbs 29 | │ │ notebook.tar.gz 30 | │ 31 | └───scripts 32 | │ Dockerfile 33 | │ d_build.sh 34 | | d_run.sh 35 | | deploy.sh 36 | | entrypoint.sh 37 | ``` 38 | 39 | ## How it's done. 40 | 41 | #### 1. Use `pipenv` and install `jupyter` 42 | 43 | ``` 44 | pip install pipenv 45 | cd path/to/your/project/ 46 | pipenv install jupyter --python 3.8 47 | ``` 48 | 49 | #### 2. Create Jupyter Configuration 50 | 51 | **Generate Default Config** 52 | ``` 53 | jupyter notebook --generate-config 54 | ``` 55 | This command creates the default `jupyter_notebook_config.py` file on your local machine. Mine was stored on `~/.jupyter/jupyter_notebook_config.py` 56 | 57 | **Create `conf/jupyter.py`** 58 | ``` 59 | mkdir conf 60 | echo "" > conf/jupyter.py 61 | ``` 62 | In `conf/jupyter.py` add: 63 | 64 | ```python 65 | import os 66 | c = get_config() 67 | # Kernel config 68 | c.IPKernelApp.pylab = 'inline' # if you want plotting support always in your notebook 69 | # Notebook config 70 | c.NotebookApp.notebook_dir = 'nbs' 71 | c.NotebookApp.allow_origin = u'cfe-jupyter.herokuapp.com' # put your public IP Address here 72 | c.NotebookApp.ip = '*' 73 | c.NotebookApp.allow_remote_access = True 74 | c.NotebookApp.open_browser = False 75 | # ipython -c "from notebook.auth import passwd; passwd()" 76 | c.NotebookApp.password = u'sha1:8da45965a489:86884d5b174e2f64e900edd129b5ef0d2f784a65' 77 | c.NotebookApp.port = int(os.environ.get("PORT", 8888)) 78 | c.NotebookApp.allow_root = True 79 | c.NotebookApp.allow_password_change = True 80 | c.ConfigurableHTTPProxy.command = ['configurable-http-proxy', '--redirect-port', '80'] 81 | ``` 82 | A few noteable setup items here: 83 | 84 | - `c.NotebookApp.notebook_dir` I set as `nbs` which means you should create a directory as `nbs` for your default notebooks directory. In my case, jupyter will open right to this directory ignoring all others. 85 | - `c.NotebookApp.password` - this has to be a hashed password. To create a new one, just run `ipython -c "from notebook.auth import passwd; passwd()"` on your command line. 86 | - `c.NotebookApp.port` - Heroku sets this value in our environment variables thus `int(os.environ.get("PORT", 8888))` as our default. 87 | 88 | 89 | Test your new configuration locally with: `jupyter notebook --config=./conf/jupyter.py` 90 | 91 | 92 | #### 3.Create a notebook under -> `nbs/Load_Unload.ipynb` 93 | This will be how you can handle the ephemeral nature of Docker containers with Jupyter notebooks. Just create a new notebook called `Load_Unload.ipynb`, and add the following: 94 | 95 | ```python 96 | mode = "unload" 97 | 98 | if mode == 'unload': 99 | # Zip all files in the current directory 100 | !tar chvfz notebook.tar.gz * 101 | 102 | elif mode == 'load: 103 | # Unzip all files in the current directory 104 | !!tar -xv -f notebook.tar.gz 105 | ``` 106 | 107 | 108 | #### 4. Add your `Dockerfile` 109 | This is the absolute minimum setup here. You might want to add additional items as needed. Certain packages, especially the ones for data science, require additional installs for our docker-based linux server. 110 | 111 | ```dockerfile 112 | FROM python:3.8.2-slim 113 | 114 | ENV APP_HOME /app 115 | WORKDIR ${APP_HOME} 116 | 117 | COPY . ./ 118 | 119 | RUN pip install pip pipenv --upgrade 120 | RUN pipenv install --skip-lock --system --dev 121 | 122 | CMD ["./scripts/entrypoint.sh"] 123 | ``` 124 | > The most noteable part of this all is that (1) I'm using `pipenv` locally and in docker and (2) I both install `pipenv` and run `pipenv install --system` to install all pipenv dependancies to the entire docker container (instead of in a virtual environment within the container as well). 125 | 126 | 127 | 128 | #### 5. Create `scripts/entrypoint.sh` 129 | 130 | I perfer using a `entrypoint.sh` script for the `CMD` in Dockerfiles. 131 | 132 | ```bash 133 | #!/bin/bash 134 | 135 | /usr/local/bin/jupyter notebook --config=./conf/jupyter.py 136 | ``` 137 | 138 | 139 | 140 | #### 6. Build & Run Docker Locally 141 | 142 | ``` 143 | docker build -t cfe-jupyter -f Dockerfile . 144 | 145 | docker run --env PORT=8888 -it -p 8888:8888 cfe-jupyter 146 | ``` 147 | 148 | #### 7. Heroku Setup 149 | 150 | ##### 1. Create heroku app 151 | ``` 152 | heroku create cfe-jupyter 153 | ``` 154 | - Change `cfe-jupyter` to your app name 155 | 156 | ##### 2. Login to Heroku Container Registry 157 | ``` 158 | heroku container:login 159 | 160 | ``` 161 | 162 | #### 7. Push & Release To Heroku 163 | 164 | ```bash 165 | heroku container:push web 166 | heroku container:release web 167 | ``` 168 | 169 | - `web` is the default for our `Dockerfile`. 170 | - On the commands above, you might have to append `-a ` like `heroku container:push web -a cfe-jupyter 171 | 172 | 173 | #### 8. That's it 174 | ``` 175 | heroku open 176 | ``` 177 | This should allow you to open up your project. 178 | 179 | 180 | ## Full Reference 181 | 182 | 183 | 184 | ### `Dockerfile` 185 | 186 | ```dockerfile 187 | FROM python:3.8.2-slim 188 | 189 | ENV APP_HOME /app 190 | WORKDIR ${APP_HOME} 191 | 192 | COPY . ./ 193 | 194 | RUN pip install pip pipenv --upgrade 195 | RUN pipenv install --skip-lock --system --dev 196 | 197 | CMD ["./scripts/entrypoint.sh"] 198 | ``` 199 | 200 | ### `Pipfile` 201 | ``` 202 | [[source]] 203 | name = "pypi" 204 | url = "https://pypi.org/simple" 205 | verify_ssl = true 206 | 207 | [dev-packages] 208 | 209 | [packages] 210 | jupyter = "*" 211 | 212 | [requires] 213 | python_version = "3.8" 214 | ``` 215 | 216 | ### `scripts/d_build.sh` 217 | ```bash 218 | docker build -t cfe-jupyter -f Dockerfile . 219 | ``` 220 | 221 | 222 | ### `scripts/d_run.sh` 223 | ```bash 224 | docker run --env PORT=8888 -it -p 8888:8888 cfe-jupyter 225 | ``` 226 | 227 | 228 | ### `scripts/deploy.sh` 229 | ```bash 230 | heroku container:push web 231 | heroku container:release web 232 | ``` 233 | 234 | 235 | ### `scripts/entrypoint.sh` 236 | 237 | ```bash 238 | #!/bin/bash 239 | 240 | /usr/local/bin/jupyter notebook --config=./conf/jupyter.py 241 | ``` 242 | 243 | 244 | ### `conf/jupyter.py` 245 | ```python 246 | import os 247 | c = get_config() 248 | # Kernel config 249 | c.IPKernelApp.pylab = 'inline' # if you want plotting support always in your notebook 250 | # Notebook config 251 | c.NotebookApp.notebook_dir = 'nbs' 252 | c.NotebookApp.allow_origin = u'cfe-jupyter.herokuapp.com' # put your public IP Address here 253 | c.NotebookApp.ip = '*' 254 | c.NotebookApp.allow_remote_access = True 255 | c.NotebookApp.open_browser = False 256 | # ipython -c "from notebook.auth import passwd; passwd()" 257 | c.NotebookApp.password = u'sha1:8da45965a489:86884d5b174e2f64e900edd129b5ef0d2f784a65' 258 | c.NotebookApp.port = int(os.environ.get("PORT", 8888)) 259 | c.NotebookApp.allow_root = True 260 | c.NotebookApp.allow_password_change = True 261 | c.ConfigurableHTTPProxy.command = ['configurable-http-proxy', '--redirect-port', '80'] 262 | ``` 263 | 264 | 265 | ### Create a notebook under -> `nbs/Load_Unload.ipynb` 266 | 267 | ```python 268 | mode = "unload" 269 | 270 | if mode == 'unload': 271 | # Zip all files in the current directory 272 | !tar chvfz notebook.tar.gz * 273 | 274 | elif mode == 'load: 275 | # Unzip all files in the current directory 276 | !!tar -xv -f notebook.tar.gz 277 | ``` 278 | 279 | 280 | ### Bonus Installs 281 | You might need additional packages (like `numpy` or `pandas` or `opencv`) in your project. Here's what you need to do in your `Dockerfile`, (on [our repo](https://github.com/codingforentrepreneurs/Jupyter-x-Docker-on-Heroku) the final docker file is listed as `Dockerfile.Bonus`) just update it to the following: 282 | 283 | ```dockerfile 284 | FROM python:3.8.2-slim 285 | 286 | ENV APP_HOME /app 287 | WORKDIR ${APP_HOME} 288 | 289 | COPY . ./ 290 | 291 | # Install Ubuntu dependencies 292 | # libopencv-dev = opencv dependencies 293 | RUN apt-get update && apt-get install -y --no-install-recommends \ 294 | tzdata \ 295 | libopencv-dev \ 296 | build-essential \ 297 | libssl-dev \ 298 | libpq-dev \ 299 | libcurl4-gnutls-dev \ 300 | libexpat1-dev \ 301 | gettext \ 302 | unzip \ 303 | supervisor \ 304 | python3-setuptools \ 305 | python3-pip \ 306 | python3-dev \ 307 | python3-venv \ 308 | python3-urllib3 \ 309 | git \ 310 | && \ 311 | apt-get clean && \ 312 | rm -rf /var/lib/apt/lists/* 313 | 314 | # Upgrade PIP 315 | RUN pip install pip pipenv --upgrade 316 | 317 | # sklearn opencv, numpy, and pandas 318 | RUN pip install scikit-learn opencv-contrib-python numpy pandas 319 | 320 | # tensorflow (including Keras) 321 | RUN pip install tensorflow keras 322 | 323 | # pytorch (cpu) 324 | RUN apt-get update && apt-get -y install gcc mono-mcs && rm -rf /var/lib/apt/lists/* 325 | RUN pip install torch==1.5.0+cpu torchvision==0.6.0+cpu -f https://download.pytorch.org/whl/torch_stable.html 326 | 327 | # fastai 328 | RUN pip install fastai 329 | 330 | # Project installs 331 | RUN pipenv install --skip-lock --system --dev 332 | 333 | 334 | CMD ["./scripts/entrypoint.sh"] 335 | ``` -------------------------------------------------------------------------------- /conf/jupyter.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | c = get_config() 4 | 5 | # Kernel config 6 | c.IPKernelApp.pylab = 'inline' # if you want plotting support always in your notebook 7 | 8 | # Notebook config 9 | c.NotebookApp.notebook_dir = 'nbs' 10 | c.NotebookApp.allow_origin = u'cfe-jupyter.herokuapp.com' # put your public IP Address here 11 | c.NotebookApp.ip = '*' 12 | c.NotebookApp.allow_remote_access = True 13 | c.NotebookApp.open_browser = False 14 | 15 | # ipython -c "from notebook.auth import passwd; passwd()" 16 | c.NotebookApp.password = u'sha1:8da45965a489:86884d5b174e2f64e900edd129b5ef0d2f784a65' 17 | c.NotebookApp.port = int(os.environ.get("PORT", 8888)) 18 | c.NotebookApp.allow_root = True 19 | c.NotebookApp.allow_password_change = True 20 | c.ConfigurableHTTPProxy.command = ['configurable-http-proxy', '--redirect-port', '80'] 21 | 22 | # Configuration file for jupyter-notebook. 23 | 24 | #------------------------------------------------------------------------------ 25 | # Application(SingletonConfigurable) configuration 26 | #------------------------------------------------------------------------------ 27 | 28 | ## This is an application. 29 | 30 | ## The date format used by logging formatters for %(asctime)s 31 | #c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' 32 | 33 | ## The Logging format template 34 | #c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' 35 | 36 | ## Set the log level by value or name. 37 | #c.Application.log_level = 30 38 | 39 | #------------------------------------------------------------------------------ 40 | # JupyterApp(Application) configuration 41 | #------------------------------------------------------------------------------ 42 | 43 | ## Base class for Jupyter applications 44 | 45 | ## Answer yes to any prompts. 46 | #c.JupyterApp.answer_yes = False 47 | 48 | ## Full path of a config file. 49 | #c.JupyterApp.config_file = '' 50 | 51 | ## Specify a config file to load. 52 | #c.JupyterApp.config_file_name = '' 53 | 54 | ## Generate default config file. 55 | #c.JupyterApp.generate_config = False 56 | 57 | #------------------------------------------------------------------------------ 58 | # NotebookApp(JupyterApp) configuration 59 | #------------------------------------------------------------------------------ 60 | 61 | ## Set the Access-Control-Allow-Credentials: true header 62 | #c.NotebookApp.allow_credentials = False 63 | 64 | ## Set the Access-Control-Allow-Origin header 65 | # 66 | # Use '*' to allow any origin to access your server. 67 | # 68 | # Takes precedence over allow_origin_pat. 69 | #c.NotebookApp.allow_origin = '' 70 | 71 | ## Use a regular expression for the Access-Control-Allow-Origin header 72 | # 73 | # Requests from an origin matching the expression will get replies with: 74 | # 75 | # Access-Control-Allow-Origin: origin 76 | # 77 | # where `origin` is the origin of the request. 78 | # 79 | # Ignored if allow_origin is set. 80 | #c.NotebookApp.allow_origin_pat = '' 81 | 82 | ## Allow password to be changed at login for the notebook server. 83 | # 84 | # While loggin in with a token, the notebook server UI will give the opportunity 85 | # to the user to enter a new password at the same time that will replace the 86 | # token login mechanism. 87 | # 88 | # This can be set to false to prevent changing password from the UI/API. 89 | #c.NotebookApp.allow_password_change = True 90 | 91 | ## Whether to allow the user to run the notebook as root. 92 | #c.NotebookApp.allow_root = False 93 | 94 | ## DEPRECATED use base_url 95 | #c.NotebookApp.base_project_url = '/' 96 | 97 | ## The base URL for the notebook server. 98 | # 99 | # Leading and trailing slashes can be omitted, and will automatically be added. 100 | #c.NotebookApp.base_url = '/' 101 | 102 | ## Specify what command to use to invoke a web browser when opening the notebook. 103 | # If not specified, the default browser will be determined by the `webbrowser` 104 | # standard library module, which allows setting of the BROWSER environment 105 | # variable to override it. 106 | #c.NotebookApp.browser = '' 107 | 108 | ## The full path to an SSL/TLS certificate file. 109 | #c.NotebookApp.certfile = '' 110 | 111 | ## The full path to a certificate authority certificate for SSL/TLS client 112 | # authentication. 113 | #c.NotebookApp.client_ca = '' 114 | 115 | ## The config manager class to use 116 | #c.NotebookApp.config_manager_class = 'notebook.services.config.manager.ConfigManager' 117 | 118 | ## The notebook manager class to use. 119 | #c.NotebookApp.contents_manager_class = 'notebook.services.contents.largefilemanager.LargeFileManager' 120 | 121 | ## Extra keyword arguments to pass to `set_secure_cookie`. See tornado's 122 | # set_secure_cookie docs for details. 123 | #c.NotebookApp.cookie_options = {} 124 | 125 | ## The random bytes used to secure cookies. By default this is a new random 126 | # number every time you start the Notebook. Set it to a value in a config file 127 | # to enable logins to persist across server sessions. 128 | # 129 | # Note: Cookie secrets should be kept private, do not share config files with 130 | # cookie_secret stored in plaintext (you can read the value from a file). 131 | #c.NotebookApp.cookie_secret = b'' 132 | 133 | ## The file where the cookie secret is stored. 134 | #c.NotebookApp.cookie_secret_file = '' 135 | 136 | ## The default URL to redirect to from `/` 137 | #c.NotebookApp.default_url = '/tree' 138 | 139 | ## Disable cross-site-request-forgery protection 140 | # 141 | # Jupyter notebook 4.3.1 introduces protection from cross-site request 142 | # forgeries, requiring API requests to either: 143 | # 144 | # - originate from pages served by this server (validated with XSRF cookie and 145 | # token), or - authenticate with a token 146 | # 147 | # Some anonymous compute resources still desire the ability to run code, 148 | # completely without authentication. These services can disable all 149 | # authentication and security checks, with the full knowledge of what that 150 | # implies. 151 | #c.NotebookApp.disable_check_xsrf = False 152 | 153 | ## Whether to enable MathJax for typesetting math/TeX 154 | # 155 | # MathJax is the javascript library Jupyter uses to render math/LaTeX. It is 156 | # very large, so you may want to disable it if you have a slow internet 157 | # connection, or for offline use of the notebook. 158 | # 159 | # When disabled, equations etc. will appear as their untransformed TeX source. 160 | #c.NotebookApp.enable_mathjax = True 161 | 162 | ## extra paths to look for Javascript notebook extensions 163 | #c.NotebookApp.extra_nbextensions_path = [] 164 | 165 | ## handlers that should be loaded at higher priority than the default services 166 | #c.NotebookApp.extra_services = [] 167 | 168 | ## Extra paths to search for serving static files. 169 | # 170 | # This allows adding javascript/css to be available from the notebook server 171 | # machine, or overriding individual files in the IPython 172 | #c.NotebookApp.extra_static_paths = [] 173 | 174 | ## Extra paths to search for serving jinja templates. 175 | # 176 | # Can be used to override templates from notebook.templates. 177 | #c.NotebookApp.extra_template_paths = [] 178 | 179 | ## 180 | #c.NotebookApp.file_to_run = '' 181 | 182 | ## Deprecated: Use minified JS file or not, mainly use during dev to avoid JS 183 | # recompilation 184 | #c.NotebookApp.ignore_minified_js = False 185 | 186 | ## (bytes/sec) Maximum rate at which stream output can be sent on iopub before 187 | # they are limited. 188 | #c.NotebookApp.iopub_data_rate_limit = 1000000 189 | 190 | ## (msgs/sec) Maximum rate at which messages can be sent on iopub before they are 191 | # limited. 192 | #c.NotebookApp.iopub_msg_rate_limit = 1000 193 | 194 | ## The IP address the notebook server will listen on. 195 | #c.NotebookApp.ip = 'localhost' 196 | 197 | ## Supply extra arguments that will be passed to Jinja environment. 198 | #c.NotebookApp.jinja_environment_options = {} 199 | 200 | ## Extra variables to supply to jinja templates when rendering. 201 | #c.NotebookApp.jinja_template_vars = {} 202 | 203 | ## The kernel manager class to use. 204 | #c.NotebookApp.kernel_manager_class = 'notebook.services.kernels.kernelmanager.MappingKernelManager' 205 | 206 | ## The kernel spec manager class to use. Should be a subclass of 207 | # `jupyter_client.kernelspec.KernelSpecManager`. 208 | # 209 | # The Api of KernelSpecManager is provisional and might change without warning 210 | # between this version of Jupyter and the next stable one. 211 | #c.NotebookApp.kernel_spec_manager_class = 'jupyter_client.kernelspec.KernelSpecManager' 212 | 213 | ## The full path to a private key file for usage with SSL/TLS. 214 | #c.NotebookApp.keyfile = '' 215 | 216 | ## The login handler class to use. 217 | #c.NotebookApp.login_handler_class = 'notebook.auth.login.LoginHandler' 218 | 219 | ## The logout handler class to use. 220 | #c.NotebookApp.logout_handler_class = 'notebook.auth.logout.LogoutHandler' 221 | 222 | ## The MathJax.js configuration file that is to be used. 223 | #c.NotebookApp.mathjax_config = 'TeX-AMS-MML_HTMLorMML-full,Safe' 224 | 225 | ## A custom url for MathJax.js. Should be in the form of a case-sensitive url to 226 | # MathJax, for example: /static/components/MathJax/MathJax.js 227 | #c.NotebookApp.mathjax_url = '' 228 | 229 | ## Dict of Python modules to load as notebook server extensions.Entry values can 230 | # be used to enable and disable the loading ofthe extensions. The extensions 231 | # will be loaded in alphabetical order. 232 | #c.NotebookApp.nbserver_extensions = {} 233 | 234 | ## The directory to use for notebooks and kernels. 235 | #c.NotebookApp.notebook_dir = '' 236 | 237 | ## Whether to open in a browser after starting. The specific browser used is 238 | # platform dependent and determined by the python standard library `webbrowser` 239 | # module, unless it is overridden using the --browser (NotebookApp.browser) 240 | # configuration option. 241 | #c.NotebookApp.open_browser = True 242 | 243 | ## Hashed password to use for web authentication. 244 | # 245 | # To generate, type in a python/IPython shell: 246 | # 247 | # from notebook.auth import passwd; passwd() 248 | # 249 | # The string should be of the form type:salt:hashed-password. 250 | #c.NotebookApp.password = '' 251 | 252 | ## Forces users to use a password for the Notebook server. This is useful in a 253 | # multi user environment, for instance when everybody in the LAN can access each 254 | # other's machine through ssh. 255 | # 256 | # In such a case, server the notebook server on localhost is not secure since 257 | # any user can connect to the notebook server via ssh. 258 | #c.NotebookApp.password_required = False 259 | 260 | ## The port the notebook server will listen on. 261 | #c.NotebookApp.port = 8888 262 | 263 | ## The number of additional ports to try if the specified port is not available. 264 | #c.NotebookApp.port_retries = 50 265 | 266 | ## DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib. 267 | #c.NotebookApp.pylab = 'disabled' 268 | 269 | ## (sec) Time window used to check the message and data rate limits. 270 | #c.NotebookApp.rate_limit_window = 3 271 | 272 | ## Reraise exceptions encountered loading server extensions? 273 | #c.NotebookApp.reraise_server_extension_failures = False 274 | 275 | ## DEPRECATED use the nbserver_extensions dict instead 276 | #c.NotebookApp.server_extensions = [] 277 | 278 | ## The session manager class to use. 279 | #c.NotebookApp.session_manager_class = 'notebook.services.sessions.sessionmanager.SessionManager' 280 | 281 | ## Shut down the server after N seconds with no kernels or terminals running and 282 | # no activity. This can be used together with culling idle kernels 283 | # (MappingKernelManager.cull_idle_timeout) to shutdown the notebook server when 284 | # it's not in use. This is not precisely timed: it may shut down up to a minute 285 | # later. 0 (the default) disables this automatic shutdown. 286 | #c.NotebookApp.shutdown_no_activity_timeout = 0 287 | 288 | ## Supply SSL options for the tornado HTTPServer. See the tornado docs for 289 | # details. 290 | #c.NotebookApp.ssl_options = {} 291 | 292 | ## Supply overrides for terminado. Currently only supports "shell_command". 293 | #c.NotebookApp.terminado_settings = {} 294 | 295 | ## Token used for authenticating first-time connections to the server. 296 | # 297 | # When no password is enabled, the default is to generate a new, random token. 298 | # 299 | # Setting to an empty string disables authentication altogether, which is NOT 300 | # RECOMMENDED. 301 | #c.NotebookApp.token = '' 302 | 303 | ## Supply overrides for the tornado.web.Application that the Jupyter notebook 304 | # uses. 305 | #c.NotebookApp.tornado_settings = {} 306 | 307 | ## Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded- 308 | # For headerssent by the upstream reverse proxy. Necessary if the proxy handles 309 | # SSL 310 | #c.NotebookApp.trust_xheaders = False 311 | 312 | ## DEPRECATED, use tornado_settings 313 | #c.NotebookApp.webapp_settings = {} 314 | 315 | ## Specify Where to open the notebook on startup. This is the 316 | # `new` argument passed to the standard library method `webbrowser.open`. 317 | # The behaviour is not guaranteed, but depends on browser support. Valid 318 | # values are: 319 | # 2 opens a new tab, 320 | # 1 opens a new window, 321 | # 0 opens in an existing window. 322 | # See the `webbrowser.open` documentation for details. 323 | #c.NotebookApp.webbrowser_open_new = 2 324 | 325 | ## Set the tornado compression options for websocket connections. 326 | # 327 | # This value will be returned from 328 | # :meth:`WebSocketHandler.get_compression_options`. None (default) will disable 329 | # compression. A dict (even an empty one) will enable compression. 330 | # 331 | # See the tornado docs for WebSocketHandler.get_compression_options for details. 332 | #c.NotebookApp.websocket_compression_options = None 333 | 334 | ## The base URL for websockets, if it differs from the HTTP server (hint: it 335 | # almost certainly doesn't). 336 | # 337 | # Should be in the form of an HTTP origin: ws[s]://hostname[:port] 338 | #c.NotebookApp.websocket_url = '' 339 | 340 | #------------------------------------------------------------------------------ 341 | # ConnectionFileMixin(LoggingConfigurable) configuration 342 | #------------------------------------------------------------------------------ 343 | 344 | ## Mixin for configurable classes that work with connection files 345 | 346 | ## JSON file in which to store connection info [default: kernel-.json] 347 | # 348 | # This file will contain the IP, ports, and authentication key needed to connect 349 | # clients to this kernel. By default, this file will be created in the security 350 | # dir of the current profile, but can be specified by absolute path. 351 | #c.ConnectionFileMixin.connection_file = '' 352 | 353 | ## set the control (ROUTER) port [default: random] 354 | #c.ConnectionFileMixin.control_port = 0 355 | 356 | ## set the heartbeat port [default: random] 357 | #c.ConnectionFileMixin.hb_port = 0 358 | 359 | ## set the iopub (PUB) port [default: random] 360 | #c.ConnectionFileMixin.iopub_port = 0 361 | 362 | ## Set the kernel's IP address [default localhost]. If the IP address is 363 | # something other than localhost, then Consoles on other machines will be able 364 | # to connect to the Kernel, so be careful! 365 | #c.ConnectionFileMixin.ip = '' 366 | 367 | ## set the shell (ROUTER) port [default: random] 368 | #c.ConnectionFileMixin.shell_port = 0 369 | 370 | ## set the stdin (ROUTER) port [default: random] 371 | #c.ConnectionFileMixin.stdin_port = 0 372 | 373 | ## 374 | #c.ConnectionFileMixin.transport = 'tcp' 375 | 376 | #------------------------------------------------------------------------------ 377 | # KernelManager(ConnectionFileMixin) configuration 378 | #------------------------------------------------------------------------------ 379 | 380 | ## Manages a single kernel in a subprocess on this host. 381 | # 382 | # This version starts kernels with Popen. 383 | 384 | ## Should we autorestart the kernel if it dies. 385 | #c.KernelManager.autorestart = True 386 | 387 | ## DEPRECATED: Use kernel_name instead. 388 | # 389 | # The Popen Command to launch the kernel. Override this if you have a custom 390 | # kernel. If kernel_cmd is specified in a configuration file, Jupyter does not 391 | # pass any arguments to the kernel, because it cannot make any assumptions about 392 | # the arguments that the kernel understands. In particular, this means that the 393 | # kernel does not receive the option --debug if it given on the Jupyter command 394 | # line. 395 | #c.KernelManager.kernel_cmd = [] 396 | 397 | ## Time to wait for a kernel to terminate before killing it, in seconds. 398 | #c.KernelManager.shutdown_wait_time = 5.0 399 | 400 | #------------------------------------------------------------------------------ 401 | # Session(Configurable) configuration 402 | #------------------------------------------------------------------------------ 403 | 404 | ## Object for handling serialization and sending of messages. 405 | # 406 | # The Session object handles building messages and sending them with ZMQ sockets 407 | # or ZMQStream objects. Objects can communicate with each other over the 408 | # network via Session objects, and only need to work with the dict-based IPython 409 | # message spec. The Session will handle serialization/deserialization, security, 410 | # and metadata. 411 | # 412 | # Sessions support configurable serialization via packer/unpacker traits, and 413 | # signing with HMAC digests via the key/keyfile traits. 414 | # 415 | # Parameters ---------- 416 | # 417 | # debug : bool 418 | # whether to trigger extra debugging statements 419 | # packer/unpacker : str : 'json', 'pickle' or import_string 420 | # importstrings for methods to serialize message parts. If just 421 | # 'json' or 'pickle', predefined JSON and pickle packers will be used. 422 | # Otherwise, the entire importstring must be used. 423 | # 424 | # The functions must accept at least valid JSON input, and output *bytes*. 425 | # 426 | # For example, to use msgpack: 427 | # packer = 'msgpack.packb', unpacker='msgpack.unpackb' 428 | # pack/unpack : callables 429 | # You can also set the pack/unpack callables for serialization directly. 430 | # session : bytes 431 | # the ID of this Session object. The default is to generate a new UUID. 432 | # username : unicode 433 | # username added to message headers. The default is to ask the OS. 434 | # key : bytes 435 | # The key used to initialize an HMAC signature. If unset, messages 436 | # will not be signed or checked. 437 | # keyfile : filepath 438 | # The file containing a key. If this is set, `key` will be initialized 439 | # to the contents of the file. 440 | 441 | ## Threshold (in bytes) beyond which an object's buffer should be extracted to 442 | # avoid pickling. 443 | #c.Session.buffer_threshold = 1024 444 | 445 | ## Whether to check PID to protect against calls after fork. 446 | # 447 | # This check can be disabled if fork-safety is handled elsewhere. 448 | #c.Session.check_pid = True 449 | 450 | ## Threshold (in bytes) beyond which a buffer should be sent without copying. 451 | #c.Session.copy_threshold = 65536 452 | 453 | ## Debug output in the Session 454 | #c.Session.debug = False 455 | 456 | ## The maximum number of digests to remember. 457 | # 458 | # The digest history will be culled when it exceeds this value. 459 | #c.Session.digest_history_size = 65536 460 | 461 | ## The maximum number of items for a container to be introspected for custom 462 | # serialization. Containers larger than this are pickled outright. 463 | #c.Session.item_threshold = 64 464 | 465 | ## execution key, for signing messages. 466 | #c.Session.key = b'' 467 | 468 | ## path to file containing execution key. 469 | #c.Session.keyfile = '' 470 | 471 | ## Metadata dictionary, which serves as the default top-level metadata dict for 472 | # each message. 473 | #c.Session.metadata = {} 474 | 475 | ## The name of the packer for serializing messages. Should be one of 'json', 476 | # 'pickle', or an import name for a custom callable serializer. 477 | #c.Session.packer = 'json' 478 | 479 | ## The UUID identifying this session. 480 | #c.Session.session = '' 481 | 482 | ## The digest scheme used to construct the message signatures. Must have the form 483 | # 'hmac-HASH'. 484 | #c.Session.signature_scheme = 'hmac-sha256' 485 | 486 | ## The name of the unpacker for unserializing messages. Only used with custom 487 | # functions for `packer`. 488 | #c.Session.unpacker = 'json' 489 | 490 | ## Username for the Session. Default is your system username. 491 | #c.Session.username = 'jmitch' 492 | 493 | #------------------------------------------------------------------------------ 494 | # MultiKernelManager(LoggingConfigurable) configuration 495 | #------------------------------------------------------------------------------ 496 | 497 | ## A class for managing multiple kernels. 498 | 499 | ## The name of the default kernel to start 500 | #c.MultiKernelManager.default_kernel_name = 'python3' 501 | 502 | ## The kernel manager class. This is configurable to allow subclassing of the 503 | # KernelManager for customized behavior. 504 | #c.MultiKernelManager.kernel_manager_class = 'jupyter_client.ioloop.IOLoopKernelManager' 505 | 506 | #------------------------------------------------------------------------------ 507 | # MappingKernelManager(MultiKernelManager) configuration 508 | #------------------------------------------------------------------------------ 509 | 510 | ## A KernelManager that handles notebook mapping and HTTP error handling 511 | 512 | ## Whether messages from kernels whose frontends have disconnected should be 513 | # buffered in-memory. 514 | # 515 | # When True (default), messages are buffered and replayed on reconnect, avoiding 516 | # lost messages due to interrupted connectivity. 517 | # 518 | # Disable if long-running kernels will produce too much output while no 519 | # frontends are connected. 520 | #c.MappingKernelManager.buffer_offline_messages = True 521 | 522 | ## Whether to consider culling kernels which are busy. Only effective if 523 | # cull_idle_timeout > 0. 524 | #c.MappingKernelManager.cull_busy = False 525 | 526 | ## Whether to consider culling kernels which have one or more connections. Only 527 | # effective if cull_idle_timeout > 0. 528 | #c.MappingKernelManager.cull_connected = False 529 | 530 | ## Timeout (in seconds) after which a kernel is considered idle and ready to be 531 | # culled. Values of 0 or lower disable culling. Very short timeouts may result 532 | # in kernels being culled for users with poor network connections. 533 | #c.MappingKernelManager.cull_idle_timeout = 0 534 | 535 | ## The interval (in seconds) on which to check for idle kernels exceeding the 536 | # cull timeout value. 537 | #c.MappingKernelManager.cull_interval = 300 538 | 539 | ## 540 | #c.MappingKernelManager.root_dir = '' 541 | 542 | #------------------------------------------------------------------------------ 543 | # ContentsManager(LoggingConfigurable) configuration 544 | #------------------------------------------------------------------------------ 545 | 546 | ## Base class for serving files and directories. 547 | # 548 | # This serves any text or binary file, as well as directories, with special 549 | # handling for JSON notebook documents. 550 | # 551 | # Most APIs take a path argument, which is always an API-style unicode path, and 552 | # always refers to a directory. 553 | # 554 | # - unicode, not url-escaped 555 | # - '/'-separated 556 | # - leading and trailing '/' will be stripped 557 | # - if unspecified, path defaults to '', 558 | # indicating the root path. 559 | 560 | ## Allow access to hidden files 561 | #c.ContentsManager.allow_hidden = False 562 | 563 | ## 564 | #c.ContentsManager.checkpoints = None 565 | 566 | ## 567 | #c.ContentsManager.checkpoints_class = 'notebook.services.contents.checkpoints.Checkpoints' 568 | 569 | ## 570 | #c.ContentsManager.checkpoints_kwargs = {} 571 | 572 | ## handler class to use when serving raw file requests. 573 | # 574 | # Default is a fallback that talks to the ContentsManager API, which may be 575 | # inefficient, especially for large files. 576 | # 577 | # Local files-based ContentsManagers can use a StaticFileHandler subclass, which 578 | # will be much more efficient. 579 | # 580 | # Access to these files should be Authenticated. 581 | #c.ContentsManager.files_handler_class = 'notebook.files.handlers.FilesHandler' 582 | 583 | ## Extra parameters to pass to files_handler_class. 584 | # 585 | # For example, StaticFileHandlers generally expect a `path` argument specifying 586 | # the root directory from which to serve files. 587 | #c.ContentsManager.files_handler_params = {} 588 | 589 | ## Glob patterns to hide in file and directory listings. 590 | #c.ContentsManager.hide_globs = ['__pycache__', '*.pyc', '*.pyo', '.DS_Store', '*.so', '*.dylib', '*~'] 591 | 592 | ## Python callable or importstring thereof 593 | # 594 | # To be called on a contents model prior to save. 595 | # 596 | # This can be used to process the structure, such as removing notebook outputs 597 | # or other side effects that should not be saved. 598 | # 599 | # It will be called as (all arguments passed by keyword):: 600 | # 601 | # hook(path=path, model=model, contents_manager=self) 602 | # 603 | # - model: the model to be saved. Includes file contents. 604 | # Modifying this dict will affect the file that is stored. 605 | # - path: the API path of the save destination 606 | # - contents_manager: this ContentsManager instance 607 | #c.ContentsManager.pre_save_hook = None 608 | 609 | ## 610 | #c.ContentsManager.root_dir = '/' 611 | 612 | ## The base name used when creating untitled directories. 613 | #c.ContentsManager.untitled_directory = 'Untitled Folder' 614 | 615 | ## The base name used when creating untitled files. 616 | #c.ContentsManager.untitled_file = 'untitled' 617 | 618 | ## The base name used when creating untitled notebooks. 619 | #c.ContentsManager.untitled_notebook = 'Untitled' 620 | 621 | #------------------------------------------------------------------------------ 622 | # FileManagerMixin(Configurable) configuration 623 | #------------------------------------------------------------------------------ 624 | 625 | ## Mixin for ContentsAPI classes that interact with the filesystem. 626 | # 627 | # Provides facilities for reading, writing, and copying both notebooks and 628 | # generic files. 629 | # 630 | # Shared by FileContentsManager and FileCheckpoints. 631 | # 632 | # Note ---- Classes using this mixin must provide the following attributes: 633 | # 634 | # root_dir : unicode 635 | # A directory against against which API-style paths are to be resolved. 636 | # 637 | # log : logging.Logger 638 | 639 | ## By default notebooks are saved on disk on a temporary file and then if 640 | # succefully written, it replaces the old ones. This procedure, namely 641 | # 'atomic_writing', causes some bugs on file system whitout operation order 642 | # enforcement (like some networked fs). If set to False, the new notebook is 643 | # written directly on the old one which could fail (eg: full filesystem or quota 644 | # ) 645 | #c.FileManagerMixin.use_atomic_writing = True 646 | 647 | #------------------------------------------------------------------------------ 648 | # FileContentsManager(FileManagerMixin,ContentsManager) configuration 649 | #------------------------------------------------------------------------------ 650 | 651 | ## If True (default), deleting files will send them to the platform's 652 | # trash/recycle bin, where they can be recovered. If False, deleting files 653 | # really deletes them. 654 | #c.FileContentsManager.delete_to_trash = True 655 | 656 | ## Python callable or importstring thereof 657 | # 658 | # to be called on the path of a file just saved. 659 | # 660 | # This can be used to process the file on disk, such as converting the notebook 661 | # to a script or HTML via nbconvert. 662 | # 663 | # It will be called as (all arguments passed by keyword):: 664 | # 665 | # hook(os_path=os_path, model=model, contents_manager=instance) 666 | # 667 | # - path: the filesystem path to the file just written - model: the model 668 | # representing the file - contents_manager: this ContentsManager instance 669 | #c.FileContentsManager.post_save_hook = None 670 | 671 | ## 672 | #c.FileContentsManager.root_dir = '' 673 | 674 | ## DEPRECATED, use post_save_hook. Will be removed in Notebook 5.0 675 | #c.FileContentsManager.save_script = False 676 | 677 | #------------------------------------------------------------------------------ 678 | # NotebookNotary(LoggingConfigurable) configuration 679 | #------------------------------------------------------------------------------ 680 | 681 | ## A class for computing and verifying notebook signatures. 682 | 683 | ## The hashing algorithm used to sign notebooks. 684 | #c.NotebookNotary.algorithm = 'sha256' 685 | 686 | ## The sqlite file in which to store notebook signatures. By default, this will 687 | # be in your Jupyter data directory. You can set it to ':memory:' to disable 688 | # sqlite writing to the filesystem. 689 | #c.NotebookNotary.db_file = '' 690 | 691 | ## The secret key with which notebooks are signed. 692 | #c.NotebookNotary.secret = b'' 693 | 694 | ## The file where the secret key is stored. 695 | #c.NotebookNotary.secret_file = '' 696 | 697 | ## A callable returning the storage backend for notebook signatures. The default 698 | # uses an SQLite database. 699 | #c.NotebookNotary.store_factory = traitlets.Undefined 700 | 701 | #------------------------------------------------------------------------------ 702 | # KernelSpecManager(LoggingConfigurable) configuration 703 | #------------------------------------------------------------------------------ 704 | 705 | ## If there is no Python kernelspec registered and the IPython kernel is 706 | # available, ensure it is added to the spec list. 707 | #c.KernelSpecManager.ensure_native_kernel = True 708 | 709 | ## The kernel spec class. This is configurable to allow subclassing of the 710 | # KernelSpecManager for customized behavior. 711 | #c.KernelSpecManager.kernel_spec_class = 'jupyter_client.kernelspec.KernelSpec' 712 | 713 | ## Whitelist of allowed kernel names. 714 | # 715 | # By default, all installed kernels are allowed. 716 | #c.KernelSpecManager.whitelist = set() 717 | 718 | 719 | # For https & letsencrypt later 720 | # c.NotebookApp.certfile = u'/your/cert/path/cert.pem' 721 | # c.NotebookApp.keyfile = u'/your/cert/path/privkey.pem' -------------------------------------------------------------------------------- /nbs/Load_Unload.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "Load_Unload.ipynb\r\n", 13 | "notebook.tar.gz\r\n" 14 | ] 15 | } 16 | ], 17 | "source": [ 18 | "mode = \"unload\"\n", 19 | "\n", 20 | "if mode == 'unload':\n", 21 | " # Zip all files in the current directory\n", 22 | " !tar chvfz notebook.tar.gz *\n", 23 | "elif mode == 'load':\n", 24 | " # Unzip all files in the current directory\n", 25 | " !tar -xv -f notebook.tar.gz" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 5, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "name": "stdout", 35 | "output_type": "stream", 36 | "text": [ 37 | "/bin/sh: 1: open: not found\r\n" 38 | ] 39 | } 40 | ], 41 | "source": [ 42 | "!open notebook.tar.gz" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [] 51 | } 52 | ], 53 | "metadata": { 54 | "kernelspec": { 55 | "display_name": "Python 3", 56 | "language": "python", 57 | "name": "python3" 58 | }, 59 | "language_info": { 60 | "codemirror_mode": { 61 | "name": "ipython", 62 | "version": 3 63 | }, 64 | "file_extension": ".py", 65 | "mimetype": "text/x-python", 66 | "name": "python", 67 | "nbconvert_exporter": "python", 68 | "pygments_lexer": "ipython3", 69 | "version": "3.8.2" 70 | } 71 | }, 72 | "nbformat": 4, 73 | "nbformat_minor": 4 74 | } 75 | -------------------------------------------------------------------------------- /nbs/notebook.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Jupyter-x-Docker-on-Heroku/f5f1eea0d18d17c89e494ebc292e3632e0366c0c/nbs/notebook.tar.gz -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | gcloud builds submit \ 2 | --tag gcr.io/codingforentrepreneurs/cfe-jupyter \ 3 | /Users/jmitch/Dev/cfe-jupyter/ \ 4 | --project codingforentrepreneurs -------------------------------------------------------------------------------- /scripts/d_build.sh: -------------------------------------------------------------------------------- 1 | docker build -t cfe-jupyter -f Dockerfile . -------------------------------------------------------------------------------- /scripts/d_build_and_run.sh: -------------------------------------------------------------------------------- 1 | docker build -t cfe-jupyter -f Dockerfile . 2 | 3 | docker run --env PORT=8888 -it -p 8888:8888 cfe-jupyter 4 | -------------------------------------------------------------------------------- /scripts/d_run.sh: -------------------------------------------------------------------------------- 1 | docker run --env PORT=8888 -it -p 8888:8888 cfe-jupyter 2 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | heroku container:push web 2 | heroku container:release web -------------------------------------------------------------------------------- /scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /usr/local/bin/jupyter notebook --config=./conf/jupyter.py --------------------------------------------------------------------------------