ARG yalnızca build sırasında kullanılan, Dockerfile'ın kendi değişkenidir ve --build-arg ile değiştirilir; imajdan başlatılan container'larda bulunmaz. ENV ise hem sonraki build adımlarına hem de imajdan oluşan her container'a aktarılan bir ortam değişkenidir ve build sırasında komut satırından değiştirilemez. Kısacası sürüm numarası gibi build ayarları için ARG, uygulamanın çalışırken okuyacağı ayarlar için ENV kullanılır; ikisi de sır taşımak için uygun değildir.

Bu yazıda iki talimatın kapsam kurallarını, çok aşamalı build'de nasıl devralındıklarını, önceden tanımlı build argümanlarını, Buildx ve BuildKit'i yöneten ortam değişkenlerinin ENV ile ilgisinin olmadığını ve Compose'taki build.args alanını resmî belgelere ve gerçek bir docker compose config çıktısına dayanarak anlatıyoruz. Serinin diğer yazıları için Docker öğrenme rehberi sayfasına bakabilirsiniz.

Benzerlikler ve farklar

Benzerlikler ve farklar: Amaç, Build sırasında değiştirme, Container içinde, İmaj metaverisi

Docker belgeleri iki talimatı birbirine benzer ama farklı amaçlara hizmet eden araçlar olarak tanımlar. İkisi de Dockerfile'da bildirilir, ikisi de docker build bayraklarıyla etkilenebilir ve ikisi de build'i parametrelemek için kullanılır. Ayrıldıkları yer, değerin nereye kadar taşındığıdır.

KonuARGENV
AmaçDockerfile talimatlarının değerlerini parametrelemekBuild ortamını ve container varsayılanlarını ayarlamak
Build sırasında değiştirme--build-arg ileDoğrudan değiştirilemez, ARG ile birleştirilir
Container içindeAçıkça aktarılmadıkça bulunmazBulunur ve kalıcıdır
İmaj metaverisiProvenance, imaj geçmişi gibi yerlerde kalabilirİmaj yapılandırmasının parçasıdır
Sır taşımaya uygun muHayırHayır

ARG: Dockerfile'ın değişkeni

Build argümanı bir talimatta kullanılmadıkça build üzerinde hiçbir etkisi yoktur. Belgeler bunların imajdan başlatılan container'larda erişilebilir olmadığını, ancak Dockerfile içinden açıkça imajın dosya sistemine veya yapılandırmasına aktarılırsa orada bulunabileceğini belirtir. Önemli bir uyarı da eklenir: build argümanları imaj metaverisinde, provenance attestation kayıtlarında ve imaj geçmişinde kalabilir; sır tutmaya uygun olmamalarının nedeni budur.

En yaygın kullanım bileşen sürümlerini belirtmektir. FROM satırından önce, dosyanın en üstünde bildirilen argümanlar hem sürümleri tek yerde toplar hem de aynı değeri birden çok yerde kullanmanızı sağlar; örneğin farklı Alpine tabanlı imajların hepsinde aynı Alpine sürümünü kullanmak gibi. Aşağıdaki yapı belgelerdeki örneğe dayanır:

dockerfile
# syntax=docker/dockerfile:1
ARG NODE_VERSION="22"
ARG ALPINE_VERSION="3.21"

FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS base
WORKDIR /src

FROM base AS build
COPY package*.json ./
RUN npm ci
RUN npm run build

FROM base AS production
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=build /src/dist/ .
CMD ["node", "app.js"]

Argümanların varsayılan değeri olduğu için build sırasında değer vermek isteğe bağlıdır. Varsayılanı değiştirmek için --build-arg kullanılır:

bash
docker build --build-arg NODE_VERSION=current .

Temel imajın sürümünü bir argümana bağlamanın sabitleme ve güncelleme açısından ne anlama geldiğini base image seçimi yazısında ele alıyoruz.

ENV: build'den container'a taşınan ortam

ENV ile bildirilen değişken, aynı build aşamasındaki sonraki tüm talimatlarda kullanılabilir ve imajdan başlatılan container'larda kalıcıdır. Belgelerdeki örnekte NODE_ENV=production ayarı, npm paket kurulumundan önce yapılır; bu değişken ayarlıyken npm yalnızca yerel geliştirmede gereken paketleri atlar. Aynı değişken container çalışırken de ayarlı kalır, yani hem build davranışını hem uygulamanın çalışma davranışını etkiler.

