Docker
- インストール: Ubuntu18.04
- CLI
- 実行が終了したら破棄
- コンテナ全削除
- buildとrunをワンライナーで
- プライベートレジストリ
- プライベートリポジトリから pull
- ホスト PC のファイルをコンテナへコピー
- Dockerfile
- プライベートレジストリへ push
- Docker Compose
- Tips
- docker runで複数行の bash コマンドを実行する
- Ubuntu:18.04
- コンテナ自動再起動
- Python3.7 の Dockerfile
- Gradle + Kotlin の Dockerfile
- Dockerfile でバージョン文字列などを変数にする
- 任意の Docker イメージでデバッグする
- alpine に yq を入れる
- docker run で引数付きコマンドで entrypoint を上書きする
- コンテナのシステム時刻を上書きする
- ディレクトリ内を再帰的に COPY する
- Dockerfile の COPY で親ディレクトリのファイルを参照する
- Linux Distribution を調べる
- COPY と一緒に chown
- ADD か COPY か
- イメージ起動時になにもしない ENTRYPOINT
- マルチステージビルドで node_module をキャッシュする
- マルチステージビルドで重複する設定を共通化する
- 指定した文字列を含むイメージを全削除
- Docker コンテナが起動中か確認する
- コンテナ内の日付を変えたい
- JIB でデプロイ
- docker-ls
- FAQ
インストール: Ubuntu18.04
# インストール
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
sudo apt-get update -y -qq
# To list the versions, run `apt-cache madison docker-ce`
DOCKER_VERSION='5:19.03.1~3-0~ubuntu-bionic'
sudo apt-get install -y docker-ce=$DOCKER_VERSION docker-ce-cli=$DOCKER_VERSION containerd.io
# sudoなしで実行できるようにする
sudo gpasswd -a $USER docker
sudo chmod 666 /var/run/docker.sock
Ref: https://qiita.com/iganari/items/fe4889943f22fd63692a
docker-compose のインストール
VERSION="1.25.3"
sudo curl -L "https://github.com/docker/compose/releases/download/${VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 実行権限をつける
sudo chmod +x /usr/local/bin/docker-compose
# bash補完を入れる
sudo curl -L https://raw.githubusercontent.com/docker/compose/${VERSION}/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
Ref:
Docker Compose のインストール| Docker ドキュメント
CLI
docker run
ボリュームマウント
--mount
または-v
オプションを使う。
--mount
の方が推奨されている。
例:
docker run \
--mount type=bind,source=/tmp,target=/usr
docker run \
--mount type=bind,source=/tmp,target=/usr,readonly
Ref: https://docs.docker.com/storage/volumes/
実行が終了したら破棄
docker run --rm [image] [COMMAND]
コンテナ全削除
docker stop `docker ps -a -q`; docker rm `docker ps -a -q`
docker stop $(docker ps -q); docker rm $(docker ps -q -a); docker rmi $(docker images -q) --force
build
とrun
をワンライナーで
docker build -t [イメージ名] . && docker run -itd --rm --name [イメージ名] [イメージ名]
プライベートレジストリ
v2 API を使う
まず、認証用の URL を取得する。
# `-D -`でレスポンスヘッダを表示
curl -D - https://my-registry.com/v2/
# 以下のように Www-Authenticateヘッダに認証用のURLをもらえる
# Www-Authenticate: Bearer realm="https://my-registry.com:5003/auth",service="Docker registry"
次に、認証トークンを取得する。
curl -u <user>:<password> -d service="Docker registry" -d scope="<scope>" -d account=<account> https://my-registry.com:5003/auth
# { "token": ******** }
取得した認証トークンを使って v2API を利用する。
curl
# 指定したイメージのタグ一覧を取得 (リクエストにベアラトークンが必要)
curl https://my-registry.com/v2/hoge/my-app/tags/list
::: tips
トークンを取得するときのscope
が正しくないと v2API の応答が UNAUTHORIZED になる。
:::
プライベートリポジトリから pull
docker login artifactory.***.com
# ログインできない場合はデバッグ
docker -D -l login artifactory.***.com
# httpsは省略できる
docker pull artifactory.***.com/hoge-snapshot/myApp:latest
docker images
docker run artifactory.***.com/hoge-snapshot/myApp:latest
ホスト PC のファイルをコンテナへコピー
Win 環境だとコンテナパスのルートは//
で書かないといけない。
docker cp ./hoge.txt myContainer://test/
Dockerfile
例
FROM openjdk:8-jdk-alpine
# bashがないイメージでbashを使いたい場合は入れる
RUN apk add --no-cache bash
# ディレクトリをコピーする場合はコピー先でディレクトリ名まで指定する必要があるので注意
ADD src /project/src
ADD .gradle /project/.gradle
ADD gradle /project/gradle
ADD build.gradle /project
ADD gradlew /project
ADD gradlew.bat /project
ADD settings.gradle /project
WORKDIR /project
#ENTRYPOINT ["ehco", "hello"]
ENTRYPOINT ["./gradlew", "bootrun"]
プライベートレジストリへ push
docker -t hoge .
docker tag hoge myrepo.aaa.com/aaa/bbb/ccc/hoge:latest
docker push myrepo.aaa.com/aaa/bbb/ccc/hoge:latest
Docker Compose
ex)
version: "2"
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- 3306:3306
rabbitmq:
image: rabbitmq:3-management
ports:
- 5672:5672
- 15672:15672
app:
image: hoge/myapp:latest
depends_on:
- db
- rabbitmq
アプリのコンテナから mysql コンテナへ接続する
sudo apt update
sudo apt install mysql-client
mysql -u root -ppassword -h db
docker-compose up
# imageのビルドも行う場合は--buildをつけるとWarningが消える
docker-compose up --build
docker-compose
ディレクトリ指定でref: stackoverflow | “docker-compose” command to set path for docker-compose.yml file
# ./hoge/docker-compose.ymlを読み込む
docker-compose -f `pwd`/hoge/docker-compose.yml up
-f
オプションで指定するパスは絶対パスである必要がある。
docker run
で環境変数を設定
docker run -it -e
サーバー起動後に初期化処理
データベース立ち上げ後に初期データを挿入するスクリプトを動かしたいときなど。
サーバーのポートが繋がるまで待機してから何かしらするスクリプトを書く。 wait_and_doSomething.sh
until curl localhost:8091 ; do
sleep 3
done
# 初期データ挿入など...
書いたスクリプトをバックグラウンドで動かしつつエントリポイントを叩くスクリプトを書く。 startup.sh
./wait_and_doSomething.sh &
./entrypoint.sh
entrypoint.sh
の呼び方はコンテナイメージによって違う。
Dockerfile でENTRYPOINT
を上書きする。
FROM hogehoge
ADD startup.sh .
ADD wait_and_doSomething.sh .
ENTRYPOINT ["./startup.sh"]
ホストとネットワークを共有する
localhost
で立ち上げた DB をコンテナから見たいときとか。
https://qiita.com/harasou/items/1f86d8db86bf88e794bc
--net=host
オプションをつかう。
docker run -itd --rm --name app --net=host my-app:latest
コンテナのログ監視
docker logs [コンテナ名]
# `-f`オプションで`tail`的なことができる
docker logs -f [コンテナ名]
使ってないリソースを削除
docker rmi $(docker images -q)
docker system prune
docker volume prune
Tips
docker run
で複数行の bash コマンドを実行する
変数は\$
とエスケープしないと外側のスクリプトの変数を参照してしまうので注意。
docker run -i --rm \
asciidoctor/docker-asciidoctor:1.0.0 \
sh << EOT
#!/usr/bin/env bash
test="hoge"
echo \$test
asciidoctor -r asciidoctor-diagram -D /dist index.adoc
EOT
Ubuntu:18.04
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
Ref: http://docs.docker.jp/engine/articles/dockerfile_best-practice.html#id6
コンテナ自動再起動
Docker 起動時に自動的に起動したいコンテナなどに
docker run --restart=always
Python3.7 の Dockerfile
FROM python:3.7.3
WORKDIR /root
COPY . .
ENTRYPOINT ["python3", "..."]
Gradle + Kotlin の Dockerfile
FROM openjdk:8-jdk-alpine as base
WORKDIR /root
COPY gradle/ gradle/
COPY build.gradle .
COPY gradlew .
COPY settings.gradle .
COPY src/ src/
RUN ./gradlew || true
FROM openjdk:8-jdk-alpine as runner
WORKDIR /root
COPY gradle/ gradle/
COPY build.gradle .
COPY gradlew .
COPY settings.gradle .
COPY src/ src/
COPY --from=base /root/.gradle/ /root/.gradle/
RUN ./gradlew run
Dockerfile でバージョン文字列などを変数にする
ARG
を使う。RUN export
だと動かない。
ARG VERSION_GRADLE='5.6.2'
RUN apt -qq install -y wget unzip
RUN wget "https://services.gradle.org/distributions/gradle-${VERSION_GRADLE}-bin.zip" -P /tmp
RUN unzip -d /opt/gradle /tmp/gradle-*.zip && rm /tmp/gradle-*.zip
Ref: https://blog.lorentzca.me/use-argument-in-dockerfile/
docker build
時に--build-arg
で値を指定することもできる。
docker build . --build-arg VERSION_GRADLE=5.6.2
任意の Docker イメージでデバッグする
docker run --rm -itd --name debug <image>
docker exec -it debug sh
# デバッグ終わったらコンテナを止めて終了
docker stop debug
alpine に yq を入れる
yq
は yaml パーサ。使い方はjq
と同じ。
FROM alpine:3.8
RUN apk add --update py-pip jq \
&& pip install --upgrade pip \
&& pip install yq
docker run で引数付きコマンドで entrypoint を上書きする
--entrypoint
ではコマンドのみ指定し、コマンドの一番最後に引数とオプションを書く。
docker run --entrypoint ls my-image . -la
コンテナのシステム時刻を上書きする
WORKDIR /
RUN sudo git clone https://github.com/wolfcw/libfaketime.git
WORKDIR /libfaketime/src
RUN sudo make install
RUN echo '/usr/local/lib/faketime/libfaketime.so.1' | sudo tee -a /etc/ld.so.preload
ENV DONT_FAKE_MONOTONIC=1
ENV FAKETIME_CACHE_DURATION=1
ENV FAKETIME='@2000-10-10 09:00:00'
Ref: https://qiita.com/Targityen/items/67682d6c80cdcbe1186c
ディレクトリ内を再帰的に COPY する
こんなディレクトリ構成のときに、root ディレクトリごと COPY したいとき。
root/
- sub/
- file01
- file02
- file01
*
を使って書けば OK。
COPY root/* ./
Dockerfile の COPY で親ディレクトリのファイルを参照する
このようなフォルダ階層のときに、hoge.txt
を COPY したい。
project
docker
my-image
Dockerfile
hoge.txt
Dockerfile では、projectをカレントディレクトリとしてパスを書く。
FROM alpine
# ../../hoge.txt ではない
COPY hoge.txt .
docker build
で-f
オプションに Dockerfile のパスを指定すると、コマンド実行時の場所をカレントとしてイメージのビルドが行われる。
cd project
docker build -t my-image -f docker/my-image/Dockerfile .
Linux Distribution を調べる
cat /etc/*-release
COPY と一緒に chown
USER
を指定した場合はCOPY
したファイルはchown
しないとファイルの権限でエラーになるが、--chown
オプションを使ってCOPY
すれば権限も一緒に指定できる。
USER hoge
COPY --chown hoge:hoge . /app
# こうすると以下のコマンドを実行する必要がなくなる
RUN chown -R hoge:hoge /app
ADD か COPY か
とりあえずCOPY
を使えばいい。
Ref: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile
イメージ起動時になにもしない ENTRYPOINT
何もしないけど終了もしない。 コンテナのデバッグをしたいときに。
ENTRYPOINT ["tail", "-f", "/dev/null"]
マルチステージビルドで node_module をキャッシュする
Nextjs アプリの Dockerfile の例:
# package.jsonが変わった時だけ依存関係をダウンロードするようにする
FROM node:10-alpine as node_cache
WORKDIR /next_cache/
RUN yarn add next@8.1.0
WORKDIR /node_cache/
ADD package.json ./
ADD yarn.lock ./
# --no-progressをつけたほうが早い
RUN yarn install --no-progress
# ビルド専用コンテナ。成果物を/distに生成する
FROM node:10-alpine as builder
WORKDIR /dist/
COPY --from=node_cache /node_cache/node_modules/ ./node_modules/
ADD . ./
RUN yarn build
# 実行用コンテナ
FROM node:10-alpine as runner
WORKDIR /app/
# nextだけ入れたnode_modulesをコピー
COPY --from=node_cache /node_cache/node_modules/ ./node_modules/
# 成果物(.next)をコピー
COPY --from=builder /dist/.next/ ./.next/
ADD ./package.json .
ENTRYPOINT ["yarn", "server"]
Ref: https://github.com/jstandish/cached-node-module-build-example/blob/master/Dockerfile
マルチステージビルドで重複する設定を共通化する
最初にベースのコンテナを作り、以降はFROM
でベースコンテナを指定する。
すると各コンテナはベースコンテナの設定を引き継ぐことができる。
環境変数を共通で設定したい場合などに便利。
FROM alpine as base
USER my-user
ENV HOGE=123
FROM base as builder
# ...
FROM base as runner
# ...
Ref: https://github.com/moby/moby/issues/37345
指定した文字列を含むイメージを全削除
# 'gcr'を含むイメージを全削除
docker rmi $(docker images | grep gcr | tr -s ' ' | cut -d ' ' -f 3)
Docker コンテナが起動中か確認する
docker inspect -f {{.State.Running}} <container name>
Ref: https://stackoverflow.com/a/33520390
コンテナ内の日付を変えたい
JIB でデプロイ
Docker デーモンなしでイメージを push できるらしい。
plugins {
id 'com.google.cloud.tools.jib' version '1.0.2'
}
repositories {
mavenCentral()
maven { url = 'https://artifactory.***/jcenter' }
}
artifactory {
contextUrl = "https://artifactory.***"
publish {
repository {
repoKey = 'my-docker-snapshot-local'
// set Circle CI Environment Variables:
// - ORG_GRADLE_PROJECT_ARTIFACTORY_USER
// - ORG_GRADLE_PROJECT_ARTIFACTORY_PASSWORD
username = project.hasProperty("ARTIFACTORY_USER") ? ARTIFACTORY_USER : ""
password = project.hasProperty("ARTIFACTORY_PASSWORD") ? ARTIFACTORY_PASSWORD : ""
}
defaults {
publications('mavenJava')
publishArtifacts = true
}
}
}
jib {
from {
image = 'openjdk:8u171-jdk-alpine'
}
to {
def version = "$System.env.CIRCLE_BUILD_NUM"
def target = ("$System.env.CIRCLE_BRANCH" == "master") ? "release" : "snapshot"
image = "artifactory.***/my-docker-${target}-local/hoge-api:${version}"
auth {
username = "$System.env.ARTIFACTORY_USER"
password = "$System.env.ARTIFACTORY_KEY"
}
}
container {
mainClass = 'com.hoge.fuga.ApplicationKt'
// workingDirectoryを指定してそこにconfig/application.ymlを後から配置すればapplication.ymlを読み込んでくれる
appRoot = "/opt/app"
workingDirectory = "/opt/app"
jvmFlags = ['-Xdebug']
ports = ['8080']
}
}
docker-ls
brew install docker-ls
使い方。
# 指定したリポジトリタグ一覧を取得
docker-ls tags -r <registory url> -u <user name> -p <password> <repository>
# ex) docker-ls tags -r https://my-registry.com -u hoge -p pass hoge/my-app
FAQ
docker run
がすぐ終了する
- コンテナに持っていくファイルが
LF
か確認するstandard_init_linux.go:190: exec user process caused "no such file or directory"
Apline
http://dl-cdn.alpinelinux.org/alpine/v3.8/main: operation timed out
ERROR:apk update
する。