Chapter sebelumnya menutup dengan satu kebutuhan yang belum terjawab: image yang sama perlu berperilaku berbeda — berbeda antara saat dibangun dan saat dijalankan, berbeda antara versi satu dan versi dua. Kebutuhan itu dijawab Dockerfile lewat sepasang instruksi yang tampak serupa namun hidup di dua dunia berbeda: ENV menetapkan variabel yang menempel pada image hingga container menyala, sedangkan ARG menerima parameter yang hanya hidup selama proses build berlangsung. Budi akan memakai keduanya sekaligus pada myapp — mode aplikasi lewat ENV, nomor versi lewat ARG — dan di sepanjang jalan kita akan menyaksikan jejak masing-masing instriksi pada metadata image, termasuk satu jejak yang wajib membuat kita berhati-hati dengan rahasia.
ENV: Variabel yang Menempel pada Image #
Instruksi ENV NODE_ENV=production menulis satu pasangan key-value ke konfigurasi image. Konsekuensinya menjalar ke dua dunia sekaligus: setiap instruksi Dockerfile setelah baris itu dapat membaca nilainya saat build, dan setiap container yang lahir dari image tersebut mewarisi variabel itu di environment-nya saat berjalan. Dockerfile myapp kini berbentuk berikut — perhatikan bahwa nomor versi tidak lagi ditulis mati pada LABEL, melainkan diambil dari ARG yang kita bedah di bagian berikutnya:
# syntax=docker/dockerfile:1
# Basis: runtime Node.js 22 di atas Alpine
FROM node:22-alpine
# Versi sebagai parameter build dengan nilai bawaan
ARG VERSI=1.0
# Metadata image — versi diambil dari parameter build
LABEL version=$VERSI deskripsi="API kecil milik Budi"
# Mode aplikasi: berlaku saat build dan saat container berjalan
ENV NODE_ENV=production
# Direktori kerja untuk semua instruksi berikutnya
WORKDIR /app
# Berkas aplikasi disalin dari build context
COPY package.json server.js ./
# Cap mode dan versi pada berkas kecil yang bisa dibaca dari container
RUN echo "MODE: ${NODE_ENV} / VERSI: ${VERSI}" > /app/mode.txt
# Port yang didengarkan aplikasi
EXPOSE 8000
# Perintah bawaan saat container berjalan
CMD ["node", "server.js"]Mari kita telaah dua baris yang baru di atas:
ENV NODE_ENV=production— menetapkan variabelNODE_ENV, konvensi ekosistem Node.js yang dibaca framework seperti Express untuk memilih perilaku produksi. Nilainya menempel pada image, bukan pada satu instruksi tertentu.RUN echo "MODE: ${NODE_ENV} / VERSI: ${VERSI}" > /app/mode.txt— instruksiRUNberjalan di dalam shell yang environment-nya sudah memuat seluruhENVdanARGyang berlaku pada titik itu; shell meresolusi kedua variabel saat perintah dieksekusi, dan hasilnya membeku sebagai berkas pada layer. KarenaRUNmenghasilkan layer — satu dari tiga instruksi pembentuk isi dari Chapter Struktur Dockerfile — berkasmode.txtini menjadi bukti permanen di dalam image.
ARG: Parameter yang Hanya Hidup Saat Build #
ARG VERSI=1.0 mendeklarasikan parameter build bernama VERSI dengan nilai bawaan 1.0. Nilai bawaan itu hanya cadangan — saat build dijalankan, nilai dapat diganti lewat flag --build-arg tanpa menyentuh satu baris Dockerfile pun. Budi membangun versi 2.0 dari myapp:
$ docker build --build-arg VERSI=2.0 -t myapp:2.0 .Output yang Dihasilkan:
[+] Building 1.2s (13/13) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 638B 0.0s
=> [internal] load metadata for docker.io/library/node:22-alpine 0.7s
=> [1/7] FROM docker.io/library/node:22-alpine 0.0s
=> => resolve docker.io/library/node:22-alpine 0.7s
=> [2/7] LABEL version=2.0 deskripsi=API kecil milik Budi 0.0s
=> [3/7] ENV NODE_ENV=production 0.0s
=> [4/7] WORKDIR /app 0.0s
=> [5/7] COPY package.json server.js ./ 0.1s
=> [6/7] RUN echo "MODE: ${NODE_ENV} / VERSI: ${VERSI}" > /app/mode.txt 0.0s
=> [7/7] EXPOSE 8000 0.0s
=> exporting layers 0.2s
=> => exporting layers 0.1s
=> => writing image sha256:9f4c8e2b1d7a3e5f7a9c1b3d5f7a9c1e3b5d7f2a4c6e8b0d2f4a6c8e0b2d4f6a8 0.1s
=> => naming to docker.io/library/myapp:2.0 0.0sMari kita telaah jejak nilai 2.0 pada output di atas:
--build-arg VERSI=2.0— nilai dari command line mengalahkan bawaan1.0di Dockerfile; tanpa flag ini,docker build -t myapp:2.0 .tetap berhasil tetapi label-nya akan tercatatversion=1.0— ketidakcocokan tag dan label yang justru menjadi alat audit: label berkata jujur tentang apa yang terjadi saat build.[2/7] LABEL version=2.0 deskripsi=...— BuildKit menampilkan instruksi setelah substitusi;$VERSItelah diganti nilainya pada baris yang dieksekusi. Kunciversionmenggantikanversiyang kita pakai pada Chapter Struktur Dockerfile — nama kunci LABEL bebas dipilih, dan bentuk lowercase Inggris ini lebih akrab dibaca tool pemindai image.[6/7] RUN echo ...— berjalan 0.0 detik dan menghasilkan layer berisimode.txt; teks perintahnya masih memuat kedua variabel dalam bentuk${...}karena resolusi terjadi di dalam shell saat eksekusi.
Bukti bahwa kedua instruksi benar-benar bekerja di dua dunianya masing-masing bisa dibaca langsung dari dalam image:
$ docker run --rm myapp:2.0 cat /app/mode.txtOutput yang Dihasilkan:
MODE: production / VERSI: 2.0$ docker run -d --name myapp-env myapp:2.0
$ docker exec myapp-env printenv NODE_ENVOutput yang Dihasilkan:
b8e3a7c2d4f5691e0a8b2c4d6e8f0a1b3c5d7e9f1a3b5c7d9e0f2a4b6c8d0e2f4a
productionDua hasil di atas memperlihatkan pembagian kerja yang tegas. mode.txt adalah bukti dunia build: kedua variabel tersedia bagi RUN, lalu hasil resolusinya membeku permanen di layer. printenv NODE_ENV adalah bukti dunia runtime: container yang baru saja dinyalakan mewarisi variabel itu tanpa perlu satu instruksi apa pun — dan nilai VERSI justru tidak lagi bisa ditanya dari container, karena ARG sudah tamat tugasnya begitu build selesai.
ENV versus ARG #
Kedua instruksi kini punya bukti kerja masing-masing, dan tabel berikut merangkum lima aspek yang membedakan mereka:
| Aspek | ENV | ARG |
|---|---|---|
| Kapan hidup | saat build dan selama container berjalan | hanya selama proses build |
| Nilai bawaan | ditulis langsung di Dockerfile | ditulis di Dockerfile, bisa ditimpa --build-arg |
| Cara mengganti nilai | flag -e saat docker run — materi Chapter Environment Variable di Section Konfigurasi Container | flag --build-arg saat docker build |
| Jejak pada image | terlihat pada docker image inspect field .Config.Env | tercatat pada docker history lewat notasi ARG di baris RUN |
| Kasus pakai khas | konfigurasi aplikasi lintas environment: NODE_ENV, PATH | parameter build: nomor versi, pilihan varian, alamat proxy |
Aturan memilihnya satu kalimat: bila nilainya perlu dibaca aplikasi saat container berjalan, gunakan ENV; bila nilainya hanya dipakai untuk merakit isi image, gunakan ARG — dan biarkan image yang dihasilkan tetap sama untuk semua orang yang membangunnya.
Jejak ENV dan ARG pada Metadata Image #
Kedua instruksi meninggalkan jejak yang bisa dibaca siapa pun yang memegang image — dan inilah bagian yang menuntut kehati-hatian. Jejak ENV terbaca dari field konfigurasi yang sudah kita kenal pada Chapter Image Inspect dan History:
$ docker image inspect myapp:2.0 --format '{{json .Config.Env}}'Output yang Dihasilkan:
["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NODE_ENV=production"]Variabel NODE_ENV duduk berdampingan dengan PATH bawaan image basis — seluruh daftar ini diwarisi setiap container dari image tersebut. Adapun jejak ARG muncul pada riwayat build:
$ docker history myapp:2.0Output yang Dihasilkan:
IMAGE CREATED CREATED BY SIZE COMMENT
9f4c8e2b1d7a 2 minutes ago CMD ["node" "server.js"] 0B
<missing> 2 minutes ago EXPOSE 8000 0B
<missing> 2 minutes ago RUN |1 VERSI=2.0 echo "MODE: ${NODE_ENV} / VERS… 34B
<missing> 2 minutes ago COPY package.json server.js ./ 620B
<missing> 2 minutes ago WORKDIR /app 0B
<missing> 2 minutes ago ENV NODE_ENV=production 0B
<missing> 2 minutes ago LABEL version=2.0 deskripsi=API kecil milik Budi 0B
...Mari kita telaah jejak-jejak tersebut:
ENV NODE_ENV=productionsebagai baris tersendiri — bernilai 0B karena murni metadata, dan nilainya utuh terpampang.LABEL version=2.0 ...— nilai hasil substitusi ARG tercatat permanen; siapa pun yang membaca history tahu image ini dibangun sebagai versi 2.0.RUN |1 VERSI=2.0 echo ...— notasi|1mencatat bahwa instruksi RUN memakai satuARGbeserta nilainya; teks perintahnya sendiri masih memuat${VERSI}yang belum terurai, tetapi nilai aslinya tercetak dengan terang-terangan.
Scope ARG: Satu Stage Satu Deklarasi #
Perilaku ARG yang paling sering mengejutkan muncul pada Dockerfile multi-stage: deklarasi ARG berlaku per stage. ARG yang ditulis sebelum baris FROM pertama hanya bisa dipakai oleh baris FROM itu sendiri, dan setiap stage harus mendeklarasikan ulang ARG yang ingin dibacanya:
ARG NODE_VER=22
FROM node:${NODE_VER}-alpine AS builder
ARG VERSI=1.0
RUN echo "membangun versi ${VERSI}"
FROM alpine:3.20
RUN echo "membangun versi ${VERSI}"Mari kita telaah akibat susunan di atas: baris ARG NODE_VER=22 di puncak hanya berlaku untuk substitusi ${NODE_VER} pada baris FROM — satu-satunya tempat variabel sebelum-FROM bisa dipakai. ARG VERSI=1.0 di dalam stage builder membuat RUN pertama berjalan mulus dengan nilai 1.0. Namun RUN pada stage kedua gagal dengan galat VERSI: unbound variable — stage yang berakar pada alpine:3.20 adalah dunia tersendiri yang tidak mewarisi deklarasi ARG dari stage lain, dan --build-arg VERSI=2.0 di command line tidak mengubah keadaan itu selama deklarasinya tidak diulang. Mekanisme stage itu sendiri kita kuasai tuntas pada Chapter Multi-Stage Build di Section Image Build dan Optimisasi.
Dua instruksinya kini lengkap: ENV membawa konfigurasi yang hidup sampai container menyala, ARG membawa parameter yang menyempurnakan resep saat build. Satu pertanyaan besar di Dockerfile myapp masih menggantung: siapa yang sebenarnya menyalakan aplikasi saat container lahir — dan apa yang terjadi bila argumen docker run menyusul setelahnya. Jawabannya berada di sepasang instruksi terpenting di dunia Dockerfile, CMD dan ENTRYPOINT, sekaligus pilihan gaya penulisannya yang menentukan nasib sinyal docker stop.
Referensi #
- Dockerfile Reference
— definisi resmi
ENV,ARG, aturan scope per stage, dan substitusi variabel. - docker build — CLI Reference
— flag
--build-arguntuk mengisi nilai ARG dari command line. - Dockerfile best practices — panduan memilih ENV atau ARG dan pola penandaan versi.