dockerfile
# syntax=docker/dockerfile:1
FROM node:20
WORKDIR /app
COPY package*.json ./
ENV NODE_ENV=production
RUN npm ci && npm cache clean --force
COPY . .
CMD ["node", "app.js"]

En iyi uygulamalar sayfası ENV için iki yaygın kullanım daha gösterir. Biri PATH değişkenini güncellemektir: ENV PATH=/usr/local/nginx/bin:$PATH satırı CMD ["nginx"] komutunun doğrudan çalışmasını sağlar. Diğeri Postgres'in PGDATA değişkeni gibi servisin beklediği ortam değişkenlerini sağlamaktır. Sürüm numaralarını ENV ile tutmak da mümkündür; ancak yalnızca build sırasında gereken bir sürüm için bu değer container'a da taşınacağından, böyle durumlarda ARG genellikle daha dar kapsamlı bir seçimdir.

ARG ile ENV'i birleştirmek

Belgelere göre ortam değişkenleri varsayılan olarak build sırasında yapılandırılamaz; değerleri Dockerfile'da bildirilmelidir. Bir ENV değerini build sırasında değiştirmek istiyorsanız onu bir argümana bağlarsınız:

dockerfile
# syntax=docker/dockerfile:1
FROM node:20
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV
WORKDIR /app
COPY package*.json ./
RUN npm ci && npm cache clean --force
COPY . .
CMD ["node", "app.js"]
bash
docker build --build-arg NODE_ENV=development .

ENV katmanda kalır

ENV katmanda kalır

Her ENV satırı, RUN komutları gibi yeni bir ara katman oluşturur. Belgelerin vurguladığı sonuç şudur: sonraki bir katmanda değişkeni kaldırsanız bile değer o katmanda kalır ve okunabilir. Belgelerdeki örnekte ENV ADMIN_USER="mark" ardından RUN unset ADMIN_USER yazılan imajdan başlatılan container'da değişken yine mark değerini verir; çünkü RUN unset yalnızca o komutun kabuğunu etkiler.

Bir değişkeni yalnızca bir adım için kullanmak istiyorsanız tanımlama, kullanma ve kaldırma işlemlerini tek bir RUN içinde yaparsınız. Komutları && ile ayırmak, biri başarısız olursa build'in de başarısız olmasını sağlar; belgeler bunun genellikle iyi bir fikir olduğunu söyler.

dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN export ADMIN_USER="mark" \
    && echo $ADMIN_USER > ./mark \
    && unset ADMIN_USER
CMD sh

Kapsam: global ARG ve build aşamaları

Kapsam kuralları en çok kafa karıştıran kısımdır. İlk FROM satırından önce bildirilen bir argüman global kapsamdadır ve build aşamalarına otomatik olarak devralınmaz; yalnızca global kapsamda, yani FROM satırlarında kullanılabilir. Belgelerdeki örnekte global ARG NAME="joe" bildirildikten sonra aşama içinde çalışan echo "hello ${NAME}!" komutu hello ! sonucunu verir, çünkü değer kapsam dışıdır.

Global argümanı bir aşamaya almak için onu aşama içinde değer vermeden yeniden bildirirsiniz; belgeler buna argümanı "tüketmek" der. Bir argüman bir aşamada bildirildiğinde ya da tüketildiğinde, o aşamadan türeyen alt aşamalar onu otomatik devralır.

dockerfile
# syntax=docker/dockerfile:1
ARG NAME="joe"

FROM alpine AS base
# global argümanı bu aşamaya al
ARG NAME
RUN echo "hello $NAME!"

FROM base AS build
# base aşamasında bildirildiği için burada da kullanılabilir
RUN echo "build: $NAME"

Önceden tanımlı build argümanları

Bazı argümanlar her build'de hazır bulunur. Çoklu platform argümanları builder'ın çalıştığı makineyi (BUILDPLATFORM, BUILDOS, BUILDARCH, BUILDVARIANT) ve --platform ile seçilen hedefi (TARGETPLATFORM, TARGETOS, TARGETARCH, TARGETVARIANT) tanımlar. Bunlar global kapsamdadır ama aşamalara otomatik devralınmaz; aşama içinde kullanmak için ARG TARGETOS gibi bildirmeniz gerekir. Çapraz derleme ayrıntıları multi-platform build yazısında.

