web-dev-qa-db-ja.com

CMDの前にスクリプトを実行する

Docker documentation :DockerfileにはCMD命令は1つしか存在できません。複数のCMDをリストすると、最後のCMDのみが有効になります。

CMDコマンド(私の場合はinit)の前に、単純なbashスクリプト(docker環境変数を処理する)を実行したいと思います。

これを行う方法はありますか?

17
kumar

カスタムエントリポイントを使用する

必要な処理を行うカスタムエントリポイントを作成し、最後にCMDを実行します。

[〜#〜] note [〜#〜]:画像が既にカスタムエントリポイントを定義している場合、それを置き換えるのではなく拡張する必要があるか、必要な動作を変更することができます。

entrypoint.sh

#!/bin/sh

## Do whatever you need with env vars here ...

# Hand off to the CMD
exec "$@"

Dockerfile

COPY entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

Dockerは、CMDを引数として使用して、エントリポイントを実行します。 CMDがinitの場合:

/entrypoint.sh init

エントリポイントスクリプトの最後にあるexecは、エントリポイントが必要な処理を終えたときにCMDに引き継ぐようにします。

これが機能する理由

ENTRYPOINTとCMDを使用すると、Dockerを初めて使用する人を混乱させることがよくあります。コメントで、あなたはそれについて混乱を表明しました。仕組みとその理由を次に示します。

ENTRYPOINTは、コンテナ内で最初に実行されるものです。引数リストとしてCMDを取ります。したがって、この例では、コンテナで実行されるのは次の引数リストです。

# ENTRYPOINT = /entrypoint.sh
# CMD        = init
["/entrypoint.sh", "init"]

# or shown in a simpler form:
/entrypoint.sh init

画像にENTRYPOINTがある必要はありません。定義しない場合、Dockerにはデフォルトの/bin/sh -cがあります。

したがって、元の状況でENTRYPOINTがなく、initのCMDを使用すると、Dockerはこれを実行します。

/bin/sh -c 'init'
^--------^  ^--^
    |         \------- CMD
    \--------------- ENTRYPOINT

当初、DockerはCMDのみを提供し、/bin/sh -cはENTRYPOINTとしてハードコーディングされていました(変更できませんでした)。途中のある時点で、人々はより多くのカスタム処理を行う必要があるユースケースがあり、DockerはENTRYPOINTを公開して、必要に応じて変更できるようにしました。

上記の例では、ENTRYPOINTがカスタムスクリプトに置き換えられています。 (ただし、#!/bin/shで始まるため、最終的にはshによって実行されます。)

そのENTRYPOINTは引数としてCMDを取ります。 entrypoint.shスクリプトの最後はexec "$@"です。 $@はスクリプトに指定された引数のリストに展開されるため、これは次のようになります。

exec "init"

そのため、スクリプトが終了すると、PID 1としてinitに置き換えられます(これがexecが行うこと-itreplaces別のコマンドを使用した現在のプロセス。

CMDを含める方法

コメントでは、DockerfileにCMDを追加することについて尋ねました。はい、できます。

Dockerfile

CMD ["init"]

または、コマンドにもっとある場合、例えばinit -a -bのような引数は、次のようになります。

CMD ["init", "-a", "-b"]
35
Dan Lowe

ダンの答えは正しかったのですが、実装するのはかなりわかりにくいと感じました。同じ状況にある人のために、CMDではなくENTRYPOINTの使用に関する彼の説明をどのように実装したかのコード例を示します。

Dockerfileの最後の数行は次のとおりです。

#change directory where the mergeandlaunch script is located.
WORKDIR /home/connextcms
ENTRYPOINT ["./mergeandlaunch", "node", "keystone.js"]

Mergeandlaunch bashシェルスクリプトの内容は次のとおりです。

#!/bin/bash

#This script should be edited to execute any merge scripts needed to
#merge plugins and theme files before starting ConnextCMS/KeystoneJS.

echo Running mergeandlaunch script

#Execute merge scripts. Put in path to each merge script you want to run here.
cd ~/theme/rtb4/
./merge-plugin

#Launch KeystoneJS and ConnextCMS
cd ~/myCMS

exec "$@"

コードの実行方法は次のとおりです。

  1. ENTRYPOINTコマンドは、mergeandlaunchシェルスクリプトを開始します
  2. 2つの引数「node」と「keystone.js」は、シェルスクリプトに渡されます。
  3. スクリプトの最後で、引数はexecコマンドに渡されます。
  4. Execコマンドは、DockerコマンドCMDと同じ方法でノードプログラムを起動しました。
4
Chris Troutner

ダンに答えてくれてありがとう。

Dockerfile内で次のようなことをしなければならなかったことがわかりました。

WORKDIR /
COPY startup.sh /
RUN chmod 755 /startup.sh
ENTRYPOINT sh /startup.sh /usr/sbin/init

注:entrypoint.shとは対照的に、スクリプトにstartup.shという名前を付けました

ここで重要なのは、「sh」を指定する必要があるということです。

参照: https://github.com/docker/compose/issues/3876

0
jersey bean