はじめに
Dockerに入門してみる。
作業環境はUbuntu 20.04
環境設定
aptでも提供されているが、Install Docker Engine on Ubuntuの手順でインストールしたほうがトラブルは少なそう。
apt版のアンインストール
$ sudo apt purge docker docker-engine docker.io containerd runc
インストール
必要なパッケージのインストール
$ sudo apt install \ 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 update $ sudo apt install docker-ce docker-ce-cli containerd.io
dockerグループへの追加
dockerコマンドをsudoなしで実行できるようにする
$ sudo gpasswd -a ${USER} docker
一度ログアウトして、再ログインすると有効化される。
最初のコンテナ
いろいろなチュートリアルで、最初にDockerを実行するのは下記のようなコマンド。
$ docker run hello-world
docker run
がいろいろなことを自動で実行するため便利だが、筆者のような初心者にはなにが起こっているか分かりづらい。
何もない状態からdocker run
を実行する場合下記のようなことが行われる。
- イメージの取得
- イメージからコンテナを作成
- コンテナの起動
- コンテナへのアタッチ
dockerのコマンドでいうと下記のような感じ
- docker pull / docker build
- docker create
- docker start
- docker attach
イメージとコンテナ
Dockerといえばコンテナ。実際コンテナを作ってその上で作業するためのツールだが、コンテナを実行するためにはイメージが必要となる。
イメージとコンテナにはそれぞれIDが割り振られる(イメージIDとコンテナID)。これらは同じような16進数のハッシュ値なので、最初は混乱するがきちんと別物だということを理解しておく。
イメージはコンテナの金型のようなもので、1つのイメージからいくつもコンテナを実行できる。
イメージIDは1つだが、コンテナIDは2つ必要になる。
コンテナでいろいろ作業して、使い終わったコンテナを削除することもできる。
通常コンテナで作業した内容はイメージには反映されない。
ネット上ではコンテナを実行する際下記のようなコマンドを示されることが多い。
$ docker run -it --rm ubuntu
自動的にbashが実行されubuntuが実行されたコンテナにログインされた状態になるため、ここでいろいろと作業することになる。
しかし--rm
によってコンテナからexitした時点でコンテナが削除されてしまう。コンテナでの作業内容は基本的にイメージに反映されないため、作業した内容が失われてしまうことになる。
Dockerでの作業状態
Dockerで作業する場合に把握しておくべき状態をまとめる。便宜上実行状態にA-Eで名前をつけることにする。
状態 | イメージ | コンテナ | 遷移する方法(作る時/A->E) | 遷移する方法(消す時/E->A) | 確認方法 |
---|---|---|---|---|---|
A | なし | なし | docker rmi | ||
B | 作成済み | なし | docker pull / docker build | --rmをつけて実行したコンテナからexit / docker rm | docker images |
C | 作成済み | 停止中 | docker create | --rmなしのコンテナからexit | docker ps -a |
D | 作成済み | 実行中 | docker start | Ctrl+P Ctrl+Q でコンテナを抜ける | docker ps |
E | 作成済み | アタッチ | docker attach / docker exec |
大体いまどこかがわかっていれば生きていける。
よく使われるrun
はこれらの状態を複数スキップというか自動実行する。
docker run
書式は下記。詳細(run)
docker run [オプション] イメージ [コマンド] [引数...]
表のAの状態でdocker runを実行すると一気にEの状態まで遷移する。ここで指定しているubuntu
はイメージ名
。
$ docker run -it ubuntu Unable to find image 'ubuntu:latest' locally latest: Pulling from library/ubuntu da7391352a9b: Pull complete 14428a6d4bcd: Pull complete 2c2d948710f2: Pull complete Digest: sha256:c95a8e48bf88e9849f3e0f723d9f49fa12c5a00cfc6e60d2bc99d87555295e4c Status: Downloaded newer image for ubuntu:latest root@9f1316bc678f:/#
--rm
をつけていないので、この状態からexitすると表のCの状態に遷移する。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
実行中のコンテナはいない。
下記のコマンドで停止中のコンテナも表示する。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9f1316bc678f ubuntu "/bin/bash" About a minute ago Exited (0) 41 seconds ago focused_pasteur
コンテナID9f1316bc678f
のコンテナが表示される。
このコンテナの元になったイメージを確認する。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest f643c72bc252 6 weeks ago 72.9MB
イメージIDがf643c72bc252
のイメージが表示される。
イメージのリポジトリとタグ
先ほど便宜上イメージ名
と言ったものは正確にはREPOSITORY
という。
1つのリポジトリにはいくつものイメージが存在する。たとえばubuntuの過去のバージョンを選択したい場合はubuntu:18.04
のように指定する。
コロン(:)のあとに続く18.04
はTAG
といい、コマンドでREPOSITORYのみ指定した場合、最新を示すlatest
というTAGが自動的に選択される。
これらのことからイメージを指定するために必要な識別子はリポジトリ名、タグ名ということになるが、イメージID
と表現を揃えるためイメージ名
と呼ぶことにする。
コンテナがある状態でdocker run
停止中とはいえ既にコンテナがある状態で同じイメージに対してdocker run
を実行するとどうなるか。
$ docker run -it ubuntu
exitして下記のコマンドを実行する。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fd274bb747d1 ubuntu "/bin/bash" 13 seconds ago Exited (0) 9 seconds ago elegant_blackburn 9f1316bc678f ubuntu "/bin/bash" 18 minutes ago Exited (0) 17 minutes ago focused_pasteur
停止中のコンテナが2つになっている。増えた方のコンテナIDはfd274bb747d1
。
作成済みのイメージからコンテナへアタッチされたことになる。つまり表のBからEに遷移される。
つまり一度作成したコンテナに対してはdocker run
では操作できないということ。docker runに指定するのがイメージ名なのでコンテナへの識別が必要となる操作はできない。
attach vs exec
実行中のコンテナへ接続する方法はattach
とexec
の2つある。これらのコマンドはコンテナ識別子を指定する。(コンテナID/コンテナ名)
書式は下記。詳細(attach)、詳細(exec)
docker attach [オプション] コンテナ docker exec [オプション] コンテナ コマンド [引数...]
docker attach
docker attach
はPID=1のプロセスに接続する。Ctrl+P、Ctrl+Qでデタッチした場合でも再接続可能。
$ docker start 9f1316bc678f $ docker attach 9f1316bc678f root@9f1316bc678f:/# echo $$ 1
環境変数$$
で実行中のPIDを取得できる。ここでは1になっている。
作業途中で抜けて再接続したい場合などはこちらで作業すると良さそう。
docker exec
コンテナ内の指定した任意のコマンドを実行できる。attachとは異なり新規にプロセスを作成する。
$ docker start 9f1316bc678f $ docker exec -it 9f1316bc678f /bin/bash root@9f1316bc678f:/# echo $$ 8
こちらに関してはCtrl+P、Ctrl+Qでデタッチした場合、このプロセスに再接続する方法がない。
実行中のコンテナで複数のターミナルを開いて作業したい場合などはこちらを使うと良さそう。
コンテナの削除
docker rm
で削除する。
書式は下記。詳細(rm)
docker rm [オプション] コンテナ [コンテナ...]
削除するには下記のようにする。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2b17b5b1a846 ubuntu "/bin/bash" 8 seconds ago Exited (0) 6 seconds ago ecstatic_jepsen $ docker rm -f 2b17b5b1a846
-f
を指定すると実行中のコンテナも削除できる。コンテナはIDでも名前でもよい。
イメージの削除
docker rmi
で削除できる。
書式は下記。詳細(rmi)
docker rmi [オプション] イメージ [イメージ...]
削除するには下記のようにする。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest f643c72bc252 6 weeks ago 72.9MB hello-world latest bf756fb1ae65 12 months ago 13.3kB $ docker rmi bf756fb1ae65
よく使うオプション(-it)
docker run
やdocker exec
で、-it
というオプションをつけているのをよく見かける。
Docker-docs-jaによると下記の通り。
option | long name | 機能 |
---|---|---|
-i | --interructive | コンテナの STDIN にアタッチ |
-t | --tty | 疑似ターミナル (pseudo-TTY) を割り当て |
標準入力を擬似ttyに接続することでインタラクティブなシェルを実現できるとのこと。
逆に言えば単発で実行されるコマンドを実行する場合は不要
$ docker start 9f1316bc678f $ docker exec 9f1316bc678f cat /etc/os-release NAME="Ubuntu" VERSION="20.04.1 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.1 LTS" VERSION_ID="20.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=focal UBUNTU_CODENAME=focal
docker runの単発実行
任意のコマンドの単発実行について触れたのでdocker run
の単発実行についても触れる。
docker run
もコマンドを指定することで、起動したコンテナで任意のコマンドを実行することができる。
$ docker run --rm ubuntu cat /etc/os-release
このコマンドを実行すると下記のことが実行される。
- イメージの取得
- コンテナの作成
- コンテナの起動
- コンテナ内でコマンドを実行
- コンテナ終了
- コンテナの削除
表の状態のA->B->C->D->E->D->Bという遷移が自動で行われる。
コンテナの作業内容の保存
コンテナ内でファイルを追加したり環境を構築したりてもコンテナを削除すると全て失われるが、
これらを保持したい場合は、docker commit
でイメージにすることができる。
書式は下記。
docker commit [オプション] コンテナ [リポジトリ[:タグ]]
下記のように実行する。
$ docker commit 9f1316bc678f my_env:version1
まとめ
いままでDockerをなんとなく使っていたが今回まとめてみた。
runが高機能すぎて、わからなくてもなんとなく使えてしまうのが良し悪しあると思う。
attachとexecも割と混乱する。
これで君もDockerマスターだ!(嘘)