Vekil sunucu argümanları ise farklı davranır: HTTP_PROXY, HTTPS_PROXY, FTP_PROXY, NO_PROXY ve ALL_PROXY büyük küçük harf duyarsızdır ve Dockerfile'da bildirilmeleri gerekmez; --build-arg ile vermeniz build'in vekili kullanması için yeterlidir. Varsayılan olarak build önbelleğinden ve docker history çıktısından hariç tutulurlar. Ancak bu argümanlara Dockerfile'da başvurursanız vekil yapılandırması önbelleğe girer.

BuildKit'in yerleşik argümanları da vardır. Bu serideki yazılarda karşılaştığınız örnekler şunlardır: Git context'lerinde .git dizinini korumak için BUILDKIT_CONTEXT_KEEP_GIT_DIR, build denetimlerini komut satırından yönetmek için BUILDKIT_DOCKERFILE_CHECK ve dosya zaman damgalarını sabitlemek için SOURCE_DATE_EPOCH. Sonuncusu önbelleği de etkiler: değerini build'ler arasında değiştirmek WORKDIR ve sonraki talimatların önbelleğini geçersiz kılar, belgeler bu yüzden yeniden üretilebilir build'ler için SOURCE_DATE_EPOCH=0 gibi sabit bir değer önerir.

Build aracı değişkenleri ENV değildir

BUILDKIT_PROGRESS, BUILDX_BUILDER, BUILDX_NO_DEFAULT_ATTESTATIONS ya da BUILDKIT_HOST gibi değişkenler adlarıyla build değişkenlerine benzese de bambaşka bir şeydir. Belgelere göre bunlar Buildx istemcisini veya BuildKit daemon'unu yapılandırır; build container'ının içinde bulunmazlar ve ENV talimatıyla ilişkileri yoktur. Örneğin export BUILDKIT_PROGRESS=plain build adımlarını sade metin olarak sıralı gösterir. Boolean değerler Go'nun strconv.ParseBool fonksiyonuyla yorumlanır; true, 1 ve T aynı anlama gelir.

Önbellek ve build argümanları

Önbellek geçersizleştirme sayfası build argümanlarının önbelleği geçersiz kıldığını açıkça belirtir. Bu iki yönlüdür: bir argümanın değerini değiştirmek, onu kullanan talimatın ve sonrasının yeniden çalışmasına yol açar. Bu yüzden sık değişen bir değeri, örneğin commit hash'ini, Dockerfile'ın başında kullanmak sonraki bütün adımların önbelleğini her build'de bozar. Böyle değerleri ihtiyaç duyulan yere, mümkün olduğunca sona yakın kullanın. Aynı davranış bilinçli olarak da kullanılır: sırların içeriği önbelleğe girmediği için, sır değiştiğinde adımı yeniden çalıştırmak üzere değiştirdiğiniz bir CACHEBUST argümanı eklenebilir. Önbelleğin genel işleyişi build cache yazısında.

Compose'ta build.args ve environment

Compose dosyasında Dockerfile ARG değerleri build.args altında verilir; eşleme ya da liste biçimi kullanılabilir. Container'ın çalışma zamanı ortam değişkenleri ise servis düzeyindeki environment alanında durur. Bu iki alan, Dockerfile'daki ARG ve ENV ayrımının Compose'taki karşılığıdır. Aşağıdaki dosya Docker CLI 29.8.1, Docker Compose v5.5.1 ile docker compose config --quiet çıkış kodu 0 verdi:

yaml
services:
  api:
    build:
      context: .
      args:
        NODE_VERSION: "22"
        GIT_COMMIT: cdc3b19
    environment:
      NODE_ENV: production

Liste biçiminde bir argümanın değerini boş bırakabilirsiniz. Belgeler bu durumda değerin build sırasında kullanıcıdan alınması gerektiğini, aksi halde argümanın ayarlanmayacağını söyler. Davranışı görmek için şu dosyayı hazırladık:

yaml
services:
  api:
    build:
      context: .
      args:
        - NODE_VERSION=22
        - GIT_COMMIT

docker compose config komutunun normalleştirilmiş çıktısında, kabukta GIT_COMMIT tanımlı değilken args bölümü yalnızca şunu içeriyordu:

yaml
      args:
        NODE_VERSION: "22"

Aynı komutu GIT_COMMIT=cdc3b19 ortam değişkeniyle çalıştırdığımızda ise değer kabuktan alındı ve çıktı şöyle oldu:

