Docker的ARG、ENV和.env配置完整指南

banq發表於2022-02-02

本文將幫助您自信地使用 Docker ARG、ENV、env_file 和 .env 檔案。您將瞭解如何使用 Docker 構建時變數、環境變數和 docker-compose 模板輕鬆配置 Docker 映像和 dockerized 應用程式。

 

常見的誤解

  • .env 檔案僅在使用docker-compose.yml 檔案時的預處理步驟中使用。美元符號變數(如 $HI)被替換為同一目錄中名為“.env”的檔案中包含的值。
  • ARG僅在構建 Docker 映像(RUN 等)期間可用,而不是在建立映像並從其啟動容器之後(ENTRYPOINT、CMD)。您可以使用 ARG 值來設定 ENV 值來解決這個問題。
  • ENV值可用於容器,但在 Docker 構建期間也可使用 RUN 樣式的命令,從引入它們的行開始。
  • 如果您使用 bash (RUN export VARI=5 && …) 在中間容器中設定環境變數,它將不會在下一個命令中持續存在。有辦法解決這個問題。
  • env_file是一種將許多環境變數一次性傳遞給單個命令的便捷方式。這不應與.env檔案混淆。
  • 設定 ARG 和 ENV 值會在 Docker 映像中留下痕跡。不要將它們用於不打算保留的祕密(好吧,您可以使用多階段構建)。

 

該指南分為以下主題:

The Dot-Env File (.env)

如果您的專案中有一個名為.env的檔案,它僅用於將值放入同一資料夾中的 docker-compose.yml 檔案中。這些與 Docker Compose 和 Docker Stack 一起使用。它與 ENV、ARG 或上面解釋的任何 Docker 特定無關。這完全是 docker-compose.yml 的事情。

檔案中的值.env用以下表示法編寫:

VARIABLE_NAME=some value
OTHER_VARIABLE_NAME=some other value, like 5

這些鍵值對用於替換 docker-compose.yml 檔案中的美元符號變數。這是一種預處理步驟,並使用生成的臨時檔案。這是避免硬編碼值的好方法。

這是一個示例 docker-compose.yml 檔案,依賴於 .env 檔案提供的值:

version: '3'

services:
  plex:
    image: linuxserver/plex
      environment:
        - env_var_name=${VARIABLE_NAME} # here it is

提示:使用 .env 檔案時,您可以很容易地除錯 docker-compose.yml 檔案。只需輸入docker-compose config。通過這種方式,您將看到 docker-compose.yml 檔案內容在執行替換步驟後的樣子,而無需執行任何其他內容。

  

ARG 和 ENV 可用性

在使用Docker時,我們區分了兩種不同型別的變數--ARG和ENV。

ARG也被稱為構建時變數。它們只在Docker檔案中用ARG指令 "宣佈 "的那一刻起可用,直到映象被構建。執行中的容器不能訪問ARG變數的值。這也適用於CMD和ENTRYPOINT指令,它們只是告訴容器在預設情況下應該執行什麼。如果你告訴Dockerfile期待各種ARG變數(沒有預設值),但在執行構建指令時卻沒有提供任何ARG變數,就會出現錯誤資訊。

然而,ARG值可以在映象建立後,通過檢視映象的docker歷史,很容易被檢查出來。因此,他們是敏感資料的一個糟糕選擇。

 

ENV變數在構建過程中也是可用的,只要你用ENV指令引入它們。然而,與ARG不同的是,它們也可以被從最終映象中啟動的容器所訪問。在啟動一個容器時,ENV值可以被覆蓋,下面會有更多的介紹。

 

下面是圍繞從Docker檔案構建Docker映象和執行容器的過程中,對ARG和ENV可用性的簡化概述。它們是重疊的,但ARG不能從容器內部使用。

Docker的ARG、ENV和.env配置完整指南

 

設定ARG值

所以,你有你的Docker檔案,其中定義了ARG和ENV值。如何設定它們,以及在哪裡設定?你可以在Docker檔案中留空,或者設定預設值。如果你沒有為預期的ARG變數提供一個值,而這些變數沒有預設值,你會得到一個錯誤資訊。

這裡有一個Dockerfile的例子,既有預設值,也有沒有預設值的。

ARG some_variable_name
# or with a hard-coded default:
ARG some_variable_name=default_value

RUN echo "Oh dang look at that $some_variable_name"
# you could also use braces - ${some_variable_name}

當從命令列構建Docker映象時,你可以使用-build-arg設定ARG值。

$ docker build --build-arg some_variable_name=a_value

使用上述Dockerfile執行該命令,將導致以下一行被列印出來(除其他外)。

Oh dang look at that a_value

那麼,這如何轉化為使用docker-compose.yml檔案?當使用docker-compose時,你可以在args塊中指定傳遞給ARG的值。

version: '3'

