web-dev-qa-db-ja.com

dockerfileを介してENTRYPOINTの前にシェルコマンドを実行する方法

私のnodejsプロジェクトには次のファイルがあります

FROM node:boron

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install



# Bundle app source
COPY . /usr/src/app

# Replace with env variable
RUN envsubs < fil1 > file2

EXPOSE 8080
CMD [ "npm", "start" ]

環境変数を提供する-eフラグでdockerコンテナーを実行します

しかし、私は交換を見ません。 env変数が使用可能な場合、Run ccommandは実行されますか?

11
user_mda

画像は不変です

Dockerfileは、イメージのビルドプロセスを定義します。一度構築されると、イメージは不変です(変更できません)。ランタイム変数は、この不変のイメージに焼き付けられるものではありません。したがって、Dockerfileはこれに対処するのに間違った場所です。

エントリポイントスクリプトを使用する

おそらくやりたいことは、デフォルトのENTRYPOINTを独自のスクリプトでオーバーライドし、そのスクリプトに環境変数で何かをさせることです。エントリポイントスクリプトは実行時(コンテナの起動時)に実行されるため、これが環境変数を収集し、それらで何かを行うのに適切なタイミングです。

最初に、エントリーポイントスクリプトについて知るためにDockerfileを調整する必要があります。 Dockerfileは環境変数の処理に直接関与していませんが、スクリプトは画像に焼き付けられるため、このスクリプトについてはまだ知る必要があります。

Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
CMD ["npm", "start"]

ここで、必要なセットアップを行うエントリポイントスクリプトを記述しますbeforeコマンドが実行され、最後にexecコマンド自体が実行されます。

entrypoint.sh:

#!/bin/sh

# Where $ENVSUBS is whatever command you are looking to run
$ENVSUBS < fil1 > file2

npm install

# This will exec the CMD from your Dockerfile, i.e. "npm start"
exec "$@"

あなたがコメントでこれについて尋ねたので、ここにnpm installを含めました。これはnpm install実行ごとにを実行することに注意してください。それが適切な場合は問題ありませんが、毎回実行されるため、起動時間に多少の遅延が発生することを指摘したいと思います。

次に、イメージを再構築します。これにより、エントリポイントスクリプトがその一部になります。

実行時の環境変数の使用

エントリポイントスクリプトは環境変数の使用方法を知っていますが、実行時に変数をインポートするようにDockerに指示する必要があります。これを行うには、-eフラグをdocker runに使用できます。

docker run -e "ENVSUBS=$ENVSUBS" <image_name>

ここでは、Dockerは環境変数ENVSUBSを定義するように指示され、割り当てられる値は現在のシェル環境からの$ENVSUBSの値です。

エントリポイントスクリプトの仕組み

これについて少し詳しく説明します。コメントでは、これがどのように組み合わされるかについて少し霧がかかっているように見えたからです。

Dockerがコンテナを起動すると、コンテナ内で1つのコマンドを実行します。このコマンドは、典型的なLinuxシステムのinitまたはsystemdと同様にPID 1になります。このプロセスは、コンテナに必要な他のプロセスの実行を担当します。

デフォルトでは、ENTRYPOINT/bin/sh -cです。 Dockerfile、docker-compose.yml、またはdockerコマンドを使用してオーバーライドできます。

コンテナーが開始されると、Dockerはentrypointコマンドを実行し、コマンド(CMD)を引数リストとして渡します。前に、独自のENTRYPOINT/entrypoint.shとして定義しました。つまり、あなたの場合、これはDockerが起動時にコンテナで実行するものです:

/entrypoint.sh npm start

["npm", "start"]がコマンドとして定義されたため、それが引数リストとしてエントリポイントスクリプトに渡されます。

-eフラグを使用して環境変数を定義したため、このエントリポイントスクリプト(およびその子)はその環境変数にアクセスできます。

エントリポイントスクリプトの最後で、exec "$@"を実行します。 $@はスクリプトに渡される引数リストに展開されるため、これは実行されます

exec npm start

また、execは引数をコマンドとして実行するため、replacing現在のプロセスをそれ自体と置き換えます。完了したら、npm startはコンテナ内のPID 1になります。

複数のCMDを使用できない理由

コメントでは、複数のCMDエントリを定義して複数のことを実行できるかどうかを尋ねました。

定義できるENTRYPOINTCMDはそれぞれ1つのみです。これらは、ビルドプロセス中にはまったく使用されません。 RUNCOPYとは異なり、これらはビルド中に実行されません。これらは、作成された画像にメタデータアイテムとして追加されます。

これらのメタデータフィールドが読み取られ、コンテナを起動するために使用されるのは、イメージがコンテナとして実行された後でのみです。

前述のように、エントリポイントは実際に実行されるものであり、CMDが引数リストとして渡されます。それらが分離している理由は部分的に歴史的です。 Dockerの初期のバージョンでは、CMDのみが利用可能なオプションであり、ENTRYPOINT/bin/sh -cとして修正されました。しかし、このような状況のため、Dockerは最終的にENTRYPOINTをユーザーが定義できるようにしました。

38
Dan Lowe

Env変数が使用可能な場合、Run ccommandは実行されますか?

runコンテナを使用すると、-eフラグで設定された環境変数が設定されます。

問題は、コンテナbuildでDockerfileが読み取られるため、RUNコマンドがnotそれらの環境変数を認識することです。 。

ビルド時に環境変数を設定する方法は、DockerfileにENV行を追加することです。 ( https://docs.docker.com/engine/reference/builder/#/environment-replacement

したがって、Dockerfileは次のようになります。

FROM node:latest

WORKDIR /src
ADD package.json .

ENV A YOLO

RUN echo "$A"

そして出力:

$ docker build .
Sending build context to Docker daemon  2.56 kB
Step 1 : FROM node:latest
 ---> f5eca816b45d
Step 2 : WORKDIR /src
 ---> Using cache
 ---> 4ede3b23756d
Step 3 : ADD package.json .
 ---> Using cache
 ---> a4671a30bfe4
Step 4 : ENV A YOLO
 ---> Running in 7c325474af3c
 ---> eeefe2c8bc47
Removing intermediate container 7c325474af3c
Step 5 : RUN echo "$A"
 ---> Running in 35e0d85d8ce2
YOLO
 ---> 78d5df7d2322

RUNコマンドが起動されると、コンテナは環境変数が設定されていることを認識しています。

2
Jacques Cornat