yaml
      args:
        GIT_COMMIT: cdc3b19
        NODE_VERSION: "22"

Yani değeri boş bırakılan argüman, kabukta karşılığı yoksa build'e hiç gönderilmez ve Dockerfile'daki varsayılan değer geçerli olur. Compose dosyasında ${DEGISKEN:-varsayilan} gibi ifadelerin nasıl çözüldüğü ve hangi kaynağın öncelikli olduğu Compose değişken interpolasyonu yazısının konusudur; çalışma zamanı ortam dosyaları için Compose rehberine bakabilirsiniz.

Küçük bir örnek: sürüm yükseltmede ne yeniden çalışır?

Yukarıdaki Node.js Dockerfile'ında NODE_VERSION global argümandır ve yalnızca FROM satırında kullanılır. --build-arg NODE_VERSION=24 ile build ettiğinizde base aşaması farklı bir imajdan başlar; önbellek kuralına göre base image değiştiği için o aşamadan türeyen build ve production aşamalarının bütün adımları yeniden çalışır. Buna karşılık Dockerfile'ın ortasında ARG GIT_COMMIT tüketip yalnızca son satırdaki bir LABEL ya da dosya yazımında kullanırsanız, her commit'te yalnızca o adım ve sonrası yeniden çalışır. Aynı değeri container çalışırken okumak istiyorsanız ENV GIT_COMMIT=$GIT_COMMIT ile bağlamanız gerekir; o zaman değer imaj yapılandırmasına girer ve uygulama tarafından okunabilir.

Sırlar için neden ikisi de uygun değil?

Build değişkenleri sayfası en başta uyarır: build argümanları ve ortam değişkenleri sırları build'e geçirmek için uygun değildir, çünkü son imajda açığa çıkarlar. ENV değeri imaj yapılandırmasının parçasıdır ve container'da görünür; ARG değeri ise imaj geçmişinde ve provenance kayıtlarında kalabilir. Token ya da parola gerektiren adımlar için secret mount veya SSH mount kullanılır; nasıl yapıldığı build secrets yazısında anlatılıyor.

Sık yapılan hatalar

Sık yapılan hatalar: Global ARG değerini aşama içinde tüketmeden kullanmak, Bir ENV değerini --build-arg ile değiştirmeye çalışmak, Bir değişkeni sonraki RUN unset ile sildiğini...
  • Global ARG değerini aşama içinde tüketmeden kullanmak: değer boş gelir.
  • Bir ENV değerini --build-arg ile değiştirmeye çalışmak: önce ARG tanımlayıp ENV'e bağlamanız gerekir.
  • Bir değişkeni sonraki RUN unset ile sildiğini sanmak: değer katmanda kalır.
  • Yalnızca build sırasında gereken değerleri ENV ile tanımlayıp container'a taşımak.
  • Commit hash'i gibi sık değişen bir argümanı Dockerfile'ın başında kullanıp önbelleği her build'de bozmak.
  • Parola ve token'ları ARG veya ENV ile geçirmek.
  • BUILDKIT_PROGRESS gibi araç değişkenlerinin build içinde okunabileceğini sanmak.

Sık Sorulan Sorular

ARG değeri çalışan container'da görünür mü?

Hayır, açıkça ENV ya da bir dosya ile imaja aktarmadıkça görünmez. Yine de imaj geçmişinde ve provenance kayıtlarında kalabileceği için sır taşımak için kullanılmamalıdır.

ENV değerini docker build sırasında değiştirebilir miyim?

Doğrudan değiştiremezsiniz. Dockerfile'da ARG tanımlayıp ENV AD=$AD ile bağlarsanız --build-arg ile verdiğiniz değer ortam değişkenine geçer.

FROM satırında değişken kullanabilir miyim?

Evet. İlk FROM satırından önce bildirilen global argümanlar FROM satırlarında kullanılabilir. Aşama içindeki talimatlarda kullanmak için argümanı aşama içinde yeniden bildirmeniz gerekir.

Compose'ta args ile environment arasındaki fark nedir?

build.args Dockerfile'daki ARG değerlerini build sırasında verir. environment ise container çalışırken ayarlanan ortam değişkenleridir ve imajın build edilmesini etkilemez.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · Docker build secrets · Compose değişken interpolasyonu · Multi-platform build · Base image seçimi · Dockerfile yazma rehberi