- 投稿日:2020-10-20T21:50:44+09:00
DockerでGPU環境構築 [2020年10月版]
概要
本記事ではDockerを使って、tensorflow2.3 + Python3.8の環境構築をします。
任意のTensorFlow、PyTorchのバージョンで、対応するCUDAとPythonのバージョンに本記事の内容を書き換えれば簡単に環境構築ができます。
DockerでGPU環境構築を行う系の記事が混在しているため、2020年10月時点で自分が行ったことを備忘録がてら整理します。本記事では、
nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04イメージをベースにPython3.8とPoetryをインストールし、仮想環境内でPoetryを使ってtensorflow2.3をインストールします。対象読者
- Docker入門者
- 複数のTensorFlowなどのフレームワークのバージョンの環境を一つのマシン上に構築したい人
環境
- Ubuntu 16.04.3 LTS
- GeForce GTX1080
以下1~3はこちらの記事の方が簡単にできそうです (自分では試してないですが)
NVIDIA Docker って今どうなってるの? (20.09 版)1. NVIDIA ドライバのインストール
GPUの型を確認 (NVIDIA製のものがある確認)。
$ lspci | grep VGA 03:00.0 VGA compatible controller: NVIDIA Corporation Device 1b80 (rev a1) 04:00.0 VGA compatible controller: NVIDIA Corporation Device 1b80 (rev a1)既にNVIDIA ドライバがインストールされていれば、削除しておく。
$ dpkg -l | grep nvidia- $ sudo apt-get purge nvidia-*ドライバのrepositoryを追加する。
$ sudo add-apt-repository ppa:graphics-drivers/ppa $ sudo apt update推奨ドライバを確認。
$ sudo ubuntu-drivers devices == /sys/devices/pci0000:00/0000:00:03.0/0000:04:00.0 == modalias : pci:v000010DEd00001B80sv00001462sd0000336Bbc03sc00i00 vendor : NVIDIA Corporation driver : nvidia-430 - third-party free recommended driver : nvidia-415 - third-party free driver : xserver-xorg-video-nouveau - distro free builtin推奨されている
nvidia-430をインストールする。$ sudo apt-get install nvidia-driver-430※ 以下のコマンドで推奨のドライバを自動でインストールすることもできる。
$ sudo ubuntu-drivers autoinstallOSを再起動する。
$ sudo rebootNVIDIA ドライバが無事インストールされているか確認。
$ nvidia-smi Thu Oct 15 16:49:51 2020 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 430.64 Driver Version: 430.64 CUDA Version: 10.1 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 1080 Off | 00000000:03:00.0 Off | N/A | | 28% 40C P8 10W / 180W | 2MiB / 8119MiB | 0% Default | +-------------------------------+----------------------+----------------------+ | 1 GeForce GTX 1080 Off | 00000000:04:00.0 On | N/A | | 28% 41C P8 13W / 180W | 533MiB / 8085MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | 1 1247 G /usr/lib/xorg/Xorg 422MiB | | 1 1583 G compiz 108MiB | +-----------------------------------------------------------------------------+2. Dockerのインストール
公式Documentに沿ってDockerをインストールすれば良い。
以下は公式Documentの一部のコピペなので、詳しくはDocumentを読んでください。SET UP THE REPOSITORY
1. Update the apt package index and install packages to allow apt to use a repository over HTTPS:
$ sudo apt-get update $ sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common2. Add Docker’s official GPG key:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - $ sudo apt-key fingerprint 0EBFCD88 pub rsa4096 2017-02-22 [SCEA] 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 uid [ unknown] Docker Release (CE deb) <docker@docker.com> sub rsa4096 2017-02-22 [S]3. Use the following command to set up the stable repository.
$ sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"INSTALL DOCKER ENGINE
1. Update the apt package index, and install the latest version of Docker Engine and containerd, or go to the next step to install a specific version:
$ sudo apt-get update $ sudo apt-get install docker-ce docker-ce-cli containerd.io3. Verify that Docker Engine is installed correctly by running the hello-world image.
$ sudo docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 0e03bdcc26d7: Pull complete Digest: sha256:8c5aeeb6a5f3ba4883347d3747a7249f491766ca1caa47e5da5dfcf6b9b717c0 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. ...Dockerが正しくインストールされたか確認。
$ dpkg -l | grep -e docker -e containerd.io ii containerd.io 1.3.7-1 amd64 An open and reliable container runtime ii docker-ce 5:19.03.13~3-0~ubuntu-xenial amd64 Docker: the open-source application container engine ii docker-ce-cli 5:19.03.13~3-0~ubuntu-xenial amd64 Docker CLI: the open-source application container engine$ sudo docker version Client: Docker Engine - Community Version: 19.03.13 API version: 1.40 Go version: go1.13.15 Git commit: 4484c46d9d Built: Wed Sep 16 17:02:59 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.13 API version: 1.40 (minimum version 1.12) Go version: go1.13.15 Git commit: 4484c46d9d Built: Wed Sep 16 17:01:30 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.3.7 GitCommit: 8fba4e9a7d01810a393d5d25a3621dc101981175 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest bf756fb1ae65 9 months ago 13.3kB[任意] sudoなしにdockerコマンドを実行可能にする。
$ sudo usermod -aG docker $USER3. NVIDIA Container Toolkit のインストール
2020年9月の更新で、
nvidia-docker2をインストールするだけでよくなったらしい。 (NVIDIA Docker って今どうなってるの? (20.09 版))
(nvidia-docker2をインストールすればnvidia-container-toolkitも一緒にインストールされる)$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID) $ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - $ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list $ sudo apt-get update $ sudo apt-get install -y nvidia-docker2 $ sudo systemctl restart docker4. Dockerでtensorflow2.3 + Python3.8の環境構築
Dockerfile_gpuに以下の内容を書き込む。
CUDA、cuDNNのバージョンは、インストールしたいフレームワークのバージョンに合わせて選択して下さい。
ここでは、tensorflow2.3に合わせて、CUDA10.1 + cuDNN7のイメージをベースにします。Dockerfile_gpuFROM nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04 ENV DEBIAN_FRONTEND noninteractive RUN apt-get update && apt-get install -y --no-install-recommends tzdata RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ curl \ make \ build-essential \ libssl-dev \ zlib1g-dev \ libbz2-dev \ libreadline-dev \ libsqlite3-dev \ llvm \ libncurses5-dev \ libncursesw5-dev \ xz-utils \ tk-dev \ libffi-dev \ liblzma-dev \ vim \ graphviz ENV TZ Asia/Tokyo WORKDIR /root/ RUN wget https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tar.xz \ && tar xvf Python-3.8.5.tar.xz \ && cd Python-3.8.5 \ && ./configure --enable-optimizations \ && make install RUN rm Python-3.8.5.tar.xz WORKDIR /root/Python-3.8.5 RUN ln -fs /root/Python-3.8.5/python /usr/bin/python RUN curl -kL https://bootstrap.pypa.io/get-pip.py | python RUN rm -rf /var/lib/apt/lists/* RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python ENV SHELL /bin/bash -l ENV POETRY_CACHE /work/.cache/poetry ENV PIP_CACHE_DIR /work/.cache/pip RUN $HOME/.poetry/bin/poetry config virtualenvs.path $POETRY_CACHE ENV PATH ${PATH}:/root/.poetry/bin:/bin:/usr/local/bin:/usr/bin CMD ["bash", "-l"]
Makefileに以下の内容を書き込む (IMAGE_NAMEは適宜書き換えて下さい)。MakefileFOLDER=$$(pwd) IMAGE_NAME=test:latest .PHONY: build-gpu build-gpu: # Build docker image echo "Building Dockerfile" docker build -t ${IMAGE_NAME} . -f Dockerfile_gpu .PHONY: start-gpu start-gpu: build-gpu # Start docker container echo "Starting container ${IMAGE_NAME}" docker run --gpus all --rm -it -v ${FOLDER}:/work -w /work ${IMAGE_NAME}Dockeイメージをbuildして、Dockerコンテナを作る。
$ make start-gpuPoetryで
tensorflow-gpu 2.3をインストール。# poetry init # poetry add tensorflow-gpu==2.3任意のファイルを実行する。
# poetry run python file_name.pyまとめ
本記事ではDockerを使って、tensorflow2.3 + Python3.8の環境構築をする手順を備忘録がてらにまとめました。
ホストOSにNVIDIAドライバ、Docker、NVIDIA Container Toolkitだけをインストールすれば良いのは便利ですね。
本記事ではPoetryでTensorFlowをインストールしましたが、Dockerfileでpip installしてももちろんOKです。Troubleshooting
apt update
Google Chrome絡みのエラー
https://sicklylife.hatenablog.com/entry/2017/08/08/193118"could not open" list file due to "permission denied"のエラー
https://askubuntu.com/a/1146593nouveau
nouveauの無効化
https://qiita.com/kawazu191128/items/8a46308be6949f5bda57#nouveau%E7%84%A1%E5%8A%B9%E5%8C%96apt-get install nvidia-driver-300
UEFIのSecure Bootが有効の場合、Secure Bootを無効にするか鍵の設定が必要。
Temporary failure resolving '....com'
https://github.com/moby/moby/issues/5779#issuecomment-323433618
DNSサーバを指定
- 投稿日:2020-10-20T21:12:55+09:00
Dockerfile リファレンス 日本語訳
Dockerfile reference の日本語訳。
Docker は Dockerfile から指示を読み取ることにより、イメージを自動的に構築できます。
Dockerfile はイメージを構築する為のコマンドを記述したテキストドキュメントです。
ユーザーがコマンドラインから呼び出して使用します。
docker build を使用することで、ユーザーは複数のコマンドライン命令を連続して実行する自動ビルドを作成できます。このページでは Dockerfile で使用できるコマンドについて説明します。
このページを読み終えたら Dockerfile Best Practices for a tip-oriented guide を参照してください。使用法
docker build コマンドは Dockerfile とコンテキストからイメージをビルドします。
ビルドのコンテキストは、指定された場所の PATH または URL にあるファイルのセットです。
PATH はローカルファイルシステム上のディレクトリです。
URL は Git リポジトリの場所です。コンテキストは再帰的に処理されます。
したがって PATH にはサブディレクトリが含まれ、 URL にはリポジトリとそのサブモジュールが含まれます。
次の例は、現在のディレクトリをコンテキストとして使用するビルドコマンドを示しています。$ docker build . Sending build context to Docker daemon 6.51 MB ...ビルドは CLI ではなく Docker デーモンによって実行されます。
ビルドプロセスが最初に行うことは、コンテキスト全体を(再帰的に)デーモンに送信することです。
ほとんどの場合、コンテキストとして空のディレクトリから開始し、Dockerfile をそのディレクトリに保持することをお勧めします。
Dockerfile の構築に必要なファイルのみを追加してください。警告
ルートディレクトリ/を PATH として使用しないでください。
ビルド実行時にハードドライブの内容全体が Docker デーモンに転送されます。ビルドコンテキストでファイルを使用する際、 Dockerfile は
COPY命令などの命令で指定されたファイルを参照します。
ビルドのパフォーマンスを向上させるには、コンテキストディレクトリに.dockerignoreファイルを追加してファイルとディレクトリを除外します。
.dockerignoreファイルを作成する方法については、このページのドキュメントを参照してください。慣例として Dockerfile はコンテキストのルートに配置しますが、
docker build で-fフラグを使用して、ファイルシステム内の任意の場所にあるDockerfileを指定できます。$ docker build -f /path/to/a/Dockerfile .ビルドが成功した場合に新しいイメージを保存するリポジトリとタグを指定できます。
$ docker build -t shykes/myapp .ビルド後にイメージを複数のリポジトリにタグ付けするには、ビルドコマンドの実行時に複数の
-tパラメータを追加します。$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .Docker デーモンは Dockerfile の命令を実行する前に、 Dockerfile の事前検証を実行し、構文が正しくない場合はエラーを返します。
$ docker build -t test/myapp . Sending build context to Docker daemon 2.048 kB Error response from daemon: Unknown instruction: RUNCMDDocker デーモンは Dockerfile 内の命令を 1 つずつ実行し、必要に応じて各命令の結果を新しいイメージにコミットしてから、最終的に新しいイメージの ID を出力します。
Docker デーモンは、送信したコンテキストを自動的にクリーンアップします。各命令は独立して実行され、新しいイメージが作成されることに注意してください。
したがってRUN cd /tmpは次の命令に影響を与えません。Docker は可能な場合は常に、中間イメージ(キャッシュ)を再利用して、Docker ビルドプロセスを大幅に高速化します。
中間イメージの再利用は、コンソール出力のUsing cacheメッセージによって示されます。
(詳細については Dockerfile ベストプラクティスガイド を参照してください)$ docker build -t svendowideit/ambassador . Sending build context to Docker daemon 15.36 kB Step 1/4 : FROM alpine:3.2 ---> 31f630c65071 Step 2/4 : MAINTAINER SvenDowideit@home.org.au ---> Using cache ---> 2a1c91448f5f Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/ ---> Using cache ---> 21ed6e7fbb73 Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh ---> Using cache ---> 7ea8aef582cc Successfully built 7ea8aef582ccビルドキャッシュは親チェーンを持つローカルイメージからのみ使用されます。
これはイメージが以前のビルドによって作成されたか、イメージのチェーン全体がdocker loadで読込まれたことを意味します。
特定のイメージのビルドキャッシュを使用する場合は--cache-fromオプションを使用して指定できます。
--cache-fromで指定されたイメージは、親チェーンを持つ必要はなく、他のレジストリから取得できます。ビルドが完了したら、リポジトリをレジストリにプッシュする方法を検討する準備が整います。
BuildKit
バージョン 18.09 以降の Docker は moby/buildkit プロジェクトによって提供されるビルドを実行するための新しいバックエンドをサポートします。
BuildKit バックエンドには、古い実装と比較して多くの利点があります。
たとえば BuildKit は次のことができます。
- 未使用のビルドステージの実行を検出してスキップします
- ビルドの独立したビルドステージを並列化します
- ビルド間でビルドコンテキスト内の変更されたファイルのみを段階的に転送します
- ビルドコンテキストで未使用のファイルの転送を検出してスキップします
- 多くの新機能を備えた外部 Dockerfile 実装を使用します
- 残りの API(中間イメージとコンテナー)での副作用を回避します
- 自動プルーニングのためにビルドキャッシュに優先順位を付けます
BuildKit バックエンドを使用するには docker build を呼び出す前に、 CLI で環境変数
DOCKER_BUILDKIT=1を設定する必要があります。BuildKit ベースのビルドで使用できる実験的な Dockerfile 構文については BuildKit リポジトリのドキュメント を参照してください。
Format
Dockerfile の形式は次のとおりです。
# Comment INSTRUCTION arguments命令では大文字と小文字は区別されません。
ただし、引数と区別しやすいように大文字にするのが慣例です。Docker は Dockerfile 内の命令を順番に実行します。
Dockerfile はFROM命令で始まる必要があります。
これは、パーサーディレクティブ、コメント、およびグローバルスコープのARGの後にある可能性があります。
FROM命令は、構築元の親イメージを指定します。
FROMの前には Dockerfile のFROM行で使用される引数を宣言する 1 つ以上のARG命令のみを付けることができます。Docker は行が有効なパーサーディレクティブでない限り
#で始まる行をコメントとして扱います。
行内の他の場所にある#マーカーは、引数として扱われます。
これにより、次のようなステートメントが可能になります。# Comment RUN echo 'we are running some # of cool things'Dockerfile 命令が実行される前にコメント行が削除されます。
つまり次の例のコメントは、echoコマンドを実行するシェルによって処理されません。
以下の両方の例は同等です。RUN echo hello \ # comment worldRUN echo hello \ world行継続文字はコメントではサポートされていません。
空白に関する注意
下位互換性のために、コメント(
#)および命令(RUNなど)の前の先頭の空白は無視されますが、推奨されません。
これらの場合、先頭の空白は保持されないため、次の例は同等です。# this is a comment-line RUN echo hello RUN echo world# this is a comment-line RUN echo hello RUN echo worldただし
RUNに続くコマンドなど、命令引数の空白は保持されるため、次の例では、先頭に空白を指定してhello worldを出力します。RUN echo "\ hello\ world"パーサーディレクティブ
パーサーディレクティブはオプションであり、 Dockerfile の後続の行が処理される方法に影響を与えます。
パーサーディレクティブはビルドにレイヤーを追加せず、ビルドステップとして表示されません。
パーサーディレクティブは# directive=valueの形式で特別なタイプのコメントとして記述されます。
1 つのディレクティブは 1 回だけ使用できます。コメント、空の行、またはビルダー命令が処理されると、 Docker はパーサーディレクティブを検索しなくなります。
パーサーディレクティブとして記述されたものをコメントとして扱い、パーサーディレクティブである可能性があるかどうかの検証を試みません。
したがって、すべてのパーサーディレクティブは Dockerfile の最上部にある必要があります。パーサーディレクティブでは大文字と小文字は区別されません。
ただし慣例では小文字にする必要があります。
慣例ではパーサーディレクティブの後に空白行を含めることもできます。
行継続文字は、パーサーディレクティブではサポートされていません。これらの規則により、次の例はすべて無効です。
行継続のため無効
# direc \ tive=value2 回表示されるため無効
# directive=value1 # directive=value2 FROM ImageNameビルダーの指示の後に表示されるため、コメントとして扱われます。
FROM ImageName # directive=valueパーサーディレクティブではないコメントの後に表示されるため、コメントとして扱われます。
# About my dockerfile # directive=value FROM ImageName
unknowndirectiveは、認識されないためコメントとして扱われます。
さらにknowndirectiveは、パーサーディレクティブではないコメントの後に表示されるため、コメントとして扱われます。# unknowndirective=value # knowndirective=valueパーサーディレクティブでは、改行のない空白が許可されています。
したがって、次の行はすべて同じように扱われます。#directive=value # directive =value # directive= value # directive = value # dIrEcTiVe=value次のパーサーディレクティブがサポートされています。
- syntax
- escape
syntax
# syntax=[remote image reference]例
# syntax=docker/dockerfile # syntax=docker/dockerfile:1.0 # syntax=docker.io/docker/dockerfile:1 # syntax=docker/dockerfile:1.0.0-experimental # syntax=example.com/user/repo:tag@sha256:abcdef...この機能は BuildKit バックエンドが使用されている場合にのみ有効になります。
syntaxディレクティブは、現在の Dockerfile のビルドに使用される Dockerfile ビルダーの場所を定義します。
BuildKit バックエンドを使用すると Docker イメージとして配布され、コンテナーサンドボックス環境内で実行されるビルダーの外部実装をシームレスに使用できます。カスタム Dockerfile 実装により、次のことが可能になります。
- デーモンを更新せずにバグ修正を自動的に取得する
- すべてのユーザーが同じ実装を使用して Dockerfile をビルドしていることを保証できる
- デーモンを更新せずに最新の機能を使用することができる
- 新しい実験的またはサードパーティの機能を試すことができる
公式リリース
Docker は DockerHub の docker/dockerfile リポジトリーに Dockerfile を構築するために使用できるイメージの公式バージョンを配布しています。
新しいイメージがリリースされるチャネルは、安定版と実験版の 2 つです。安定版チャネルは、セマンティックバージョニングに従います。
例:
- docker/dockerfile:1.0.0 - 不変バージョン 1.0.0 のみを許可する
- docker/dockerfile:1.0 - バージョン 1.0.* を許可する
- docker/dockerfile:1 - versions 1.. を許可する
- docker/dockerfile:latest - 安定版チャネルの最新リリース
実験版チャネルは、リリース時の安定版チャネルからのメジャーコンポーネントとマイナーコンポーネントを使用したインクリメンタルバージョン管理を使用します。
例:
- docker/dockerfile:1.0.1-experimental - 不変バージョン 1.0.1-experimental のみを許可する
- docker/dockerfile:1.0-experimental - 1.0 以降の最新の実験版リリース
- docker/dockerfile:experimental - 実験版チャネルの最新リリース
ニーズに適したチャネルを選択する必要があります。
バグ修正のみが必要な場合は docker/dockerfile:1.0 を使用する必要があります。
実験的な機能を活用したい場合は、実験版チャネルを使用する必要があります。
実験チャネルを使用している場合、新しいリリースには下位互換性がない可能性があるため、不変のフルバージョンバリアントを使用することをお勧めします。マスタービルドとナイトリー機能リリースについては ソースリポジトリの説明 を参照してください。
escape
# escape=\ (backslash)または
# escape=` (backtick)エスケープディレクティブは Dockerfile 内の文字をエスケープするために使用される文字を設定します。
指定しない場合、デフォルトのエスケープ文字は\です。エスケープ文字は、行内の文字をエスケープするためと、改行をエスケープするための両方に使用されます。
これにより Dockerfile 命令を複数行にまたがることができます。
escapeパーサーディレクティブが Dockerfile に含まれているかどうかに関係なく、エスケープは、行の終わりを除いて、RUNコマンドでは実行されないことに注意してください。エスケープ文字を「 ` 」に設定すると Windows で特に役立ちます。
ここでは\はディレクトリパスの区切り文字です。
「 ` 」は Windows PowerShell と一貫性があります。Windows で自明ではない方法で失敗する次の例を考えてみましょう。
2 行目の終わりにある 2 番目の\は、最初の\からのエスケープのターゲットではなく、改行のエスケープとして解釈されます。
同様に 3 行目の終わりにある\は、実際に命令として処理されたとすると、行の継続として扱われます。
この dockerfile の結果は 2 行目と 3 行目が単一の命令と見なされることです。FROM microsoft/nanoserver COPY testfile.txt c:\\ RUN dir c:\実行結果:
PS C:\John> docker build -t cmd . Sending build context to Docker daemon 3.072 kB Step 1/2 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/2 : COPY testfile.txt c:\RUN dir c: GetFileAttributesEx c:RUN: The system cannot find the file specified. PS C:\John>上記の解決策の 1 つは
COPY命令とdirの両方のターゲットとして/を使用することです。
ただし、この構文は Windows のパスでは自然ではないため混乱を招きます。
最悪の場合 Windows のすべてのコマンドがパス区切り文字として/をサポートしているわけではないため、エラーが発生しやすくなります。
escapeパーサーディレクティブを追加することにより、次の Dockerfile は Windows のファイルパスに自然なプラットフォームセマンティクスを使用して期待どおりに成功します。# escape=` FROM microsoft/nanoserver COPY testfile.txt c:\ RUN dir c:\実行結果:
PS C:\John> docker build -t succeeds --no-cache=true . Sending build context to Docker daemon 3.072 kB Step 1/3 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/3 : COPY testfile.txt c:\ ---> 96655de338de Removing intermediate container 4db9acbb1682 Step 3/3 : RUN dir c:\ ---> Running in a2c157f842f5 Volume in drive C has no label. Volume Serial Number is 7E6D-E0F7 Directory of c:\ 10/05/2016 05:04 PM 1,894 License.txt 10/05/2016 02:22 PM <DIR> Program Files 10/05/2016 02:14 PM <DIR> Program Files (x86) 10/28/2016 11:18 AM 62 testfile.txt 10/28/2016 11:20 AM <DIR> Users 10/28/2016 11:20 AM <DIR> Windows 2 File(s) 1,956 bytes 4 Dir(s) 21,259,096,064 bytes free ---> 01c7f3bef04f Removing intermediate container a2c157f842f5 Successfully built 01c7f3bef04f PS C:\John>環境変数の置換
環境変数(
ENVステートメントで宣言)は、 Dockerfile によって解釈される変数として特定の命令で使用することもできます。
エスケープは、変数に似た構文をそのままステートメントに含めるためにも処理されます。環境変数は Dockerfile で
$variable_nameまたは${variable_name}のいずれかで表記されます。
それらは同等に扱われ、中括弧構文は通常${foo} _barのように空白のない変数名の問題に対処するために使用されます。
${variable_name}構文は、以下に指定されている標準の bash 修飾子のいくつかもサポートしています。
${variable:-word}は変数が設定されている場合、結果がその値になることを示します。 変数が設定されていない場合wordが結果になります。${variable:+word}は、変数が設定されている場合はwordが結果になり、それ以外の場合は結果が空の文字列になることを示します。すべての場合において
wordは、追加の環境変数を含む任意の文字列にすることができます。エスケープは変数の前に
\を追加することで可能です。
たとえば\$ fooまたは\${foo}は、$fooと${foo}に変換されます。例(解析された表現は
#の後に表示されます):FROM busybox ENV FOO=/bar WORKDIR ${FOO} # WORKDIR /bar ADD . $FOO # ADD . /bar COPY \$FOO /quux # COPY $FOO /quux環境変数は Dockerfile の以下に示す命令でサポートされています。
- ADD
- COPY
- ENV
- EXPOSE
- FROM
- LABEL
- STOPSIGNAL
- USER
- VOLUME
- WORKDIR
- ONBUILD (上記のサポートされている手順の 1 つと組み合わせた場合)
環境変数の置換では、命令全体を通じて各変数に同じ値が使用されます。
言い換えると、この例では次のようになります。ENV abc=hello ENV abc=bye def=$abc ENV ghi=$abc結果は
byeではなくhelloの値を持つdefになります。
ただしghiはabcをbyeに設定したのと同じ命令の一部ではないため、byeの値になります。.dockerignore ファイル
docker CLI はコンテキストを docker デーモンに送信する前に、コンテキストのルートディレクトリで
.dockerignoreという名前のファイルを探します。
このファイルが存在する場合 CLI はコンテキストを変更して、その中のパターンに一致するファイルとディレクトリを除外します。
これにより、大きなファイルや機密性の高いファイルやディレクトリをデーモンに不必要に送信したり、ADDまたはCOPYを使用してイメージに追加したりすることを回避できます。CLIは
.dockerignoreファイルを Unix シェルのファイルグロブに似た改行で区切られたパターンのリストとして解釈します。
照合の目的で、コンテキストのルートは作業ディレクトリとルートディレクトリの両方であると見なされます。
たとえば、パターン/foo/barとfoo/barはどちらも、PATHのfooサブディレクトリまたは URL にある git リポジトリのルートにあるbarという名前のファイルまたはディレクトリを除外します。
どちらも他のものを除外しません。
.dockerignoreファイルの行が 1 列目の#で始まる場合、この行はコメントと見なされ、 CLI によって解釈される前に無視されます。
.dockerignoreファイルの記述例を示します:# comment */temp* */*/temp* temp?このファイルにより、次のビルド動作が発生します。
ルール 動作 # comment無視します。 */temp*ルートの直接のサブディレクトリで、名前が tempで始まるファイルとディレクトリを除外します。たとえば、プレーンファイル/somedir/temporary.txtは除外され、ディレクトリ/somedir/tempも除外されます。*/*/temp*ルートの 2 階層下にあるサブディレクトリから tempで始まるファイルとディレクトリを除外します。たとえば、/somedir/subdir/temporary.txtは除外されます。temp?名前が temp + 1 文字であるルートディレクトリ内のファイルとディレクトリを除外します。たとえば、 /tempaと/tempbは除外されます。マッチングは Go の
filepath.Matchルールを使用して行われます。
前処理ステップでは Go のfilepath.Cleanを使用して、先頭と末尾の空白を削除し、.要素と..要素を削除します。
前処理後に空白の行は無視されます。Docker は Go の
filepath.Matchルールに加えて、任意の数のディレクトリ(ゼロを含む)に一致する特別なワイルドカード文字列**もサポートしています。
たとえば**/*.goはビルドコンテキストのルートを含むすべてのディレクトリにある.goで終わるすべてのファイルを除外します。
!(感嘆符)で始まる行を使用して、除外の例外を作成できます。
以下は、この仕組みを使用する.dockerignoreファイルの例です。*.md !README.md
README.mdを除くすべてのマークダウンファイルはコンテキストから除外されます。
!例外ルールの配置は、動作に影響を与えます。
特定のファイルに一致する.dockerignoreの最後の行は、そのファイルが含まれるか除外されるかを決定します。
次の例を考えてみましょう。*.md !README*.md README-secret.md
README-secret.md以外のREADMEファイルを除いて、マークダウンファイルはコンテキストに含まれていません。ここで、この例を検討します。
*.md README-secret.md !README*.mdすべての
READMEファイルが含まれています。
!README*.mdはREADME-secret.mdと一致し、最後に来るため、真ん中の行は効果がありません。
.dockerignoreファイルを使用して Dockerfile ファイルと.dockerignoreファイルを除外することもできます。
これらのファイルは、そのジョブを実行する必要があるため、引き続きデーモンに送信されます。
ただしADDおよびCOPY命令はそれらをイメージにコピーしません。最後に、除外するファイルではなく、コンテキストに含めるファイルを指定することをお勧めします。
これを実現するには、最初のパターンとして*を指定し、その後に 1 つ以上の!例外パターンを指定します。注意
歴史的な理由から、パターン
.は無視されます。FROM
FROM [--platform=<platform>] <image> [AS <name>]または
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]または
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
FROM命令は、新しいビルドステージを初期化し、後続の命令のベースイメージを設定します。
そのため、有効な Dockerfile はFROM命令で始まる必要があります。
イメージは任意の有効なイメージを指定することができます。
パブリックリポジトリからイメージを取得することから始めるのは特に簡単です。
ARGは Dockerfile のFROMの前にある可能性がある唯一の命令です。ARGとFROMの相互作用を理解する を参照してください。FROMは、単一の Dockerfile 内に複数回出現して、複数のイメージを作成したり、あるビルドステージを別のビルドステージの依存関係として使用したりできます。 新しいFROM命令の前に、commitによって出力された最後のイメージ ID をメモするだけです。 各FROM命令は、前の命令によって作成されたすべての状態をクリアします。- オプションで
FROM命令にAS nameを追加することにより、新しいビルドステージに名前を付けることができます。 この名前は、後続のFROMおよびCOPY --from=<name>命令で使用して、このステージで作成されたイメージを参照できます。- タグまたはダイジェスト値はオプションです。 いずれかを省略すると、ビルダーはデフォルトで最新のタグを想定します。 タグ値が見つからない場合、ビルダーはエラーを返します。
オプションの
--platformフラグを使用して、FROMがマルチプラットフォームイメージを参照する場合にイメージのプラットフォームを指定できます。
たとえば、linux/amd64、linux/arm64、またはwindows/amd64です。
デフォルトでは、ビルドリクエストのターゲットプラットフォームが使用されます。
このフラグの値にはグローバルビルド引数を使用できます。
たとえば、自動プラットフォーム引数を使用すると、ステージをネイティブビルドプラットフォームに強制し、それを使用してステージ内のターゲットプラットフォームにクロスコンパイルできます。
(--platform=$BUILDPLATFORM)
ARGとFROMの相互作用を理解する
FROM命令は、最初のFROMの前に発生するARG命令によって宣言される変数をサポートします。ARG CODE_VERSION=latest FROM base:${CODE_VERSION} CMD /code/run-app FROM extras:${CODE_VERSION} CMD /code/run-extras
FROMの前に宣言されたARGはビルドステージの外にあるため、FROMの後の命令では使用できません。
最初のFROMの前に宣言されたARGのデフォルト値を使用するには、ビルドステージ内で値なしでARG命令を使用します。ARG VERSION=latest FROM busybox:$VERSION ARG VERSION RUN echo $VERSION > image_versionRUN
RUNは 2 種類の形式があります:
RUN <command>(シェル形式。コマンドはシェル上で実行される。 Linux の既定シェルは/bin/sh -c。 Windows の既定シェルはcmd /S /C)RUN ["executable", "param1", "param2"](exec形式)
RUN命令は、現在のイメージ上にある新しいレイヤーでコマンドを実行し、結果をコミットします。
結果がコミットされたイメージは Dockerfile の次のステップで使用されます。
RUN命令を階層化し、コミットを生成することは、コミットが安価で、ソース管理のようにイメージの履歴の任意のポイントからコンテナを作成できる Docker のコアコンセプトに準拠しています。
exec形式を使用すると、シェル文字列の変更を回避したり、指定したシェル実行可能ファイルを含まないベースイメージを使用してRUNコマンドを実行できます。シェル形式の既定のシェルは
SHELLコマンドを使用して変更できます。シェル形式では、
\(バックスラッシュ)を使用して、単一のRUN命令を次の行に続けることができます。
たとえば、次の 2 行について考えてみます。RUN /bin/bash -c 'source $HOME/.bashrc; \ echo $HOME'これらを合わせると、次の 1 行に相当します。
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
/bin/sh以外の別のシェルを使用するには、目的のシェルを渡すexec形式を使用します。例えば:RUN ["/bin/bash", "-c", "echo hello"]注意
exec形式は JSON 配列として解析されます。
つまり一重引用符(')ではなく、単語の前後に二重引用符(")を使用する必要があります。シェル形式とは異なり、
exec形式はコマンドシェルを呼び出しません。
これは、通常のシェル処理が行われないことを意味します。
たとえば、RUN ["echo", "$HOME"]は、$HOMEの変数置換を行いません。
シェル処理が必要な場合は、シェル形式を使用するか、シェルを直接実行します。
例:RUN ["sh", "-c", "echo $ HOME"]。
シェル形式の場合のように、exec形式を使用してシェルを直接実行する場合、環境変数の展開を行うのは Docker ではなく、シェルです。注意
JSON 形式では、バックスラッシュをエスケープする必要があります。
これは、バックスラッシュがパス区切り文字である Windows に特に関係があります。
次の行は、有効な JSON ではないため、シェル形式として扱われ、予期しない方法で失敗します:RUN ["c:\windows\system32\tasklist.exe"]この例の正しい構文は次のとおりです:
RUN ["c:\\windows\\system32\\tasklist.exe"]
RUN命令のキャッシュは、次のビルド中に自動的に無効になることはありません。
RUN apt-get dist-upgrade -yのような命令のキャッシュは、次のビルドで再利用されます。
RUN命令のキャッシュは--no-cacheフラグを使用して無効にすることができます(例:docker build --no-cache)。詳細については Dockerfile ベストプラクティスガイド を参照してください。
RUN命令のキャッシュは、ADDおよびCOPY命令によって無効にすることができます。既知の問題(
RUN)
- イシュー 783 は、 AUFS ファイルシステムの使用時に発生する可能性のあるファイル権限の問題に関するものです。 たとえば、ファイルを
rmしようとしたときに気付くかもしれません。 最近の aufs バージョンがあるシステム(つまりdirperm1マウントオプションを設定できる)の場合、 docker はdirperm1オプションを使用してレイヤーをマウントすることで問題を自動的に修正しようとします。dirperm1オプションの詳細については aufs の man ページ を参照してください。 システムでdirperm1がサポートされていない場合、 イシュー 783 は回避策を説明しています。CMD
CMD命令は 3 つの形式を持ちます:
CMD ["executable","param1","param2"](exec形式。これが推奨される形式です)CMD ["param1","param2"](ENTRYPOINTへのデフォルトパラメータとして使用します)CMD command param1 param2(シェル形式)Dockerfile には 1 つの
CMD命令しか存在できません。
複数のCMDを列記すると、最後のCMDのみが有効になります。
CMDの主な目的は、実行中のコンテナに既定の動作を提供することです。
これらの既定の動作には、executableを含めることも、executableを省略することもできます。
executableを省略する場合はENTRYPOINT命令も指定する必要があります。
CMDを使用してENTRYPOINT命令のデフォルトの引数を提供する場合は、CMD命令とENTRYPOINT命令の両方を JSON 配列形式で指定する必要があります。注意
exec形式は JSON 配列として解析されます。
つまり単語の前後に一重引用符(')ではなく、二重引用符(")を使用する必要があります。シェル形式とは異なり、
exec形式はコマンドシェルを呼び出しません。
これは、通常のシェル処理が行われないことを意味します。
たとえばCMD ["echo", "$HOME"]は、$HOMEで変数置換を行いません。
シェル処理が必要な場合は、シェル形式を使用するか、シェルを直接実行します。
例:CMD ["sh"、 "-c"、 "echo $ HOME"]
シェル形式の場合のように、exec形式を使用してシェルを直接実行する場合、環境変数の展開を行うのは Docker ではなく、シェルです。シェル形式または
exec形式で使用する場合、CMD命令は、イメージの実行時に実行されるコマンドを設定します。
CMDのシェル形式を使用する場合、<command>は/bin/sh -cで実行されます:FROM ubuntu CMD echo "This is a test." | wc -シェルなしで
<command>を実行したい場合は、コマンドを JSON 配列として表現し、executableへのフルパスを指定する必要があります。
この配列形式は、CMDの推奨フォーマットです。
追加のパラメータは、配列内の文字列として個別に表現する必要があります。FROM ubuntu CMD ["/usr/bin/wc","--help"]コンテナで毎回同じ
executableを実行したい場合は、ENTRYPOINTをCMDと組み合わせて使用することを検討する必要があります。
ENTRYPOINTを参照してください。ユーザーが docker run の引数を指定すると、
CMDで指定された既定値が上書きされます。注意
RUNとCMDを混同しないでください。
RUNは実際にコマンドを実行し、結果をコミットします。
CMDはビルド時に何も実行しませんが、イメージに実行させたいコマンドを指定します。LABEL
LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL命令はメタデータをイメージに追加します。
LABELはキーと値のペアです。
LABELの値にスペースを含めるには、コマンドライン解析の場合と同じように引用符とバックスラッシュを使用します。使用例:
LABEL "com.example.vendor"="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0" LABEL description="This text illustrates \ that label-values can span multiple lines."イメージには複数のラベルを付けることができます。
1 行に複数のラベルを指定できます。
Docker 1.10 より前は、これにより最終イメージのサイズが小さくなりましたが、現在はそうではありません。
次の 2 つの方法のいずれかで、 1 つの命令で複数のラベルを指定することもできます。LABEL multi.label1="value1" multi.label2="value2" other="value3"LABEL multi.label1="value1" \ multi.label2="value2" \ other="value3"ベースイメージまたは親イメージ(
FROM行のイメージ)に含まれるラベルは、子イメージに継承されます。
ラベルがすでに存在するが値が異なる場合、最後に適用された値が以前に設定された値を上書きします。イメージのラベルを表示するには
docker image inspectコマンドを使用します。
--formatオプションを使用してラベルのみを表示できます。docker image inspect --format='' myimage{ "com.example.vendor": "ACME Incorporated", "com.example.label-with-value": "foo", "version": "1.0", "description": "This text illustrates that label-values can span multiple lines.", "multi.label1": "value1", "multi.label2": "value2", "other": "value3" }MAINTAINER (非推奨)
MAINTAINER <name>
MAINTAINER命令は、生成されたイメージのAuthorフィールドを設定します。
LABEL命令はMAINTAINERよりもはるかに柔軟に必要なメタデータを設定できます。
代わりにLABELを使用してください。
たとえばdocker inspectを使用して簡単に表示できます。
MAINTAINERフィールドに対応するラベルを設定するには:LABEL maintainer="SvenDowideit@home.org.au"これは、他のラベルとともに
docker inspectから表示されます。EXPOSE
EXPOSE <port> [<port>/<protocol>...]
EXPOSE命令は、コンテナ実行時に指定されたネットワークポートで待受けすることを Docker に通知します。
ポートが TCP と UDP のどちらで待受けするかを指定できます。
プロトコルが指定されていない場合、既定値は TCP です。
EXPOSE命令は、実際にはポートを公開しません。
これは、イメージを作成する人とコンテナーを実行する人の間の一種のドキュメントとして機能し、ポートの公開が意図されています。
コンテナの実行時に実際にポートを公開するには、 docker run で-pフラグを使用して 1 つ以上のポートを公開して紐づけするか、-Pフラグを使用して公開されたすべてのポートを公開し、それらを上位ポートに紐づけします。デフォルトでは
EXPOSEは TCP を想定していますが、
UDP を指定することもできます。EXPOSE 80/udpTCP と UDP の両方で公開するには、次の 2 行を記述します。
EXPOSE 80/tcp EXPOSE 80/udpこの場合 docker run で
-Pを使用すると、ポートは TCP 用に 1 回、 UDP 用に 1 回公開されます。
-Pはホスト上で一時的な上位ホストポートを使用するため、ポートは TCP と UDP で同じではないことに注意してください。
EXPOSE設定に関係なく-pフラグを使用して実行時にそれらをオーバーライドできます。例:
docker run -p 80:80/tcp -p 80:80/udp ...ホストシステムでポートリダイレクションを設定するには
-Pフラグの使用を参照してください。
docker networkコマンドは、特定のポートを公開(expose または publish)する必要なしに、コンテナー間の通信用のネットワークの作成をサポートします。
これは、ネットワークに接続されたコンテナーが任意のポートを介して相互に通信できるためです。
詳細については、 docker network 機能の概要 を参照してください。ENV
ENV <key>=<value> ...
ENV命令は、環境変数<key>を値<value>に設定します。
この値は、ビルドステージの後続のすべての命令の環境にあり、多くの場合、インラインで置き換えることができます。
値は他の環境変数に対して解釈されるため、引用符がエスケープされていない場合は削除されます。
コマンドライン解析と同様に、引用符とバックスラッシュを使用して値にスペースを含めることができます。例:
ENV MY_NAME="John Doe" ENV MY_DOG=Rex\ The\ Dog ENV MY_CAT=fluffy
ENV命令では、複数の<key>=<value> ...変数を一度に設定できます。
以下の例では、最終的なイメージで同じ最終結果が得られます。ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \ MY_CAT=fluffy
ENVを使用して設定された環境変数は、結果のイメージからコンテナが実行されたときに保持されます。
docker inspectを使用して値を表示し、docker run --env <key>=<value>を使用して値を変更できます。環境変数の永続性は、予期しない副作用を引き起こす可能性があります。
たとえばENV DEBIAN_FRONTEND=noninteractiveを設定すると、apt-getの動作が変更され、イメージのユーザーを混乱させる可能性があります。環境変数がビルド中にのみ必要であり、最終イメージでは必要ない場合は、代わりに単一のコマンドの値を設定することを検討してください。
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...または最終的なイメージに保持されない
ARGを使用します。ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y ...代替記法
ENV命令では代替構文ENV <key> <value>を使用でき、=を省略できます。例:
ENV MY_VAR my-valueこの構文では複数の環境変数を 1 つの
ENV命令に設定することはできず、混乱を招く可能性があります。
たとえば次のように、単一の環境変数ONEを値"TWO = THREE = world"で設定します。ENV ONE TWO= THREE=world代替構文は下位互換性のためにサポートされていますが、上記の理由により推奨されておらず、将来のリリースで削除される可能性があります。
ADD
ADDは 2 つの形式を持ちます:ADD [--chown=<user>:<group>] <src>... <dest> ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]空白を含むパスには後者の形式が必要です。
注意
--chown機能は Linux コンテナの構築に使用される Dockerfile でのみサポートされており、 Windows コンテナでは機能しません。
ユーザーとグループの所有権の概念は Linux と Windows の間で変換されないため、ユーザー名とグループ名を ID に変換するために/etc/passwdと/etc/groupを使用すると、この機能は Linux OS ベースのコンテナである場合に限り実行可能に制限されます。
ADD命令は、新しいファイル、ディレクトリ、またはリモートファイルの URL を<src>からコピーし、パス<dest>でイメージのファイルシステムに追加します。複数の
<src>リソースを指定できますが、それらがファイルまたはディレクトリの場合、パスはビルドのコンテキストのソースからの相対パスとして解釈されます。各
<src>にはワイルドカードを含めることができ、照合は Go のfilepath.Matchルールを使用して行われます。
例えばhomで始まるすべてのファイルを追加するには:ADD hom* /mydir/以下の例では
?はhome.txtなどの任意の 1 文字に置き換えられています。ADD hom?.txt /mydir/
<dest>は絶対パス、またはWORKDIRから見た相対パスであり、ソースは宛先コンテナ内にコピーされます。以下の例では、相対パスを使用して
test.txtを<WORKDIR>/relativeDir/に追加しています:ADD test.txt relativeDir/この例では絶対パスを使用して
test.txtを/abstractDir/に追加します。ADD test.txt /absoluteDir/特殊文字(
[や]など)を含むファイルやディレクトリを追加する場合は、一致するパターンとして扱われないように、 Go 言語のルールに従ってこれらのパスをエスケープする必要があります。
たとえば、arr[0].txtという名前のファイルを追加するには、次を使用します。ADD arr[[]0].txt /mydir/追加されたコンテンツの特定の所有権を要求するために、オプションの
--chownフラグが特定のユーザー名、グループ名、またはUID / GIDの組み合わせを指定しない限り、すべての新しいファイルとディレクトリは UID と GID が 0 で作成されます。
--chownフラグの形式では、ユーザー名とグループ名の文字列、または直接整数の UID と GID を任意の組み合わせで使用できます。
グループ名なしのユーザー名または GID なしの UID を指定すると、 GID と同じ数値の UID が使用されます。
ユーザー名またはグループ名が指定されている場合、コンテナのルートファイルシステムの/etc/passwdファイルと/etc/groupファイルを使用して、名前から整数の UID または GID への変換がそれぞれ実行されます。
次の例は、--chownフラグの有効な定義を示しています。ADD --chown=55:mygroup files* /somedir/ ADD --chown=bin files* /somedir/ ADD --chown=1 files* /somedir/ ADD --chown=10:11 files* /somedir/コンテナルートファイルシステムに
/etc/passwdまたは/etc/groupファイルが含まれておらず、ユーザー名またはグループ名が--chownフラグで使用されている場合、ADD操作でビルドは失敗します。
数値 ID の使用はルックアップを必要とせず、コンテナルートファイルシステムのコンテンツに依存しません。
<src>がリモートファイルの URL の場合、宛先には 600 の権限があります。
取得するリモートファイルに HTTP Last-Modified ヘッダーがある場合、そのヘッダーのタイムスタンプを使用して、宛先ファイルの mtime を設定します。
ただしADD中に処理される他のファイルと同様に、 mtime は、ファイルが変更されたかどうかの判断には含まれず、キャッシュを更新する必要があります。注意
Dockerfile を
STDIN(docker build- <somefile)に渡してビルドする場合、ビルドコンテキストがないため、 Dockerfile には URL ベースのADD命令のみを含めることができます。
圧縮されたアーカイブをSTDIN: (docker build- <archive.tar.gz)を介して渡すこともできます。アーカイブのルートにある Dockerfile と、アーカイブの残りの部分がビルドのコンテキストとして使用されます。URL ファイルが認証を使用して保護されている場合、
ADD命令は認証をサポートしていないため、RUN wgetやRUN curlを使用するか、コンテナ内から別のツールを使用する必要があります。注意
最初に検出された
ADD命令は、<src>の内容が変更された場合、 Dockerfile からの後続のすべての命令のキャッシュを無効にします。
これにはRUN命令のキャッシュの無効化が含まれます。
詳細については Dockerfile ベストプラクティスガイド – ビルドキャッシュを活用する を参照してください。
ADDは次のルールに従います。
<src>パスはビルドのコンテキスト内にある必要があります。 docker build の最初のステップはコンテキストディレクトリ(およびサブディレクトリ)を docker デーモンに送信することであるため、ADD ../something / somethingはできません。<src>が URL であり、<dest>が末尾のスラッシュで終わっていない場合、ファイルは URL からダウンロードされ、<dest>にコピーされます。<src>が URL で、<dest>が末尾にスラッシュで終わっている場合、ファイル名は URL から推測され、ファイルは<dest>/<filename>にダウンロードされます。 たとえば、ADD http://example.com/foobar /はファイル/foobarを作成します。 この場合、適切なファイル名を検出できるように URL には重要なパスが必要です(http://example.comは機能しません)。<src>がディレクトリの場合、ファイルシステムのメタデータを含むディレクトリの内容全体がコピーされます。注意
ディレクトリ自体はコピーされず、その内容だけがコピーされます。
<src>が認識された圧縮形式(gzip,bzip2またはxz)のローカル tar アーカイブである場合、ディレクトリとして解凍されます。 リモート URL からのリソースは解凍されません。 ディレクトリがコピーまたは解凍されるとtar -xと同じ動作になり、結果は次の和集合になります。
- 宛先パスに存在するものは何でも
- 競合するソースツリーの内容はファイルごとに
2を優先して解決されます。注意
ファイルが認識された圧縮形式として識別されるかどうかは、ファイルの名前ではなく、ファイルの内容のみに基づいて行われます。
たとえば、空のファイルがたまたま.tar.gzで終わっている場合、これは圧縮ファイルとして認識されず、解凍エラーメッセージは生成されず、ファイルは単に宛先にコピーされます。
<src>が他の種類のファイルの場合、メタデータとともに個別にコピーされます。 この場合<dest>の末尾にスラッシュ/が付いていると、ディレクトリと見なされ、<src>の内容は<dest>/base(<src>)に書き込まれます。- 直接またはワイルドカードの使用により複数の
<src>リソースが指定されている場合、<dest>はディレクトリである必要があり、スラッシュ/で終了する必要があります。<dest>が末尾のスラッシュで終わっていない場合、それは通常のファイルと見なされ、<src>の内容は<dest>に書き込まれます。<dest>が存在しない場合は、パスに欠落しているすべてのディレクトリとともに作成されます。COPY
COPYは 2 つの形式を持ちます:COPY [--chown=<user>:<group>] <src>... <dest> COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]後者の形式は、空白を含むパスに必要です。
注意
--chown機能は Linux コンテナの構築に使用される Dockerfile でのみサポートされており、 Windows コンテナでは機能しません。
ユーザーとグループの所有権の概念は Linux と Windows の間で変換されないため、ユーザー名とグループ名を ID に変換するために/etc/passwdと/etc/groupを使用します。
この機能は Linux OS ベースのコンテナである場合に限り実行可能に制限されます。
COPY命令は、新しいファイルまたはディレクトリを<src>からコピーし、パス<dest>でコンテナのファイルシステムに追加します。複数の
<src>リソースを指定できますが、ファイルとディレクトリのパスは、ビルドのコンテキストのソースから見た相対パスとして解釈されます。各
<src>にはワイルドカードを含めることができ、照合は Go のfilepath.Matchルールを使用して行われます。
例えばhomで始まるすべてのファイルを追加するには:COPY hom* /mydir/以下の例では
?はhome.txtなどの任意の 1 文字に置き換えられています。COPY hom?.txt /mydir/
<dest>は絶対パス、またはWORKDIRに相対的なパスであり、ソースは宛先コンテナ内にコピーされます。以下の例では相対パスを使用して
test.txtを<WORKDIR>/relativeDir/に追加しています。COPY test.txt relativeDir/この例では絶対パスを使用して
test.txtを/abstractDir/に追加します。COPY test.txt /absoluteDir/特殊文字(
[や]など)を含むファイルやディレクトリをコピーする場合は、Go 言語のルールに従ってこれらのパスをエスケープして、一致するパターンとして扱われないようにする必要があります。
たとえば、arr[0].txtという名前のファイルをコピーするには、次を使用します。COPY arr[[]0].txt /mydir/オプションの
--chownフラグが、コピーされたコンテンツの特定の所有権を要求するために特定のユーザー名、グループ名、またはUID / GIDの組み合わせを指定しない限り、すべての新しいファイルとディレクトリは UID と GID が 0 で作成されます。
--chownフラグの形式では、ユーザー名とグループ名の文字列、または直接整数の UID と GID を任意の組み合わせで使用できます。
グループ名なしのユーザー名または GID なしの UID を指定すると、 GID と同じ数値の UID が使用されます。
ユーザー名またはグループ名が指定されている場合、コンテナのルートファイルシステムの/etc/passwdファイルと/etc/groupファイルを使用して、名前から整数の UID または GID への変換がそれぞれ実行されます。
次の例は、--chownフラグの有効な定義を示しています。COPY --chown=55:mygroup files* /somedir/ COPY --chown=bin files* /somedir/ COPY --chown=1 files* /somedir/ COPY --chown=10:11 files* /somedir/コンテナのルートファイルシステムに
/etc/passwdまたは/etc/groupファイルが含まれておらず、ユーザー名またはグループ名が--chownフラグで使用されている場合、ビルドはCOPY操作で失敗します。
数値 ID の使用はルックアップを必要とせず、コンテナルートファイルシステムのコンテンツに依存しません。注意
STDIN(docker build- < somefile)を使用してビルドする場合、ビルドコンテキストがないためCOPYは使用できません。オプションで
COPYは、ソースの場所を前のビルドステージ(FROM .. AS <name>で作成)に設定するために使用できるフラグ--from=<name>を受け入れます。
ユーザーが送信するビルドコンテキストの代わりに使用されます。
指定された名前のビルドステージが見つからない場合は、代わりに同じ名前のイメージが使用されます。
COPYは次のルールに従います:
<src>パスはビルドのコンテキスト内にある必要があります。dockerbuildの最初のステップはコンテキストディレクトリ(およびサブディレクトリ)を docker デーモンに送信することであるため、COPY ../something /somethingはできません。<src>がディレクトリの場合、ファイルシステムのメタデータを含むディレクトリの内容全体がコピーされます。注意
ディレクトリ自体はコピーされず、その内容だけがコピーされます。
<src>がディレクトリ以外の種類のファイルの場合、メタデータとともに個別にコピーされます。 この場合<dest>の末尾にスラッシュ/が付いていると、ディレクトリと見なされ、<src>の内容は<dest>/base(<src>)に書き込まれます。- 直接またはワイルドカードの使用により複数の
<src>リソースが指定されている場合、<dest>はディレクトリである必要があり、スラッシュ/で終了する必要があります。<dest>が末尾のスラッシュで終わっていない場合、それは通常のファイルと見なされ、<src>の内容は<dest>に書き込まれます。<dest>が存在しない場合は、パスに欠落しているすべてのディレクトリとともに作成されます。注意
最初に検出された
COPY命令は<src>の内容が変更された場合、 Dockerfile からの後続のすべての命令のキャッシュを無効にします。
これにはRUN命令のキャッシュの無効化が含まれます。
詳細については Dockerfile ベストプラクティスガイド – ビルドキャッシュを活用する を参照してください。ENTRYPOINT
ENTRYPOINTは 2 つの形式を持ちます:推奨形式は
exec形式です:ENTRYPOINT ["executable", "param1", "param2"]シェル形式:
ENTRYPOINT command param1 param2
ENTRYPOINTを使用すると、executableが実行されるコンテナを構成できます。たとえば次の例では、 nginx をデフォルトのコンテンツで開始し、ポート 80 で待受けます。
$ docker run -i -t --rm -p 80:80 nginx
docker run <image>へのコマンドライン引数はexec形式ENTRYPOINTのすべての要素の後に追加され、CMDを使用して指定されたすべての要素を上書きします。
これにより、引数をエントリポイントに渡すことができます。
つまりdocker run <image> -dは-d引数をエントリポイントに渡します。
docker run --entrypointフラグを使用してENTRYPOINT命令を上書きできます。シェル形式では
CMDまたはコマンドライン引数の実行が使用されなくなりますが、ENTRYPOINTが信号を渡さない/bin/sh -cのサブコマンドとして開始されるという欠点があります。
これはexecutableがコンテナの PID 1 ではなく、 Unix シグナルを受信しないことを意味します。
したがってexecutableはdocker stop <container>からSIGTERMを受信しません。Dockerfile の最後の
ENTRYPOINT命令のみが有効になります。Exec 形式の
ENTRYPOINTの例
exec形式のENTRYPOINTを使用して、かなり安定したデフォルトのコマンドと引数を設定してから、いずれかの形式のCMDを使用して、変更される可能性が高い追加の既定動作を設定できます。FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"]コンテナを実行すると
topが唯一のプロセスであることがわかります。$ docker run -it --rm --name test top -H top - 08:25:00 up 7:27, 0 users, load average: 0.00, 0.01, 0.05 Threads: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem: 2056668 total, 1616832 used, 439836 free, 99352 buffers KiB Swap: 1441840 total, 0 used, 1441840 free. 1324440 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 19744 2336 2080 R 0.0 0.1 0:00.04 top結果をさらに調べるには
docker execを使用できます。$ docker exec -it test ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 2.6 0.1 19752 2352 ? Ss+ 08:24 0:00 top -b -H root 7 0.0 0.1 15572 2164 ? R+ 08:25 0:00 ps auxまた
docker stop testを使用してtopを正常にシャットダウンするように要求できます。次の Dockerfile は
ENTRYPOINTを使用して Apache をフォアグラウンドで(つまり PID 1 として)実行する方法を示しています。FROM debian:stable RUN apt-get update && apt-get install -y --force-yes apache2 EXPOSE 80 443 VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"] ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]単一の
executableのスタータースクリプトを作成する必要がある場合はexecおよびgosuコマンドを使用して、最後のexecutableが Unix シグナルを確実に受信できるようにすることができます。#!/usr/bin/env bash set -e if [ "$1" = 'postgres' ]; then chown -R postgres "$PGDATA" if [ -z "$(ls -A "$PGDATA")" ]; then gosu postgres initdb fi exec gosu postgres "$@" fi exec "$@"最後に、シャットダウン時に追加のクリーンアップを実行する(または他のコンテナと通信する)必要がある場合、または複数の
executableを調整する場合は、ENTRYPOINTスクリプトが Unix シグナルを送受信してさらにいくつかの作業を実行することを確認する必要があります。#!/bin/sh # Note: I've written this using sh so it works in the busybox container too # USE the trap if you need to also do manual cleanup after the service is stopped, # or need to start multiple services in the one container trap "echo TRAPed signal" HUP INT QUIT TERM # start service in background here /usr/sbin/apachectl start echo "[hit enter key to exit] or run 'docker stop <container>'" read # stop service and clean up here echo "stopping apache" /usr/sbin/apachectl stop echo "exited $0"このイメージを
dockerrun -it --rm -p 80:80 --name test apacheで実行すると、docker execまたはdocker topでコンテナーのプロセスを調べることができ、後続のスクリプトに Apache を停止するように依頼します。$ docker exec -it test ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.1 0.0 4448 692 ? Ss+ 00:42 0:00 /bin/sh /run.sh 123 cmd cmd2 root 19 0.0 0.2 71304 4440 ? Ss 00:42 0:00 /usr/sbin/apache2 -k start www-data 20 0.2 0.2 360468 6004 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start www-data 21 0.2 0.2 360468 6000 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start root 81 0.0 0.1 15572 2140 ? R+ 00:44 0:00 ps aux $ docker top test PID USER COMMAND 10035 root {run.sh} /bin/sh /run.sh 123 cmd cmd2 10054 root /usr/sbin/apache2 -k start 10055 33 /usr/sbin/apache2 -k start 10056 33 /usr/sbin/apache2 -k start $ /usr/bin/time docker stop test test real 0m 0.27s user 0m 0.03s sys 0m 0.03s注意
--entrypointを使用してENTRYPOINT設定を上書きできますが、これはbinaryをexecにのみ設定できます(sh -cは使用されません)。注意
exec形式は JSON 配列として解析されます。
つまり単語の前後に一重引用符(')ではなく二重引用符(")を使用する必要があります。シェル形式とは異なり
exec形式はコマンドシェルを呼び出しません。
これは通常のシェル処理が行われないことを意味します。
たとえばENTRYPOINT ["echo", "$HOME"]は、$HOMEの変数置換を行いません。
シェル処理が必要な場合はシェル形式を使用するか、シェルを直接実行します。
例:ENTRYPOINT ["sh", "-c", "echo $HOME"]
シェル形式の場合のようにexec形式を使用してシェルを直接実行する場合、環境変数の展開を行うのは Docker ではなくシェルです。シェル形式の ENTRYPOINT 記述例
ENTRYPOINTにプレーンな文字列を指定すると/bin/sh -cで実行されます。
この形式はシェル処理を使用してシェル環境変数を置き換え、CMDまたは docker run コマンドライン引数を無視します。
長時間実行されているENTRYPOINT executableをdocker stopが正しく通知するようにするには、execで開始することを忘れないでください。FROM ubuntu ENTRYPOINT exec top -bこのイメージを実行すると単一の PID 1 プロセスが表示されます。
$ docker run -it --rm --name test top Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached CPU: 5% usr 0% sys 0% nic 94% idle 0% io 0% irq 0% sirq Load average: 0.08 0.03 0.05 2/98 6 PID PPID USER STAT VSZ %VSZ %CPU COMMAND 1 0 root R 3164 0% 0% top -b
docker stopできれいに終了します:$ /usr/bin/time docker stop test test real 0m 0.20s user 0m 0.02s sys 0m 0.04s
ENTRYPOINTの先頭にexecを追加するのを忘れた場合:FROM ubuntu ENTRYPOINT top -b CMD --ignored-param1次にそれを実行できます(次のステップの名前を付けます)。
$ docker run -it --name test top --ignored-param2 Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached CPU: 9% usr 2% sys 0% nic 88% idle 0% io 0% irq 0% sirq Load average: 0.01 0.02 0.05 2/101 7 PID PPID USER STAT VSZ %VSZ %CPU COMMAND 1 0 root S 3168 0% 0% /bin/sh -c top -b cmd cmd2 7 1 root R 3164 0% 0% top -b指定された
ENTRYPOINTは、topの出力から PID 1 ではないことがわかります。その後
docker stop testを実行すると、コンテナーは正常に終了しません。
タイムアウト後にstopコマンドは強制的にSIGKILLを送信します。$ docker exec -it test ps aux PID USER COMMAND 1 root /bin/sh -c top -b cmd cmd2 7 root top -b 8 root ps aux $ /usr/bin/time docker stop test test real 0m 10.19s user 0m 0.04s sys 0m 0.03s
CMDとENTRYPOINTの相互作用を理解する
CMD命令とENTRYPOINT命令はどちらも、コンテナの実行時に実行されるコマンドを定義します。
CMDとENTRYPOINTの協業を説明する規則を示します。
- Dockerfile は少なくとも 1 つの
CMDまたはENTRYPOINTコマンドを指定する必要があります。- コンテナで
executableを使用する場合はENTRYPOINTを定義する必要があります。CMDはENTRYPOINTコマンドのデフォルト引数を定義する方法として、またはコンテナでアドホックコマンドを実行する方法として使用する必要があります。- 代替引数を使用してコンテナーを実行すると
CMDが上書きされます。次の表はさまざまな
ENTRYPOINT/CMDの組み合わせに対して実行されるコマンドを示しています。
No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”] No CMD error, not allowed /bin/sh -c exec_entry p1_entry CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry 注意
ベースイメージから
CMDが定義されている場合、ENTRYPOINTを設定するとCMDが空の値にリセットされます。
このシナリオで値を設定するには現在のイメージでCMDを定義する必要があります。VOLUME
VOLUME ["/data"]
VOLUME命令は、指定された名前でマウントポイントを作成し、ネイティブホストまたは他のコンテナーから外部にマウントされたボリュームを保持するものとしてマークします。
値は JSON 配列VOLUME ["/var/log/"]、またはVOLUME /var/logや
VOLUME /var/log/ var/dbなどの複数の引数を持つプレーン文字列にすることができます。
Docker クライアントを介した詳細、使用例とマウント手順については、ボリュームを介したディレクトリの共有を参照してください。docker run コマンドは、新しく作成されたボリュームをベースイメージ内の指定された場所に存在するデータで初期化します。
たとえば、次の Dockerfile スニペットについて考えてみます。FROM ubuntu RUN mkdir /myvol RUN echo "hello world" > /myvol/greeting VOLUME /myvolこの Dockerfile は docker run が
/myvolに新しいマウントポイントを作成し、新しく作成されたボリュームにgreetingファイルをコピーするイメージになります。ボリュームの指定についての注意事項
Dockerfile のボリュームについては、次の点に注意してください。
- Windows ベースのコンテナー上のボリューム: Windows ベースのコンテナーを使用する場合、コンテナー内のボリュームの宛先は次のいずれかである必要があります。
- 存在しない、または空のディレクトリ
C:以外のドライブ- Dockerfile 内からのボリュームの変更: ビルドステップで宣言後にボリューム内のデータが変更された場合、それらの変更は破棄されます。
- JSON フォーマット: リストは JSON 配列として解析されます。 単語は一重引用符(
')ではなく二重引用符(")で囲む必要があります。- ホストディレクトリはコンテナの実行時に宣言されます。 ホストディレクトリ(マウントポイント)はその性質上、ホストに依存します。 特定のホストディレクトリがすべてのホストで使用可能であるとは限らないため、これはイメージの移植性を維持するためです。 このため Dockerfile 内からホストディレクトリをマウントすることはできません。
VOLUME命令はhost-dirパラメーターの指定をサポートしていません。 コンテナを作成または実行するときに、マウントポイントを指定する必要があります。USER
USER <user>[:<group>]または
USER <UID>[:<GID>]
USER命令はイメージの実行時と、 DockerfileでRUN、CMD、ENTRYPOINTに続く命令で使用するユーザー名(または UID)とオプションでユーザーグループ(またはGID)を設定します。ユーザーのグループを指定する場合、ユーザーは指定されたグループメンバーシップのみを持つことに注意してください。
その他の構成済みグループメンバーシップは無視されます。警告
ユーザーがプライマリグループを持っていない場合、イメージ(または次の手順)はルートグループで実行されます。
Windows では、組み込みアカウントでない場合は最初にユーザーを作成する必要があります。
これは Dockerfile の一部として呼び出されるnetuserコマンドを使用して実行できます。FROM microsoft/windowsservercore # Create Windows user in the container RUN net user /add patrick # Set it for subsequent commands USER patrickWORKDIR
WORKDIR /path/to/workdir
WORKDIR命令は、 Dockerfile でそれに続くすべてのRUN、CMD、ENTRYPOINT、COPY、およびADD命令の作業ディレクトリを設定します。
WORKDIR` が存在しない場合は、後続の Dockerfile 命令で使用されていなくても作成されます。
WORKDIR命令は Dockerfile で複数回使用できます。
相対パスが指定されている場合、それは前のWORKDIR命令のパスから見た相対パスになります。例えば:WORKDIR /a WORKDIR b WORKDIR c RUN pwdこの Dockerfile の最後の
pwdコマンドの出力は/a/b/cになります。
WORKDIR命令は、以前にENVを使用して設定された環境変数を解決できます。
Dockerfile で明示的に設定された環境変数のみを使用できます。
例えば:ENV DIRPATH=/path WORKDIR $DIRPATH/$DIRNAME RUN pwdこの Dockerfile の最後の
pwdコマンドの出力は/path/$DIRNAMEになります。ARG
ARG <name>[=<default value>]
ARG命令はユーザーがビルド時に `--build-arg <varname>=<value>` フラグを使用して docker build コマンドでビルダーに渡すことができる変数を定義します。
ユーザーが Dockerfile で定義されていないビルド引数を指定すると、ビルドは警告を出力します。[Warning] One or more build-args [foo] were not consumed.Dockerfile には 1 つ以上の
ARG命令が含まれる場合があります。
たとえば以下は有効な Dockerfile です。FROM busybox ARG user1 ARG buildno # ...警告
github のキー、ユーザー資格情報などの秘密情報を渡すためにビルド時変数を使用することはお勧めしません。
ビルド時の変数値はdocker historyコマンドを使用してイメージのすべてのユーザーに表示されます。イメージをビルドするときに秘密情報を使用する安全な方法については BuildKit を使用してイメージをビルドする を参照してください。
既定値
ARG命令には、オプションでデフォルト値を含めることができます。FROM busybox ARG user1=someuser ARG buildno=1 # ...
ARG命令にデフォルト値があり、ビルド時に値が渡されない場合、ビルダーはデフォルトを使用します。Scope
ARG変数の定義は、コマンドラインや他の場所での引数の使用からではなく、 Dockerfile で定義されている行から有効になります。
たとえば、次の Dockerfile について考えてみます。FROM busybox USER ${user:-some_user} ARG user USER $user # ...ユーザーは、次のコマンドを呼び出してこのファイルをビルドします。
$ docker build --build-arg user=what_user .2 行目の
USERは、次の 3 行目でユーザー変数が定義されているためsome_userと評価されます。
4 行目のUSERは、ユーザーが定義され、what_user値がコマンドラインに渡されたときにwhat_userと評価されます。
ARG命令で定義される前は、変数を使用すると文字列が空になります。
ARG命令は、それが定義されたビルドステージの最後でスコープ外になります。
複数のステージでargを使用するには、各ステージにARG命令を含める必要があります。FROM busybox ARG SETTINGS RUN ./run/setup $SETTINGS FROM busybox ARG SETTINGS RUN ./run/other $SETTINGS
ARG変数の使用
ARGまたはENV命令を使用してRUN命令で使用可能な変数を指定できます。
ENV命令を使用して定義された環境変数は、常に同じ名前のARG命令を上書きします。
ENVおよびARG命令を含むこの Dockerfile について考えてみます。FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER=v1.0.0 RUN echo $CONT_IMG_VER次に、このイメージが次のコマンドで作成されていると仮定します。
$ docker build --build-arg CONT_IMG_VER=v2.0.1 .この場合
RUN命令はuser:v2.0.1によって渡されたARG設定の代わりに v1.0.0 を使用します。
この動作は、ローカルスコープの変数が引数として渡された変数または環境から継承された変数を定義の観点から上書きするシェルスクリプトに似ています。上記の例を使用しますが、異なる
ENV仕様を使用すると、ARGとENV命令の間にさらに便利な相互作用を作成できます。FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0} RUN echo $CONT_IMG_VER
ARG命令とは異なり、ENV値は常にビルドされたイメージに保持されます。
--build-argフラグのない docker build を考えてみましょう:$ docker build .この Dockerfile の例を使用すると
CONT_IMG_VERは引き続きイメージに保持されますが、ENV命令によって 3 行目で設定された既定値であるため、その値は v1.0.0 になります。この例の変数展開手法を使用すると、コマンドラインから引数を渡し、
ENV命令を利用してそれらを最終イメージに永続化できます。
変数展開は Dockerfile 命令の限られた組合せでのみサポートされます。定義済み
ARGDocker には Dockerfile 内の対応する
ARG命令なしで使用できる定義済みARG変数のセットがあります。
- HTTP_PROXY
- http_proxy
- HTTPS_PROXY
- https_proxy
- FTP_PROXY
- ftp_proxy
- NO_PROXY
- no_proxy
これらを使用するには、フラグを使用してコマンドラインで渡すだけです。
--build-arg <varname>=<value>デフォルトでは、これらの定義済み変数は
docker historyの出力から除外されます。
定義済み変数を除外すると、HTTP_PROXY変数内の機密認証情報が誤って漏洩するリスクが軽減されます。たとえば
--build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.comを使用して次の Dockerfile をビルドすることを検討してください。FROM ubuntu RUN echo "Hello World"この場合
HTTP_PROXY変数の値は、docker historyで使用できず、キャッシュされません。
場所を変更し、プロキシサーバーがhttp://user:pass@proxy.sfo.example.comに変更された場合、後続のビルドでキャッシュミスが発生することはありません。この動作を上書きする必要がある場合は、次のように Dockerfile に
ARGステートメントを追加することで上書きできます。FROM ubuntu ARG HTTP_PROXY RUN echo "Hello World"この Dockerfile をビルドすると、
HTTP_PROXYはdocker historyに保存され、その値を変更するとビルドキャッシュが無効になります。グローバルスコープの自動プラットフォーム ARG
この機能は BuildKit バックエンドを使用している場合にのみ使用できます。
Docker は、ビルドを実行するノードのプラットフォーム(ビルドプラットフォーム)と結果のイメージのプラットフォーム(ターゲットプラットフォーム)に関する情報を使用して、一連の
ARG変数を事前定義します。
ターゲットプラットフォームは docker build の--platformフラグで指定できます。次の
ARG変数が自動的に設定されます。
- TARGETPLATFORM - ビルド結果のプラットフォーム。 例: linux/amd64, linux/arm/v7, windows/amd64.
- TARGETOS - TARGETPLATFORM の OS コンポーネント
- TARGETARCH - TARGETPLATFORM のアーキテクチャーコンポーネント
- TARGETVARIANT - TARGETPLATFORM の変数コンポーネント
- BUILDPLATFORM - ビルドを実行するノードのプラットフォーム。
- BUILDOS - BUILDPLATFORM の OS コンポーネント
- BUILDARCH - BUILDPLATFORM のアーキテクチャーコンポーネント
- BUILDVARIANT - BUILDPLATFORM の変数コンポーネント
これらの引数はグローバルスコープで定義されているため、ビルドステージ内や
RUNコマンドで自動的に使用することはできません。
ビルドステージ内でこれらの引数の 1 つを公開するには、値なしで再定義します。例えば:
FROM alpine ARG TARGETPLATFORM RUN echo "I'm building for $TARGETPLATFORM"ビルドキャッシュへの影響
ARG変数は、ENV変数のようにビルドされたイメージに永続化されません。
ただしARG変数は同様の方法でビルドキャッシュに影響を与えます。
Dockerfile が以前のビルドとは値が異なるARG変数を定義している場合、その定義ではなく、最初の使用時にcache missが発生します。
特にARG命令に続くすべてのRUN命令は、ARG変数を暗黙的に(環境変数として)使用するため、キャッシュミスを引き起こす可能性があります。
Dockerfile に一致するARGステートメントがない限り、すべての定義済みARG変数はキャッシュから除外されます。たとえば次の 2 つの Dockerfile について考えてみます。
FROM ubuntu ARG CONT_IMG_VER RUN echo $CONT_IMG_VERFROM ubuntu ARG CONT_IMG_VER RUN echo helloコマンドラインで
--build-arg CONT_IMG_VER=<value>を指定した場合、どちらの場合も、 2 行目の指定でキャッシュミスは発生しません。
3 行目はキャッシュミスを引き起こします。
ARG CONT_IMG_VERにより、RUN行はCONT_IMG_VER=<value> echo helloの実行と同じものとして識別されるため、<value>が変更されるとキャッシュミスが発生します。同じコマンドラインで別の例を考えてみましょう。
FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER=$CONT_IMG_VER RUN echo $CONT_IMG_VERこの例ではキャッシュミスは 3 行目で発生します。
キャッシュミスはENV変数の値がARG変数を参照し、その変数がコマンドラインで変更されるために発生します。
この例ではENVコマンドにより、イメージに値が含まれます。この Dockerfile のように、
ENV命令が同じ名前のARG命令を上書きする場合:FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER=hello RUN echo $CONT_IMG_VER3 行目では
CONT_IMG_VERの値が定数(hello)であるため、キャッシュミスは発生しません。
その結果RUN(4 行目)で使用される環境変数と値はビルド間で変更されません。ONBUILD
ONBUILD <INSTRUCTION>
ONBUILD命令はイメージが別のビルドのベースとして使用されるときに、後で実行されるトリガー命令をイメージに追加します。
トリガーは、ダウンストリーム Dockerfile のFROM命令の直後に挿入されたかのように、ダウンストリームビルドのコンテキストで実行されます。任意のビルド命令をトリガーとして登録できます。
これは他のイメージをビルドするためのベースとして使用されるイメージをビルドする場合に役立ちます。
たとえばアプリケーションビルド環境や、ユーザー固有の構成でカスタマイズできるデーモンなどです。たとえばイメージが再利用可能な Python アプリケーションビルダーである場合、特定のディレクトリにアプリケーションソースコードを追加する必要があり、その後にビルドスクリプトを呼び出す必要がある場合があります。
アプリケーションのソースコードにはまだアクセスできず、アプリケーションのビルドごとに異なるため、今は単純にADDとRUNを呼び出すことはできません。
アプリケーション開発者にボイラープレート Dockerfile を提供して、アプリケーションにコピーアンドペーストすることもできますが、
これは非効率的で、エラーが発生しやすく、アプリケーション固有のコードと混在するため、更新が困難です。解決策は
ONBUILDを使用して、次のビルドステージで後で実行する事前命令を登録することです。仕組みは次のとおりです。
ONBUILD命令が発生すると、ビルダーはビルド中のイメージのメタデータにトリガーを追加します。 それ以外の場合、命令は現在のビルドに影響を与えません。- ビルドの最後に、すべてのトリガーのリストがイメージマニフェストの
OnBuildキーの下に保存されます。 それらはdocker inspectコマンドで検査できます。- 後で
FROM命令を使用して、イメージを新しいビルドのベースとして使用できます。FROM命令の処理の一環として、ダウンストリームビルダーはONBUILDトリガーを探し、登録されたのと同じ順序でそれらを実行します。 いずれかのトリガーが失敗すると、FROM命令が中止され、ビルドが失敗します。 すべてのトリガーが成功すると、FROM命令が完了し、ビルドは通常どおり続行されます。- トリガーは、実行後に最終イメージからクリアされます。 言い換えれば、それらは「孫」ビルドによって継承されません。
たとえば次のようなものを追加できます。
ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src警告
ONBUILD ONBUILDを使用してONBUILD命令を連鎖させることは許可されていません。
ONBUILD命令はFROMまたはMAINTAINER命令をトリガーしない場合があります。STOPSIGNAL
STOPSIGNAL signal
STOPSIGNAL命令は、終了するためにコンテナに送信されるシステムコール信号を設定します。
このシグナルは、カーネルのsyscallテーブル内の位置(たとえば 9)と一致する有効な符号なしの番号、またはSIGNAME形式のシグナル名(たとえばSIGKILL)にすることができます。HEALTHCHECK
HEALTHCHECK命令には 2 種類の形式があります:
HEALTHCHECK [OPTIONS] CMD command(コンテナ内でコマンドを実行して、コンテナの状態を確認します)HEALTHCHECK NONE(ベースイメージから継承されたヘルスチェックを無効にする)
HEALTHCHECK命令は、コンテナをテストしてコンテナがまだ機能していることを確認する方法を Docker に指示します。
これにより、サーバープロセスがまだ実行されていても Web サーバーが無限ループに陥り、新しい接続を処理できないなどのケースを検出できます。コンテナにヘルスチェックが指定されている場合、通常のステータスに加えてヘルスステータスがあります。
このステータスは最初は「開始中」です。
ヘルスチェックに合格すると、ヘルスチェックが「正常」になります(以前の状態に関係なく)。
一定数の連続した失敗の後、「異常」となります。
CMDの前に表示されるオプションは次のとおりです。
--interval=DURATION(既定値: 30s)--timeout=DURATION(既定値: 30s)--start-period=DURATION(既定値: 0s)--retries=N(既定値: 3)ヘルスチェックは、最初にコンテナが開始されてから数秒後に実行され、次に前の各チェックが完了してから数秒後に再度実行されます。
チェックの 1 回の実行にタイムアウト秒より長い時間がかかる場合、チェックは失敗したと見なされます。
コンテナが異常であると見なされるには、ヘルスチェックの連続した失敗を再試行する必要があります。
開始期間はブートストラップに時間が必要なコンテナーの初期化時間を提供します。
その期間中のプローブ障害は、最大再試行回数にはカウントされません。
ただし、開始期間中にヘルスチェックが成功した場合、コンテナーは開始されたと見なされ、連続するすべての失敗は最大再試行回数にカウントされます。Dockerfile には 1 つの
HEALTHCHECK命令しか存在できません。
複数列記すると最後のHEALTHCHECKのみが有効になります。
CMDキーワードの後のコマンドは、シェルコマンド(例:HEALTHCHECK CMD /bin/check-running)またはexec配列(他の Dockerfile コマンドと同様)のいずれかです。
(詳細についてはENTRYPOINTを参照してください)コマンドの終了ステータスは、コンテナのヘルスステータスを示します。
有効な値は次のとおりです。
- 0: success - コンテナは正常ですぐに使用できます
- 1: unhealthy - コンテナが正しく機能していません
- 2: reserved - この終了コードは使用しないでください
たとえば 5 分ごとにチェックして、ウェブサーバーが 3 秒以内にサイトのメインページにサービスを提供できるようにするには、次のようにします。
HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1失敗したプローブのデバッグを支援するために、コマンドが
stdoutまたはstderrに書き込む出力テキスト(UTF-8 エンコード)はヘルスステータスに保存されdocker inspectで検索できます。
このような出力は短くする必要があります(現在、最初の 4096 バイトのみが格納されています)。コンテナのヘルスステータスが変更されると、新しいステータスで
health_statusイベントが生成されます。
HEALTHCHECK機能は Docker 1.12 から追加されました。SHELL
SHELL ["executable", "parameters"]
SHELL命令を使用すると、シェル形式のコマンドに使用されるデフォルトのシェルを上書きできます。
Linux のデフォルトシェルは["/bin/sh", "-c"]です。
Windows のデフォルトシェルは["cmd", "/S", "/C"]です。
SHELL命令は Dockerfile に JSON 形式で記述する必要があります。
SHELL命令は一般的に使用されているまったく異なる 2 つのネイティブシェル(cmdとpowershell)と、shを含む代替シェルが利用可能な Windows で特に役立ちます。
SHELL命令は複数回表示される可能性があります。
各SHELL命令は、以前のすべてのSHELL命令を上書きし、後続のすべての命令に影響を与えます。
例:FROM microsoft/windowsservercore # Executed as cmd /S /C echo default RUN echo default # Executed as cmd /S /C powershell -command Write-Host default RUN powershell -command Write-Host default # Executed as powershell -command Write-Host hello SHELL ["powershell", "-command"] RUN Write-Host hello # Executed as cmd /S /C echo hello SHELL ["cmd", "/S", "/C"] RUN echo hello次の命令はシェル形式が Dockerfile で使用されている場合に
SHELL命令の影響を受ける可能性があります:
RUNCMDENTRYPOINT次の例は
SHELL命令を使用して合理化できる Windows で見られる一般的なパターンです。RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"docker によって呼び出されるコマンドは次のようになります。
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"これは 2 つの理由で非効率的です。
まず、不要なcmd.exeコマンドプロセッサ(別名シェル)が呼び出されています。
次に、シェル形式の各RUN命令には、コマンドの前に追加のpowershell -commandが必要です。これをより効率的にするために 2 つのメカニズムのうちの 1 つを使用することができます。
1 つは次のようなRUNコマンドの JSON 形式を使用することです。RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]JSON 形式は明確であり、不要な
cmd.exeを使用しませんが、二重引用符とエスケープにより、より詳細な情報が必要になります。
別のメカニズムはSHELL命令とシェル形式を使用することです。
これにより、特にエスケープパーサーディレクティブと組み合わせると Windows ユーザーにとってより自然な構文になります。# escape=` FROM microsoft/nanoserver SHELL ["powershell","-command"] RUN New-Item -ItemType Directory C:\Example ADD Execute-MyCmdlet.ps1 c:\example\ RUN c:\example\Execute-MyCmdlet -sample 'hello world'実行結果:
PS E:\docker\build\shell> docker build -t shell . Sending build context to Docker daemon 4.096 kB Step 1/5 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/5 : SHELL powershell -command ---> Running in 6fcdb6855ae2 ---> 6331462d4300 Removing intermediate container 6fcdb6855ae2 Step 3/5 : RUN New-Item -ItemType Directory C:\Example ---> Running in d0eef8386e97 Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 10/28/2016 11:26 AM Example ---> 3f2fbf1395d9 Removing intermediate container d0eef8386e97 Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\ ---> a955b2621c31 Removing intermediate container b825593d39fc Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world' ---> Running in be6d8e63fe75 hello world ---> 8e559e9bf424 Removing intermediate container be6d8e63fe75 Successfully built 8e559e9bf424 PS E:\docker\build\shell>
SHELL命令は、シェルの動作方法を変更する目的にも使用できます。
たとえば Windows でSHELL cmd /S /C /V:ON|OFFを使用すると、遅延環境変数の拡張セマンティクスを変更できます。
SHELL命令は zsh, csh, tcsh などの代替シェルが必要な場合に Linux でも使用できます。
SHELL機能は Docker 1.12 で追加されました。外部実装機能
この機能は BuildKit バックエンドを使用している場合にのみ使用できます。
docker build は、構文ディレクティブを使用してビルダーの外部実装を使用することで有効になる、キャッシュマウント、ビルドシークレット、 ssh 転送などの実験的な機能をサポートします。
これらの機能については BuildKit リポジトリのドキュメント を参照してください。Dockerfile 記述例
以下に Dockerfile 構文の例をいくつか示します。
# Nginx # # VERSION 0.0.1 FROM ubuntu LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0" RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server# Firefox over VNC # # VERSION 0.3 FROM ubuntu # Install vnc, xvfb in order to create a 'fake' display and firefox RUN apt-get update && apt-get install -y x11vnc xvfb firefox RUN mkdir ~/.vnc # Setup a password RUN x11vnc -storepasswd 1234 ~/.vnc/passwd # Autostart firefox (might not be the best way, but it does the trick) RUN bash -c 'echo "firefox" >> /.bashrc' EXPOSE 5900 CMD ["x11vnc", "-forever", "-usepw", "-create"]# Multiple images example # # VERSION 0.1 FROM ubuntu RUN echo foo > bar # Will output something like ===> 907ad6c2736f FROM ubuntu RUN echo moo > oink # Will output something like ===> 695d7793cbe4 # You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with # /oink.
- 投稿日:2020-10-20T18:15:51+09:00
docker-compose コマンド一覧(Rails用)
忘れないために書きます
docker起動
#foregroundで起動 docker-compose up # #backgroundで起動 docker-compose up -ddocker停止
#foregroundで起動時 Ctr + C #backgroundで起動時 docker-compose stopGemfile変更時
docker-compose buildコントローラーを作成
docker-compose run web bundle exec rails g controller <コントローラー名> <アクション名>モデルの作成
docker-compose run web bundle exec rails g model <モデル名> <カラム名:型>テーブルの作成
docker-compose run web bundle exec rake db:migrate全部消すとき
docker-compose down --rmi all --volumesまた新しいこと覚えたときに追加します。
- 投稿日:2020-10-20T18:09:43+09:00
【Docker】開発環境構築 Rails6 / Ruby2.7 / MySQL8
はじめに
DockerでRails6, MySQLにて環境構築をする際になかなかてこずってしまったので、備忘録もかねて記事に残します。
つまずいた部分として、
Rails5 とは異なり Rails6 ではモダンなフロントエンド開発を強力にサポートするWebpackをRuby on Railsで使うためのgemパッケージであるWebpackerの導入が必須となったことがある。※Docker初心者であり各ファイルの記述についても理解できていない部分も多いです。
環境・バージョン
- Macbook Air Catalina
- Ruby 2.7
- Rails 6
- MySQL 8.0
環境構築完了までの手順
- プロジェクトのフォルダを用意
- 5つのファイルを用意
- 各ファイルを記述
- Rails プロジェクトの開始(rails new)
- Dockerイメージのビルド
- database.yml の編集
- DBを作成(db:create)
- コンテナを起動
実際に環境構築してみる
1. プロジェクトのフォルダを用意
任意の名前のフォルダを作成する(コマンドでなくてもOK)
mkdir dockerSampleApp2. 5つのファイルを用意
1.で作成したフォルダ内にファイルを作成する
Dockerfiledocker-compose.ymlGemfileGemfile.lockentrypoint.sh3. 各ファイルを記述
Dockerfile
プロジェクトのフォルダ名に関係なくmyappの箇所はmyappのままでOKです。
DockerfileFROM ruby:2.7 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \ && apt-get update -qq \ && apt-get install -y nodejs yarn \ && mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]docker-compose.yml
docker-compose.ymlversion: '3' services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: password ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db stdin_open: true tty: true volumes: mysql-data: driver: localGemfile
Gemfilesource 'https://rubygems.org' gem 'rails', '~>6'Gemfile.lock
Gemfile.lock# このファイルには何も記述しないentrypoint.sh
entrypoint.sh#!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@"4. Rails プロジェクトの開始(rails new)
コマンドを実行
$ docker-compose run web rails new . --force --no-deps --database=mysql --skip-test --webpacker --api今回使用オプションについて
--force既存のGemfileを上書きする--no-depsリンクしたサービスを起動しない--database=mysqlデータベースにMySQLを指定--skip-testMinitest のインストールをスキップ(テストはRSpecを導入予定のため)--webpackerwebpacker をインストール(Rails6 では必須のパッケージ管理ツール)--apiAPIだけ作りたいためAPIモードで実行。これにより不要なView・UI関連のライブラリがインストールされない。※オプションについては適時カスタムして使用する
5. Dockerイメージのビルド
イメージビルドとは、各種依存ライブラリやミドルウェアをインストールしたり、自分のアプリケーションをインストール・設定したりすること。
コマンドを実行
$ docker-compose build6. database.yml の編集
database.ymlの該当部分を修正。
docker-compose.ymlのservicesとMYSQL_ROOT_PASSWORDの設定に合わせて該当箇所を修正。config/database.yml# ~ 省略 ~ default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password # -> 空欄を password に修正 host: db # -> localhostから db に修正 # ~ 省略 ~7. DBを作成(db:create)
コマンドを実行してDBを作成
$ docker-compose run web rails db:create8. コンテナを起動
最後にコマンドを実行してコンテナを起動する
$ docker-compose up少し時間がかかるかもですが、ターミナルにこんなログが流れればOK
web_1 | => Booting Puma web_1 | => Rails 6.0.3.4 application starting in development web_1 | => Run `rails server --help` for more startup options web_1 | Puma starting in single mode... web_1 | * Version 4.3.6 (ruby 2.7.2-p137), codename: Mysterious Traveller web_1 | * Min threads: 5, max threads: 5 web_1 | * Environment: development web_1 | * Listening on tcp://0.0.0.0:3000 web_1 | Use Ctrl-C to stop
localhost:3000にアクセスすると無事ページが表示される。はず!!最後に
なんとか環境構築ができました!
今後Dockerなどインフラ面についても学習して理解を深めて行きたいです!参考資料
大変参考にさせていただきました!
- https://qiita.com/nsy_13/items/9fbc929f173984c30b5d
- https://qiita.com/kodai_0122/items/795438d738386c2c1966
- https://qiita.com/azul915/items/5b7063cbc80192343fc0
- https://qiita.com/c5meru/items/1c921676de8a5a038f70
ありがとうございました!!
- 投稿日:2020-10-20T16:00:05+09:00
Docker - OCI runtime create failed エラー ("process_linux.go:449: container init caused \")
エラー内容
$ sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi ~ 省略 ~ docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: nvidia-container-cli: requirement error: unsatisfied condition: cuda>=11.0, please update your driver to a newer version, or use an earlier cuda container\\\\n\\\"\"": unknown.はじめに
エラー文を全部読まず脳死でコピペしてしまった自分に対する戒めです.
こんな簡単なエラーで脳死でググっているようでは一行に成長しませんね.反省しかありません.
(ご丁寧にどうすればいいのかすら書いてくれているので優しいエラー文...)ホスト環境
- Ubuntu18.04
- Docker 19.03
結論
現在インストールされているNVIDIAドライバーのバージョンが低いためCUDA11.0以上に対応していないことが原因です.
nvidia-smiを叩いてCUDA Versionの欄が11.0以上でないといけません.また,
vidia-container-cli: requirement error: unsatisfied condition: cuda>=11.0, please update your driver to a newer version, or use an earlier cuda container
と出力してくれていて,エラー文を全部読まずにGoogleに投げてしまう癖を直さないといけないなと再確認しました.
上記から,NVIDIAのドライバーを最新にしましょう.
普段,ホストマシーンはCUDAのバージョンが10.0だったためこのようなドライバーとCUDAの整合性でエラーがでることがなかったので,良い機会ですのでドライバーの再インストールの手順も一応残しておきます.
また,私は直接runファイルを手動で実行してインストールしているため,aptを使って入れている方はaptの手順に従ってアップグレードしたら大丈夫だと思います.再インストール手順
今回は,最新のドライバーがCUDA 11.0以下に対応しているため
nvidia-smiを叩いてCUDA Versionが11.0にすることを目指します.
sudo nvidia-uninstallでドライバーのアンインストールをする.- 再起動する
- 最新のドライバーを公式サイトから取得する.(ここではNVIDIA-Linux-x86_64-450.80.02.runがダウンロードされたとします.)
sudo bash NVIDIA-Linux-x86_64-450.80.02.runでドライバーをインストールする.- 再起動する
まとめ
プログラムを書いているときも,初めて見るエラー文は少し読んでとりあえず先人の知恵を使おう精神ですぐ検索してしまうことが多いので,これからはしっかりエラー文を読むように心がけたいと思います.
また,最近になって,遅ればせながらDockerを使ってコンテナ上でGPUを使えるようにしたんですが,もっと早くしておけばよかったです.
- 投稿日:2020-10-20T15:46:41+09:00
【Linux】RedhatにDocker環境構築
はじめに
RedhatでDocker環境構築する方法をメモ
環境情報
- OS:Redhat 7.7
Docker環境構築
yumをアップデート
yum updateyumをアップグレード
yum upgrade必要なパッケージをインストール
yum install -y yum-utils device-mapper-persistent-data lvm2リポジトリを有効化
yum-config-manager --enable rhel-7-server-rhui-optional-rpms yum-config-manager --enable rhel-7-server-rhui-rh-common-rpms yum-config-manager --enable rhel-7-server-rhui-rpms yum-config-manager --enable rhel-7-server-rhui-extras-rpmsdockerインストール
yum install docker-io設定ファイルの修正
- 設定ファイル :/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false --bip=172.20.250.1/24 -g /var/lib/docker'Dockerサービス有効化
systemctl daemon-reload systemctl start docker systemctl enable dockerDockerの起動確認
systemctl status docker正常に起動しない場合はログを確認
journalctl -eu dockerDocker-composeを使用する場合
docker-composeダウンロード
curl -L "https://github.com/docker/compose/releases/download/【version】/docker-compose-$(uname -s)-$(uname -m)" -o /bin/docker-composedocker-composeに実行権限を付与
chmod +x /bin/docker-compose
- 投稿日:2020-10-20T15:40:25+09:00
【Linux】RedhatでDocker環境構築
はじめに
RedhatでDocker環境構築する方法をメモ
環境情報
- OS:Redhat 7.7
Docker環境構築
yumをアップデート
yum updateyumをアップグレード
yum upgrade必要なパッケージをインストール
yum install -y yum-utils device-mapper-persistent-data lvm2リポジトリを有効化
yum-config-manager --enable rhel-7-server-rhui-optional-rpms yum-config-manager --enable rhel-7-server-rhui-rh-common-rpms yum-config-manager --enable rhel-7-server-rhui-rpms yum-config-manager --enable rhel-7-server-rhui-extras-rpmsdockerインストール
yum install docker-io設定ファイルの修正
- 設定ファイル :/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false --bip=172.20.250.1/24 -g /var/lib/docker'Dockerサービス有効化
systemctl daemon-reload systemctl start docker systemctl enable dockerdocker-composeダウンロード
curl -L "https://github.com/docker/compose/releases/download/【version】/docker-compose-$(uname -s)-$(uname -m)" -o /bin/docker-composedocker-composeに実行権限を付与
chmod +x /bin/docker-compose
- 投稿日:2020-10-20T15:40:25+09:00
【Linux】Amazon Linux 2でDocker環境構築
はじめに
Amazon Linux 2でDocker環境構築する方法をメモ
環境情報
- OS:Amazon Linux 2
Docker環境構築
yumをアップデート
yum updateyumをアップグレード
yum upgradedockerインストール
yum install docker-io設定ファイルの修正
- 設定ファイル :/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald --bip=172.20.250.1/24 -g /var/lib/docker'Dockerサービス有効化
systemctl daemon-reload systemctl start docker systemctl enable dockerDockerの起動確認
systemctl status docker正常に起動しない場合はログを確認
journalctl -eu dockerDocker-composeを使用する場合
docker-composeダウンロード
curl -L "https://github.com/docker/compose/releases/download/【version】/docker-compose-$(uname -s)-$(uname -m)" -o /bin/docker-composedocker-composeに実行権限を付与
chmod +x /bin/docker-compose
- 投稿日:2020-10-20T12:59:40+09:00
WSL2 + Docker Desktop for WindowsでMySQLコンテナだけ立ち上がらない
dockerでMySQLだけ立ち上がらなかった
具体的にはWSL2 + Docker Desktop for Windows (+ Docker Compose) で諸々のコンテナを
docker-compose up -dで立ち上げようとしたらMySQLのコンテナ(5.7の最新版)だけ立ち上がらなかった# docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------ test-_back_1 /wait-for-it.sh mysql-db ... Up 0.0.0.0:8080->8080/tcp test-_front_1 /bin/sh -c envsubst '$$TES ... Up 0.0.0.0:3000->80/tcp test-_mysql-db_1 docker-entrypoint.sh mysqld Exit 1logを見てみる
docker-compose logs -fでlogを確認logmysql-db_1 | 2020-10-17 02:54:50+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.31-1debian10 started. mysql-db_1 | 2020-10-17 02:54:50+09:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql' mysql-db_1 | 2020-10-17 02:54:50+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.31-1debian10 started. mysql-db_1 | 2020-10-17 02:54:50+09:00 [Note] [Entrypoint]: Initializing database files mysql-db_1 | mysqld: [Warning] World-writable config file '/etc/mysql/conf.d/my.cnf' is ignored. mysql-db_1 | 2020-10-16T17:54:50.236065Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). mysql-db_1 | 2020-10-16T17:54:50.243510Z 0 [Warning] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive mysql-db_1 | 2020-10-16T17:54:50.984126Z 0 [Warning] InnoDB: New log files created, LSN=**** mysql-db_1 | 2020-10-16T17:54:51.113491Z 0 [Warning] InnoDB: Creating foreign key constraint system tables. mysql-db_1 | 2020-10-16T17:54:51.128211Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: ******** mysql-db_1 | 2020-10-16T17:54:51.133628Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened. mysql-db_1 | mysqld: Can't change permissions of the file 'ca-key.pem' (Errcode: 1 - Operation not permitted) mysql-db_1 | 2020-10-16T17:54:51.184562Z 0 [ERROR] Could not set file permission for ca-key.pem mysql-db_1 | 2020-10-16T17:54:51.184583Z 0 [ERROR] Aborting mysql-db_1 |と出ていて最終的には
mysql-db_1 | 2020-10-16T17:54:51.184562Z 0 [ERROR] Could not set file permission for ca-key.pem mysql-db_1 | 2020-10-16T17:54:51.184583Z 0 [ERROR] Abortingでこけてる
解決方法
ググると以下のIssueが見つかった
見てると
mysql:5.7からmysql:5.7.16へ変更すると動くというレスがあったのでバージョンを変更してみたら動くようになりました。
(自分の場合はdocker-compose.ymlにMySQLのバージョンを書いてたのでそこを変更)おわり
- マウントする際の権限云々が関係してる?みたいですが自分的にはローカルでとりあえず動けばいいのでこれで良しとしておきます
- 投稿日:2020-10-20T12:00:54+09:00
DockerでRailsの環境構築で出てきたエラーyaml.scanner.ScannerError: while scanning for the next tokenの対処法
Dockerでrails newした際に出てきたエラーです
yaml.scanner.ScannerError: while scanning for the next tokendocker-compose.ymlファイルではタブを使って改行するとこのエラーが出るみたいです
空白部分をスペースで変えて実行したらできました。
- 投稿日:2020-10-20T09:48:40+09:00
PHP 7(.4)のDockerコンテナ(fpm-alpine)にphp-mecabを導入してPHPでMeCabを使う
DockerのPHPイメージにMeCabとmecab-ipadic-NEologdを導入して、PHPから使えるように設定する方法を紹介します?
PHPフレームワークやWebサーバーを導入せず、PHPでMeCabを使えるかどうかまで確認します。ここで導入できたら必要なものを追加しましょう✨
PHPのイメージは次を用いて確認しています。
DockerfileFROM php:7.4.12-fpm-alpinedocker-composeの設定
起動・終了を簡単にするためdocker-composeを用います。次の
docker-compose.ymlをプロジェクトのルートに作成します。
- PHPコンテナにMeCabをインストールしてカスタムでコンテナを作るため、新規作成するDockerfileの場所を
buildのdockerfileで指定しますvolumesにはPHPでMeCabを使うサンプルスクリプトを配置するホスト側のディレクトリとコンテナ側のディレクトリをマウントします- PHPのコンテナを起動させ続けるために
ttyをtrueにしておきますdocker-compose.ymlversion: '3' services: php-mecab: build: context: ./ dockerfile: Dockerfile volumes: - ./src:/app tty: trueMeCabとmecab-ipadic-NEologdを導入する
同じくプロジェクトのルートに
Dockerfileを作成して、PHPのコンテナにMeCabとmecab-ipadic-NEologdを導入します。古い記事ですが、PHP7.4.12の現在もこちらの記事と同じ方法で構築できます。
https://qiita.com/nownabe/items/4171776aec1f05de9f28DockerfileFROM php:7.4.12-fpm-alpine ## ここから # https://qiita.com/nownabe/items/4171776aec1f05de9f28#dockerfile RUN apk add --update --no-cache build-base ENV MECAB_VERSION 0.996 ENV IPADIC_VERSION 2.7.0-20070801 ENV mecab_url https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE ENV ipadic_url https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM ENV build_deps 'curl git bash file sudo openssh' ENV dependencies 'openssl' RUN apk add --update --no-cache ${build_deps} \ # Install dependencies && apk add --update --no-cache ${dependencies} \ # Install MeCab && curl -SL -o mecab-${MECAB_VERSION}.tar.gz ${mecab_url} \ && tar zxf mecab-${MECAB_VERSION}.tar.gz \ && cd mecab-${MECAB_VERSION} \ && ./configure --enable-utf8-only --with-charset=utf8 \ && make \ && make install \ && cd \ # Install IPA dic && curl -SL -o mecab-ipadic-${IPADIC_VERSION}.tar.gz ${ipadic_url} \ && tar zxf mecab-ipadic-${IPADIC_VERSION}.tar.gz \ && cd mecab-ipadic-${IPADIC_VERSION} \ && ./configure --with-charset=utf8 \ && make \ && make install \ && cd \ # Install Neologd && git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git \ && mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n -y \ # Clean up && apk del ${build_deps} \ && rm -rf \ mecab-${MECAB_VERSION}* \ mecab-${IPADIC_VERSION}* \ mecab-ipadic-neologd ## ここまでphp-mecabを導入する
MeCabをPHPで使う場合はphp-mecabモジュールを導入する必要があります。Dockerfileを作るポイントとしては次のとおりです。
autoconfを導入しないとphp-mecabのビルドに必要なconfigureが生成されないphp-config,mecab-configは/usr/local/bin/以下に配置されているこのポイントを踏まえてphp-mecabを導入するため Dockerfileに追記すると 次のようになります。
Dockerfile# ... ## ここまで ## ここから追記する ENV build_deps_phpmecab 'git autoconf' COPY php.mecab.ini /usr/local/etc/php/conf.d/ RUN apk add --update --no-cache ${build_deps_phpmecab} \ && git clone https://github.com/rsky/php-mecab.git \ && cd ./php-mecab/mecab \ && phpize \ && ./configure --with-php-config=/usr/local/bin/php-config --with-mecab=/usr/local/bin/mecab-config \ && make \ && make test \ && make install \ # Clean up && cd \ && rm -rf php-mecab \ && apk del ${build_deps_phpmecab} # ▼▼このコマンドが最後に来るようにしてください RUN docker-php-ext-install pdo pdo_mysql
php.mecab.iniをCOPYしていますが、次の手順でこのファイルを作成します。PHPからMeCabモジュールを読み込む
導入したphp-mecabのモジュールをPHPで有効にするため、PHPの設定ファイル(
php.mecab.ini)を作成してmecab.soを指定します。php.mecab.iniextension=mecab.so最終的には次のファイル構成になります。
$ tree . ├── Dockerfile ├── docker-compose.yml └── php.mecab.iniPHPでMeCabを使う
PHP7向けに
MeCab_Taggerから\MeCab\Taggerに変更されています。 バックスラッシュもそのまま使います。sample_php_mecab.php<?php $str = 'センテンススプリングでも文春でもどっちでもいいだろ'; $options = array('-d', '/usr/local/lib/mecab/dic/mecab-ipadic-neologd'); $mecab = new \MeCab\Tagger($options); $nodes = $mecab->parseToNode($str); echo $str . "\n"; foreach ($nodes as $n) { $stat = $n->getStat(); // 単語かどうか if ($stat != 0) { continue; } $features = explode(',', $n->getFeature()); if ($features[0] !== '名詞') { continue; } // 単語 echo "Surface: " . $n->getSurface() . "\n"; }docker-compose up --build -d php-mecab docker-compose exec php-mecab /bin/sh php /app/sample_php_mecab.phpこれでMeCabが使えるPHPのコンテナが作成できます。
この構成ではWebブラウザで表示して確認することはできないので、
- Laravelなどのフレームワークを導入して開発用サーバーを立ち上げる
- 別途NginxなどのWebサーバーのコンテナを導入して、このPHPコンテナで動作しているFPMと接続させる
などの作業は必要です。
参考
Alpine LinuxでMeCab with NEologd - Qiita
https://qiita.com/nownabe/items/4171776aec1f05de9f28phpでmecab - Qiita
https://qiita.com/kojirock5260/items/1787d70b9cfca3e43d12phpizeでエラー : てるてる坊主
http://teru2-bo2.blogspot.com/2012/05/phpize.htmlPHP7.0+mecabでハマった事 - Qiita
https://qiita.com/murota/items/3c76cc3ca0fd819dbac7
- 投稿日:2020-10-20T03:36:41+09:00
Raspberry Pi 4 と Raspberry Pi OS に Docker をインストール
はじめに
$ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: busterインストール
$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.sh $ sudo usermod -aG docker `whoami` $ exitここでグループを反映させるために再ログイン
$ sudo systemctl status docker $ docker version
- 投稿日:2020-10-20T03:36:41+09:00
Raspberry Pi 4 と Raspberry Pi OS 64bit に Docker をインストール
はじめに
$ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster $ uname -m aarch64docker
$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.sh $ sudo usermod -aG docker `whoami` $ exitここでグループを反映させるために再ログイン
$ sudo systemctl status docker $ docker versiondocker-compose
https://docs.docker.com/compose/install/ を参考にやると失敗した。
(aarch64 用が無かった)ので、pip でインストールしようとしたけれど依存パッケージの
bcryptのビルドに失敗するのでこれもダメ。失敗例したけど一応$ sudo apt -y install python3-pip $ pip3 install --upgrade pip $ sudo -H pip3 install -U docker-composeので、これ。
docker で docker-compose を実行することになる。仕方ない。$ sudo curl -L --fail https://raw.githubusercontent.com/linuxserver/docker-docker-compose/master/run.sh -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose
- 投稿日:2020-10-20T01:04:13+09:00
もはや DB は Docker でインストールする時代!初心者のための DB インストール on Docker
この記事について
データベース、これは 2020 年になっても、エンタープライズなどのアプリケーション開発において、必ずと言っていいほど使用されるものだと思います。
ただ、従来同様、本番環境や検証環境、開発環境に至るまで、未だに人力で頑張ってホスト OS に直接インストールしている方が多いというのが現状です。(少し誇張が過ぎるかもですが)
開発環境のデータベースのインストールに 5 分以上時間をかけるのは時間の無駄です!今、このタイミングで、Docker でサクッと DB をインストールできることを覚えましょう。
ただし、本番環境など、冗長化構成や可用性を担保する必要がある場合などは、きちんと要求に合致したインストール方法を実施をしましょう。Oracle Database on Docker
※ちょっとインストール方法が面倒なので、後日追記します。早く情報を知りたい方は、参考情報に記載の内容をご参照ください。
SQL Server on Docker
- Docker Hub - Microsoft SQL Server (Ubuntu ベース)
GitHub にて公開しているこちらのリポジトリを参考に、docker-compose.yaml を作成してください。
※下記の yaml は RHEL ベースの SQL Server (on Linux) on Docker です。
※GitHub のリポジトリでは、ブランチで RHEL ベースと Ubuntu ベースの 2 つを用意しています。(2017 は Ubuntu のみ)docker-compose.yamlversion: '3' services: mssql: image: mcr.microsoft.com/mssql/rhel/server:2019-latest container_name: 'mssql2019-latest-rhel' environment: - MSSQL_SA_PASSWORD=<your_strong_password> - ACCEPT_EULA=Y # - MSSQL_PID=<your_product_id> # default: Developer # - MSSQL_PID=Express # - MSSQL_PID=Standard # - MSSQL_PID=Enterprise # - MSSQL_PID=EnterpriseCore ports: - 1433:1433 # volumes: # Mounting a volume does not work on Docker for Mac # - ./mssql/log:/var/opt/mssql/log # - ./mssql/data:/var/opt/mssql/data
docker-compose up -dで、コンテナーを起動すれば、SQL Server のインストールは完了です。docker-compose up -dMySQL on Docker
GitHub にて公開しているこちらのリポジトリを参考に、docker-compose.yaml を作成してください。
docker-compose.yamlversion: '3' services: db: image: mysql:8 container_name: mysql restart: always environment: MYSQL_ROOT_PASSWORD: P@ssw0rd #required # MYSQL_DATABASE: employees #optional # MYSQL_USER: user #optional # MYSQL_PASSWORD: P@ssw0rd #optional # MYSQL_ALLOW_EMPTY_PASSWORD: "yes" #optional # MYSQL_RANDOM_ROOT_PASSWORD: "yes" #optional # MYSQL_ONETIME_PASSWORD: "yes" #optional (MySQL 5.6 or above) # MYSQL_INITDB_SKIP_TZINFO: "" #optional ports: - 3306:3306 volumes: - ./data/mysql:/var/lib/mysql - ./conf:/etc/mysql/conf.d
docker-compose up -dで、コンテナーを起動すれば、MySQL のインストールは完了です。docker-compose up -dPostgreSQL on Docker
GitHub にて公開しているこちらのリポジトリを参考に、docker-compose.yaml を作成してください。
docker-compose.yamlversion: '3' services: db: image: postgres:13 container_name: postgres restart: always environment: POSTGRES_PASSWORD: P@ssw0rd #required # POSTGRES_USER: postgres #optional # POSTGRES_DB: postgres #optional # POSTGRES_INITDB_ARGS: "--data-checksums" #optional # POSTGRES_INITDB_WALDIR: "" #optional (PostgreSQL 10+ or above) # POSTGRES_INITDB_XLOGDIR: "" #optional (PostgreSQL 9.x only) # POSTGRES_HOST_AUTH_METHOD: trust #optional # PGDATA: /var/lib/postgresql/data/pgdata #optional ports: - 5432:5432 volumes: - ./data:/var/lib/postgresql/data
docker-compose up -dで、コンテナーを起動すれば、PostgreSQL のインストールは完了です。docker-compose up -dMongoDB on Docker
GitHub にて公開しているこちらのリポジトリを参考に、docker-compose.yaml を作成してください。
docker-compose.yamlversion: '3' services: mongo: image: mongo:latest container_name: mongodb restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: P@ssw0rd ports: - 27017:27017 volumes: - ./data/db:/data/db - ./data/configdb:/data/configdb # Command 1: Customize configuration without configuration file # Command 2: Setting WiredTiger cache size limits # command: > # --serviceExecutor adaptive # --wiredTigerCacheSizeGB 1.5 mongo-express: image: mongo-express:latest container_name: mongo-express restart: always ports: - 8081:8081 environment: ME_CONFIG_MONGODB_ADMINUSERNAME: root ME_CONFIG_MONGODB_ADMINPASSWORD: P@ssw0rd
docker-compose up -dで、コンテナーを起動すれば、MongoDB のインストールは完了です。docker-compose up -d管理ツール
管理ツールについては、各自好きなものを使用すれば良いと思いますが、おすすめは Visual Studio Code を使う方法です。
Docker Compose も DB 操作も Visual Studio Code 内で行えるため、とても便利です。
詳細は以下の記事を参照してください。
- Visual Studio Code 上で SQL Database を操作するための便利な拡張機能
- Visual Studio Code 上で MySQL を操作するための便利な拡張機能
- Visual Studio Code 上で PostgreSQL と Cosmos DB を操作するための便利な拡張機能
- Visual Studio Code 上で MongoDB を操作するための便利な拡張機能
また、MySQL と PostgreSQL のところで記載している adminer のコンテナーを一緒に作るのもアリかと思います。
参考情報
Oracle Database
- GitHub - oracle/docker-images
- 公式 Oracle Database の Docker イメージを構築
- Oracle Database 19c available on GitHub
- [Oracle Database] 公式Docker Imageを利用してOracle Database 19c環境を構築してみた
SQL Server
MySQL
PostgresSQL
MongoDB
