Aplikasi selesai secara fungsional, tetapi “jalan di laptop saya” belum berarti “siap dijalankan di server”. Tiga hal memisahkan keduanya: lokasi database tidak boleh tertanam di kode, versi dependensi tidak boleh mengapung, dan lingkungan jalannya harus dapat direproduksi. Bagian ini menuntaskan ketiganya — environment variable, pyproject.toml final, dan Dockerfile — mengikuti pola chapter Containerization dengan Docker dan Deployment Aplikasi Web.
Konfigurasi lewat Environment Variable #
Satu-satunya nilai konfigurasi proyek ini adalah lokasi berkas database. Ubah tiga baris pertama app/database.py dari Bagian 3 — sisanya tidak berubah:
import os
import sqlite3
from collections.abc import Iterator
DB_PATH = os.environ.get("TUGAS_DB_PATH", "tugas.db")os.environ.get("TUGAS_DB_PATH", "tugas.db") membaca variable TUGAS_DB_PATH bila ada, dan memakai "tugas.db" bila tidak — pola yang sama dengan chapter Environment Variables. Pengembangan lokal tidak berubah sama sekali, sementara lingkungan lain cukup menyetel satu variable tanpa menyentuh kode. Bukti keduanya lewat skrip sementara cek_api.py:
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
respons = client.post("/tugas", json={"judul": "Cek konfigurasi"})
print(respons.status_code, respons.json())Output yang Dihasilkan:
201 {'id': 1, 'judul': 'Cek konfigurasi', 'selesai': False}Tanpa variable, berkas tugas.db muncul di direktori kerja. Sekarang jalankan ulang dengan variable yang menunjuk ke berkas lain:
TUGAS_DB_PATH=db-lain.db python3 cek_api.pyOutput yang Dihasilkan:
201 {'id': 1, 'judul': 'Cek konfigurasi', 'selesai': False}Kali ini yang tercipta adalah db-lain.db — tugas.db tidak tersentuh. Test dari Bagian 5 pun tidak terganggu: fixture di sana memakai monkeypatch.setattr(database, "DB_PATH", ...) yang menimpa atribut module secara langsung, mengesampingkan environment. Menjalankan ulang pytest tetap menghasilkan 7 passed.
pyproject.toml Final #
[project]
name = "api-manajemen-tugas"
version = "1.0.0"
description = "REST API manajemen tugas dengan FastAPI dan SQLite"
requires-python = ">=3.12"
dependencies = [
"fastapi==0.128.0",
"uvicorn==0.44.0",
]
[project.optional-dependencies]
dev = [
"httpx==0.28.1",
"pytest==9.0.2",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["."]Dua perubahan dibanding Bagian 1. Pertama, setiap dependensi dikunci dengan == alih-alih >= — prinsip chapter Dependency Pinning: build hari ini harus menghasilkan aplikasi yang identik dengan build bulan depan. Kedua, [tool.pytest.ini_options] memberi tahu pytest bahwa test tinggal di tests/ dan direktori root proyek adalah tempat mencari package — dengan pythonpath = ["."], perintah pytest polos kini sama sahnya dengan python -m pytest:
pytestOutput yang Dihasilkan:
============================== 7 passed in 0.95s ===============================Baris durasi bervariasi antar mesin dan antarjalankan — inti pesannya tetap 7 passed.
Dockerfile #
Buat berkas Dockerfile di root proyek:
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
TUGAS_DB_PATH=/data/tugas.db
WORKDIR /app
RUN useradd --create-home apiuser
COPY pyproject.toml ./
RUN pip install --no-cache-dir fastapi==0.128.0 uvicorn==0.44.0
COPY app ./app
RUN mkdir /data && chown apiuser:apiuser /data
USER apiuser
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]Mari kita bedah keputusan-keputusannya:
FROM python:3.12-slim: image dasar versi Python yang sama dengan pengembangan, varianslimtanpa toolchain compiler yang tidak terpakai.ENV ...: tiga variable sekaligus.PYTHONDONTWRITEBYTECODE=1menghentikan pembuatan__pycache__di dalam container,PYTHONUNBUFFERED=1membuat log stdout muncul seketika tanpa buffering, danTUGAS_DB_PATH=/data/tugas.dbmemindahkan database ke direktori data yang akan dipasangkan volume.RUN useradd ...danUSER apiuser: container tidak dijalankan sebagai root — bila penyerang lolos ke dalam proses, kewenangannya terbatas.- Urutan
COPY:pyproject.tomldisalin dan dependensi dipasang lebih dulu, baruapp/disalin. Layer instalasi tetap valid selama dependensi tidak berubah, sehingga mengubah kode aplikasi tidak memicu pengunduhan ulang seluruh dependensi. RUN mkdir /data && chown ...: menyiapkan rumah untuktugas.dbmilikapiuser.EXPOSE 8000: dokumentasi port yang dipakai container;CMDmenjalankan uvicorn di0.0.0.0agar API terjangkau dari luar container.
Build dan Run #
docker build -t api-manajemen-tugas:1.0.0 .Output yang Dihasilkan (ilustratif):
[+] Building 24.3s (11/11) FINISHED
=> [1/4] FROM docker.io/library/python:3.12-slim
=> [2/4] RUN useradd --create-home apiuser
=> [3/4] COPY pyproject.toml ./
=> [4/4] COPY app ./app
=> exporting to image
=> => naming to docker.io/library/api-manajemen-tugas:1.0.0Jalankan container dengan volume untuk data dan kebijakan restart otomatis:
docker run -d --restart unless-stopped -p 8000:8000 -v tugas-data:/data api-manajemen-tugas:1.0.0Setelah container aktif, endpoint kesehatan siap diperiksa:
curl http://127.0.0.1:8000/healthOutput yang Dihasilkan (ilustratif):
{"status":"ok"}Daftar Periksa Deployment #
Sebelum API benar-benar melayani pengguna, lewati daftar periksa ini:
- Test hijau sebelum build — jalankan
pytestpada setiap perubahan, idealnya otomatis di CI seperti chapter *Continuous Integration`. - Dependensi terkunci di
pyproject.tomldanDockerfile, versi Python seragam antara laptop dan image. - Container berjalan sebagai
apiuser, bukan root. - Data berada di volume (
tugas-data:/data), sehingga container boleh dibuat ulang kapan saja tanpa kehilangan tugas. - Endpoint
/healthdipantau — sinyal pertama saat service bermasalah, dasar dari praktik chapter *Monitoring Aplikasi Web`. - Akses dari luar melewati reverse proxy dengan TLS, bukan langsung ke uvicorn — pembahasan chapter TLS dan HTTPS dari Course Python.
- Kebutuhan naik skala disadari: perintah
--workers 4pada CMD memakai beberapa core CPU, tetapi empat proses berbagi satu berkas SQLite. Untuk beban tulis yang padat, pindahkan ke PostgreSQL atau MySQL seperti chapter Pengenalan PostgreSQL dan MySQL.
Dengan ini proyek tuntas: API manajemen tugas yang tervalidasi, teruji, terkonfigurasi, dan siap dibangun kapan pun. Berkas pyproject.toml dan Dockerfile tahap ini tersedia pada bagian Berkas Sumber di bawah halaman — perubahan tiga baris pada app/database.py diterapkan pada berkas dari Bagian 3. Dari sini, arah pengembangan selanjutnya terbuka: autentikasi dari chapter Authentication dan Authorization, atau pagination dan filtering untuk daftar tugas yang memanjang.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
pyproject.toml
Unduh berkas[project]
name = "api-manajemen-tugas"
version = "1.0.0"
description = "REST API manajemen tugas dengan FastAPI dan SQLite"
requires-python = ">=3.12"
dependencies = [
"fastapi==0.128.0",
"uvicorn==0.44.0",
]
[project.optional-dependencies]
dev = [
"httpx==0.28.1",
"pytest==9.0.2",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["."]