<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Docker on kenji.blog</title><link>http://kenji.blog/id/tags/docker/</link><description>Recent content in Docker on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>id</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 01:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/id/tags/docker/index.xml" rel="self" type="application/rss+xml"/><item><title>Langkah-langkah Membangun Lingkungan Pengembangan Lokal yang Dapat Direproduksi Menggunakan Docker</title><link>http://kenji.blog/id/p/docker-reproducible-local-dev-environment/</link><pubDate>Sun, 13 Sep 2026 01:00:00 +0900</pubDate><guid>http://kenji.blog/id/p/docker-reproducible-local-dev-environment/</guid><description>&lt;img src="http://kenji.blog/p/docker-reproducible-local-dev-environment/img/eyecatch.jpg" alt="Featured image of post Langkah-langkah Membangun Lingkungan Pengembangan Lokal yang Dapat Direproduksi Menggunakan Docker" />&lt;h2 id="1-pendahuluan-keluar-dari-siklus-di-lingkungan-saya-berjalan-normal">1. Pendahuluan: Keluar dari Siklus &amp;ldquo;Di Lingkungan Saya Berjalan Normal&amp;rdquo;
&lt;/h2>&lt;p>Dalam dunia pengembangan perangkat lunak, masalah &amp;ldquo;Di lingkungan saya berjalan normal (It works on my machine)&amp;rdquo; yang disebabkan oleh perbedaan lingkungan antar pengembang, telah lama menjadi faktor yang membuang-buang waktu dalam banyak proyek. Perbedaan OS, versi bahasa yang diinstal, dependensi pustaka, konflik dengan alat yang diinstal secara global, dll. membuat lingkungan lokal selalu dihadapkan pada &amp;ldquo;ketidakpastian status&amp;rdquo;.&lt;/p>
&lt;p>Hal yang dapat menyelesaikan masalah ini dari akarnya adalah teknologi kontainer seperti &lt;strong>Docker&lt;/strong>, dan paradigma &lt;strong>Infrastructure as Code (IaC)&lt;/strong>. Dengan mengontainerisasi lingkungan pengembangan lokal, kita dapat mewujudkan isolasi di tingkat OS, serta memungkinkan sistem kontrol versi pada lingkungan itu sendiri bersama dengan basis kode.&lt;/p>
&lt;p>Dalam artikel ini, kita akan membahas secara mendalam, lengkap dengan perspektif matematis dan mekanisme teknis yang mendasarinya, mengenai langkah-langkah membangun &lt;strong>&amp;ldquo;lingkungan pengembangan lokal yang dapat direproduksi, sehingga siapa pun, kapan pun, dan di mesin mana pun ketika dihidupkan, akan menghasilkan kondisi yang persis sama&amp;rdquo;&lt;/strong>, dengan memanfaatkan Docker, Docker Compose, dan VSCode DevContainers.&lt;/p>
&lt;hr>
&lt;h2 id="2-kedekatan-antara-infrastructure-as-code-iac-dan-teknologi-kontainer">2. Kedekatan antara Infrastructure as Code (IaC) dan Teknologi Kontainer
&lt;/h2>&lt;h3 id="prinsip-iac-dan-penerapannya-di-lingkungan-lokal">Prinsip IaC dan Penerapannya di Lingkungan Lokal
&lt;/h3>&lt;p>Infrastructure as Code (IaC) adalah pendekatan di mana pengelolaan dan penyediaan konfigurasi infrastruktur dilakukan melalui file definisi yang dapat dibaca mesin, bukan melalui proses manual. Prinsip inti IaC mencakup elemen-elemen berikut:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Pendekatan Deklaratif (Declarative Approach)&lt;/strong>: Mendefinisikan &amp;ldquo;seperti apa status akhir seharusnya&amp;rdquo; daripada &amp;ldquo;bagaimana cara mengubah status tersebut&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Idempotensi (Idempotency)&lt;/strong>: Tidak peduli seberapa sering skrip dieksekusi, hasil yang sama (status) selalu terjamin.&lt;/li>
&lt;li>&lt;strong>Kontrol Versi (Version Control)&lt;/strong>: Status infrastruktur disimpan sebagai kode dalam VCS seperti Git, yang memungkinkan pelacakan riwayat perubahan dan tinjauan rekan (peer review).&lt;/li>
&lt;/ol>
&lt;p>Mempraktikkan IaC dalam lingkungan pengembangan lokal berarti mengodekan &amp;ldquo;bentuk ideal&amp;rdquo; dari lingkungan pengembangan menggunakan &lt;code>Dockerfile&lt;/code>, &lt;code>docker-compose.yml&lt;/code>, dan &lt;code>devcontainer.json&lt;/code>. Dengan ini, anggota baru yang bergabung dalam tim dapat merasakan pengalaman pengenalan (onboarding) di mana mereka hanya perlu meng-clone repositori dan menjalankan satu perintah untuk dapat langsung memulai pengembangan.&lt;/p>
&lt;h3 id="fitur-kernel-yang-mendukung-teknologi-kontainer">Fitur Kernel yang Mendukung Teknologi Kontainer
&lt;/h3>&lt;p>Berbeda dengan virtualisasi tipe hypervisor seperti Mesin Virtual (VM), teknologi kontainer adalah teknologi virtualisasi ringan yang mengisolasi proses sambil berbagi kernel OS host. Untuk mewujudkan hal ini, fungsi-fungsi kernel Linux berikut ini banyak digunakan:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Namespaces&lt;/strong>: Menyediakan tampilan yang independen dari sumber daya sistem (PID, jaringan, titik pemasangan (mount points), pengguna, dll.) untuk setiap proses.&lt;/li>
&lt;li>&lt;strong>Cgroups (Control Groups)&lt;/strong>: Melakukan pembatasan dan alokasi sumber daya fisik yang dapat digunakan oleh proses (CPU, memori, I/O disk, dll.).&lt;/li>
&lt;li>&lt;strong>UnionFS (Union File System)&lt;/strong>: Teknologi yang memungkinkan tumpang tindih secara transparan dari beberapa struktur direktori (lapisan/layer) agar tampak sebagai satu sistem file tunggal. Lapisan citra (image layer) Docker bergantung pada teknologi ini.&lt;/li>
&lt;/ul>
&lt;p>Mari pertimbangkan model matematika dari pembatasan sumber daya. Misalkan total kapasitas memori mesin host adalah $M_{\text{total}}$, dan batas memori untuk $n$ buah kontainer yang berjalan di host adalah $m_i$. Kondisi yang diperlukan agar sistem dapat berjalan stabil, dengan memperhitungkan basis memori $M_{\text{os}}$ yang dikonsumsi oleh OS host dan proses lainnya, dapat direpresentasikan oleh pertidaksamaan berikut:&lt;/p>
$$ \sum_{i=1}^{n} m_i \le M_{\text{total}} - M_{\text{os}} $$&lt;p>Dengan menggunakan Cgroups untuk mendefinisikan $m_i$ secara ketat bagi setiap kontainer, saat terjadi kebocoran memori pada kontainer tertentu, kita dapat mencegah kontainer lain atau keseluruhan sistem host ikut mati akibat OOM (Out Of Memory) Killer.&lt;/p>
&lt;hr>
&lt;h2 id="3-desain-dockerfile-yang-efisien-menguasai-build-multi-tahap-multi-stage-build">3. Desain Dockerfile yang Efisien: Menguasai Build Multi-tahap (Multi-stage Build)
&lt;/h2>&lt;p>Langkah pertama menuju lingkungan yang dapat direproduksi adalah mendesain &lt;code>Dockerfile&lt;/code> yang mendefinisikan lingkungan eksekusi aplikasi. Di sini, dengan mengambil Python (FastAPI) sebagai contoh, kita akan membahas praktik terbaik untuk Dockerfile yang aman dan ringan dengan memanfaatkan &lt;strong>build multi-tahap&lt;/strong>.&lt;/p>
&lt;p>Build multi-tahap adalah teknik yang memisahkan lingkungan build (lingkungan berat yang mencakup kompiler dan alat pengembangan) dari lingkungan eksekusi (lingkungan ringan yang hanya berisi hasil akhir yang diperlukan) dengan menggunakan beberapa perintah &lt;code>FROM&lt;/code> di dalam sebuah &lt;code>Dockerfile&lt;/code> tunggal.&lt;/p>
&lt;h3 id="dockerfile-praktis-untuk-python-fastapi">Dockerfile Praktis untuk Python FastAPI
&lt;/h3>&lt;p>Kode berikut ini merupakan contoh &lt;code>Dockerfile&lt;/code> tingkat lanjut yang menggabungkan pengelolaan dependensi menggunakan Poetry dengan build multi-tahap.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Stage 1: Builder (Lingkungan Build)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> python:3.11-slim AS builder&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Pengaturan variabel lingkungan yang diperlukan&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PYTHONUNBUFFERED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PYTHONDONTWRITEBYTECODE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_VERSION&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>.6.1 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_HOME&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/opt/poetry&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_VIRTUALENVS_IN_PROJECT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">POETRY_NO_INTERACTION&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Menginstal dependensi paket&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> apt-get update &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> apt-get install -y --no-install-recommends &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> curl build-essential &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> curl -sSL https://install.python-poetry.org &lt;span class="p">|&lt;/span> python3 - &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> apt-get clean &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/lib/apt/lists/*&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$POETRY_HOME&lt;/span>&lt;span class="s2">/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Menyalin dan menginstal file dependensi&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install --no-root --only main&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Stage 2: Runtime (Lingkungan Eksekusi)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># ---------------------------------------------------------&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> python:3.11-slim AS runtime&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PYTHONUNBUFFERED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PYTHONDONTWRITEBYTECODE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/app/.venv/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Membuat pengguna dengan hak akses non-privelege minimum&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> groupadd -r appuser &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> useradd -r -g appuser appuser&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Hanya menyalin lingkungan virtual (dependensi) dari builder&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --from&lt;span class="o">=&lt;/span>builder --chown&lt;span class="o">=&lt;/span>appuser:appuser /app/.venv /app/.venv&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Menyalin kode aplikasi&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --chown&lt;span class="o">=&lt;/span>appuser:appuser ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Beralih ke pengguna non-privilege&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">USER&lt;/span>&lt;span class="s"> appuser&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Perintah default saat kontainer dijalankan&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENTRYPOINT&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;uvicorn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;src.main:app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--host&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--port&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="evaluasi-matematis-ukuran-citra-karena-build-multi-tahap">Evaluasi Matematis Ukuran Citra karena Build Multi-tahap
&lt;/h3>&lt;p>Misalkan ukuran citra ketika di-build pada satu tahap adalah $S_{\text{single}}$, dan ukuran citra saat build multi-tahap diterapkan adalah $S_{\text{multi}}$. Tingkat pengurangan ukuran $R$ dapat dihitung sebagai berikut:&lt;/p>
$$ R = \left( 1 - \frac{S_{\text{multi}}}{S_{\text{single}}} \right) \times 100 \ (\%) $$&lt;p>Sebagai contoh, jika $S_{\text{single}}$ mencakup citra dasar OS (sekitar 110MB), paket pengembangan (gcc, dll. sekitar 150MB), Poetry itu sendiri (sekitar 40MB), pustaka dependensi proyek (sekitar 80MB), dan kode sumber (sekitar 5MB), sehingga total menjadi 385MB.
Di sisi lain, pada $S_{\text{multi}}$, hanya pustaka dependensi (80MB) dan kode sumber (5MB) yang disalin ke citra dasar (110MB), sehingga totalnya menjadi 195MB.&lt;/p>
$$ R = \left( 1 - \frac{195}{385} \right) \times 100 \approx 49.35\% $$&lt;p>Dengan menerapkan build multi-tahap seperti ini, kita dapat mengurangi ukuran citra sekitar setengahnya. Pengurangan ukuran citra akan berdampak langsung pada pemendekan waktu pull dari registry, penghematan kapasitas disk, serta peningkatan keamanan dengan mengurangi area serangan (Attack Surface).&lt;/p>
&lt;hr>
&lt;h2 id="4-orkestrasi-berbagai-kontainer-menggunakan-docker-compose">4. Orkestrasi Berbagai Kontainer Menggunakan Docker Compose
&lt;/h2>&lt;p>Dalam pengembangan aplikasi web modern, arsitektur layanan mikro yang menggabungkan banyak komponen seperti server Web, basis data, dan server cache adalah hal yang umum. Untuk mengelola semua ini secara terpusat di lingkungan lokal, kita menggunakan &lt;code>docker-compose.yml&lt;/code>.&lt;/p>
&lt;p>Kali ini, kita akan membangun sistem dengan struktur tiga lapisan di lingkungan lokal: &amp;ldquo;Web (FastAPI)&amp;rdquo;, &amp;ldquo;Basis Data (PostgreSQL)&amp;rdquo;, dan &amp;ldquo;Cache (Redis)&amp;rdquo;.&lt;/p>
&lt;h3 id="diagram-arsitektur-mermaid">Diagram Arsitektur (Mermaid)
&lt;/h3>&lt;p>Diagram blok di bawah ini mengilustrasikan hubungan antara masing-masing kontainer, jaringan, dan volume pada mesin lokal.&lt;/p>
&lt;pre class="mermaid">
graph TD
User[&amp;#34;Mesin Host (Browser/curl)&amp;#34;] --&amp;gt;|Localhost:8000| Web[&amp;#34;Kontainer Web FastAPI&amp;#34;]
subgraph &amp;#34;Jaringan Docker Bridge (app-network)&amp;#34;
Web --&amp;gt;|Port 5432| DB[&amp;#34;Kontainer PostgreSQL&amp;#34;]
Web --&amp;gt;|Port 6379| Redis[&amp;#34;Kontainer Redis&amp;#34;]
end
DB --&amp;gt; Volume1[&amp;#34;Volume Bernama (postgres_data)&amp;#34;]
Redis --&amp;gt; Volume2[&amp;#34;Volume Bernama (redis_data)&amp;#34;]
HostDir[&amp;#34;Kode Sumber Host (./src)&amp;#34;] -.-&amp;gt;|Bind Mount| Web
&lt;/pre>
&lt;h3 id="implementasi-dan-penjelasan-mendalam-tentang-docker-composeyml">Implementasi dan Penjelasan Mendalam tentang docker-compose.yml
&lt;/h3>&lt;p>Berikut disajikan contoh &lt;code>docker-compose.yml&lt;/code> yang kokoh, yang dapat diandalkan untuk membangun lingkungan yang nyata.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.8&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">web&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">context&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">target&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">runtime&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_web&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;8000:8000&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">./src:/app/src:ro &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Melakukan mount kode host sebagai read-only (untuk hot reload)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">REDIS_URL=redis://redis:6379/0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env_file&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">.env&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">db&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_healthy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_started&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;uvicorn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;src.main:app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--host&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--port&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;8000&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--reload&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">db&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">postgres:15-alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_db&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;5432:5432&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_USER&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">postgres&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_PASSWORD&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${POSTGRES_PASSWORD}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">POSTGRES_DB&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${POSTGRES_DB}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">postgres_data:/var/lib/postgresql/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">healthcheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;CMD-SHELL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;pg_isready -U postgres -d ${POSTGRES_DB}&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">interval&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">5s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">timeout&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">5s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">retries&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">redis:7-alpine&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dev_redis&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;6379:6379&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">redis_data:/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">app-network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;redis-server&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;--appendonly&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;yes&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">postgres_data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">redis_data&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">networks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app-network&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">driver&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">bridge&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="volume-volumes-dan-persistensi-data">Volume (Volumes) dan Persistensi Data
&lt;/h3>&lt;p>Secara prinsip, kontainer bersifat &amp;ldquo;stateless (tanpa status)&amp;rdquo; dan &amp;ldquo;ephemeral (berumur pendek)&amp;rdquo;. Saat kontainer dihancurkan, data di dalamnya juga akan hilang. Untuk menyimpan data basis data atau cache, kita perlu melakukan mount ke area sistem file mesin host pada kontainer.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Bind Mount&lt;/strong>: Pada layanan &lt;code>web&lt;/code> di atas, pengaturan &lt;code>./src:/app/src:ro&lt;/code> merupakan Bind Mount. Direktori spesifik di host dipetakan secara langsung ke dalam kontainer. Ini digunakan untuk langsung mencerminkan pengeditan kode lokal ke dalam kontainer (hot reload). Praktik terbaik dari perspektif keamanan adalah dengan memberikan opsi &lt;code>:ro&lt;/code> (Read-Only) sehingga kontainer tidak dapat mengubah kode sumber pada host.&lt;/li>
&lt;li>&lt;strong>Volume Bernama (Named Volume)&lt;/strong>: Contohnya adalah &lt;code>postgres_data&lt;/code> dan &lt;code>redis_data&lt;/code>. Ini adalah area yang dikelola secara internal oleh Docker (seperti &lt;code>/var/lib/docker/volumes/&lt;/code>), memiliki performa I/O yang lebih baik daripada bind mount, dan dapat menyerap perbedaan sistem file di berbagai OS. Untuk memastikan keberlangsungan basis data, pastikan untuk menggunakan opsi ini.&lt;/li>
&lt;/ul>
&lt;h3 id="jaringan-networking-dan-penemuan-layanan-service-discovery">Jaringan (Networking) dan Penemuan Layanan (Service Discovery)
&lt;/h3>&lt;p>Docker Compose secara default akan membuat jaringan bridge sendiri untuk tiap proyek. Inilah jaringan &lt;code>app-network&lt;/code> pada contoh di atas.
Kontainer-kontainer yang berada di jaringan yang sama dapat saling meresolusi nama (resolusi DNS) bukan dengan alamat IP, melainkan dengan nama layanannya (contoh: &lt;code>db&lt;/code>, &lt;code>redis&lt;/code>) sebagai nama host.
Misalnya, dari kontainer Web, kita bisa mengakses basis data menggunakan URL &lt;code>postgresql://postgres:password@db:5432/mydb&lt;/code>. Hal ini memungkinkan pergantian tujuan koneksi secara transparan dengan menggunakan variabel lingkungan, baik di lingkungan lokal maupun lingkungan produksi, tanpa perlu mengubah kode infrastruktur.&lt;/p>
&lt;h3 id="pemeriksaan-kesehatan-healthcheck-dan-kontrol-urutan-booting">Pemeriksaan Kesehatan (Healthcheck) dan Kontrol Urutan Booting
&lt;/h3>&lt;p>Arahan &lt;code>depends_on&lt;/code> memang mengontrol urutan pengaktifan kontainer, namun jika kita hanya menentukan &lt;code>depends_on&lt;/code>, kontainer Web mungkin akan aktif saat &amp;ldquo;kontainer DB diaktifkan&amp;rdquo;. Padahal, proses inisialisasi basis data (seperti peluncuran proses PostgreSQL atau persiapan tabel) membutuhkan waktu beberapa detik, dan dapat menyebabkan koneksi dari kontainer Web menuju DB mengalami kegagalan/error.
Untuk mencegah hal tersebut, kita mendefinisikan &lt;code>healthcheck&lt;/code>, dan dengan menyetel &lt;code>condition: service_healthy&lt;/code>, kita bisa menunda aktifnya kontainer Web sampai &amp;ldquo;DB terkonfirmasi berada dalam status siap menerima permintaan koneksi&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="5-manajemen-variabel-lingkungan-dan-keamanan-env">5. Manajemen Variabel Lingkungan dan Keamanan (.env)
&lt;/h2>&lt;p>Memasukkan informasi rahasia ke dalam &lt;code>docker-compose.yml&lt;/code> secara langsung, seperti kata sandi basis data maupun kunci API, adalah pola anti yang mutlak harus dihindari. Sebaliknya, gunakan file variabel lingkungan &lt;code>.env&lt;/code> untuk menyuntikkan nilai-nilai tersebut.&lt;/p>
&lt;p>Buat file &lt;code>.env&lt;/code> di akar proyek (project root).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># file .env (Pastikan untuk menambahkannya ke .gitignore agar tidak dikelola oleh Git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">POSTGRES_PASSWORD&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">supersecretpassword&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">POSTGRES_DB&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">devdb&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">API_SECRET_KEY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">dev_secret_key_12345&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Docker Compose secara default akan membaca file &lt;code>.env&lt;/code> yang berada di direktori eksekusi dan mengekspansi &lt;em>placeholder&lt;/em> &lt;code>${VAR_NAME}&lt;/code> di dalam file YAML. Pendekatan ini memungkinkan pengelolaan yang aman dari nilai-nilai konfigurasi yang berbeda untuk berbagai lingkungan, seperti lokal, staging, dan lingkungan produksi, tanpa perlu memodifikasi kode infrastruktur.&lt;/p>
&lt;hr>
&lt;h2 id="6-pengalaman-pengembangan-terbaik-melalui-vscode-devcontainers">6. Pengalaman Pengembangan Terbaik melalui VSCode DevContainers
&lt;/h2>&lt;p>Sampai di sini, kita telah sukses membangun ekosistem backend yang kokoh memakai Docker. Meski begitu, masih ada langkah ekstra yang bisa dilakukan. Dengan memanfaatkan fitur &lt;strong>VSCode DevContainers (Remote - Containers)&lt;/strong>, kita dapat menjalankan bagian backend dari editor (VSCode) secara langsung dari dalam kontainer.&lt;/p>
&lt;p>Melalui hal ini, kita bahkan tidak perlu menginstal Python maupun Node.js ke mesin lokal. Seluruh komponen, mulai dari Linter (flake8/eslint), formatters (black/prettier), hingga ekstensi IDE, bisa didefinisikan ke dalam basis kode (codebase) dan dibagikan ke seluruh tim.&lt;/p>
&lt;h3 id="konfigurasi-devcontainerjson">Konfigurasi devcontainer.json
&lt;/h3>&lt;p>Buatlah direktori bernama &lt;code>.devcontainer&lt;/code> di akar proyek, lalu letakkan file konfigurasi di dalamnya.&lt;/p>
&lt;p>&lt;code>.devcontainer/devcontainer.json&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Lingkungan Dev Python FastAPI&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;dockerComposeFile&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;../docker-compose.yml&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;service&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;web&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;workspaceFolder&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/app&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;customizations&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;vscode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;settings&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;python.defaultInterpreterPath&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/app/.venv/bin/python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;python.formatting.provider&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;black&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;editor.formatOnSave&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;extensions&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.vscode-pylance&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ms-python.black-formatter&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tamasfe.even-better-toml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;forwardPorts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">8000&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5432&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6379&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;remoteUser&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;appuser&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;postCreateCommand&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;poetry install&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan menyertakan file tersebut di repositori, begitu VSCode dipakai untuk membuka proyek, akan muncul dialog &amp;ldquo;Reopen in Container&amp;rdquo;. Cukup satu klik, seluruh kontainer yang diperlukan bakal aktif, ekstensi akan dipasang, dan kita siap memulai kegiatan koding secara instan. Ini benar-benar mirip sebuah sihir.&lt;/p>
&lt;hr>
&lt;h2 id="7-pemodelan-performa-dan-urutan-proses-permintaan-request">7. Pemodelan Performa dan Urutan Proses Permintaan (Request)
&lt;/h2>&lt;p>Kita akan menggunakan diagram urutan untuk meninjau siklus hidup pemrosesan permintaan (request) pada aplikasi Web dalam lingkungan pengembangan lokal yang telah dibuat, lalu kita telaah model matematik dari performanya.&lt;/p>
&lt;h3 id="diagram-urutan-alur-permintaan--request-flow">Diagram Urutan (Alur Permintaan / Request Flow)
&lt;/h3>&lt;pre class="mermaid">
sequenceDiagram
participant Client as &amp;#34;Browser / VSCode&amp;#34;
participant Web as &amp;#34;FastAPI (Web)&amp;#34;
participant Redis as &amp;#34;Cache Redis&amp;#34;
participant DB as &amp;#34;PostgreSQL&amp;#34;
Client-&amp;gt;&amp;gt;Web: &amp;#34;GET /api/users/123&amp;#34;
activate Web
Web-&amp;gt;&amp;gt;Redis: &amp;#34;Cek Cache untuk user:123&amp;#34;
activate Redis
alt &amp;#34;Cache Hit (Data tersedia)&amp;#34;
Redis--&amp;gt;&amp;gt;Web: &amp;#34;Kembalikan Data User dari Cache&amp;#34;
Web--&amp;gt;&amp;gt;Client: &amp;#34;200 OK (Respons Cepat)&amp;#34;
else &amp;#34;Cache Miss (Data tidak tersedia)&amp;#34;
Redis--&amp;gt;&amp;gt;Web: &amp;#34;Null (Tidak Ditemukan)&amp;#34;
deactivate Redis
Web-&amp;gt;&amp;gt;DB: &amp;#34;SELECT * FROM users WHERE id = 123&amp;#34;
activate DB
DB--&amp;gt;&amp;gt;Web: &amp;#34;Kembalikan Baris Database&amp;#34;
deactivate DB
Web-&amp;gt;&amp;gt;Redis: &amp;#34;SET Data user:123 (TTL: 60s)&amp;#34;
activate Redis
Redis--&amp;gt;&amp;gt;Web: &amp;#34;OK&amp;#34;
deactivate Redis
Web--&amp;gt;&amp;gt;Client: &amp;#34;200 OK (Respons Standar)&amp;#34;
end
deactivate Web
&lt;/pre>
&lt;h3 id="model-matematis-untuk-penundaan-proses-latensi">Model Matematis untuk Penundaan Proses (Latensi)
&lt;/h3>&lt;p>Mari rumuskan model matematis dari waktu pemrosesan permintaan rerata $T_{\text{total}}$ dalam ekosistem ini.
Waktu latensi untuk setiap bagian didefinisikan sebagai berikut:&lt;/p>
&lt;ul>
&lt;li>$T_{\text{net}}$: Latensi jaringan di antara klien dengan kontainer Web&lt;/li>
&lt;li>$T_{\text{app}}$: Waktu proses esensial (pure) di bagian aplikasi (serialisasi dll.)&lt;/li>
&lt;li>$T_{\text{cache}}$: Waktu baca-tulis dari dan ke Redis&lt;/li>
&lt;li>$T_{\text{db}}$: Waktu pengeksekusian kueri menuju PostgreSQL&lt;/li>
&lt;li>$p_{\text{miss}}$: Persentase kegagalan cache (Cache miss rate) ($0 \le p_{\text{miss}} \le 1$)&lt;/li>
&lt;/ul>
&lt;p>Dengan begitu, nilai harapan untuk waktu respon rerata bisa dirumuskan menjadi:&lt;/p>
$$ T_{\text{total}} = T_{\text{net}} + T_{\text{app}} + T_{\text{cache}} + p_{\text{miss}} \times (T_{\text{db}} + T_{\text{cache\_write}}) $$&lt;p>Untuk lingkungan pengembangan lokal (di dalam Docker), $T_{\text{net}}$ nilainya akan nyaris 0. Namun, ada aspek yang butuh perhatian serius: &lt;strong>performa I/O saat melakukan Bind Mount&lt;/strong>. Pada Docker Desktop versi Windows atau macOS, waktu tunda (overhead) akibat aktivitas berbagi file antara host OS dan mesin virtual (kontainer) berisiko membengkakkan $T_{\text{app}}$ (waktu bacaan kode dll.). Sebagai solusi atas masalah ini, kami sangat merekomendasikan pemakaian DevContainers seperti dibahas di atas agar seluruh kode sumber ditampung pada named volume, atau memosisikan Docker Engine supaya berjalan secara asli pada sistem WSL2 (Windows Subsystem for Linux 2).&lt;/p>
&lt;hr>
&lt;h2 id="8-mengoptimalkan-kinerja-build-docker-strategi-lapisan-cache-layer-cache">8. Mengoptimalkan Kinerja Build Docker: Strategi Lapisan Cache (Layer Cache)
&lt;/h2>&lt;p>Saat menulis Dockerfile, durasi penyusunan (build time) bisa berubah secara drastis apabila kita memahami cara kerja sistem &amp;ldquo;layer cache&amp;rdquo;.
Untuk tiap baris instruksi yang ada di Dockerfile (contoh: &lt;code>FROM&lt;/code>, &lt;code>RUN&lt;/code>, &lt;code>COPY&lt;/code>), Docker akan membuat sistem file pembanding (lapisan/layer), kemudian mempertahankannya sebagai cache. Ketika dilakukan penyusunan ulang, ia akan memakai kembali layer dari cache yang tiada perubahan.&lt;/p>
&lt;p>Prinsip pentingnya: &lt;strong>&amp;ldquo;Tuliskan berurutan mulai dari yang paling jarang mengalami perubahan&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Mari modelkan dampak perubahan kode sumber terhadap waktu build. Waktu build keseluruhan adalah $T_{\text{build}}$, lama eksekusi tiap tahapan $T_{\text{layer}_i}$, dan probabilitas tersedianya cache sebagai variabel boolean $c_i \in \{0, 1\}$ (bernilai 1 jika cache ditemukan).&lt;/p>
$$ T_{\text{build}} = T_{\text{init}} + \sum_{i=1}^{n} (1 - c_i) \times T_{\text{layer}_i} $$&lt;p>Sekali saja terjadi gagal memanggil cache di lapisan tertentu $k$ ($c_k = 0$), cache di setiap lapisan berikutnya ($j > k$) akan otomatis tak beroperasi ($c_j = 0$).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Praktik Buruk (Mendahulukan penyalinan source code)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan posisi seperti ini, mengubah satu kalimat di kode sumber akan membuat &lt;code>COPY&lt;/code> awal gagal mengakses cache, sehingga &lt;code>RUN poetry install&lt;/code> yang memakan waktu akan terus-terusan dieksekusi.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Praktik Terbaik (Menyelesaikan pengaturan dependensi terlebih dulu)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> pyproject.toml poetry.lock ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> poetry install&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./src /app/src&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Apabila disusun begini, kendati kode sumbernya diubah, cache layer untuk proses instalasi dependensi (&lt;code>poetry install&lt;/code>) akan teraplikasikan ($c_i = 1$). Pada akhirnya, proses penyusunan (build) bisa dipersingkat sedemikian jauh; dari hitungan menit berubah jadi sekadar beberapa detik saja.&lt;/p>
&lt;hr>
&lt;h2 id="9-penyelesaian-masalah-dan-tips">9. Penyelesaian Masalah dan Tips
&lt;/h2>&lt;p>Berikut daftar masalah dan solusi yang lazim ditemukan sewaktu menjalankan ekosistem lokal.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Error bentrok port (Port conflict error)&lt;/strong>
Jika terjadi pesan error layaknya &lt;code>Bind for 0.0.0.0:8000 failed: port is already allocated&lt;/code>, kemungkinan besar port tersebut sedang dipakai di mesin lokal. Solusi ringkasnya adalah mengganti angka pada port host, dengan menjadikannya &lt;code>ports: - &amp;quot;8080:8000&amp;quot;&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Kapasitas disk habis&lt;/strong>
Pemakaian Docker dalam kurun waktu lama tanpa dirawat bisa membuat berbagai volume dan citra yang tidak penting lagi (Dangling Images/Volumes) kian menumpuk. Disk bahkan bisa termakan sampai belasan GB. Cobalah sering-sering mengeksekusi ini guna menata ulang sistem:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker system prune -a --volumes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>Problem hak akses file (Permission issues)&lt;/strong>
Apabila kamu menerapkan Bind Mount pada Linux, user pemilik file yang digenerate di dalam kontainer akan ditetapkan sebagai &lt;code>root&lt;/code>, yang membuat sang file kadang tak dapat dimodifikasi di pihak host. Langkah penanganannya, yaitu bikinlah profil pengguna non-privilege di &lt;code>Dockerfile&lt;/code>, lantas serasikan UID/GID dengan profil kamu sendiri yang ada di OS (contoh: 1000:1000).&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="10-penutup-peran-penjaminan-keberulangan-demi-efisiensi-perkembangan-proyek">10. Penutup: Peran Penjaminan Keberulangan demi Efisiensi Perkembangan Proyek
&lt;/h2>&lt;p>Pemaduan Docker, Docker Compose, serta VSCode DevContainers berhasil menciptakan ruang kerja lokal tangguh dan kebal masalah, sebuah metode sempurna yang membuat &lt;strong>&amp;ldquo;siapa pun yang merilis lingkungan, kondisinya akan tetap sama dengan sebelumnya&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Hadirnya pendekatan IaC (Infrastructure as Code) di ekosistem pengembangan tidak melulu demi mempersingkat langkah-langkah pengaturan pada tahap pertama. Konsep ini justru berfungsi sebagai tameng yang menghapus kecemasan terhadap resiko yang menyertai tiap perubahan setup, membuat eksplorasi teknologi baru bertambah gampang, memfasilitasi peralihan secara mulus ke proses CI/CD, dan secara menakjubkan mendongkrak laju sekaligus standar siklus proyek.&lt;/p>
&lt;p>Praktikkan segala panduan mengenai penyederhanaan kapasitas citra dengan build multi-tahap, pengelolaan status via healthcheck, ataupun pemanfaatan cache di Dockerfile yang semuanya sudah terjabarkan di dalam esai ini. Cobalah secepatnya untuk menciptakan pengalaman pengembangan (DX: Developer Experience) bermutu tinggi bagi karya-karyamu.&lt;/p></description></item><item><title>Panduan Pengaturan Lingkungan Pengembangan Ultimate untuk WSL2 (Windows Subsystem for Linux)</title><link>http://kenji.blog/id/p/wsl2-ultimate-development-setup-guide/</link><pubDate>Sat, 12 Sep 2026 23:00:00 +0900</pubDate><guid>http://kenji.blog/id/p/wsl2-ultimate-development-setup-guide/</guid><description>&lt;img src="http://kenji.blog/p/wsl2-ultimate-development-setup-guide/img/eyecatch.jpg" alt="Featured image of post Panduan Pengaturan Lingkungan Pengembangan Ultimate untuk WSL2 (Windows Subsystem for Linux)" />&lt;p>&amp;ldquo;WSL2 (Windows Subsystem for Linux 2)&amp;rdquo;, yang menyediakan lingkungan pengembangan native Linux di Windows, telah menjadi alat yang sangat penting dalam pengembangan perangkat lunak modern. Namun, ada perbedaan besar dalam kinerja dan pengalaman pengembangan antara menggunakannya dalam status default dan memahaminya serta menyesuaikan arsitekturnya dengan tepat.&lt;/p>
&lt;p>Artikel ini membahas segala hal mulai dari penjelasan arsitektur yang menjadi inti dari WSL2, hingga pengaturan untuk memaksimalkan kinerja, membangun lingkungan terminal yang nyaman, integrasi mulus dengan Docker dan VS Code, dan pengaturan jaringan lanjutan. Kami akan menjelaskan secara menyeluruh semua langkah untuk membangun &amp;ldquo;Lingkungan Pengembangan Ultimate&amp;rdquo; yang dibutuhkan oleh insinyur profesional dalam volume lebih dari 10.000 karakter.&lt;/p>
&lt;hr>
&lt;h2 id="1-arsitektur-wsl2-dan-evolusi-dari-wsl1">1. Arsitektur WSL2 dan Evolusi dari WSL1
&lt;/h2>&lt;p>Untuk sepenuhnya memaksimalkan potensi WSL2, penting untuk memahami terlebih dahulu struktur internalnya. Pendekatan untuk menjalankan binari Linux di Windows sangat berbeda antara WSL generasi pertama (WSL1) dan WSL2.&lt;/p>
&lt;h3 id="wsl1-lapisan-konversi-panggilan-sistem">WSL1: Lapisan Konversi Panggilan Sistem
&lt;/h3>&lt;p>WSL1 mengadopsi mekanisme untuk mengonversi (menerjemahkan) panggilan sistem Linux ke API NT Windows secara real time. Ini memiliki keuntungan berupa overhead sumber daya yang sangat kecil karena tidak menggunakan mesin virtual (VM). Namun, sulit untuk sepenuhnya meniru panggilan sistem yang kompleks seperti operasi I/O sistem file, dan menyebabkan penurunan kinerja yang drastis, terutama pada proses yang menangani sejumlah besar file kecil, seperti &lt;code>npm install&lt;/code> pada Node.js atau operasi repositori Git.&lt;/p>
&lt;h3 id="wsl2-vm-utilitas-ringan-dan-kernel-linux-penuh">WSL2: VM Utilitas Ringan dan Kernel Linux Penuh
&lt;/h3>&lt;p>Pada WSL2, arsitekturnya telah diperbarui, dan kernel Linux asli yang dibangun oleh Microsoft berjalan secara langsung di atas &lt;strong>&amp;ldquo;VM Utilitas Ringan&amp;rdquo; yang menggunakan subset dari arsitektur Hyper-V&lt;/strong>. Ini menjamin kompatibilitas 100% untuk panggilan sistem dan secara dramatis meningkatkan kinerja I/O file dibandingkan dengan WSL1 dengan menggunakan disk virtual (VHDX) yang memanfaatkan sistem file ext4 native Linux.&lt;/p>
&lt;p>Diagram Mermaid di bawah ini menunjukkan perbedaan struktural antara WSL1 dan WSL2.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
subgraph &amp;#34;Lingkungan OS Windows&amp;#34;
A[&amp;#34;Kernel NT Windows&amp;#34;]
A --&amp;gt; F[&amp;#34;Sistem File NTFS (Drive C:)&amp;#34;]
end
subgraph &amp;#34;Arsitektur WSL2&amp;#34;
B[&amp;#34;Hypervisor Hyper-V&amp;#34;]
B --&amp;gt; C[&amp;#34;VM Utilitas Ringan&amp;#34;]
C --&amp;gt; D[&amp;#34;Kernel Linux (Microsoft)&amp;#34;]
D --&amp;gt; E[&amp;#34;Ruang Pengguna Ubuntu (glibc, bash, dll.)&amp;#34;]
D --&amp;gt; G[&amp;#34;Disk Virtual ext4 (.vhdx)&amp;#34;]
end
A -.-&amp;gt;|&amp;#34;Berbagi File Jaringan Protokol Plan 9 (9P)&amp;#34;| D
style B fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
&lt;/pre>
&lt;p>Pelajaran penting yang dapat diambil dari struktur ini adalah &lt;strong>&amp;ldquo;Akses ke file di sisi Linux (di dalam VHDX) sangat cepat, namun akses ke file di sisi Windows (&lt;code>/mnt/c/&lt;/code>) sangat lambat karena harus melalui protokol 9P&amp;rdquo;&lt;/strong>. Kode sumber proyek harus selalu ditempatkan di bawah direktori home (&lt;code>~&lt;/code>) pada sisi WSL.&lt;/p>
&lt;hr>
&lt;h2 id="2-analisis-matematika-kinerja-mengapa-wsl2-cepat">2. Analisis Matematika Kinerja: Mengapa WSL2 Cepat?
&lt;/h2>&lt;p>Mari kita evaluasi peningkatan kinerja WSL2 secara kuantitatif menggunakan model matematika. Salah satu operasi yang paling memakan waktu dalam pengembangan perangkat lunak adalah proses yang melibatkan sejumlah besar I/O file (misalnya, menginstal pustaka atau mem-build).&lt;/p>
&lt;p>Total waktu eksekusi $T_{total}$ untuk suatu proses dinyatakan sebagai jumlah waktu komputasi oleh CPU $T_{compute}$ dan waktu yang dibutuhkan untuk disk I/O $T_{io}$.&lt;/p>
$$ T_{total} = T_{compute} + T_{io} $$&lt;p>Dalam kasus WSL1, karena ada overhead untuk mengonversi operasi sisi Linux ke operasi NTFS, waktu I/O dimodelkan sebagai berikut. Di sini, $n$ adalah jumlah operasi file, $t_{ntfs\_syscall}$ adalah waktu eksekusi panggilan sistem sisi Windows, dan $t_{trans}$ adalah overhead dari lapisan konversi.&lt;/p>
$$ T_{wsl1\_io} = \sum_{i=1}^{n} (t_{ntfs\_syscall_i} + t_{trans_i}) $$&lt;p>Di sisi lain, pada kasus WSL2, karena kernel mengeluarkan I/O secara langsung ke sistem file ext4, overheadnya hanya berupa penundaan yang sangat kecil $t_{virt}$ akibat virtualisasi.&lt;/p>
$$ T_{wsl2\_io} = \sum_{i=1}^{n} (t_{ext4_i} + t_{virt_i}) $$&lt;p>Pada sistem file umum, karena $t_{ext4} \ll t_{ntfs\_syscall} + t_{trans}$, jika $n$ sangat besar (melakukan puluhan hingga ratusan ribu operasi file), perbedaan waktu I/O antara WSL1 dan WSL2 akan melebar secara eksponensial.&lt;/p>
&lt;p>Selain itu, jika rasio overhead komputasi CPU di lingkungan virtualisasi adalah $\rho$, dengan virtualisasi berbantuan perangkat keras terbaru (Intel VT-x / AMD-V), rasio tersebut akan berada pada kisaran $\rho \approx 0.01 \sim 0.03$ (1 hingga 3%). Oleh karena itu, bahkan pada tugas komputasi murni, ia akan memberikan kinerja sebesar $97\% \sim 99\%$ yang sebanding dengan lingkungan native Linux.&lt;/p>
&lt;hr>
&lt;h2 id="3-instalasi-dan-pembangunan-fondasi">3. Instalasi dan Pembangunan Fondasi
&lt;/h2>&lt;p>Pada Windows 10/11, instalasi WSL2 telah menjadi sangat sederhana. Cukup buka PowerShell dengan hak administrator dan jalankan perintah berikut.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># WSL2 dan Ubuntu akan diinstal secara default&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Jika Anda ingin menentukan distribusi tertentu&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Dapat diperiksa dengan wsl --list --online&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">24.04&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Setelah penginstalan dan melalui proses restart, Anda akan diminta untuk mengatur nama pengguna dan kata sandi UNIX saat pertama kali dijalankan. Pengguna ini terpisah dari pengguna Windows dan hanya valid di dalam WSL.&lt;/p>
&lt;p>Jika Anda sudah menggunakan WSL1, konversikan ke WSL2 dengan perintah berikut.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Mengonversi distribusi yang ada ke WSL2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-set-version&lt;/span> &lt;span class="n">Ubuntu&lt;/span> &lt;span class="mf">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Menjadikan WSL2 sebagai versi default untuk distribusi yang akan ditambahkan di masa mendatang&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-set-default-version&lt;/span> &lt;span class="mf">2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="4-rahasia-kontrol-sumber-daya-wslconfig-dan-wslconf">4. Rahasia Kontrol Sumber Daya: .wslconfig dan wsl.conf
&lt;/h2>&lt;p>Salah satu jebakan terbesar di WSL2 adalah &amp;ldquo;konsumsi memori tak terbatas (pembengkakan proses Vmmem)&amp;rdquo;. Karena WSL2 menggunakan cache halaman dari kernel Linux, setiap kali I/O dilakukan, ia akan memakan memori host (Windows) tanpa batas. Untuk mencegah hal ini, perlu dilakukan pembatasan sumber daya melalui file konfigurasi.&lt;/p>
&lt;p>File konfigurasi WSL2 dibagi menjadi dua: &lt;strong>&lt;code>.wslconfig&lt;/code> yang memengaruhi Windows secara keseluruhan&lt;/strong>, dan &lt;strong>&lt;code>wsl.conf&lt;/code> yang memengaruhi internal setiap distribusi&lt;/strong>.&lt;/p>
&lt;h3 id="41-wslconfig-sisi-windows">4.1. .wslconfig (Sisi Windows)
&lt;/h3>&lt;p>Buat file di direktori profil pengguna Windows (&lt;code>C:\Users\&amp;lt;Nama Pengguna&amp;gt;\.wslconfig&lt;/code>) untuk mengontrol alokasi sumber daya ke VM.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># C:\Users\&amp;lt;Nama Pengguna&amp;gt;\.wslconfig&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[wsl2]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Jumlah memori maksimum yang dialokasikan untuk VM. Disarankan sekitar 50% hingga 75% dari total memori host&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">memory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">16GB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Jumlah core CPU yang digunakan (Jika dihilangkan, semua core akan digunakan)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">processors&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ukuran file swap&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">swap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">8GB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Lokasi penyimpanan file swap (Jika ingin menghemat ruang di drive C)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># swapfile=D:\\wsl\\swap.vhdx&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Aktifkan penerusan localhost (Untuk mengakses WSL melalui localhost dari sisi Windows)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">localhostForwarding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Secara otomatis melepaskan memori (Hanya Windows 11)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Secara dinamis melepaskan cache halaman untuk mencegah pembengkakan Vmmem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">autoMemoryReclaim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">dropcache&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[experimental]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Fitur jaringan lanjutan tersedia pada Windows 11 22H2 dan lebih baru&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Hal ini memungkinkan dukungan IPv6 dan berbagi alamat IP yang sama antara WSL dan Windows&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">networkingMode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">mirrored&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">dnsTunneling&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">firewall&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">autoProxy&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-wslconf-sisi-linux">4.2. wsl.conf (Sisi Linux)
&lt;/h3>&lt;p>Edit &lt;code>/etc/wsl.conf&lt;/code> di dalam WSL untuk mengontrol perilaku khusus distribusi.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># /etc/wsl.conf (Diedit di dalam WSL)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[network]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Nonaktifkan pembuatan /etc/resolv.conf yang dibuat secara otomatis saat WSL dijalankan&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Berguna jika Anda ingin mengatur DNS kustom (misalnya: 8.8.8.8)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">generateResolvConf&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Atur nama host kustom&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">hostname&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">WSL-DevNode&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[automount]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pengaturan saat memasang drive Windows&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">enabled&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">options&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;metadata,uid=1000,gid=1000,umask=022&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ubah titik pemasangan (mount point) drive C dari /mnt/c ke /c (untuk mempersingkat jalur)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">root&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[boot]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Aktifkan systemd (WSL 0.67.6 atau lebih baru)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ini memungkinkan snap dan berbagai daemon (seperti Docker) untuk berjalan secara native&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">systemd&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[user]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pengguna default untuk login&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">kenji&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Untuk menerapkan pengaturan ini, Anda perlu menjalankan &lt;code>wsl --shutdown&lt;/code> di PowerShell untuk menghentikan sepenuhnya VM WSL sebelum menghidupkannya kembali.&lt;/p>
&lt;hr>
&lt;h2 id="5-lingkungan-terminal-ultimate-zsh--powerlevel10k">5. Lingkungan Terminal Ultimate: Zsh + Powerlevel10k
&lt;/h2>&lt;p>Produktivitas tidak akan meningkat jika Anda tetap menggunakan bash bawaan. Kami akan membangun prompt terkuat dengan menggabungkan Zsh, yang menawarkan fitur pelengkapan otomatis dan visibilitas yang kuat, dengan tema super cepat &amp;ldquo;Powerlevel10k&amp;rdquo;.&lt;/p>
&lt;h3 id="51-pengenalan-dan-pengaturan-windows-terminal">5.1. Pengenalan dan Pengaturan Windows Terminal
&lt;/h3>&lt;p>Instal &amp;ldquo;Windows Terminal&amp;rdquo; dari Microsoft Store. Buka pengaturan JSON (&lt;code>settings.json&lt;/code>), tetapkan profil default ke WSL (Ubuntu), dan ubah font menjadi Nerd Font untuk pengembangan (misalnya: &lt;code>HackGen Console NF&lt;/code> atau &lt;code>MesloLGS NF&lt;/code>).&lt;/p>
&lt;h3 id="52-menginstal-zsh-dan-oh-my-zsh">5.2. Menginstal Zsh dan Oh My Zsh
&lt;/h3>&lt;p>Jalankan perintah berikut di terminal WSL.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Memperbarui paket dan menginstal Zsh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt update &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> sudo apt upgrade -y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install -y zsh git curl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Menjalankan skrip instalasi Oh My Zsh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sh -c &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-menginstal-powerlevel10k-dan-plugin">5.3. Menginstal Powerlevel10k dan Plugin
&lt;/h3>&lt;p>Kami akan memperkenalkan plugin (penyorotan sintaksis dan pelengkapan otomatis input) untuk lebih meningkatkan Zsh, serta tema Powerlevel10k.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Powerlevel10k&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone --depth&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> https://github.com/romkatv/powerlevel10k.git &lt;span class="si">${&lt;/span>&lt;span class="nv">ZSH_CUSTOM&lt;/span>&lt;span class="k">:-&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="p">/.oh-my-zsh/custom&lt;/span>&lt;span class="si">}&lt;/span>/themes/powerlevel10k
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zsh-autosuggestions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/zsh-users/zsh-autosuggestions &lt;span class="si">${&lt;/span>&lt;span class="nv">ZSH_CUSTOM&lt;/span>&lt;span class="k">:-&lt;/span>&lt;span class="p">~/.oh-my-zsh/custom&lt;/span>&lt;span class="si">}&lt;/span>/plugins/zsh-autosuggestions
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zsh-syntax-highlighting&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/zsh-users/zsh-syntax-highlighting.git &lt;span class="si">${&lt;/span>&lt;span class="nv">ZSH_CUSTOM&lt;/span>&lt;span class="k">:-&lt;/span>&lt;span class="p">~/.oh-my-zsh/custom&lt;/span>&lt;span class="si">}&lt;/span>/plugins/zsh-syntax-highlighting
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Edit &lt;code>~/.zshrc&lt;/code> untuk mengaktifkan tema dan plugin.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Perubahan pada ~/.zshrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ZSH_THEME&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;powerlevel10k/powerlevel10k&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Tambahkan ke array plugin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">plugins&lt;/span>&lt;span class="o">=(&lt;/span>git zsh-autosuggestions zsh-syntax-highlighting&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Simpan dan jalankan &lt;code>source ~/.zshrc&lt;/code>, panduan konfigurasi Powerlevel10k (&lt;code>p10k configure&lt;/code>) akan dimulai. Ikuti petunjuk di layar untuk menyesuaikan prompt Anda sendiri (gaya prompt, ada/tidaknya ikon, informasi yang ditampilkan, dll.). Nama cabang dan status Git, versi Node.js, waktu eksekusi perintah, dll. akan ditampilkan secara real-time, sehingga secara dramatis meningkatkan efisiensi pengembangan Anda.&lt;/p>
&lt;hr>
&lt;h2 id="6-vs-code-remote---integrasi-mulus-dengan-wsl">6. VS Code Remote - Integrasi Mulus dengan WSL
&lt;/h2>&lt;p>Dalam pengembangan menggunakan WSL2, ekstensi &amp;ldquo;Remote - WSL&amp;rdquo; adalah mekanisme yang memungkinkan akses mulus ke file di dalam WSL dari IDE (Visual Studio Code) yang diinstal pada sisi Windows.&lt;/p>
&lt;h3 id="penjelasan-arsitektur">Penjelasan Arsitektur
&lt;/h3>&lt;p>Diagram urutan di bawah ini menunjukkan bagaimana VS Code berkomunikasi dengan WSL2.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
autonumber
participant U as &amp;#34;Pengembang&amp;#34;
participant V as &amp;#34;UI VS Code (Windows)&amp;#34;
participant S as &amp;#34;Server VS Code (WSL2)&amp;#34;
participant F as &amp;#34;Sistem File ext4 (WSL2)&amp;#34;
U-&amp;gt;&amp;gt;V: &amp;#34;Ketik `code .` di Terminal WSL&amp;#34;
V-&amp;gt;&amp;gt;S: &amp;#34;Membangun Koneksi RPC melalui Vsock&amp;#34;
Note over V,S: Berkomunikasi menggunakan Hyper-V socket alih-alih TCP/IP
S-&amp;gt;&amp;gt;F: &amp;#34;Membaca File Sumber / Menjalankan Linter&amp;#34;
F--&amp;gt;&amp;gt;S: &amp;#34;Mengembalikan Data &amp;amp; Analisis&amp;#34;
S--&amp;gt;&amp;gt;V: &amp;#34;Mengalirkan hasil Language Server ke UI&amp;#34;
V--&amp;gt;&amp;gt;U: &amp;#34;Menampilkan penyorotan sintaksis &amp;amp; kesalahan&amp;#34;
&lt;/pre>
&lt;p>VS Code di sisi Windows hanya berfungsi sebagai &amp;ldquo;klien tipis (UI)&amp;rdquo;, dan semua tugas berat seperti Language Server, debugger, dan eksekusi terminal diproses oleh &amp;ldquo;VS Code Server&amp;rdquo; di sisi WSL. Hal ini memungkinkan lingkungan yang bersih hanya di sisi WSL tanpa perlu menginstal Node.js atau Python di sisi Windows.&lt;/p>
&lt;h3 id="pengaturan-vs-code-yang-wajib">Pengaturan VS Code yang Wajib
&lt;/h3>&lt;p>Instal &lt;strong>&amp;ldquo;WSL&amp;rdquo; (ms-vscode-remote.remote-wsl)&lt;/strong> dari &amp;ldquo;Extensions&amp;rdquo; di VS Code. Setelah itu, cukup pindah ke direktori proyek di terminal WSL dan jalankan &lt;code>code .&lt;/code>, dan VS Code di sisi Windows akan diluncurkan dengan direktori tersebut terbuka.&lt;/p>
&lt;p>&lt;strong>Poin Penting (Masalah Kode Baris Baru):&lt;/strong>
Kode baris baru berbeda antara Windows dan Linux (Windows menggunakan &lt;code>CRLF&lt;/code>, Linux menggunakan &lt;code>LF&lt;/code>). Saat mengembangkan di WSL, pastikan untuk mengatur pengaturan &lt;code>core.autocrlf&lt;/code> Git dan pengaturan default file VS Code ke &lt;code>LF&lt;/code>. Jika Anda mengabaikan hal ini, Anda akan diganggu oleh kesalahan misterius saat menjalankan skrip shell atau kontainer Docker.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pengaturan kode baris baru Git di sisi WSL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global core.autocrlf input
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Tambahkan juga hal berikut ini ke &lt;code>settings.json&lt;/code> (pengaturan remote) di VS Code.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;files.eol&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;\n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;terminal.integrated.defaultProfile.linux&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;zsh&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-optimasi-docker-desktop-dan-integrasi-wsl2">7. Optimasi Docker Desktop dan Integrasi WSL2
&lt;/h2>&lt;p>Ada dua pendekatan utama untuk menggunakan Docker di lingkungan WSL2.&lt;/p>
&lt;ol>
&lt;li>Menginstal &lt;strong>Docker Desktop for Windows&lt;/strong> dan mengaktifkan fitur integrasi WSL2.&lt;/li>
&lt;li>Menginstal langsung &lt;strong>Docker Engine Native&lt;/strong> di dalam WSL2 (seperti Ubuntu).&lt;/li>
&lt;/ol>
&lt;h3 id="pendekatan-1-docker-desktop-direkomendasikan">Pendekatan 1: Docker Desktop (Direkomendasikan)
&lt;/h3>&lt;p>Ini sering kali direkomendasikan karena mudah dikelola dengan GUI dan akses transparan ke kontainer antara Windows dan WSL. Periksa hal-hal berikut dari Pengaturan (Settings) Docker Desktop.&lt;/p>
&lt;ul>
&lt;li>Centang &lt;code>General&lt;/code> -&amp;gt; &lt;code>Use the WSL 2 based engine&lt;/code>.&lt;/li>
&lt;li>Centang &lt;code>Resources&lt;/code> -&amp;gt; &lt;code>WSL Integration&lt;/code> -&amp;gt; &lt;code>Enable integration with my default WSL distro&lt;/code> dan nyalakan tombol geser untuk distribusi (Ubuntu) yang Anda gunakan.&lt;/li>
&lt;/ul>
&lt;p>Ini memungkinkan Anda menjalankan perintah &lt;code>docker&lt;/code> langsung dari terminal WSL2, dan komunikasi dengan daemon Docker akan dialihkan melalui VM ringan khusus (&lt;code>docker-desktop&lt;/code> dan &lt;code>docker-desktop-data&lt;/code>) yang dikelola oleh Docker Desktop.&lt;/p>
&lt;h3 id="pendekatan-2-pengenalan-langsung-docker-engine-native">Pendekatan 2: Pengenalan Langsung Docker Engine Native
&lt;/h3>&lt;p>Jika Anda memiliki batasan jaringan perusahaan (seperti menghindari versi berbayar Docker Desktop) atau ingin mengurangi overhead kinerja hingga batas ekstrem, aktifkan &lt;code>systemd&lt;/code> di &lt;code>/etc/wsl.conf&lt;/code> lalu instal Docker sebagai server Ubuntu murni.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Kutipan dari prosedur instalasi resmi Docker di WSL2 Ubuntu dengan systemd diaktifkan&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get install ca-certificates curl gnupg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo install -m &lt;span class="m">0755&lt;/span> -d /etc/apt/keyrings
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -fsSL https://download.docker.com/linux/ubuntu/gpg &lt;span class="p">|&lt;/span> sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chmod a+r /etc/apt/keyrings/docker.gpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Menambahkan repositori&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="s2">&amp;#34;deb [arch=&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>dpkg --print-architecture&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34; signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>. /etc/os-release &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$VERSION_CODENAME&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34; stable&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Menambahkan pengguna saat ini ke grup docker (untuk menjalankan tanpa sudo)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo usermod -aG docker &lt;span class="nv">$USER&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Setelah restart, &lt;code>systemctl start docker&lt;/code> akan berfungsi persis seperti di lingkungan Linux native dan menawarkan kinerja yang tinggi.&lt;/p>
&lt;hr>
&lt;h2 id="8-integrasi-kunci-ssh-otentikasi-mulus-di-windows-dan-wsl">8. Integrasi Kunci SSH: Otentikasi Mulus di Windows dan WSL
&lt;/h2>&lt;p>Saat melakukan kloning SSH dari Git atau koneksi SSH ke server jarak jauh, mengelola kunci SSH secara terpisah di sisi Windows dan sisi WSL sangatlah merepotkan. Untuk menyeimbangkan antara keamanan dan kenyamanan, kami akan mengonfigurasi jembatan untuk menghubungkan agen SSH (atau manajer kata sandi seperti 1Password) yang berjalan di Windows ke sisi WSL.&lt;/p>
&lt;p>Di sini, kita akan membahas pendekatan yang paling aman dan modern, yaitu menggunakan &lt;strong>fitur agen SSH 1Password&lt;/strong> atau &lt;strong>OpenSSH Authentication Agent dari Windows&lt;/strong> dan meneruskannya ke soket domain UNIX WSL2 menggunakan &lt;code>npiperelay&lt;/code> atau &lt;code>socat&lt;/code>.&lt;/p>
&lt;h3 id="penerusan-soket-ssh-agent">Penerusan Soket ssh-agent
&lt;/h3>&lt;p>Biasanya, agen SSH yang disediakan sebagai Named Pipe (pipa bernama) di Windows perlu dikonversi ke file soket di sisi WSL. Anda dapat menggunakan &lt;code>wsl-ssh-agent&lt;/code> atau fitur yang disediakan oleh 1Password untuk membuatnya lebih mudah.&lt;/p>
&lt;p>Di layar pengaturan 1Password, aktifkan &amp;ldquo;Developer&amp;rdquo; -&amp;gt; &amp;ldquo;Gunakan Agen SSH&amp;rdquo;.
Selanjutnya, tambahkan pengaturan berikut ke &lt;code>~/.zshrc&lt;/code> atau &lt;code>~/.bashrc&lt;/code> di sisi WSL untuk mengikat soket secara otomatis saat login.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Menambahkan ke ~/.zshrc (Contoh jika menggunakan Agen SSH 1Password)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">SSH_AUTH_SOCK&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nv">$HOME&lt;/span>/.ssh/agent.sock
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Jika soket tidak ada atau proses tidak terikat saat WSL dijalankan, teruskan menggunakan socat dan npiperelay&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">ALREADY_RUNNING&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>ps -aux &lt;span class="p">|&lt;/span> grep &lt;span class="s2">&amp;#34;[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> wc -l&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> &lt;span class="nv">$ALREADY_RUNNING&lt;/span> -eq &lt;span class="m">0&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> -S &lt;span class="nv">$SSH_AUTH_SOCK&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> rm &lt;span class="nv">$SSH_AUTH_SOCK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Memulai socat di latar belakang dan menghubungkan Named Pipe di sisi Windows ke soket UNIX di sisi WSL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">(&lt;/span>setsid socat UNIX-LISTEN:&lt;span class="nv">$SSH_AUTH_SOCK&lt;/span>,fork EXEC:&lt;span class="s2">&amp;#34;npiperelay.exe -ei -s //./pipe/openssh-ssh-agent&amp;#34;&lt;/span>,nofork &lt;span class="p">&amp;amp;&lt;/span>&lt;span class="o">)&lt;/span> &amp;gt;/dev/null 2&amp;gt;&lt;span class="p">&amp;amp;&lt;/span>&lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>*Anda harus menginstal &lt;code>npiperelay.exe&lt;/code> dan menambahkannya ke path di sisi Windows terlebih dahulu.&lt;/p>
&lt;p>Setelah pengaturan ini selesai, ketika Anda menjalankan &lt;code>ssh-add -l&lt;/code> dari terminal WSL, daftar kunci publik dari kunci SSH yang terdaftar di 1Password atau di sisi Windows akan ditampilkan. Dengan demikian, Anda dapat lolos otentikasi dengan aman tanpa harus menyalin file kunci privat ke dalam WSL.&lt;/p>
&lt;hr>
&lt;h2 id="9-pemeliharaan-optimasi-kompaksi-vhdx-yang-membengkak">9. Pemeliharaan: Optimasi (Kompaksi) VHDX yang Membengkak
&lt;/h2>&lt;p>Salah satu kelemahan terbesar WSL2 adalah bahwa &amp;ldquo;ukuran file dari disk virtual di sisi Windows (.vhdx) tidak menyusut secara otomatis bahkan jika Anda menghapus image Docker atau menghapus file&amp;rdquo;. Jika Anda terus mengembangkan untuk jangka waktu yang lama, file ext4.vhdx dapat membengkak hingga puluhan atau ratusan GB.&lt;/p>
&lt;p>Untuk mengosongkan ruang disk, Anda perlu mengoptimalkan (Compact) VHDX dari sisi Windows secara berkala.&lt;/p>
&lt;ol>
&lt;li>Pertama, matikan WSL sepenuhnya.
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-shutdown&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>Buka PowerShell dengan hak administrator, dan jalankan perintah &lt;code>diskpart&lt;/code> di bawah ini, atau perintah &lt;code>Optimize-VHD&lt;/code> dari modul Hyper-V (yang terakhir hanya dapat digunakan jika Hyper-V diaktifkan).&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Jika modul Hyper-V tersedia&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Optimize-VHD&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$env:LOCALAPPDATA&lt;/span>&lt;span class="s2">\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState\ext4.vhdx&amp;#34;&lt;/span> &lt;span class="n">-Mode&lt;/span> &lt;span class="n">Full&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Jika menggunakan diskpart&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">diskpart&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Masukkan secara interaktif dalam prompt di bawah ini&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="nb">select &lt;/span>&lt;span class="n">vdisk&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="s2">&amp;#34;C:\Users\&amp;lt;Nama Pengguna&amp;gt;\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState\ext4.vhdx&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">attach&lt;/span> &lt;span class="n">vdisk&lt;/span> &lt;span class="n">readonly&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">compact&lt;/span> &lt;span class="n">vdisk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">detach&lt;/span> &lt;span class="n">vdisk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DISKPART&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">exit&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dengan melakukan operasi ini secara berkala, Anda bisa memulihkan ruang kosong di drive C yang terbuang percuma.&lt;/p>
&lt;hr>
&lt;h2 id="10-penutup">10. Penutup
&lt;/h2>&lt;p>WSL2 telah sepenuhnya melampaui batasan sebagai &amp;ldquo;sekadar bonus Linux yang berjalan di Windows&amp;rdquo;, dan telah berevolusi menjadi platform pengembangan yang kuat yang tidak kalah, atau bahkan lebih baik dari mesin macOS atau mesin Linux native.&lt;/p>
&lt;p>Dengan menerapkan semua pengaturan yang dijelaskan dalam artikel ini (optimasi sumber daya dengan &lt;code>.wslconfig&lt;/code>, peningkatan terminal dengan Zsh + Powerlevel10k, akses transparan dengan VS Code Remote, serta integrasi SSH dan pemeliharaan VHDX), Anda akan dapat melengkapi &amp;ldquo;Lingkungan Pengembangan Ultimate&amp;rdquo; yang bebas stres, cepat, dan aman.&lt;/p>
&lt;p>Meskipun membutuhkan sedikit upaya untuk menyiapkan lingkungan tersebut, begitu Anda menetapkan pengaturannya, produktivitas rekayasa perangkat lunak Anda akan meningkat secara dramatis di masa mendatang. Kami harap Anda mengeksplorasi penyesuaian lebih lanjut berdasarkan panduan ini sesuai dengan proyek dan preferensi Anda.&lt;/p></description></item></channel></rss>