108 lines
3.7 KiB
Markdown
108 lines
3.7 KiB
Markdown
# Notes App — Docker Assignment
|
|
|
|
## What the application does
|
|
|
|
A simple **Notes** web application where users can create, view, and delete short text notes. Notes are stored persistently in a PostgreSQL database. The app is accessible via a web browser.
|
|
|
|
## Services
|
|
|
|
| Container | Image | Port | Description |
|
|
|---|---|---|---|
|
|
| `app_frontend` | custom (Nginx) | `8080→80` | Serves the static HTML/JS frontend and proxies `/api/` requests to the backend |
|
|
| `app_backend` | custom (Flask/Python) | internal `5000` | REST API for CRUD operations on notes |
|
|
| `app_db` | `postgres:16-alpine` | internal `5432` | Relational database storing notes persistently |
|
|
| `app_adminer` | `adminer:4` | `8081→8080` | Web UI for browsing and managing the PostgreSQL database |
|
|
|
|
## Networks
|
|
|
|
| Network | Purpose |
|
|
|---|---|
|
|
| `frontend_net` | Connects the Nginx frontend container (externally reachable) |
|
|
| `backend_net` | Internal network connecting frontend→backend→database and Adminer→database |
|
|
|
|
The database is only on `backend_net` and is never directly exposed to the host.
|
|
|
|
## Volumes
|
|
|
|
| Volume | Used by | Purpose |
|
|
|---|---|---|
|
|
| `postgres_data` | `app_db` | Persists PostgreSQL data across container restarts and stops |
|
|
|
|
## Container configuration
|
|
|
|
- **app_db**: configured via environment variables (`POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`). The `db/init.sql` file is mounted read-only into `/docker-entrypoint-initdb.d/` and runs once on first startup to create the `notes` table and insert seed data.
|
|
- **app_backend**: receives `DATABASE_URL` as an environment variable pointing to the `db` service. Built from `./backend/Dockerfile` using Python 3.12-slim with Flask and psycopg2.
|
|
- **app_frontend**: built from `./frontend/Dockerfile` using Nginx 1.27-alpine. The custom `nginx.conf` proxies all `/api/` requests to `app_backend:5000` and serves `index.html` for all other paths.
|
|
- **app_adminer**: uses the official Adminer image with no extra configuration. Reachable on port `8081`.
|
|
- All containers use `restart: on-failure`.
|
|
|
|
## Requirements
|
|
|
|
- Linux OS
|
|
- Docker Engine ≥ 24 with the Compose plugin (`docker compose`)
|
|
|
|
## Instructions
|
|
|
|
### Prepare (build images)
|
|
```bash
|
|
./prepare-app.sh
|
|
```
|
|
|
|
### Start
|
|
```bash
|
|
./start-app.sh
|
|
```
|
|
|
|
### Stop (data is preserved)
|
|
```bash
|
|
./stop-app.sh
|
|
```
|
|
|
|
### Remove everything
|
|
```bash
|
|
./remove-app.sh
|
|
```
|
|
|
|
## Viewing the application
|
|
|
|
| URL | Description |
|
|
|---|---|
|
|
| http://localhost:8080 | Notes web application |
|
|
| http://localhost:8081 | Adminer — log in with Server: `db`, User: `appuser`, Password: `apppassword`, Database: `appdb` |
|
|
|
|
## Example workflow
|
|
|
|
```bash
|
|
./prepare-app.sh
|
|
# Preparing app...
|
|
|
|
./start-app.sh
|
|
# Running app...
|
|
# The app is available at http://localhost:8080
|
|
# Adminer (DB UI) is available at http://localhost:8081
|
|
|
|
# Open browser, add/delete notes
|
|
|
|
./stop-app.sh
|
|
# Stopping app...
|
|
# App stopped. Data in volumes is preserved.
|
|
|
|
./start-app.sh
|
|
# Notes are still there — volume was preserved
|
|
|
|
./remove-app.sh
|
|
# Removing app.
|
|
```
|
|
|
|
## Resources used
|
|
|
|
- [Docker documentation](https://docs.docker.com/)
|
|
- [Flask documentation](https://flask.palletsprojects.com/)
|
|
- [Nginx documentation](https://nginx.org/en/docs/)
|
|
- [PostgreSQL Docker image](https://hub.docker.com/_/postgres)
|
|
- [Adminer Docker image](https://hub.docker.com/_/adminer)
|
|
|
|
## Use of artificial intelligence
|
|
|
|
This project was created with the assistance of **Kiro AI** (kiro-cli chat agent). The AI generated the initial structure of all files including the Docker Compose configuration, Flask application, Nginx configuration, frontend HTML/JS, and shell scripts. All generated code was reviewed and understood by the author. The AI was used as a coding assistant, not as a replacement for understanding the solution.
|