services:
  somename:
    build:
      context: ./app
      dockerfile: Dockerfile
      args:
        some_variable_name: a_value

當你試圖設定一個在Docker檔案中沒有提到的ARG變數時,Docker會抱怨。

 

設定ENV值

那麼,如何設定ENV值呢?你可以在啟動容器時設定(我們將在下面討論這個問題),但你也可以通過硬編碼在Docker檔案中直接提供預設ENV值。此外,你還可以為環境變數設定動態的預設值!

在構建映象時,你能提供的唯一東西是ARG值,如上所述。你不能直接提供ENV變數的值。然而,ARG和ENV都可以一起工作。你可以使用ARG來設定ENV變數的預設值。下面是一個基本的Docker檔案,使用硬編碼的預設值。

# no default value
ENV hey
# a default value
ENV foo /bar
# or ENV foo=/bar

# ENV values can be used during the build
ADD . $foo
# or ADD . ${foo}
# translates to: ADD . /bar

這裡是一個Docker檔案的片段,使用動態構建時的環境值。

# expect a build-time variable
ARG A_VARIABLE
# use the value to set the ENV var default
ENV an_env_var=$A_VARIABLE
# if not overridden, that value of an_env_var will be available to your containers!

 

一旦映象構建完成,你可以通過三種不同的方式啟動容器,併為ENV變數提供數值,可以從命令列或使用docker-compose.yml檔案。所有這些都將覆蓋Docker檔案中的任何預設ENV值。與ARG不同,你可以向容器傳遞所有種類的環境變數。即使是那些在Dockerfile中沒有明確定義的變數。然而,這取決於你的應用程式是否會做任何事情。

  • 1. 逐一提供數值

    在命令列中,使用-e標誌。

$ docker run -e "env_var_name=another_value" alpine env

來自docker-compose.yml :

version: '3'

services:
  plex:
    image: linuxserver/plex
      environment:
        - env_var_name=another_value
 

  • [b]2. 從你的主機傳遞環境變數值[/b]
    

這和上面的方法是一樣的。唯一的區別是,你不提供一個值,而只是命名這個變數。這將使Docker訪問主機環境中的當前值,並將其傳遞給容器。

$ docker run -e env_var_name alpine env

對於docker-compose.yml檔案,省去等號和後面的所有內容,以達到同樣的效果。

version: '3'

services:
  plex:
    image: linuxserver/plex
      environment:
        - env_var_name

 

  • 3. 從一個檔案中取值(env_file)

我們可以指定一個檔案來讀取這些變數的值,而不是把這些變數寫出來或硬編碼(根據12因素的人的意見,這不是好的做法)。這樣一個檔案的內容看起來像這樣。

env_var_name=another_value

上面的檔案叫做env_file_name(名稱任意),它位於當前目錄下。你可以引用這個檔名,通過解析,提取要設定的環境變數。

$ docker run --env-file=env_file_name alpine env

在docker-compose.yml檔案中,我們只需引用一個env_file,然後Docker就會解析它,找出要設定的變數。

version: '3'

services:
  plex:
    image: linuxserver/plex
    env_file: env_file_name

 

這裡有一張小抄,結合了ARG和ENV可用性的概述以及從命令列設定它們的常用方法。

Docker的ARG、ENV和.env配置完整指南

 

 

在我們繼續之前:如果你是Docker的新手,並且不習慣考慮映象和容器,就會經常遇到一個問題:如果你試圖在RUN語句中設定一個環境變數的值,比如RUN export VARI=5 && ...,你將無法在接下來的RUN語句中訪問它。其原因是,對於每個RUN語句,一個新的容器會從一箇中間映像中啟動。命令結束後會儲存一個映象,但環境變數不會以這種方式持續存在。

如果你對一個映像感到好奇,想知道它是否在容器啟動前提供了預設的ENV變數值,你可以檢查Image映像,看看哪些ENV條目是預設設定的。

# first, get the images on your system and their ids
$ docker images
# use one of those ids to take a closer look
$ docker inspect image-id

# look out for the "Env" entries

 

覆蓋ENV值

假設你有一個由Dockerfile構建的映象,它提供了預設的ENV值。從它啟動的容器可以訪問Dockerfile中定義的ENV變數。然而,這些值可以通過提供單一的環境變數或env_files來覆蓋,環境變數被解析並傳入容器。

一旦一個程式在容器內執行,或者當一個命令被評估時,他們可以為自己改變環境值。像這樣的東西。

$docker run myimage SOME_VAR=hi python app.py

將完全覆蓋你可能為app.py指令碼設定的任何SOME_VAR,即使在最後命令之前有一些帶有-e標誌的值。

優先順序是,從強到弱:容器化應用程式集的東西,來自單一環境條目的值,來自env_file(s)的值,最後是Dockerfile預設值。

 

相關文章