docker
docker proxy 設定
ubuntuでaptパッケージでインストールされているなら/etc/default/dockerでproxy設定ができるのでそこで設定する。
または~/.docker/config.json
環境変数に渡しているだけっぽいので直接わたしてもよいか。
code: docker
export HTTP_PROXY="${http_proxy}"
export HTTPS_PROXY="${https_proxy}"
よくわからないがsystemdのunitfileのEnvironmentじゃないとうまくproxy設定が伝搬しなかった系もあった。
docker login
なんか失敗した。以下のパッケージinstallで対応
code:sh
sudo apt install dbus gnupg2 pass dbus-x11
Dockerfile
文法はこんなかんじ。ファイル名はDockerfileであること。
code:Dockerfile例
# どのイメージを基にするか
FROM ubuntu
# 作成したユーザの情報
LABEL tanisobe <tanisobe@example.com>
# PROXY配下でdocker build時のproxy設定
ENV HTTP_PROXY <HTTP_PROXY>
ENV HTTPS_PROXY
# ADD: localfilesystemのファイルをdocker上のdirectoryにコピーする
ADD script.sh /
# RUN: docker buildするときに実行される
RUN echo "now building..."
# CMD: docker runするときに実行される
CMD echo "now running..."
# EXPOSE: ポートを開放する。ややこしいのがこれはコンテナとしてポート開放しているだけである。
# bridge network driver利用時で外部からアクセスさせたい場合はさらにdocker host portとcontariner portのマッピングが必要
# 下記コマンドで localhost:8080を公開したコンテナの80 portにマッピング
# docker run -p 8080:80
EXPOSE 80/TCP
entrypointのshellスクリプトのせいでdocker runの引数が吸われる場合の対応 参考 docker exec, docker runは最後の引数にコマンドを書くと起動時に実行するCMDの内容を上書きして、任意のコマンドをコンテナ起動時に実行できる。しばしばコンテナのログインにはこの仕様を利用して下記のようなコマンドを実行してコンテナ内に疑似ログインできる。(正確に書くとdokcer execは対象コンテナと同じnamspaceでbashを実行してttyをローカルにもってきている。dokcer runは対象コンテナイメージの起動コマンドをbashに上書きして新規にコンテナを立ち上げてttyをローカルに持ってきている)
code:shell
docker run -it IMAGE_NAME /bin/bash
docker exec -it CONTAINER_NAME /bin/bash
dockerコンテナは起動時にCMD:だけではなくENTRYPOINT:という起動時にコマンドを実行する仕様もある。ここで問題になるのがENTRYPOINT:を設定したdockerコンテナはdocker runで与えたCOMMAND引数をENTRYPOINT:で指定したコマンドの引数として処理してしまう挙動である。この場合コンテナ起動時の実行コマンドとして/bin/bashを指定しても、ETNRYPOINT:で指定したコマンドの引数に/bin/bashが文字列として与えられてしまい/bin/bashが実行されない。これで対象イメージのコンテナの状態を確認するのが難しくなる。
対策としてdocker runの際に--entrypointというオプションでbashを指定してENTRYPOINT:を上書きしてコンテナを起動するという手がある。これでENTRYPOINT:が設定されたイメージでもいじることができる。
code:shell
docker run -it --rm --entrypoint "bash" IMAGE_NAME
docker volume
dockerが提供する永続ボリュームの仕組み。
data volume
基本的にはローカルホストの/var/lib/docker/volumes以下にそれぞれのコンテナでマウント用の領域を作っている。data volumeを利用するdocker containerは起動時に指示されたマウントポイントにマウント。
これでcontainerの状態に応じずデータが永続化する。各ボリュームに名前がついていて、次のコマンドを使うとボリュームの情報が見える。
code: bash
docker volume inspect basic_data
[
{
"CreatedAt": "2019-01-15T13:26:49+09:00",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "basic",
"com.docker.compose.volume": "data"
},
"Mountpoint": "/var/lib/docker/volumes/basic_data/_data",
"Name": "basic_data",
"Options": null,
"Scope": "local"
}
]
data volume contaner
data volume cotainerは対象データをマウントしたコンテナから、別のコンテナがそのデータボリュームを使えるという仕組み。
docker build cache
docker buildにはcache機構がある。場合によっては更新があってもcacheが使われてbuildされることもある。その場合にはdocker buildに--no-cacheてcacheを使わないように指定できる。この記事でソースコードレベルでdocker build cacheの動作について調べている(未読 docker directly connected network
docker container はデフォルトはdocker0という専用ブリッジインターフェースに接続された内部に閉じたbridgeネットワークを利用する。bridgeネットワークを使う場合は外への通信はdocker0を介してNATの形で行われる。
この場合L2のブロードキャスト等に頼るアプリケーションをdocker containerで動かしたい場合に困る場合がある。
例えばDHCPサーバーをdocker containerで動かしたい場合がこれにあたる。
bridge driver
前述の通りdockerのbridge driverではNAT動作を行い内部のdocker network上のcontainerが外部と通信をできるようにしている。具体的にはiptablesでこの動作を実現している。
code:=iptables
//この例ではradius用docker containerがbr-5261122483fb2と紐づいている。
//docker hostのudp1812,1813をradisu containerのupd1812,1813にforwadingする設定がされている。
*nat
// 全ての自身へのパケットをDOCKER chainで処理
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
// 宛先が自身ではない外部への全パケットをDOCKER chainで処理
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
//br-526112483fb2はdokcer containerが接続するbridge(docker-composeが自動作成)
//docker bridge以外のインターフェースで送信するsrc ipがdocker network ipではないパケットはSNAT
-A POSTROUTING -s 172.19.0.0/16 ! -o br-526112483fb2 -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
//port mappingしているコンテナが自身にたいして発信する場合
-A POSTROUTING -s 172.19.0.2/32 -d 172.19.0.2/32 -p udp -m udp --dport 1813 -j MASQUERADE
-A POSTROUTING -s 172.19.0.2/32 -d 172.19.0.2/32 -p udp -m udp --dport 1812 -j MASQUERADE
// docker bridgeを使ったパケットなら何もしない
-A DOCKER -i br-526112483fb2 -j RETURN
-A DOCKER -i docker0 -j RETURN
// docker brdige以外のインターフェースで受信したdport1813,1812パケットの場合はDNAT。
// docker ホストのudp1812,1813をコンテナのudp1812,1813にDNATしている。
-A DOCKER ! -i br-526112483fb2 -p udp -m udp --dport 1813 -j DNAT --to-destination 172.19.0.2:1813
-A DOCKER ! -i br-526112483fb2 -p udp -m udp --dport 1812 -j DNAT --to-destination 172.19.0.2:1812
その他のnetwork driver
docker containerで外部ネットワークのインターフェースを利用するには次のdriverを使えばよい。
host netwrork driverを利用する。
macvlan network driverを利用する。
host
hostネットワークはhostのネットワークインターフェースをそのまま共有する。
直接dockerホストのインターフェースを使うため、あるコンテナでport 80を使ってしまった場合は他のhostネットワークコンテナはもちろん、コンテナホスト上でもport 80は利用できなくなる。IPアドレスも当然共有している。
macvlan
hostの指定インターフェースにmacvlan bridgeを作成しコンテナはそのbridgeに接続する。
host driverとは違いdockerホストとは論理的には別のインターフェースを使えるので別のIPを振れて、外部ネットワークへdockerホストとはインターフェースを共有しない形で直接L2の足を出せる形になるのがメリット。
docker のmacvlan driverでサポートしているのはmacvlanのbridge modeのみ。デフォルトもbridge mode。
ホストとは利用するIPも変わるので、あるコンテナでport 80を使っても別のコンテナは影響をうけないし、コンテナホストも影響をうけない。公式ドキュメント code: example
macvlan driverを利用したdocker network macvlan 作成
$ network create -d macvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=eth0 macvlan
作成したmacvlanネットワークを利用したコンテナ起動。コンテナには192.168.0.10/24を明示して振る。
$ docker run --rm -it --network macvlan --ip=192.168.0.10 --name test-macvlan busybox
注意点
VM上のdocker containerでmacvlan Networkを利用する場合にcontainerが外部と通信できない場合がある。
macvlan Network作成時にparentに指定するVMの仮想NICにhyper-v等のハイパーバイザー側からmac spoofing防止の設定が入っている時、VMからパケットが送出できてもハイパーバイザー側で管理外の不正なmacaddressを利用しているものとしてパケットドロップされてしまうためだ。
これを回避するためにハイパーバイザー側でVMに割り当てる仮想NICでpromisscass modeを許可するような設定を事前に入れておく必要がある。
multipe network
端的に書くとdokcer network connectで対象コンテナにネットワークを追加する形で複数のネットワークと紐づけができる。
code: example
# 事前に作成したnetworkAと紐づけたc1コンテナ作成
docker create -it --net networkA --name c1 busybox sh
# connectコマンドでnetworkBをさらにc1コンテナに紐づける
docker network connect networkB c1
# 起動
docker start c1
example Dockerfile
code:=Dockerfile
FROM ubuntu:1804
MAINTAINER tanisobe@example.com
RUN set -x && \
sudo apt update && \
sudo apt -y --no-install-recommends install hoge
CMD ["hoge", \
"-x" \
]
Docker image file export , import
dokcer saveでイメージを出力できる。デフォルトはstdoutに出力。
code:bash
# IMAGEを最新状態に更新
docker pull IMAGE
# imageファイルにでIMAGEというdocker image IMAGEを出力.出力形式はtar
docker save -o image.tar IMAGE
# gzip 圧縮
docker save myimage:latest | gzip > myimage_latest.tar.gz
# tar.gzでもloadはできる。
docker load < busybox.tar.gz
Linter
docker desktopが必要にある
ベースコンテナイメージ
小さいイメージを作るなら、これらをベースに。
scratch
busybox
alpine linux
distroless
各言語のランタイムを乗せたイメージ
docker fileのコマンド(RUN, COPY等)ごとにレイヤーができてしまう。レイヤーは少ない方がイメージが小さくなる。
ただしレイヤーごとにキャッシュが効くのでレイヤーを適切に分割するとキャッシュによるビルド高速化につながる。
下のレイヤーに変更が入りやすいものがあると、キャッシュの再利用しにくい。
multi stage buildを意識するとイメージサイズを小さくできる
code:DockerFile
# stage1: ビルド用
From ... AS hoge
COPY
WORKDIR
RUn go install ./
# stage2: 実行用
FROM ...