2016-12-01 56 views
7

我無法創建,並在Dockerfile使用變量使用變量插值 - 我建通過Dockerfile泊塢窗圖像使用此命令:在字符串中泊塢

$ docker build --build-arg s=scripts/a.sh -t a . 

(所以,因爲我使用--build-阿根廷,$ S將在Dockerfile可用的說法,而這部分作品)

的Dockerfile是像這樣:

ARG s 

RUN echo $s 

RUN useradd -ms /bin/bash newuser 

USER newuser 
WORKDIR /home/newuser 

ENV fn=$(filename $s) # fails on this line 

COPY $s . 

ENTRYPOINT ["/bin/bash", "/home/newuser/$fn"] 

我的問題是,碼頭工人正在搭建failin g在上面指出的線上。

Error response from daemon: Syntax error - can't find = in "$s)". Must be of the form: name=value 

如果我把上面一行是:

RUN fn=$(filename $s) 

我得到這個錯誤:

Error: Command failed: docker build --build-arg s=scripts/a.sh -t a . 
The command '/bin/sh -c fn=$(filename $s)' returned a non-zero code: 127 

任何人都知道正確的方法來

  1. 創建內部變量碼頭文件
  2. 使用字符串插值與變量,這樣我可以參考的變量在入口點的參數如下所示:

    入口點[「/斌/慶典」,「/家庭/ NEWUSER/$ VAR」]

即使我這樣做:

ARG s 

ARG sname 

RUN echo $s   # works as expected 
RUN echo $sname  # works as expected 

RUN useradd -ms /bin/bash newuser 

USER newuser 
WORKDIR /home/newuser 


COPY $s . # works as expected (I believe) 

ENTRYPOINT /bin/bash /home/newuser/$sname # does not work as expected 
即使我使用的入口點的「非JSON」版本

,它似乎仍然沒有回暖的$sname變量的值。

回答

10

我會避免在ENTRYPOINT中使用變量。這很棘手,需要對發生的事情有深入的瞭解。很容易被意外打破。只要考慮下列其中一項。

使用已知名稱爲您的啓動腳本創建鏈接。

RUN ln -s /home/newuser/$sname /home/newuser/docker_entrypoint.sh 
ENTRYPOINT ["/home/newuser/docker_entrypoint.sh"] 

或編寫獨立的入口點腳本,運行你所需要的。

但是,如果您想知道您的問題中的解決方案如何工作,請繼續閱讀。

首先一些定義。

  • ENV - 是聯編(docker build)和運行時(docker run
  • ARG期間可用環境變量 - 是環境變量只生成時

如果你看一下https://docs.docker.com/engine/reference/builder/#environment-replacement期間提供您請參閱直接支持這些環境變量的dockerfile指令列表。正如你所說,這就是爲什麼COPY「拿起變量」。

請注意,沒有RUN也沒有ENTRYPOINT。它是如何工作的?

您需要深入瞭解文檔。第一個RUNhttps://docs.docker.com/engine/reference/builder/#run)。有兩種形式。第一個通過shell執行命令,這個shell可以訪問buildtime環境變量。

# this works because it is called as /bin/sh -c 'echo $sname' 
# the /bin/sh replace $sname for you  
RUN echo $sname 

# this does NOT work. There is no shell process to do $sname replacement 
# for you 
RUN ["echo", "$sname"] 

同樣的事情適用於ENTRYPOINTCMD除了僅在運行的變量是容器啓動時可用。

# first you need to make some runtime variable from builtime one 
ENV sname $sname 

# Then you can use it during container runtime 
# docker runs `/bin/sh -c '/bin/bash /home/newuser/$sname'` for you 
# and this `/bin/sh` proces interprets `$sname` 
ENTRYPOINT /bin/bash /home/newuser/$sname 

# but this does NOT work. There is no process to interpolate `$sname` 
# docker runs what you describe. 
ENTRYPOINT ["/bin/bash", "/home/newuser/$sname"] 

編輯2017年4月3日:更新鏈接到碼頭工人文檔和輕微的重述,以避免,我從其他的答案和評論感知混亂。

+0

那麼爲什麼不是ARG,一個構建時參數,可用於ENTRYPOINT參數插值,也可以在構建時? 我只是在Dockerfile中尋找某種變量,所以我不必在整個地方複製和粘貼相同的字符串,而無需使用某種外部模板工具。 我想知道爲什麼這個功能被添加,如果它不一致可用。 – pdxleif

+0

這個問題應該指向碼頭工作組。我必須看看再次添加了「ARG」的公關,但如果我的記憶是正確的,這種可能性甚至沒有討論過。 Docker開發者在GitHub上非常活躍,所以在那裏問問。 – Villlem

1

我要求@Villem回答,他的回答更明確,但以下內容將起作用(只是不是穩定的解決方案)。他的回答基本上是說,這個回答是不是一個好辦法做到這一點:

ARG s   # passed in via --build-arg s=foo 
ARG sname  # passed in via --build-arg sname=bar 

RUN echo $s  
RUN echo $sname 

ENV sname $sname # this is the key part 

RUN useradd -ms /bin/bash newuser 

USER newuser 
WORKDIR /home/newuser 

COPY $s . 

ENTRYPOINT /bin/bash /home/newuser/$sname # works, but is not stable! 

不要問我爲什麼COPY命令拿起這是通過ARG聲明的變量,但入口點命令不不是似乎拿起通過ARG聲明的變量,但只拾取通過ENV聲明的變量。至少,這似乎是這種情況。

+1

也許'COPY'(和'ADD'?)在shell的後面運行'cp'命令,並且將參數保留爲'cp',以便它們可以擴展bash變量? – pdxleif

+0

我認爲你的問題是關聯到https://github.com/moby/moby/issues/18492 – ygk