dockerコンテナの操作方法について解説します。
dockerコンテナのアタッチとデタッチ
dockerコンテナは意図的に起動したままにしないと停止してしまったりします。
シェルがあるコンテナであれば、起動しているコンテナに入ってシェルを操作できます。これをアタッチと言います。(アタッチはコンテナの標準入出力を手元のコンソールに繋ぐこと)
逆にデタッチはコンテナのシェルから抜けること(コンテナの標準入出力を手元のコンソールから霧花明日こと)です。
実際にアタッチとデタッチを体感してみます。
起動したままのコンテナを作成してアタッチしてみる
##distrolessのイメージのうちシェルを含むdebugイメージ(base-debian11:debug)を起動 -iは--interactiveで標準入力を受け付け、-tはコンテナにttyを割り当て -dはデタッチ
$ docker run -d -it --name debian-base gcr.io/distroless/base-debian11:debug
##起動したコンテナを確認(docker psで出てくるので起動中)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0cfd74bdb1b gcr.io/distroless/base-debian11:debug "/busybox/sh" 5 seconds ago Up 4 seconds debian-base
## コンテナにアタッチしてシェルに入る(-dで起動したので今はデタッチ状態)
$ docker attach debian-base
## 以下はdebian-baseのコンテナのシェルを動かしてる
/ # ls
bin busybox etc lib root sbin tmp var
boot dev home proc run sys usr
/ # pwd
/
# exit
## ↑ exitして抜けるとコンテナが停止する
## docker psだと起動中のコンテナのみ表示 (-aだと停止中も表示)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
docker run -d -it --name debian-base gcr.io/distroless/base-debian11:debug
-dはデタッチ状態で起動(なしではアタッチした状態で起動)
-itは現在のシェルの標準入出力をコンテナにバインド→コンテナ内のシェル(があれば)を操作可能にします。-tで擬似端末を有効化
–nameはコンテナに名前をつける。名前がなくてもCONTAINER IDでコンテナ操作はできる
gcr.io/distroless/base-debian11 → dockerイメージを配布しているdockerHub ホスト名
:debug → base-debian11のバージョン。よくあるのはlatestとか11とかのバージョン識別子
docker runでコンテナを作成した際には指定したベースイメージがなければdocker hubからpullしてイメージをダウンロードしてコンテナを作成、起動してくれます。これはpull create startの一連のコマンドが含まれているからです。
git pullがfetchとmergeをやっているのと同じです。
当然個別に実行しても良いですが、結果は同じになります。
docker startで停止中のコンテナを起動する
##停止を確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
##docker startで起動する(オプションなしではデタッチ状態で起動)
$ docker start debian-base
debian-base
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0cfd74bdb1b gcr.io/distroless/base-debian11:debug "/busybox/sh" 15 minutes ago Up 4 seconds debian-base
##アタッチしてみる
### 現環境を確認 → mac
$ sw_vers | head -1
ProductName: macOS
###アタッチする
$ docker attach debian-base
####コンテナに入ったかを確認する → debianになってる
/ # cat /etc/os-release | grep -i version=
VERSION="Debian GNU/Linux 11 (bullseye)"
#### Ctrl + qでデタッチ(ダメならCtrl +p, qを押す) (exitしないとデタッチ状態に戻る = 起動したまま)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0cfd74bdb1b gcr.io/distroless/base-debian11:debug "/busybox/sh" 27 minutes ago Up 11 seconds debian-base
##おまけ アタッチ状態で停止→起動する
$ docker start -i debian-base
dockerコンテナを停止する
docker attachで入って「exit または Ctrl + C」以外にも停止方法はある
$ docker stop debian-base
## 停止したかどうかをdocker ps -aで確認(statusがexitedになってればOK)
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0cfd74bdb1b gcr.io/distroless/base-debian11:debug "/busybox/sh" 41 minutes ago Exited (137) About a minute ago debian-base
コンテナを削除する
停止したままではコンテナは存在した状態です。
停止で放っておくと、docker ps -aでたくさん出てきて見にくいので
入らなければ削除しましょう
コンテナの削除は dokcer rm で行います。
## 対象はnameでもCONTAINER IDでも良い
$ docker rm debian-base
debian-base
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
イメージも削除する
コンテナを作成した際にベースとなるイメージファイルがローカルに残っています。
コンテナ作成時にいちいちダウンロードすると時間がかかるのでキャッシュしていますが、不要なら削除できます。
## imageを確認してみる latest(通常版)とdebug(シェル有り版)のイメージがある
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gcr.io/distroless/base-debian11 latest 421767200b8f 2 days ago 17.3MB
gcr.io/distroless/base-debian11 debug ba51ed56693b 2 days ago 18.6MB
## imageの削除
$ docker rmi ba51ed56693b
## 確認 → debugのイメージが消えてる
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gcr.io/distroless/base-debian11 latest 421767200b8f 2 days ago 17.3MB
停止と同時に削除する
コンテナは停止状態でずっと取っておくようなものでもないため、
停止と同時に削除したいことも多いです。
そんな時は起動時にrmオプションをつけておくと良いです。
## --rmオプションを入れて起動する
$ docker run --rm -it --name debian-base gcr.io/distroless/base-debian11:debug
Unable to find image 'gcr.io/distroless/base-debian11:debug' locally
debug: Pulling from distroless/base-debian11
5f80a38cb015: Already exists
a839fcbfad1b: Already exists
4f70717a8bb3: Pull complete
Digest: sha256:db70d0593de8052385f9c0d0980fa9d5256d9b41d934f0f77f6fa08669747d32
Status: Downloaded newer image for gcr.io/distroless/base-debian11:debug
8879fde70135e04a7dfd48e3473a3b5fffd043eec84cbc0d6abde2fd8e6c679f
## コンテナのシェルでexitして停止する
/ # exit
## docker psで見ると停止中のコンテナはない→削除されてる
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
## imageは削除されずに残るので、イメージ削除は別途必要
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gcr.io/distroless/base-debian11 latest 421767200b8f 2 days ago 17.3MB
gcr.io/distroless/base-debian11 debug ba51ed56693b 2 days ago 18.6MB
コンテナで実行する(コマンドを実行する)
コンテナ内の実行ファイルを実行する方法としては
1. docker run時にコマンドを指定する (docker run -it –name debian-base gcr.io/distroless/base-debian11:debug)
2. 起動中にexecで起動する
方法があります。
起動中にexecコマンドで起動する方法
起動中のコンテナ(debian-base)中のシェルを起動してみます。
$ docker exec -it debian-base /busybox/sh
/ #
/ # exit
## ここでexitしてもコンテナは終了しない(起動したシェルを閉じただけなので)
## debian-base(buxybox)には/bin/bashがない。あればそっちを実行してOK
$ docker exec -it ubuntu /bin/bash
/ # echo $SHELL
/bin/bash
上の例のようにコンテナの中に入り込んでシェルを起動して操作することはよくあると思います。
execで起動した場合はexitしてもシェル終了だけでOKですが、docker runで起動したコンテナに対してattachしてシェル操作を行なっている時に流れで「exit」してしまうとコンテナが終了してしまいます。
あっさりと意図せずにコンテナを停止してしまうことになるので、運用中のコンテナをいじる場合は注意しましょう。
dockerコマンドのオプション
docker runやdocker createコマンドにオプションをつけると様々な設定ができます。
代表的なオプションを載せます。
- –name ContainerName → コンテナの名前をつける
- –env EnvVar → 環境変数を追加
- –ip ***.***.***.*** → IPアドレスの追加
- –mount /mount/point → ファイルシステムのマウント
- -i → アタッチ済みで起動
- -t →tty割り当て
- –rm → コンテナ終了時にコンテナ削除
- -p 9800:8080 →ホストの9800をコンテナの8080にバインド
コンテナの中身の詳細を確認する
inspectでコンテナの詳細情報を確認できます
$ docker container inspect {containername}
コンテナにファイルをコピーする docker cp
コンテナ内にホストのファイルをコピーする方法はいくつかあります。
- dockerfileでCOPYで記述する
- docker cpコマンドでコピーする
- バインドマウントやNFSで共有する
起動中のコンテナに対して特に設定変更せずにコピーできるのはdocker cpコマンドを使った方法です、
$ docker cp ./go.mod golang-container:/go/src/
## ./go.modはホストのカレントディレクトリにあるgo.modファイル(コピー元)
## golong-containerはコンテナの名前
## /go/src/はコンテナ内のコピー先のディレクトリ
ファイルシステムのマウント方法(-vではなく–mountが推奨) データ永続化
ファイルシステムのマウントには-vが従来から使われているが、やや冗長だが–mountが推奨されている
https://matsuand.github.io/docs.docker.jp.onthefly/storage/bind-mounts/
dockerの特性上、永続ボリュームを持たないのが良いとされるが、
・永続ボリュームをもたせたい場合
・はDockerホストのファイルシステムを共有したい
という場合はマウントする。
mountオプションを使ってマウントする
例:
$ docker run -d \
--name debian-base \
--mount type=bind,src=$(pwd)/src,dst=/src \
gcr.io/distroless/base-debian11:debug
type=(bind |volume|tmpfs) マウントのタイプを指定する
- bind バインドマウント
- Dockerホスト上にあるディレクトリを共有する
- volume ボリューム
- ボリュームをマウントする
- tmpfs tmpfsをマウント
- メモリ上のファイルシステムをマウントする(揮発性)
バインドマウントのメリット:ホスト上のファイルを共有できる
バインドマウントのデメリット:ホスト上のファイル有無でコンテナの挙動が変わる
ボリュームマウントのメリット:コンテナに新規のファイルシステムをマウントできる。バックアップしやすく、移行しやすい。おすすめ
ボリュームマウントのデメリット:??
tmpfsのメリット:高速なメモリファイルシステムを利用できる
tmpfsのデメリット:データが非永続
バインドマウント
src/dst マウント元とマウント先の指定
type=bind,src=/var/www/html/,dst=/var/www/
##ホストの/var/www/html/ディレクトリをコンテナ内の/var/www/バインドマウントする
バインドプロパゲーション (bind-propagation=shared,slave,private,rshared,rslave,rprivate)
バインドマウント状態でマウント元またはマウント先で新たにマウントした際にそれが互いに反映されるか無視されるか?を設定できます。
デフォルトはマウント元, 先どちらに新たにマウントしても共有されません(bind-propagation=rprivate)。
tmpfsをマウントする
tmpfsのマウントの場合はsrcの指定はしない
type=tmpfs,dst=/volume
tmpfsはデフォルトでは無制限に領域を割り当てます。
サイズを指定したい場合は、「tmpfs-size=バイト」を指定します。
type=tmpfs,dst=/volume,tmpfs-size=51200000
ボリュームのマウント
ボリュームをマウントする場合はあらかじめdocker volumeを作成します。
$ docker volume create docker-volume
$ docker volume ls
DRIVER VOLUME NAME
local docker-volume
## ちなみに削除は
$ docker volume rm docker-volume
作成したボリュームをマウントする
--mount type=volume,src=docker-volume,target=/volume
## 例
$ docker run -it --name debian-baae --mount type=volume,src=docker-volume,target=/volume gcr.io/distroless/base-debian11:debug
debian-baseという名前のbase-debian11:debugをベースイメージとしたコンテナを作成、docker-volumeというdockerボリュームを/volumeにマウントした状態で起動
src=には作成したdockerボリュームを指定します。
ボリュームのバックアップ(ファイルの書き出し)
dockerボリュームのバックアップはバックアップ用コンテナを立ち上げてtarにまとめることで簡単にできます。
言葉だと分かりにくいので、実際にやってみましょう。
操作概要
・バックアップしたいボリューム:docker-volume ($ docker volume ls | grep docker-volume)
・起動中のdocker-volumeをマウントしたコンテナ名:debian-base (docker ps | grep debian)
・docker-volumeのマウント場所:/volume (debian-baseコンテナの中)
・バックアップ名:backup.tar.gz
・バックアップ保存先:/bakcup (新規コンテナとカレントディレクトリ)
バックアップしたいボリューム(docker-volume)をマウントした起動中のコンテナdebian-baseを–volumes-fromで指定して、新しいデータコピー用の使い捨てコンテナを立ち上げる(run –rm)。
-vでホストのカレントディレクトリ($(pwd))をコピー用のコンテナ/backupにバインドマウントしておく。(コンテナ内の/backup配下にバックアップを作成したらホスト上にもコピーしたいから)
バックアップ用新規使い捨てコンテナ上でバックアップ対象のディレクトリ(/volume)の内容を/backup/配下に作成した後にコンテナを削除する。コンテナを削除しても、ホスト側にもバインドマウントしているのでバックアップファイルは存在しているので問題なし。
##バックアップコマンド
$ docker run --rm --volumes-from debian-base -v $(pwd):/backup busybox tar zcvf /backup/backup.tar.gz /volume
##バックアップが作成されているのを確認する(ホスト上での操作、ただし↑でrun立ち上げたコンテナはすでに削除されている(--rm)
$ pwd
bakcup.tar.gz
## tarファイルを解凍
$ tar -xzvf backup.tar.gz
$ pwd
backup.tar.gz volume/
$ cat volume/newdir/newfiles
this is new files
######## おまけ (↑のnewfilesの準備した方法)##########
###マウントしてるボリュームの存在確認
$ docker volume ls
local docker-volume
### docker-volumeを/volumeにマウントして起動する
$ docker run -it --name debian-baae --mount type=volume,src=docker-volume,target=/volume gcr.io/distroless/base-debian11:debug
##コンテナ内##
/ # ls
bin busybox etc lib root sbin tmp var
boot dev home proc run sys usr volume
/ # mkdir -p volume/newdir && echo "this is new files" > newfiles
/ # cat volume/newdir/newfiles
this is new files
##↑デタッチ##
### debian-baseコンテナの起動確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
490826efa2a8 gcr.io/distroless/base-debian11:debug "/busybox/sh" 6 minutes ago Up 6 minutes
###############################################
※volumes-fromは指定したコンテナ同じマウント状態でコンテナを起動する
※ busyboxはUNIXコマンドが入った最低限のシェル環境イメージ(tar cvfを実行する)
※tarコマンドの使い方:tar zcvf バックアップ名.tar.gz 対象ディレクトリ・ファイル
ボリュームの復元
バックアップファイルからボリュームの復元はバックアップしたファイルをコンテナ内でuntarすれば良いです。
$ docker run --rm --volumes-from debian-base -v $(pwd):/backup busybox bash -c "cd /volume && tar xzcf /backup/backup.tar.gz --strip 1"
※ –strip 1はuntarした後に作成されるディレクトリを1階層分無視する。ここでは/volumeの中に/volume/volume/newdir/newfilesというようにvolumeディレクトリが重複するのを回避している。
書き込み制御フラグ readonly (volume,tmpfs,bindで共通)
$ docker --mount type=bind,src=/var/www/html/,dst=/var/www/,readonly
readonlyオプションをつけると読み込み専用になる
コンテナ間のファイル共有方法
作成したコンテナのファイルを教諭したい場合があります。
コンテナ間のデータを共有する方法はいくつかあります。
- クラウドストレージサービス S3などを利用する
- NFSを利用
vieux/sshfsプラグインのボリュームドライバーを利用する
ssh先のファイルシステムを利用する
nfsはネットワークストレージで同じNFSをコンテナ間で利用すれば、コンテナ間でデータを共有することができます。