Arsitektur Aplikasi Modern
Di era digital yang terus berkembang pesat ini, arsitektur aplikasi telah mengalami banyak evolusi. Gone are the days di mana kita mengembangkan aplikasi sebagai satu blok monolitik besar, yang mana segala fitur dan fungsionalitasnya dikemas dalam satu paket raksasa. Sekarang, kita beralih ke pendekatan yang lebih modular dan fleksibel, yaitu arsitektur berbasis microservices.
Microservices adalah sebuah pendekatan dalam pengembangan software di mana aplikasi dibangun sebagai kumpulan layanan yang lebih kecil, mandiri, dan bisa di-deploy secara independen. Setiap layanan ini memiliki fungsionalitas spesifik, berkomunikasi dengan layanan lainnya melalui API yang terdefinisi dengan baik, biasanya melalui HTTP/REST atau messaging queues.
Keuntungan Arsitektur Microservices
Era Deployment Tradisional
Zaman dulu, ngirim atau deploy aplikasi ke lingkungan produksi itu sering kali dilakukan secara manual. Prosesnya bisa panjang dan penuh dengan risiko. Mulai dari transfer file secara manual, konfigurasi server, sampai melakukan restart layanan secara langsung di server produksi. Proses ini tidak hanya memakan waktu, tapi juga rentan terhadap human error yang bisa menyebabkan downtime atau masalah serius lainnya.
Docker muncul sebagai alat yang mempermudah proses deployment aplikasi. Dengan menggunakan kontainer, Docker memastikan bahwa aplikasi akan berjalan dengan konsisten di berbagai lingkungan, dari development hingga produksi. Ini menghilangkan masalah "works on my machine" yang sering dihadapi developer.
Dalam dunia pengembangan dan pengoperasian aplikasi, dua teknologi yang sering dibanding-bandingkan adalah Virtual Machine (VM) dan Container. Kedua teknologi ini memiliki kelebihan dan kekurangannya masing-masing, tergantung pada kebutuhan spesifik proyek atau organisasi Anda.
Virtual Machine: Apartemen Pribadi di Dunia Komputasi
Virtual Machine, atau VM, adalah emulasi dari sebuah komputer sistem. Setiap VM berjalan di atas fisik hardware tetapi terisolasi dari hardware tersebut dan VM lainnya, berkat layer yang disebut Hypervisor. Hypervisor bertindak seperti manajer gedung apartemen, yang memastikan setiap "apartemen" (VM) memiliki sumber daya yang dibutuhkan dan tidak mengganggu penghuni lain.
Container: Berbagi Sumber Daya dengan Efisien
Container, di sisi lain, membagi sistem operasi yang sama dan menjalankan aplikasi beserta dependensinya dalam paket yang terisolasi. Ini seperti tinggal di kost-kostan, di mana kamu membagi beberapa fasilitas utama dengan penghuni lain tetapi memiliki ruang pribadi kamu sendiri.
Definisi Docker
Mengapa Docker Itu Penting?
Nah, sebelum kita masuk ke teknisnya, mari kita bahas dulu kenapa sih Docker ini penting banget buat kita yang berkecimpung di dunia pengembangan software. Jadi, Docker ini menyediakan solusi untuk masalah klasik yang sering ditemui developer: "Aplikasi saya jalan dengan sempurna di komputer saya, kok pas di tempat lain malah error, ya?"
Docker datang sebagai penyelamat dengan konsep kontainerisasi. Bayangin, aplikasi kita dengan semua kebutuhan dan ketergantungannya dibungkus dengan rapi dalam sebuah kontainer. Kontainer ini bisa dijalankan di mana saja, mulai dari komputer pribadi kita, server di kantor, sampai ke server cloud yang jauh di sana. Singkatnya, Docker memastikan bahwa "It works on my machine" bisa berubah jadi "It works everywhere".
Docker telah mengubah cara kita mengembangkan, mengirimkan, dan menjalankan aplikasi dengan memberikan solusi kontainerisasi yang efisien. Untuk memahami bagaimana Docker dapat melakukan ini, penting untuk mengenal arsitektur dasar Docker dan komponen-komponen utamanya.
Arsitektur Docker terdiri dari beberapa komponen utama yang bekerja bersama untuk memungkinkan pembuatan, penjalanan, dan distribusi kontainer.
Docker Daemon
Docker Daemon (dockerd
) adalah proses background yang mengelola objek-objek Docker seperti kontainer, gambar (images), jaringan, dan volume. Daemon Docker menerima perintah dari Docker Client melalui CLI atau REST API, mengelola operasi Docker, dan berkomunikasi dengan daemon lain untuk mengelola layanan Docker.
Docker Client
Docker Client (docker
) adalah cara utama pengguna berinteraksi dengan Docker. Ketika Anda menggunakan perintah seperti docker run
atau docker build
, Docker Client mengirimkan perintah ini ke Docker Daemon, yang kemudian menjalankannya. Client Docker dapat berkomunikasi dengan lebih dari satu daemon.
Docker Registry
Docker Registry menyimpan Docker images. Docker Hub adalah registry publik yang paling dikenal dan digunakan untuk berbagi gambar secara luas. Namun, pengguna juga dapat menjalankan registry pribadi mereka sendiri. Ketika Anda menggunakan perintah docker pull
atau docker push
, images diambil atau dikirim ke registry yang ditentukan.
Cara Kerja Docker
Bayangin kamu mau bikin kue. Apa yang kamu butuh? Resep dong. Nah, dalam dunia Docker, resep untuk membuat aplikasi kamu itu namanya Dockerfile. Dockerfile ini kayak panduan step-by-step buat Docker dalam mengemas aplikasi kamu jadi satu paket lengkap yang siap dijalankan sebagai kontainer.
Apa Itu Dockerfile?
Dockerfile adalah sebuah file teks tanpa ekstensi yang berisi serangkaian instruksi untuk Docker tentang cara membangun sebuah Docker Image. Image yang dibangun ini nantinya bisa kamu gunakan untuk menjalankan aplikasi kamu di lingkungan apa pun.
Komponen Utama Dockerfile
Dockerfile terdiri dari berbagai instruksi yang dimengerti oleh Docker, seperti:
FROM
: Memulai dengan menentukan base image. Misal, FROM ubuntu:18.04
berarti kamu mulai dengan image Ubuntu versi 18.04 sebagai dasar.WORKDIR
: Mengatur direktori kerja di dalam image. Contoh, WORKDIR /app
akan membuat direktori /app
dan menjadikannya sebagai direktori kerja.COPY
atau ADD
: Menyalin file dan direktori dari komputer kamu ke dalam image. COPY . /app
berarti menyalin semua file di direktori saat ini ke dalam /app
di image.RUN
: Menjalankan perintah saat membangun image. Ini bisa untuk menginstal paket, membuat file, atau seting lainnya. Misal, RUN apt-get update && apt-get install -y git
.CMD
: Menentukan perintah default yang dijalankan saat kontainer di-start. Contoh, CMD ["python", "app.py"]
akan menjalankan app.py
dengan Python.Contoh Dockerfile Sederhana
Misalnya, kamu ingin membuat aplikasi web Python sederhana:
# Pilih base image
FROM python:3.8
# Set direktori kerja
WORKDIR /app
# Salin semua file ke dalam image
COPY . .
# Instal dependencies
RUN pip install -r requirements.txt
# Tentukan perintah yang dijalankan saat kontainer start
CMD ["python", "./app.py"]
Setelah Dockerfile kamu siap, kamu bisa membangun Docker Image dengan perintah:
docker build -t nama-aplikasi-kamu .
Tanda titik . di akhir berarti Docker akan mencari Dockerfile di direktori saat ini.
Dalam pengembangan aplikasi, sering kali kita butuh cara yang fleksibel untuk mengkonfigurasi aplikasi tergantung lingkungan tempat aplikasi itu dijalankan. Misalnya, setting database di lingkungan development bisa berbeda dengan di production. Nah, di sinilah keajaiban variabel lingkungan atau Environment Variables berperan dalam Docker.
Apa Itu Environment Variables?
Environment Variables adalah variabel yang dapat digunakan untuk menyetel konfigurasi yang bisa berubah-ubah dalam aplikasi tanpa harus mengubah kode. Dalam konteks Docker, environment variables bisa sangat berguna untuk menyesuaikan perilaku kontainer saat runtime, memudahkan konfigurasi aplikasi di berbagai lingkungan.
Menggunakan Environment Variables
Kamu bisa menentukan environment variables saat menjalankan kontainer dengan perintah docker run
menggunakan flag -e
atau --env
:
docker run -d -e "DATABASE_URL=jdbc:mysql://localhost:3306/mydb" my_web_app
Docker Image adalah template baca-saja yang berisi instruksi untuk membuat kontainer Docker. Images digunakan untuk menyimpan dan mengirimkan aplikasi dan lingkungan eksekusinya. Anda dapat membangun images sendiri atau menggunakan images yang dibuat oleh orang lain dan dihosting di registry.
Bayangin ini kayak blueprint atau resep dari aplikasi kita. Semua yang perlu ada di dalam kontainer, termasuk aplikasi dan lingkungannya, ada di sini.
Mengapa Docker Image itu Penting?
Coba bayangkan, kamu punya aplikasi yang ingin dijalankan di berbagai lingkungan, dari laptop pribadi, server di kantor, hingga cloud. Docker Image inilah yang memastikan aplikasi kamu bisa berjalan konsisten di semua tempat itu tanpa hambatan. Ia membungkus aplikasi kamu beserta semua yang dibutuhkan aplikasi itu untuk berjalan: kode aplikasi, runtime, library, variabel lingkungan, dan file konfigurasi lainnya. Semacam koper siap pakai yang tinggal dibawa ke mana saja.
Setelah kita ngomongin tentang Docker Images sebagai blueprint, sekarang kita masuk ke jantungnya Docker: Kontainer. Bayangin Docker Image itu seperti cetakan kue, sedangkan Docker Container itu kuenya sendiri. Kontainer adalah instansi nyata yang berjalan dari sebuah image, yang bisa kamu lihat, sentuh, dan tentu saja, jalankan aplikasi kamu di dalamnya.
Apa Itu Docker Container?
Docker Container adalah paket software ringan, portabel, dan isolasi yang memungkinkan aplikasi untuk berjalan dengan cepat dan konsisten di berbagai lingkungan komputasi. Kontainer Docker mengemas aplikasi dan semua yang dibutuhkan untuk menjalankan aplikasi tersebut, termasuk sistem operasi, kode aplikasi, runtime, sistem perpustakaan, dan file konfigurasi.
Mengelola Kontainer
Docker juga menyediakan berbagai perintah untuk mengelola kontainer, seperti:
docker ps
: Menampilkan semua kontainer yang berjalan.docker stop
: Menghentikan kontainer yang sedang berjalan.docker rm
: Menghapus kontainer yang sudah berhenti.docker logs
: Melihat log dari kontainer yang berjalan.Ketika kita berbicara tentang kontainer dan bagaimana mereka merevolusi cara kita mengembangkan, mengirimkan, dan menjalankan aplikasi, dua konsep penting yang harus kita pahami adalah Cgroups (Control Groups) dan Namespaces. Kedua mekanisme ini adalah fitur inti dari kernel Linux yang memungkinkan kontainerisasi bekerja dengan efisien dan aman.
Cgroups: Mengelola Sumber Daya
Cgroups, atau Control Groups, adalah fitur Linux yang memungkinkan pembagian dan pembatasan sumber daya sistem (seperti CPU, memori, bandwidth I/O) untuk sekelompok proses. Dengan Cgroups, kita bisa memastikan bahwa setiap kontainer hanya menggunakan bagian sumber daya yang telah ditentukan, mencegah satu kontainer dari mengambil sumber daya lebih dari yang seharusnya dan mempengaruhi kontainer atau proses lain pada sistem.
Namespaces: Isolasi Proses
Namespaces adalah fitur yang menyediakan isolasi untuk sekelompok proses, sehingga proses dalam satu namespace tidak bisa melihat atau berinteraksi dengan proses di namespace lain. Ini memungkinkan kita untuk menjalankan banyak kontainer pada satu sistem host tanpa kontainer tersebut saling mengganggu. Namespaces membungkus setiap kontainer dalam "dinding" virtualnya sendiri, menjaga isolasi lingkungan operasi.
Saat kita ngomongin kontainer dan aplikasi yang berjalan di dalamnya, nggak bisa lepas dari yang namanya jaringan atau network. Docker Network ini adalah fitur keren dari Docker yang memungkinkan kontainer-kontainer untuk berkomunikasi satu sama lain dan juga dengan dunia luar. Mirip seperti jaringan sosial tapi buat kontainer, gitu deh.
Kenapa Docker Network itu Penting?
Bayangin kalau setiap kontainer itu orang di suatu acara. Tanpa adanya jaringan, mereka bakal kesulitan berkomunikasi. Docker Network memastikan semua "orang" (baca: kontainer) ini bisa ngobrol dan berinteraksi dengan lancar, baik di dalam satu "ruangan" (host) maupun antar "ruangan" (host).
Ketika kita ngobrolin tentang Docker dan kontainer-kontainer kecenya, ada satu pertanyaan yang sering muncul: "Gimana sih cara kita nyimpen data yang bisa bertahan meskipun kontainernya udah dihapus?" Nah, jawabannya ada pada Docker Volumes.
Apa Itu Docker Volumes?
Docker Volumes adalah mekanisme yang disediakan oleh Docker untuk menyimpan atau membagikan data di antara kontainer-kontainer atau antara host dan kontainer. Volume ini diatur oleh Docker Daemon dan terpisah dari siklus hidup kontainer itu sendiri. Artinya, data yang kamu simpan di volume bakal tetap ada meski kontainer sudah lenyap.
Kenapa Pakai Docker Volumes?
Cara Kerja Docker Volumes
Saat kamu membuat volume dengan Docker, Docker Daemon akan menyimpan volume tersebut di dalam host filesystem tetapi di luar filesystem kontainer. Kamu bisa menentukan pathnya sendiri atau membiarkan Docker yang mengatur lokasinya.
My Personal Host Spesification
.-/+oossssoo+/-. raflihadiana@Kamado
`:+ssssssssssssssssss+:` -------------------
-+ssssssssssssssssssyyssss+- OS: Ubuntu 22.04.2 LTS on Windows 10 x86_64
.ossssssssssssssssssdMMMNysssso. Kernel: 5.15.133.1-microsoft-standard-WSL2
/ssssssssssshdmmNNmmyNMMMMhssssss/ Uptime: 12 hours, 20 mins
+ssssssssshmydMMMMMMMNddddyssssssss+ Packages: 723 (dpkg), 6 (snap)
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Shell: bash 5.1.16
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Theme: Adwaita [GTK3]
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Icons: Adwaita [GTK3]
ossyNMMMNyMMhsssssssssssssshmmmhssssssso Terminal: Windows Terminal
ossyNMMMNyMMhsssssssssssssshmmmhssssssso CPU: AMD Ryzen 5 4600H with Radeon Graphics (12) @ 2.994GHz
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ GPU: 4e65:00:00.0 Microsoft Corporation Device 008e
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Memory: 1158MiB / 3601MiB
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
+sssssssssdmydMMMMMMMMddddyssssssss+
/ssssssssssshdmNNNNmyNMMMMhssssss/
.ossssssssssssssssssdMMMNysssso.
-+sssssssssssssssssyyyssss+-
`:+ssssssssssssssssss+:`
.-/+oossssoo+/-.
You need to install Docker based on your Host OS. Then install gcloud client for accessing the Google Cloud Service Provider troughout terminal.
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world
Install Google Cloud CLI
Installation Link: https://cloud.google.com/sdk/docs/install
Download the binary by curl
curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-463.0.0-linux-x86_64.tar.gz
Extract the binary to be output /google-cloud-sdk
tar -xf google-cloud-cli-463.0.0-linux-x86_64.tar.gz
Execute the script
./google-cloud-sdk/install.sh
Start the project inisialization
./google-cloud-sdk/bin/gcloud init
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/...
Pick cloud project to use:
[1] boot-camp-gdsc
Your Google Cloud SDK is configured and ready to use!
In this demo we'll cover two application example to use.
This APIs was developed using:
- Node.Js v18.13.0
- Express v4.18.2
- Supabase
How to run this APIs manually
Clone this project to your GCP project’s repository
git clone https://github.com/hiskandaryps/express-example-app
Install all the required depedencies
npm install
Provide the required data for the .env
file, that consist of : SUPABASE_URL
, SUPABASE_KEY
, PORT
cp .env.example .env
Here's the value for the .env
PORT=3000
VERSION=v1
SUPABASE_URL=https://bwstuipaunilvlgodbzq.supabase.co
SUPABASE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJ3c3R1aXBhdW5pbHZsZ29kYnpxIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDY3OTg0MjEsImV4cCI6MjAyMjM3NDQyMX0.dDRT8SkJho2JYSuK0DGbW1drdybzZp7Nf88SU3kK96A
Run the back-end application
npm start
How to run Dockerize the App
Create Dockerfile to build the image
Initialize the file
cd express-example-app
touch Dockerfile
Configure the Dockerfile align with API Spec
FROM node:18-alpine
WORKDIR /opt/app
COPY . .
RUN npm install
EXPOSE 3000
CMD [ "npm", "start"]
Create a file called .dockerignore
.idea
.gitignore
node_modules/
Build the image
docker build -t gdsc/test .
Run the custom application image
docker run -p 8080:4000 -d gdsc/test
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
20d00bcf7d9d gdsc/test "docker-entrypoint.s…" 16 minutes ago Up 16 minutes 0.0.0.0:8080->3000/tcp, :::8080->3000/tcp laughing_margulis
This APIs was developed using:
- Node.Js v18.13.0
- Express v4.18.2
- PostgreSQL
How to run this APIs manually
Clone this project to your GCP project’s repository
git clone https://github.com/raflihadiana/nodejs-example-app
cd nodejs-example-app/src
Install all the required depedencies
npm install
Start a PostgreSQL databases and create the tables
docker run -it -e "POSTGRES_HOST_AUTH_METHOD=trust" -p 5432:5432 postgres
npm run migrate
Run the back-end application
npm start
How to run Dockerize the App
Create Dockerfile to build the image
Initialize the file
cd nodejs-example-app
touch Dockerfile
Configure the Dockerfile align with API Spec
FROM node:18.16.0-alpine3.17
RUN mkdir -p /opt/app
WORKDIR /opt/app
COPY src/package.json src/package-lock.json .
RUN npm install
COPY src/ .
EXPOSE 3000
CMD [ "npm", "start"]
Create a file called .dockerignore
.git
.gitignore
src/node_modules/
Build the image
docker build -t addressbook .
Run the custom application image
Run the image with customized port to expose
docker run -it -p 3000:3000 addressbook
Run the image with docker compose
for network & DB Configuration
# docker-compose.yml
version: "3.9"
services:
postgres:
image: postgres:latest
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- '5432:5432'
volumes:
- addressbook-db:/var/lib/postgresql/data
addressbook:
build:
context: .
environment:
DB_SCHEMA: postgres
DB_USER: postgres
DB_PASSWORD: postgres
DB_HOST: postgres
depends_on:
- postgres
ports:
- '3000:3000'
volumes:
addressbook-db:
docker compose run addressbook npm run migrate
docker compose up --build
Validate by Postman testing
If you want to stop the container
docker compose down
Push the Image to Dockerhub
Login in the terminal to your Docker Account
docker login
Change the Docker Image tag align with Dockerhub Repository
docker tag gdsc/test raflihadiana/gdsc:test
Push to the Default Registry Dockerhub
docker push raflihadiana/gdsc:test
The push refers to repository [docker.io/raflihadiana/gdsc]
def9ba6d524e: Pushed
295b4b0b0a9e: Pushed
a75f8c5b7682: Pushed
b325b33b9813: Pushed
4a0d315ad53e: Pushed
29e213bad130: Pushed
d4fc045c9e3a: Pushed
test: digest: sha256:1d9dd48767e5d9351cbbbae9236cda8c57e87586a7b1569e339c0a6db8e30b6f size: 1786
Push the Image to GCP Artifact Repository
Go to your Google Cloud Console then Create a repository for your image
Copy this path as the configured location server
Mine is asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2
Authenticate yourself in CLI for Registry Access
gcloud auth asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2
Change your local image tag to your image domain path
docker tag gdsc/test asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2:test
Push your image to configured location repository path
docker push asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2:test
The push refers to repository [asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2/version]
def9ba6d524e: Pushed
295b4b0b0a9e: Pushed
a75f8c5b7682: Pushed
b325b33b9813: Pushed
4a0d315ad53e: Pushed
29e213bad130: Pushed
d4fc045c9e3a: Pushed
test: digest: sha256:1d9dd48767e5d9351cbbbae9236cda8c57e87586a7b1569e339c0a6db8e30b6f size: 1786
Validate the pushed image in your Artifact Registry Console
Docker Credentials Error
Error Statement:
Error saving credentials: error storing credentials – err: exec: “docker-credential-desktop”: executable file not found in $PATH, out:
There are several ways to resolve this issue. One easiest way would be making any of the following changes in ~/.docker/config.json
file.
For more detail solution you can check it here.