This Git repository serves two purposes:
- Backup of my resume for development and rapid deployment
- Showcasing a few skills while I'm at it:
- Docker
- docker-compose
- kubernetes (and sidecars)
- CI testing
- Github Actons
- Makefile (m4 macro language)
- Build/Publish Scripting
- K8s Volumes
- Python3
- Flask Web Framework
- BASH
- Jinja2
- Pandoc
- HTML5, Jquery, CSS, and Bootstrap
- Class singleton concept
- Making Great Documentation
- Resume - Jonathan D Kelley - jon-kelley.com
This repository is a showcase around docker, kubernetes, python, flask, markdown, json, REST and sidecars to make a very simple app serve my resume. From Makefile
to production you can see how I've deployed my website. The Flask app I wrote is the centerpiece here, but the glue makes it portable and easy to deploy anywhere. My flask app permits being updated from the resume.json
in this repository after it's been built to make dynamic updates post-deployment easier.
See this code live on my website Jon-Kelley.com 100% powered by Kubernetes!
Having a resume for years in Markdown as data format and converting to PDF/DOCX etc using Pandoc got old and tiring. Portability and maintainability has long been a dream so that resume management isn't a drain.
Now I store all my experience in a JSON file and just let code handle the rest. We can dockerize anything, why not a resume? Now I update resume.json
and with eventual consistency, and all things resume align like stars in the sky⭐.
A simplified component diagram of this architecture is below which should give you a simplified idea of how the codebase works, even if you're not technical.
I've provided behavior-driven tests using pydoc. To invoke tests, you can run
pip3 install -r requirements-test.txt
make test
This is how I prefer to develop my Docker projects.
If you have docker-compose installed, you can simply run
docker-compose build
docker-compose up
or, more simply
make run
Then open 127.0.0.1:5001.
This secret is used to do dynamic updates to resume.json while the application is running.
kubectl create secret generic secret-jonk-resume-app --from-literal=resume-update-secret=changeme
kubectl apply -f https://raw.githubusercontent.com/jondkelley/python_resume/master/deployments/baremetal/resources.yaml
This secret is used to do dynamic updates to resume.json while the application is running.
kubectl create secret generic secret-jonk-resume-app --from-literal=resume-update-secret=changeme
kubectl apply -f https://raw.githubusercontent.com/jondkelley/python_resume/master/deployments/minikube/resources.yaml
kubectl expose deployment jonk-resume-app --type=NodePort
minikube service jonk-resume-app --url
You'll see output similar to
🏃 Starting tunnel for service jonk-resume-app.
|-----------|-----------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-----------------|-------------|------------------------|
| default | jonk-resume-app | | http://127.0.0.1:12345 |
|-----------|-----------------|-------------|------------------------|
You can visit http://127.0.0.1:12345 to use the application.
Always an option, but the pandoc container won't work with this, so the hard-copy resume links will throw errors.
git clone https://github.com/jondkelley/python_resume.git
cd python_resume
virtualenv venv
source venv/bin/activate
python3 setup.py install
myresume &
Then open 127.0.0.1:5001.
Quickly make and publish artifacts to dockerhub.
make build
make push
- 2021 Jonathan Kelley
This Resume was inspired by an interactive dynamic resume created by web designer Pascal Van Gemert (Github).
I ported his PHP / bootstrap framework over to Python / Flask / Jinja2, with my own inspiration along the way. Then I Dockerized my project and made it work on my bare metal kubernetes cluster using emptyDir volumes and MetalLB for load balancing. Docker-compose is available for local development and running the unit tests.
The container is built using a sidecar running pandoc in a bash loop, and uses the emptyDir volume to make various rendered resume formats (every 10 seconds) available to the Flask webserver.