Github: https://github.com/blazingraptor/exercise-python-application.git
Docker Hub: https://hub.docker.com/repository/docker/blazingraptor/exercise-python-application/general
1. Clone it
blazingraptor@galactica:~/git$ git clone https://github.com/blazingraptor/exercise-python-application.git Cloning into 'exercise-python-application'... remote: Enumerating objects: 3, done. remote: Counting objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (3/3), done.
2a. Create virtual enviornment
blazingraptor@galactica:~/git/exercise-python-application$ python3 -m venv ~/git/exercise-python-application/venv The virtual environment was not created successfully because ensurepip is not available. On Debian/Ubuntu systems, you need to install the python3-venv package using the following command. apt install python3.10-venv You may need to use sudo with that command. After installing the python3-venv package, recreate your virtual environment. Failing command: /home/blazingraptor/git/exercise-python-application/venv/bin/python3
2b. Install it
blazingraptor@galactica:~/git/exercise-python-application$ su - (truncated output) root@galactica:~# apt install python3.10-venv (truncated output)
2c. Re-try Create virtual enviornment
blazingraptor@galactica:~/git/exercise-python-application$ python3 -m venv ~/git/exercise-python-application/venv
2d. Install Flask
blazingraptor@galactica:~/git/exercise-python-application$ pip3 install flask Defaulting to user installation because normal site-packages is not writeable Collecting flask Downloading flask-3.1.0-py3-none-any.whl (102 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 103.0/103.0 KB 2.3 MB/s eta 0:00:00 Collecting Jinja2>=3.1.2 Downloading jinja2-3.1.5-py3-none-any.whl (134 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.6/134.6 KB 9.1 MB/s eta 0:00:00 Collecting blinker>=1.9 Downloading blinker-1.9.0-py3-none-any.whl (8.5 kB) Collecting itsdangerous>=2.2 Downloading itsdangerous-2.2.0-py3-none-any.whl (16 kB) Collecting click>=8.1.3 Downloading click-8.1.8-py3-none-any.whl (98 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 98.2/98.2 KB 14.3 MB/s eta 0:00:00 Collecting Werkzeug>=3.1 Downloading werkzeug-3.1.3-py3-none-any.whl (224 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 224.5/224.5 KB 13.8 MB/s eta 0:00:00 Collecting MarkupSafe>=2.0 Downloading MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (20 kB) Installing collected packages: MarkupSafe, itsdangerous, click, blinker, Werkzeug, Jinja2, flask WARNING: The script flask is installed in '/home/blazingraptor/.local/bin' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. Successfully installed Jinja2-3.1.5 MarkupSafe-3.0.2 Werkzeug-3.1.3 blinker-1.9.0 click-8.1.8 flask-3.1.0 itsdangerous-2.2.0
2e. Run your application
blazingraptor@galactica:~/git/exercise-python-application$ python3 app.py * Serving Flask app 'app' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5001 * Running on http://172.28.218.96:5001 Press CTRL+C to quit
2f. Test it locally
It's a Flask application running on POD!
3a. Create Dockerfile
blazingraptor@galactica:~/git/exercise-python-application$ docker init Welcome to the Docker Init CLI! This utility will walk you through creating the following files with sensible defaults for your project: - .dockerignore - Dockerfile - compose.yaml - README.Docker.md Let's get started! ? What application platform does your project use? Python ? What version of Python do you want to use? 3.10.12 ? What is the command you use to run your app? app.run(host='0.0.0.0', port=5001, debug=false) ✔ Created → .dockerignore ✔ Created → Dockerfile ✔ Created → compose.yaml ✔ Created → README.Docker.md → Your Docker files are ready! Review your Docker files and tailor them to your application. Consult README.Docker.md for information about using the generated files. ! Warning → No requirements.txt file found. Create one with the dependencies for your application before running it. What's next? Start your application by running → docker compose up --build Your application will be available at http://localhost:5001
3b. Docker compose
blazingraptor@galactica:~/git/exercise-python-application$ docker compose up --build [+] Building 3.9s (11/12) docker:default => [server internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 1.69kB 0.0s => [server] resolve image config for docker-image://docker.io/docker/dockerfile:1 1.2s => [server] docker-image://docker.io/docker/dockerfile:1@sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e 1.0s => => resolve docker.io/docker/dockerfile:1@sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d80 0.0s => => sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d801e66d25 8.40kB / 8.40kB 0.0s => => sha256:6427b0634e7650a14afc322b71a37b4654b4471539d1f9a19cb16525a2fb2e56 850B / 850B 0.0s => => sha256:6e15488ac914a453a6e13f419cde418c67927d93d6b0a0f23b5c70c8ecda3fc6 1.26kB / 1.26kB 0.0s => => sha256:8a2af9a64344571e7f712dde5e52bb25729d3ea0f3208ec86dd5af836b4ef1b9 12.78MB / 12.78MB 0.8s => => extracting sha256:8a2af9a64344571e7f712dde5e52bb25729d3ea0f3208ec86dd5af836b4ef1b9 0.2s => [server internal] load build definition from Dockerfile 0.0s => WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match (line 10) 0.0s => [server internal] load metadata for docker.io/library/python:3.10.12-slim 1.0s => [server internal] load .dockerignore 0.0s => => transferring context: 671B 0.0s => CANCELED [server base 1/5] FROM docker.io/library/python:3.10.12-slim@sha256:4d440b214e447deddc0a94de23a3 0.2s => => resolve docker.io/library/python:3.10.12-slim@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb 0.0s => => sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 1.65kB / 1.65kB 0.0s => => sha256:13cc673c11ee90d6ba92d95f35f4d8e59148937f1e3b4044788e93268bfe9d2e 1.37kB / 1.37kB 0.0s => => sha256:f31204aad67273a64cc5b0e64e2a613ded5d817d9094b02d37db6fd522933b16 6.92kB / 6.92kB 0.0s => => sha256:52d2b7f179e32b4cbd579ee3c4958027988f9a8274850ab0c7c24661e3adaac5 0B / 29.12MB 0.2s => => sha256:2b8a9a2240c1224b34f6aafbc3310f9a3fe65bd6893050906d02e89fc8326aa9 0B / 3.50MB 0.2s => => sha256:618a49bbc6c68a58b082ceb072a9464370d0203a55c70e9cfc16caf6c3c8f383 0B / 17.43MB 0.2s => [server internal] load build context 0.2s => => transferring context: 9.31MB 0.2s => CACHED [server base 2/5] WORKDIR /app 0.0s => CACHED [server base 3/5] RUN adduser --disabled-password --gecos "" --home "/nonexistent" 0.0s => ERROR [server base 4/5] RUN --mount=type=cache,target=/root/.cache/pip --mount=type=bind,source=requi 0.0s ------ > [server base 4/5] RUN --mount=type=cache,target=/root/.cache/pip --mount=type=bind,source=requirements.txt,target=requirements.txt python -m pip install -r requirements.txt: ------ failed to solve: failed to compute cache key: failed to calculate checksum of ref 63f6572d-a101-41fc-915a-3e508325c64c::rztvyqa9p4l5me5aetep5reu9: "/requirements.txt": not found
3c. Fix it
https://www.freecodecamp.org/news/python-requirementstxt-explained/
blazingraptor@galactica:~/git/exercise-python-application$ pip3 freeze > requirements.txt blazingraptor@galactica:~/git/exercise-python-application$ less requirements.txt blazingraptor@galactica:~/git/exercise-python-application$ cat requirements.txt blinker==1.9.0 click==8.1.8 command-not-found==0.3 configobj==5.0.6 cryptography==3.4.8 dbus-python==1.2.18 distro==1.7.0 distro-info==1.1+ubuntu0.2 Flask==3.1.0 httplib2==0.20.2 importlib-metadata==4.6.4 itsdangerous==2.2.0 jeepney==0.7.1 Jinja2==3.1.5 keyring==23.5.0 launchpadlib==1.10.16 lazr.restfulclient==0.14.4 lazr.uri==1.0.6 MarkupSafe==3.0.2 more-itertools==8.10.0 netifaces==0.11.0 oauthlib==3.2.0 psutil==5.9.0 pycairo==1.20.1 PyGObject==3.42.1 PyJWT==2.3.0 pyparsing==2.4.7 python-apt==2.4.0+ubuntu3 PyYAML==5.4.1 SecretStorage==3.3.1 six==1.16.0 ssh-import-id==5.11 systemd-python==234 terminator==2.1.1 ubuntu-pro-client==8001 ufw==0.36.1 unattended-upgrades==0.1 wadllib==1.3.6 Werkzeug==3.1.3 zipp==1.0.0
still doesn't work
3d. Fix it again
blazingraptor@galactica:~/git/exercise-python-application$ cp -a requirements.txt requirements.old blazingraptor@galactica:~/git/exercise-python-application$ vim requirements.txt blazingraptor@galactica:~/git/exercise-python-application$ cat requirements.txt Flask==3.1.0 blazingraptor@galactica:~/git/exercise-python-application$ tail -1 Dockerfile CMD app.run(host='0.0.0.0', port=5001, debug=false) blazingraptor@galactica:~/git/exercise-python-application$ cp -a Dockerfile Dockerfile.old blazingraptor@galactica:~/git/exercise-python-application$ vim Dockerfile blazingraptor@galactica:~/git/exercise-python-application$ tail -1 Dockerfile CMD python3 app.py
3e. Run it again
blazingraptor@galactica:~/git/exercise-python-application$ docker compose up --build [+] Building 1.4s (14/14) FINISHED docker:default => [server internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 1.66kB 0.0s => [server] resolve image config for docker-image://docker.io/docker/dockerfile:1 0.6s => CACHED [server] docker-image://docker.io/docker/dockerfile:1@sha256:93bfd3b68c109427185cd78b4779fc82b484b 0.0s => [server internal] load build definition from Dockerfile 0.0s => WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match (line 10) 0.0s => [server internal] load metadata for docker.io/library/python:3.10.12-slim 0.4s => [server internal] load .dockerignore 0.0s => => transferring context: 671B 0.0s => [server base 1/5] FROM docker.io/library/python:3.10.12-slim@sha256:4d440b214e447deddc0a94de23a3d97d28dfa 0.0s => [server internal] load build context 0.1s => => transferring context: 66.09kB 0.1s => CACHED [server base 2/5] WORKDIR /app 0.0s => CACHED [server base 3/5] RUN adduser --disabled-password --gecos "" --home "/nonexistent" 0.0s => CACHED [server base 4/5] RUN --mount=type=cache,target=/root/.cache/pip --mount=type=bind,source=requ 0.0s => CACHED [server base 5/5] COPY . . 0.0s => [server] exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:30a944cf3e205b5fe271e2bdc6f3b223f788035daaecfd2108bfaa75be2837f4 0.0s => => naming to docker.io/library/exercise-python-application-server 0.0s => [server] resolving provenance for metadata file 0.0s [+] Running 1/0 ✔ Container exercise-python-application-server-1 Created 0.0s Attaching to server-1 server-1 | * Serving Flask app 'app' server-1 | * Debug mode: off server-1 | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. server-1 | * Running on all addresses (0.0.0.0) server-1 | * Running on http://127.0.0.1:5001 server-1 | * Running on http://172.18.0.2:5001 server-1 | Press CTRL+C to quit server-1 | 172.18.0.1 - - [12/Feb/2025 21:02:45] "GET / HTTP/1.1" 200 - server-1 | 172.18.0.1 - - [12/Feb/2025 21:02:45] "GET /favicon.ico HTTP/1.1" 404 - server-1 | 172.18.0.1 - - [12/Feb/2025 21:03:08] "GET / HTTP/1.1" 200 - server-1 | 172.18.0.1 - - [12/Feb/2025 21:03:08] "GET /favicon.ico HTTP/1.1" 404 - v View in Docker Desktop o View Config w Enable Watch
3f. View it in a local browser
Works
Remotely
http://galactica.starlabs.us:5001/
Works
Ctrl+C shutdown the app
Gracefully stopping... (press Ctrl+C again to force) [+] Stopping 1/1 ✔ Container exercise-python-application-server-1 Stopped
Build an image
blazingraptor@galactica:~/git/exercise-python-application$ docker build -t blazingraptor/exercise-python-application:1.0 . [+] Building 0.8s (13/13) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 1.66kB 0.0s => resolve image config for docker-image://docker.io/docker/dockerfile:1 0.4s => CACHED docker-image://docker.io/docker/dockerfile:1@sha256:93bfd3b68c109427185cd78 0.0s => [internal] load build definition from Dockerfile 0.0s => [internal] load metadata for docker.io/library/python:3.10.12-slim 0.2s => [internal] load .dockerignore 0.0s => => transferring context: 671B 0.0s => [base 1/5] FROM docker.io/library/python:3.10.12-slim@sha256:4d440b214e447deddc0a9 0.0s => [internal] load build context 0.1s => => transferring context: 66.19kB 0.0s => CACHED [base 2/5] WORKDIR /app 0.0s => CACHED [base 3/5] RUN adduser --disabled-password --gecos "" --home "/ 0.0s => CACHED [base 4/5] RUN --mount=type=cache,target=/root/.cache/pip --mount=type= 0.0s => CACHED [base 5/5] COPY . . 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:066a6668105c866659f52693269e5d58b26723b4a9192e77e9248e2c67 0.0s => => naming to docker.io/blazingraptor/exercise-python-application:1.0 0.0s 1 warning found (use docker --debug to expand): - JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 51)
Fix git
Make a key
ssh-keygen -t rsa -b 4096 -C "test@example.com"
It generates 2 new keys
github-blazingraptor github-blazingraptor.pub
Move them to
~/.ssh/
Authorize them
blazingraptor@galactica:~/git/exercise-python-application$ cat ~/.ssh/config Host github.com IdentityFile ~/.ssh/github-blazingraptor AddKeysToAgent yes
Test your connection
blazingraptor@galactica:~/git/exercise-python-application$ ssh -T git@github.com Hi blazingraptor! You've successfully authenticated, but GitHub does not provide shell access.
Push to git
git commit -m "new stuff" git config --global user.email "test@example.com" git config --global user.name "Test User" git commit -m "new stuff" git push origin main
Update code - Push to git
blazingraptor@galactica:~/git/exercise-python-application$ git commit -m "update change" On branch main Your branch is up to date with 'origin/main'. Changes not staged for commit: (use "git add..." to update what will be committed) (use "git restore ..." to discard changes in working directory) modified: Dockerfile modified: k8s/deployment.yml modified: k8s/service.yml no changes added to commit (use "git add" and/or "git commit -a")
Add it properly
blazingraptor@galactica:~/git/exercise-python-application$ git commit -m "update change" On branch main Your branch is up to date with 'origin/main'. Changes not staged for commit: (use "git add..." to update what will be committed) (use "git restore ..." to discard changes in working directory) modified: Dockerfile modified: k8s/deployment.yml modified: k8s/service.yml no changes added to commit (use "git add" and/or "git commit -a") blazingraptor@galactica:~/git/exercise-python-application$ git add Dockerfile blazingraptor@galactica:~/git/exercise-python-application$ git add k8s/deployment.yml blazingraptor@galactica:~/git/exercise-python-application$ git add k8s/service.yml blazingraptor@galactica:~/git/exercise-python-application$ git commit -m "update change"
Push the image
blazingraptor@galactica:~$ docker push blazingraptor/exercise-python-application:1.0 The push refers to repository [docker.io/blazingraptor/exercise-python-application] a6f30f13c95b: Pushed 0bd28b033959: Pushed 5b50daaf37d9: Pushed ffa224b85f68: Pushed 54512d0df01f: Mounted from library/python 43574d3b4af9: Mounted from library/python 1b9e3cebd93c: Mounted from library/python 5b60283f3630: Mounted from library/python 511780f88f80: Mounted from library/python 1.0: digest: sha256:ff3360982c4e0097d6285a56127d4f2c1b44aa4fb3aab9f238f4198299f72b16 size: 2206