Docker Compose
What is Docker Compose?
Docker Compose adalah sebuah alat untuk mendefinisikan dan menjalankan aplikasi Docker multi-kontainer. Dengan Docker Compose, Anda dapat menggunakan sebuah file YAML untuk mendefinisikan layanan, jaringan, dan volume untuk aplikasi Anda, lalu menjalankan semua komponen tersebut hanya dengan satu perintah.
Fitur Utama Docker Compose
- Multiple Containers:
- Mengelola banyak kontainer dalam satu perintah.
- Misalnya, Anda dapat menjalankan database, backend, dan frontend dalam satu konfigurasi.
- Definisi dalam File YAML:
- Semua konfigurasi layanan (image, port, volume, jaringan) didefinisikan dalam file
docker-compose.yml.
- Semua konfigurasi layanan (image, port, volume, jaringan) didefinisikan dalam file
- Deklaratif:
- Anda hanya mendefinisikan konfigurasi, dan Docker Compose mengatur semua layanan sesuai definisi Anda.
- Orkestrasi Layanan:
- Mengatur dependensi antar layanan (misalnya, layanan database harus siap sebelum backend berjalan).
- Skalabilitas:
- Anda dapat dengan mudah memperbanyak layanan menggunakan perintah
docker-compose up --scale.
- Anda dapat dengan mudah memperbanyak layanan menggunakan perintah
Kapan Menggunakan Docker Compose?
- Ketika aplikasi Anda memerlukan beberapa layanan yang berjalan bersama (misalnya, aplikasi web + database).
- Saat Anda ingin mengotomatiskan pengaturan lingkungan pengembangan atau pengujian.
- Untuk memudahkan deploy aplikasi lokal atau dalam tim.
Komponen Utama dalam Docker Compose
- Layanan (
services):- Setiap kontainer didefinisikan sebagai layanan di dalam
docker-compose.yml. - Contoh:
web,db,redis.
- Setiap kontainer didefinisikan sebagai layanan di dalam
- Jaringan (
networks):- Docker Compose secara otomatis membuat jaringan terisolasi untuk layanan Anda.
- Volume (
volumes):- Untuk menyimpan data yang persisten, bahkan jika kontainer dihentikan atau dihapus.
Writing a docker-compose.yml file
File docker-compose.yml adalah file YAML yang digunakan untuk mengkonfigurasi semua layanan aplikasi Anda. Dalam file ini, Anda dapat mendefinisikan layanan, bangunan, jaringan, dan lain-lain.
Running multi-container applications
Setelah file docker-compose.yml dibuat, Anda dapat menggunakan perintah docker-compose up untuk memulai semua layanan yang didefinisikan. Perintah ini juga akan memastikan semua layanan terhubung pada jaringan yang sesuai.
Main Syntax
- Build image
docker compose build- melakukan build semua image yang didefinikasi di docker-compose.yml dan memiliki sintaks build
- tambahkan
--no-cachejika ingin membuat ulang image tanpa menggunakan cache dari build sebelumnyadocker compose build --no-cache.
- Menjalankan Layanan
docker compose up- Menjalankan semua layanan yang didefinisikan dalam
docker-compose.yml. - tambahakn -d untuk menjalankan di latar belakang docker compose up -d
- Menjalankan layanan di latar belakang (detached mode).
- Menjalankan semua layanan yang didefinisikan dalam
docker compose start- memulai kembali layanan
docker compose restart- restart layanan
- Menghentikan Layanan
docker compose down- Menghentikan dan menghapus semua layanan, jaringan, dan volume yang dibuat oleh Compose.
- Menghentikan Layanan tanpa menghapus container
docker compose stop- Hanya menghentikan kontainer yang sedang berjalan, tetapi tidak menghapusnya. Kontainer tersebut bisa dijalankan kembali menggunakan
docker-compose start.
- Hanya menghentikan kontainer yang sedang berjalan, tetapi tidak menghapusnya. Kontainer tersebut bisa dijalankan kembali menggunakan
- Melihat Log
docker compose logs- Menampilkan log dari semua layanan.
- tambahkan -f utk realtime logs
docker compose logs -f
- Menskalakan Layanan
docker compose up --scale web=3- Menjalankan 3 instance dari layanan
web.
- Menjalankan 3 instance dari layanan
- Melihat list container
docker compose ps- Menampilkan status dari container yang dikelola oleh Docker Compose.
- melihat list images
docker compose images
- Melihat docker compose config
docker compose config
- Menjalankan perintah di dalam container
docker compose exec <service_name> <command>docker compose exec fastapi bash- Menjalankan shell di dalam container service
fastapi
- Menjalankan shell di dalam container service
- Menampilkan perintah docker compose lainnya
docker compose help
- spesifik service ex. fastapi
- docker compose build fastapi
- docker compose up fastapi
- docker compose stop fastapi
- docker compose logs fastapi
- docker compose down fastapi
- docker compose up –scale fastapi=3
- dll..
Build image first or build image in docker-compose
Kedua pendekatan—build dulu image-nya atau build di Docker Compose—memiliki kelebihan dan kekurangannya masing-masing, dan pilihan terbaik sangat tergantung pada kebutuhan proyek dan workflow tim. Namun, secara umum, berikut adalah panduan best practice yang lebih disarankan berdasarkan beberapa pertimbangan:
Build di Docker Compose (Best Practice untuk Proyek Kolaboratif dan Otomatisasi)
Untuk sebagian besar proyek pengembangan aplikasi, menggunakan build langsung di Docker Compose lebih disarankan. Ini adalah pendekatan yang lebih otomatis, mudah diatur, dan mempermudah kolaborasi tim.
Keuntungan:
- Kemudahan dan Otomatisasi: Docker Compose akan menangani pembuatan image secara otomatis setiap kali kamu menjalankan
docker-compose up, yang membuat proses pengembangan menjadi lebih cepat dan mudah. Kamu tidak perlu secara manual membangun image terlebih dahulu. - Reproducibility (Reproduksi): Dengan menyertakan konfigurasi build dalam file
docker-compose.yml, semua anggota tim dapat membangun dan menjalankan aplikasi yang sama persis tanpa perlu langkah-langkah tambahan. Cukup jalankandocker-compose up, dan semuanya akan dibangun dan dijalankan. - Fleksibilitas untuk Perubahan: Jika ada perubahan di dalam kode atau Dockerfile, kamu hanya perlu menjalankan
docker-compose up --build, dan Docker Compose akan menghandle proses build ulang image, yang sangat memudahkan saat pengembangan. - Integrasi CI/CD: Dengan mengandalkan
docker-compose.ymluntuk build image, pipeline Continuous Integration (CI) dan Continuous Deployment (CD) dapat lebih mudah diterapkan, karena build image langsung terintegrasi dengan pengaturan file Compose.
Contoh Konfigurasi Docker Compose untuk Build:
version: '3'
services:
fastapi:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
Build Dulu Image-nya (Best Practice untuk Pengelolaan Image Khusus atau Produksi)
Pendekatan ini lebih tepat untuk situasi di mana kamu ingin memiliki kontrol lebih besar atas pembuatan image, terutama dalam konteks pengelolaan image untuk lingkungan produksi atau dalam proyek yang membutuhkan versi image yang lebih stabil dan konsisten.
Keuntungan:
- Kontrol yang lebih besar atas image: Dengan membuat image terlebih dahulu menggunakan
docker build, kamu bisa memastikan image yang dibangun sudah stabil dan teruji, dan hanya image yang telah divalidasi yang digunakan dalamdocker-compose.yml. - Pengelolaan Versi dan Penerapan Tagging: Jika kamu bekerja dengan image versi tertentu atau membutuhkan kontrol lebih besar dalam pengelolaan versi image, ini memungkinkan kamu untuk memberi tag pada image secara eksplisit (
my-node-app:v1.0, misalnya). Ini penting untuk menghindari ketidakcocokan versi antara tim pengembang atau dalam lingkungan produksi. - Integrasi dengan Registri Docker: Jika kamu menggunakan Docker Hub atau registri pribadi untuk menyimpan image, membangun image terlebih dahulu dan menandainya memungkinkan kamu untuk mengunggahnya ke registri dan menarik image tersebut di berbagai lingkungan.
Contoh Workflow:
1.build image secara manual
docker build -t fast-api .2.Definisikan image yang telah dibangun dalam docker-compose.yml:
version: '3'
services:
fastapi:
image: fast-api:latest
ports:
- "8000:8000"Pendekatan ini lebih cocok untuk aplikasi yang sudah siap untuk produksi, di mana kamu ingin menggunakan image yang sudah teruji dan terverifikasi.
Kapan Memilih Masing-Masing Pendekatan?
Pilih Build di Docker Compose jika:
- Kamu sedang dalam fase pengembangan dan ingin otomatisasi, kemudahan penggunaan, dan integrasi yang lebih baik dengan workflow tim.
- Proyekmu berfokus pada kecepatan pengembangan dan iterasi, di mana membangun ulang image secara otomatis saat ada perubahan lebih menguntungkan.
- Tim atau CI/CD pipeline akan lebih mudah beradaptasi dengan proses otomatis tanpa langkah tambahan untuk membangun image.
Pilih Build Dulu Image-nya jika:
- Kamu bekerja di lingkungan yang lebih stabil, terutama dalam konteks produksi atau untuk aplikasi dengan pengelolaan versi yang ketat.
- Kamu perlu mengelola image secara manual dan menggunakan registri image (Docker Hub atau private registry) untuk distribusi image ke berbagai lingkungan.
- Proyekmu membutuhkan kontrol penuh atas proses pembuatan image dan penandaan (tagging) yang lebih eksplisit untuk distribusi.
Kesimpulan:
- Untuk pengembangan aplikasi yang lebih cepat dan lebih dinamis, build di Docker Compose lebih disarankan.
- Untuk proyek yang lebih fokus pada produksi, stabilitas, dan manajemen versi image, membangun image terlebih dahulu adalah pilihan terbaik.
Namun, dalam kebanyakan proyek pengembangan aplikasi modern, terutama jika bekerja dengan tim, build di Docker Compose sering kali menjadi pilihan yang lebih praktis dan efisien.
Perbandingan:
| Aspek | Build Dulu Image-nya | Build di Docker Compose |
|---|---|---|
| Kontrol terhadap Image | Lebih besar kontrol terhadap versi image dan tag. | Kurang kontrol, Docker Compose akan otomatis build. |
| Kemudahan Penggunaan | Harus build manual dengan docker build. | Build otomatis saat menjalankan docker-compose up. |
| Cocok untuk Proyek Apa? | Proyek dengan kebutuhan stabilitas image atau versi. | Proyek pengembangan yang sering membutuhkan rebuild. |
| Keuntungan dalam CI/CD | Perlu konfigurasi tambahan untuk otomatisasi. | Lebih mudah diintegrasikan dengan pipeline CI/CD. |
| Keuntungan untuk Pengembangan | Memungkinkan untuk kontrol penuh terhadap image. | Mudah dan cepat saat bekerja dalam tim atau saat pengembangan. |
Build Context
jika dalam file docker-compose.yml kamu tidak menggunakan build.context, maka Docker Compose tidak akan membangun image dari sumber kode di direktori proyek. Sebaliknya, Docker Compose hanya akan menggunakan image yang sudah ada, yang sebelumnya telah dibangun atau ditarik dari registry Docker (seperti Docker Hub atau registry lain).
Penjelasan:
build.context: .: Ini memberi tahu Docker Compose untuk membangun image dari konteks build (direktori proyek saat ini). Jika kamu mendefinisikan bagianbuildseperti ini, Docker Compose akan menjalankan proses build berdasarkan Dockerfile yang ada di dalam konteks tersebut.- Tanpa
build(hanyaimage): Jika kamu tidak menyertakan bagianbuilddan hanya menyebutkanimage, Docker Compose akan menggunakan image yang sudah ada. Jika image tersebut tidak ada di lokal, Docker Compose akan mencoba untuk menariknya (pull) dari registry Docker (misalnya, Docker Hub).
#dengan build
version: '3'
services:
app:
build:
context: ./app_fastapi
dockerfile: Dockerfile
ports:
- "8000:8000"
#tanpa build
version: '3'
services:
app:
image: fastapi_app:v1.0 # Menggunakan image yang sudah ada
ports:
- "8000:8000"
Build multiple image in docker compose
Jika ada banyak image yang perlu dibangun di dalam satu proyek menggunakan Docker Compose, kamu bisa mengatur beberapa layanan di dalam file docker-compose.yml, dan masing-masing layanan bisa memiliki Dockerfile yang berbeda. Dalam hal ini, kamu perlu menentukan nama file Dockerfile secara eksplisit jika nama file Dockerfile-nya bukan Dockerfile default atau berada di direktori yang berbeda.
contoh struktur direktori
/my_project
│
├── /app_fastapi
│ ├── Dockerfile
│ ├── main.py
│ └── requirements.txt
│
├── /app_frontend
│ ├── Dockerfile
│ ├── index.html
│ └── package.json
│
├── /db
│ └── Dockerfile
│
└── docker-compose.ymlcontoh file docker-compose.yml
version: '3'
services:
fastapi_app:
build:
context: ./app_fastapi
dockerfile: Dockerfile # Gunakan nama default 'Dockerfile'
image: fastapi-app:latest
container_name: fs-app
ports:
- "8000:8000"
frontend_app:
build:
context: ./app_frontend
dockerfile: Dockerfile # Gunakan nama default 'Dockerfile'
image: frontend-app:latest
container_name: fe-app
ports:
- "3000:3000"
db_app:
build:
context: ./db
dockerfile: Dockerfile # Gunakan nama default 'Dockerfile'
image: database-app:latest
container_name: db-app
ports:
- "5432:5432" # Contoh untuk database PostgreSQL
Penjelasan:
build.context: Ini adalah direktori tempat Dockerfile dan aplikasi kamu berada. Misalnya, untukfastapi_app, Docker Compose akan mencari Dockerfile di dalam folder./app_fastapi.dockerfile: Di sini, kamu menentukan nama file Dockerfile. Jika kamu menggunakan nama file default yang bernamaDockerfile, kamu tidak perlu menambahkannya (Docker Compose secara otomatis akan mencarinya). Jika file Dockerfile-nya memiliki nama lain, misalnyaDockerfile.dev, maka kamu bisa menulisnya seperti ini:dockerfile: Dockerfile.dev.
Contoh Jika Dockerfile Memiliki Nama Berbeda:
Misalnya, jika kamu memiliki beberapa file Dockerfile untuk pengembangan dan produksi, kamu dapat menamai file Dockerfile yang berbeda, seperti Dockerfile.dev dan Dockerfile.prod. Berikut contoh penggunaan nama file Dockerfile yang berbeda:
version: '3'
services:
fastapi_app:
build:
context: ./app_fastapi
dockerfile: Dockerfile.dev # Menggunakan Dockerfile.dev untuk build
image: fastapi-app:latest
container_name: fs-app
ports:
- "8000:8000"
frontend_app:
build:
context: ./app_frontend
dockerfile: Dockerfile.prod # Menggunakan Dockerfile.prod untuk build
image: frontend-app:latest
container_name: fe-app
ports:
- "3000:3000"
db_app:
build:
context: ./db
dockerfile: Dockerfile # Menggunakan Dockerfile default untuk database
image: database-app:latest
container_name: db-app
ports:
- "5432:5432"
environment vs env_file
env_file
- Fungsi: Mengimpor variabel lingkungan dari file eksternal (biasanya
.env) ke dalam kontainer. - Penggunaan: Kamu cukup merujuk file
.envyang berisi variabel lingkungan yang ingin digunakan. - Keuntungan:
- Manajemen konfigurasi lebih mudah: Jika kamu memiliki banyak variabel lingkungan, lebih baik memisahkannya dalam file
.envdan hanya merujuk file tersebut didocker-compose.yml. - Pengelolaan versi lebih baik: Kamu bisa memiliki file
.envyang berbeda untuk berbagai lingkungan (misalnya,.env.development,.env.production), dan cukup mengganti file tersebut sesuai dengan kebutuhan.
- Manajemen konfigurasi lebih mudah: Jika kamu memiliki banyak variabel lingkungan, lebih baik memisahkannya dalam file
- Kekurangan:
- Tidak dapat mengubah variabel lingkungan secara dinamis: Semua variabel yang ada di dalam file
.envakan dimuat pada saat kontainer dimulai. Kamu tidak bisa menambahkan atau mengubah variabel lingkungan setelah kontainer berjalan tanpa me-restart kontainer.
- Tidak dapat mengubah variabel lingkungan secara dinamis: Semua variabel yang ada di dalam file
contoh
#.env
MONGO_URI=mongodb://mongodb:27017/userdb#docker-compose.yml
services:
app:
env_file:
- ./.envenvironment
- Fungsi: Mendefinisikan variabel lingkungan langsung di dalam file
docker-compose.yml. - Penggunaan: Variabel lingkungan didefinisikan langsung di bagian
environmentuntuk setiap service. - Keuntungan:
- Lebih langsung dan eksplisit: Kamu bisa melihat dan mengonfigurasi variabel lingkungan langsung di dalam file
docker-compose.yml. - Fleksibilitas tinggi: Sangat berguna jika hanya ada sedikit variabel lingkungan yang perlu dikonfigurasi atau jika kamu ingin mendefinisikan variabel secara langsung dalam file Compose.
- Lebih langsung dan eksplisit: Kamu bisa melihat dan mengonfigurasi variabel lingkungan langsung di dalam file
- Kekurangan:
- File Compose bisa menjadi panjang dan berantakan: Jika ada banyak variabel lingkungan, file
docker-compose.ymlbisa menjadi sangat besar dan susah dibaca. - Kurang terstruktur: Tidak ada pembagian atau struktur terpisah antara kode aplikasi dan konfigurasi lingkungan, yang dapat mengurangi fleksibilitas dalam pengelolaan berbagai lingkungan (misalnya pengembangan vs produksi).
- File Compose bisa menjadi panjang dan berantakan: Jika ada banyak variabel lingkungan, file
contoh
#docker-compose.yml
services:
app:
environment:
- MONGO_URI=mongodb://mongodb:27017/userdb
Perbandingan:
| Fitur | env_file | environment |
|---|---|---|
| Sumber Variabel | Mengimpor dari file .env eksternal | Mendefinisikan variabel langsung di Compose |
| Pengelolaan | Lebih terorganisir, file .env terpisah | Langsung dalam file Compose, lebih eksplisit |
| Fleksibilitas | Kurang fleksibel untuk perubahan dinamis | Fleksibel, bisa langsung mengubah variabel |
| Kapan Digunakan | Banyak variabel, pemisahan lingkungan | Sedikit variabel atau spesifik untuk service |
Kapan Menggunakan env_file vs environment?
- Gunakan
env_fileketika:- Kamu memiliki banyak variabel lingkungan dan ingin mengelola mereka secara terpisah dalam file
.envuntuk kemudahan pengelolaan. - Kamu ingin memisahkan konfigurasi aplikasi dan environment, seperti
.env.development,.env.production, dll. - Kamu ingin menjaga
docker-compose.ymltetap bersih dan tidak terlalu panjang.
- Kamu memiliki banyak variabel lingkungan dan ingin mengelola mereka secara terpisah dalam file
- Gunakan
environmentketika:- Kamu hanya memiliki sedikit variabel lingkungan atau hanya perlu menambahkan satu atau dua variabel.
- Kamu ingin mendefinisikan variabel lingkungan secara eksplisit dan langsung di dalam file
docker-compose.yml. - Kamu perlu mendefinisikan variabel lingkungan yang bersifat spesifik atau dinamis dalam konteks sebuah service.
Contoh Gabungan:
Kamu juga bisa menggunakan keduanya bersama-sama. Misalnya, kamu bisa menggunakan env_file untuk memuat variabel umum, dan menggunakan environment untuk menambahkan beberapa variabel spesifik:
services:
app:
env_file:
- ./.env
environment:
- APP_ENV=production
Best Practices Docker Compose
1. Gunakan versi yang tepat
- Selalu gunakan versi terbaru dari Docker Compose yang didukung
- Alasan: Versi terbaru menawarkan fitur dan kompatibilitas yang lebih baik.
2. Strukturkan file dengan rapi
- Pisahkan bagian utama seperti
services,volumes,networks, danconfigs. - alasan
- Membantu membaca dan memahami file dengan lebih mudah.
- Memisahkan definisi layanan, volume, dan jaringan.
version: '3.9'
services:
app:
image: my-app:latest
..
db:
image: postgres:15
..
volumes:
db_data:
networks:
app_network:
driver: bridge3. Gunakan build context untuk aplikasi kustom
- Jika Anda membangun image aplikasi sendiri, gunakan direktori konteks dan
Dockerfilesecara eksplisit: - alasan
- Memastikan konteks build spesifik.
- Menghindari konflik jika ada banyak Dockerfile di proyek.
build:
context: .
dockerfile: Dockerfile
4. Gunakan Variabel environment
- Gunakan file
.envuntuk mengelola variabel lingkungan agar tidak mengungkapkan informasi sensitif di filedocker-compose.yml - alasan
- keamanan: Informasi sensitif seperti password tidak langsung disimpan di
docker-compose.yml. - Kemudahan konfigurasi untuk berbagai lingkungan (development, production, dll.).
- keamanan: Informasi sensitif seperti password tidak langsung disimpan di
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}file .env
POSTGRES_USER=admin
POSTGRES_PASSWORD=securepassword5. Gunakan depends_on dengan bijak
- Gunakan
depends_onhanya untuk menentukan urutan startup layanan, tetapi tidak mengandalkan ini untuk memastikan layanan siap: - alasan:
depends_onhanya memastikan bahwa layanan dimulai lebih dulu, tetapi tidak memeriksa apakah layanan siap.- Gunakan alat seperti
healthcheckuntuk memastikan layanan siap.
depends_on:
- db6. Tambahkan healthcheck
- Tambahkan
healthcheckuntuk memastikan layanan benar-benar siap sebelum layanan lain mencoba berkomunikasi: - alasan:
- Memastikan layanan hanya tersedia jika benar-benar siap.
- Menghindari kesalahan koneksi antar-layanan.
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 57. Gunakan volume untuk data persistent
- Selalu gunakan volume untuk menyimpan data penting seperti database:
- alasan:
- Volume bersifat persisten, sehingga data tetap ada meskipun container dihapus.
- Menghindari hilangnya data saat container dihentikan atau diperbarui.
volumes:
- db_data:/var/lib/postgresql/data8. Definisikan Jaringan Secara Eksplisit
- Gunakan jaringan khusus untuk memisahkan layanan jika diperlukan:
- alasan
- Isolasi jaringan antar-layanan.
- Mengurangi risiko keamanan dari akses tak terduga.
networks:
app_network:
driver: bridge9. Gunakan nama container yang jelas
- Tentukan nama container agar mudah dikenali, terutama dalam pengelolaan log dan debugging:
- alasan
- Membantu mengidentifikasi layanan dalam perintah seperti
docker logsataudocker ps.
- Membantu mengidentifikasi layanan dalam perintah seperti
container_name: my-app-container10. Atur Restart Policy
- Tambahkan kebijakan restart untuk meningkatkan ketersediaan layanan:
- alasan
- Secara otomatis memulai kembali layanan yang gagal.
- Meningkatkan ketahanan aplikasi.
restart: unless-stopped11. Gunakan Resource Limits
- Batasi sumber daya yang dapat digunakan oleh container untuk menghindari satu layanan membebani sistem:
- alasan:
- Membantu mengelola penggunaan sumber daya di lingkungan yang terbatas.
deploy:
resources:
limits:
cpus: "1.0"
memory: "512M"
reservations:
memory: "256M"12. Gunakan Versi Tag untuk Image
- Selalu gunakan tag versi spesifik untuk image, bukan
latest: - alasan:
- Menjamin konsistensi lingkungan saat membangun atau menjalankan aplikasi.
- Menghindari masalah yang disebabkan oleh pembaruan otomatis ke versi terbaru.
image: postgres:1513. Gunakan Logging yang Dikelola
- Tambahkan konfigurasi log driver untuk layanan penting:
- alasan:
- Membatasi ukuran log untuk menghemat ruang disk.
- Mempermudah pengelolaan log container.
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"14. Gunakan Mode Tertentu untuk Jaringan
- Jika layanan memerlukan akses jaringan yang spesifik, gunakan mode seperti
hostataunone: - alasan:
- Memberikan fleksibilitas pengaturan jaringan.
- Mengoptimalkan komunikasi antar-layanan.
network_mode: bridge15. Dokumentasikan Konfigurasi
- Tambahkan komentar di file
docker-compose.ymluntuk menjelaskan konfigurasi: - alasan:
- Membantu tim lain memahami konfigurasi.
- Memudahkan debugging dan pemeliharaan.
services:
app:
image: my-app:latest # Backend aplikasi
ports:
- "8080:8080" # Ekspos API di port 8080Study case
Endpoint CRUD untuk Data User dengan FastAPI dan MongoDB
struktur folder & file project
my_project/
│
├── app/ # Direktori untuk kode sumber aplikasi
│ ├── main.py # File aplikasi FastAPI
│ └── requirements.txt # File dependensi Python
│
├── mongo_data/ # Direktori untuk data MongoDB (bind mount)
│ └── (data files) # File data MongoDB
│
├── docker-compose.yml # File konfigurasi Docker Compose
└── Dockerfile # File untuk build image FastAPImain.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
from pymongo import MongoClient
from bson import ObjectId
import os
app = FastAPI()
# Mengambil URI MongoDB dari environment variable
MONGO_URI = os.getenv("MONGO_URI", "mongodb://localhost:27017")
client = MongoClient(MONGO_URI)
db = client["myDatabase"]
collection = db["users"]
class User(BaseModel):
name: str
email: str
@app.post("/user/", response_model=User)
def create_user(user: User):
user_id = collection.insert_one(user.dict()).inserted_id
return user
@app.get("/user/{user_id}", response_model=User)
def get_user(user_id: str):
user = collection.find_one({"_id": ObjectId(user_id)})
return user
@app.get("/users/", response_model=List[User])
def list_users():
users = list(collection.find())
return users
@app.put("/user/{user_id}", response_model=User)
def update_user(user_id: str, user: User):
collection.update_one({"_id": ObjectId(user_id)}, {"$set": user.dict()})
return collection.find_one({"_id": ObjectId(user_id)})
@app.delete("/user/{user_id}")
def delete_user(user_id: str):
collection.delete_one({"_id": ObjectId(user_id)})
return {"message": "User deleted"}
Dockerfile for fastapi image
# Gunakan image Python sebagai base image
FROM python:3.10-slim
# Setel working directory di dalam container
WORKDIR /app
# Salin file requirements.txt ke dalam container
COPY ./app/requirements.txt /app/
# Install dependencies yang dibutuhkan
RUN pip install --no-cache-dir -r requirements.txt
# Salin semua kode aplikasi ke dalam container
COPY ./app /app/
# Setel variabel lingkungan untuk FastAPI
ENV UVICORN_CMD="uvicorn main:app --host 0.0.0.0 --port 8000 --reload"
# Ekspose port 8000 untuk aplikasi FastAPI
EXPOSE 8000
# Perintah untuk menjalankan FastAPI menggunakan Uvicorn
CMD ["sh", "-c", "$UVICORN_CMD"]Dengan menyalin requirements.txt terlebih dahulu sebelum salinan seluruh kode aplikasi, Docker dapat memanfaatkan layer caching. Ini mempercepat build image karena pip hanya akan diinstal ulang ketika ada perubahan pada file requirements.txt, bukan setiap kali ada perubahan di dalam kode aplikasi.
Penjelasan:
FROM python:3.10-slim:- Menggunakan image Python 3.10 yang lebih ringan (
slim) sebagai base image untuk container.
- Menggunakan image Python 3.10 yang lebih ringan (
WORKDIR /app:- Menetapkan direktori kerja di dalam container sebagai
/app, tempat aplikasi FastAPI akan ditempatkan.
- Menetapkan direktori kerja di dalam container sebagai
COPY requirements.txt /app/:- Menyalin file
requirements.txtdari host ke dalam container. File ini berisi daftar dependensi yang perlu diinstal untuk aplikasi FastAPI.
- Menyalin file
RUN pip install --no-cache-dir -r requirements.txt:- Menggunakan
pipuntuk menginstal dependensi yang ada direquirements.txtke dalam container.
- Menggunakan
COPY ./app /app/:- Menyalin seluruh kode aplikasi dari folder
./appdi host ke dalam container di folder/app.
- Menyalin seluruh kode aplikasi dari folder
ENV UVICORN_CMD="...":- Menetapkan variabel lingkungan untuk perintah yang menjalankan FastAPI menggunakan Uvicorn. Dalam hal ini, aplikasi FastAPI akan dijalankan di port 8000 dengan opsi
--reloaduntuk pengembangan.
- Menetapkan variabel lingkungan untuk perintah yang menjalankan FastAPI menggunakan Uvicorn. Dalam hal ini, aplikasi FastAPI akan dijalankan di port 8000 dengan opsi
EXPOSE 8000:- Mengekspos port 8000 dari container, karena FastAPI akan berjalan pada port ini di dalam container.
CMD ["sh", "-c", "$UVICORN_CMD"]:- Menjalankan perintah untuk memulai aplikasi FastAPI menggunakan
uvicorn. Perintah ini akan menjalankan aplikasi di dalam container pada saat container dijalankan.
- Menjalankan perintah untuk memulai aplikasi FastAPI menggunakan
requirements.txt
fastapi
uvicorn
pymongodocker-compose.yml
- 2 services :
- fastapi
- build image in docker-comp using Dockerfile
- mongodb
- build image first by pull from registry
- fastapi
- network :
- bridge
version: '3'
services:
fastapi:
build:
context: .
dockerfile: Dockerfile
image: my-fastapi-app:latest # Menentukan nama image dan tag
container_name: fastapi-app
ports:
- "8000:8000" # Menyambungkan port 800 di host ke port 8000 di container (MongoDB)
depends_on:
- mongodb # Ensure service mongodb starts before fastapi
environment:
MONGO_URI: mongodb://root:admin12345@mongodb:27017 # URI untuk menghubungkan FastAPI ke MongoDB
APP_ENV: production # Menetapkan lingkungan aplikasi (production)
volumes:
- ./app:/app # Bind mount untuk source code aplikasi
networks:
- app_network # Menghubungkan ke jaringan kustom yang didefinisikan di bawah
restart: unless-stopped # Mengatur agar container restart otomatis jika terhenti
mongodb:
image: "mongo:4.4"
container_name: mongodb
ports:
- "27017:27017" # Menyambungkan port 27017 di host ke port 27017 di container (MongoDB)
environment:
MONGO_INITDB_ROOT_USERNAME: root # Username admin untuk MongoDB
MONGO_INITDB_ROOT_PASSWORD: admin12345 # Password admin untuk MongoDB
MONGO_INITDB_DATABASE: myDatabase # Nama database yang akan dibuat pada inisialisasi
volumes:
- ./mongo_data:/data/db # Bind mount untuk penyimpanan data MongoDB
networks:
- app_network # Menghubungkan ke jaringan kustom
healthcheck: # Menetapkan healthcheck untuk memastikan MongoDB siap digunakan
test: ["CMD", "mongo", "--eval", "db.runCommand({ ping: 1 })"]
interval: 10s # Pemeriksaan dilakukan setiap 10 detik
timeout: 5s # Timeout jika tidak mendapat respons dalam 5 detik
retries: 5 # Coba hingga 5 kali
restart: unless-stopped # Mengatur agar container MongoDB restart otomatis jika terhenti
#volumes:
# Bind mount is already used, so volumes section remains empty
networks:
app_network:
name: app_network # Menentukan nama jaringan secara eksplisit
driver: bridge # Custom bridge networkPenjelasan:
version: '3':- Menentukan versi Docker Compose yang digunakan. Versi
3adalah versi yang umum dan mendukung fitur-fitur modern.
- Menentukan versi Docker Compose yang digunakan. Versi
services:- Di bagian ini, kita mendefinisikan dua services :
fastapidanmongodb: - fastapi service
- build: Bagian ini menginstruksikan Docker Compose untuk membangun image menggunakan
Dockerfileyang ada di direktori saat ini (context: .). image: my-fastapi-app:latest. menentukan nama image dan tag ketika di buildcontainer_name: fastapi-app: Nama container yang digunakan untuk layanan FastAPI.ports: "8000:8000": Mengalihkan port 8000 di host ke port 8000 di container, di mana aplikasi FastAPI akan berjalan.depends_on: Menjamin bahwa MongoDB akan dimulai terlebih dahulu sebelum FastAPI.environment: Menyediakan variabel lingkungan, sepertiMONGO_URIyang digunakan oleh FastAPI untuk menghubungkan ke MongoDB.volumes: Mengaitkan direktori./appdari host ke/appdi dalam container, sehingga kode aplikasi bisa diakses oleh container.networks: Menghubungkan container FastAPI ke jaringan kustomapp_network.restart: unless-stopped: Mengatur agar container FastAPI secara otomatis restart jika terhenti, kecuali dihentikan secara eksplisit.
- build: Bagian ini menginstruksikan Docker Compose untuk membangun image menggunakan
- mongodb service:
image: mongo:4.4: Menggunakan image resmi MongoDB versi 4.4 dari Docker Hub.- study kasus ini kita menggunakan versi 4 karena versi 5 keatas membutuhkan ram 4 gb
container_name: mongodb: Nama container untuk MongoDB.ports: "27017:27017": Mengalihkan port 27017 di host ke port 27017 di container, port default untuk MongoDB.environment: Menyediakan variabel lingkungan untuk MongoDB, seperti username, password, dan nama database (userdb).volumes: Mengaitkan direktori./mongo_datadari host ke/data/dbdi container untuk memastikan data MongoDB bertahan.healthcheck: Menetapkan pemeriksaan kesehatan untuk memastikan MongoDB sudah siap digunakan.restart: unless-stopped: Mengatur agar container MongoDB secara otomatis restart jika terhenti, kecuali dihentikan secara eksplisit.
- Di bagian ini, kita mendefinisikan dua services :
networks:app_network: Menetapkan jaringan kustom bernamaapp_network, dengan driverbridgeyang merupakan jaringan default Docker untuk komunikasi antar container di satu host.-
name : app_network, menentukan nama jaringan secara explisit driver : bridge, menentukan jenis jaringan yang digunakan pada kasus ini menggunakan jaringan bridge
running
1. Jalankan code dibawah untuk melakukan build image utk service yg membutuhkan build dalam hal ini fastapi
docker compose build

2. Aktifkan service dengan perintah docker compose up -d
- docker compose up akan mengecek file docker-compose.yml, pastikan anda berada pada path dimana file tersebut berada

- jika image belum ada di local, maka docker-compose akan mendownload (pull) image di docker hub

- docker-compose.yml telah berhasil dijalankan dengan mengaktifkan network, dan 2 container (fastapi-app dan mongodb)
3. cek container

- 2 container telah berhasil diaktifkan dan dijalankan
4. Cek mongodb client
- anda dapat menggunakan mogodb compas,
- kemudian add new connection
- pada bagian proxy/SSH masukkan credential server seperti host, username, password
- pada bagian authentication masukkan username dan password yang sudah didefine di file docker-compose.yml untuk database nya dikosongkan saja.

- saat pertamakali build, database dan collection masih kosong,
- setelah dilakukan insert maka otomatis database dan collection akan dibuat
5. cek browser
- kita dapat mengakses aplikasi fastapi di url localhost:8000
- untuk melihat api documentation swagger di /docs

6. cek api function dengan swagger atau postman
- insert data user dengan swagger

- lihat data nya di mongodb compass

- data berhasil masuk
- database dan collection berhasil terbuat

- directory mongodata di host computer yg di bind mount otomatis terisi
- sehingga jika container mongodb nya mati atau terhapus data masih ada ketika service nya di aktifkan lagi
shutdown
mematikan semua service di docker-compose.yml jalankan code docker compose down
- container dan network akan dinonaktifkan dan dihapus dari list
