- 本記事にはアフィリエイト広告が含まれます -
こんにちは、キクです。
本記事は、僕が自己学習で学んだことをブログでアウトプットするシリーズになります。
今回は、技術書「Docker&Kubernetsのきほんのきほん」をベースにして学んだことを『Docker(基礎編)』として整理しようと思います。
実際にコマンドを使った操作については「実践編」の方で整理したので、気になる方はそちらも読んでみてください。
それでは、よろしくお願いします。
Dockerについて
Dockerとは
データやプログラムを隔離できる仕組み
通常、サーバ上ではApacheやMySQLなどの複数のプログラム(ソフトウェア)が同時に動いている
Dockerでは、こうした複数のプログラムやデータを「コンテナ」としてそれぞれ独立した環境に隔離することができる
また、Dockerでは「隔離」だけでなく「多重稼働」という側面もある
通常、物理マシンをWebサーバとして稼働させたい場合には1筐体が1サーバとなる
しかし、コンテナを利用することで複数のWebサーバを1筐体上で稼働させることも可能になる
隔離する主な理由
異なるシステムにおいて共通のソフトウェアを利用しているケースにおいて、片方の都合だけでソフトウェアのバージョンアップが実施できないことがある
例えば、システムAおよびシステムBでは共通して「MySQL Ver.X」を利用しているが、システムBのみMySQL Ver.Yへのバージョンアップが必要といったケース
このようなケースにおいて「システムBのためにMySQLをVer.Yにバージョンアップしたら、システムAが動かなくなってしまった」みたいなことがある
DockerによってシステムAとシステムBを異なるコンテナで稼働させ、それぞれで別のMySQLを稼働させることで上記の問題が解消したりする
ベースはLinux
Dockerの根幹部分ではLinux OSで使っている
WindowsやMacでDockerを使う場合においても、何かしらの形でLinuxが必要となる
また、コンテナ内にはWindowsやMac用のソフトウェア(WordやExcelなど)を入れることができない
もし入ったとしても正常に動かない
WindowsやMacでDockerを使える理由
「ベースはLinux」とは言ったものの、今回の学習も含め「Windos」や「Mac」の環境でもDockerを利用することはできる
利用方法としては、主に以下のパターンがある
- Virtual BoxなどでLinux OSサーバを建てて、その上でDockerを利用する
- 専用ソフトウェアを利用してDockerを利用する
専用ソフトウェアは「Docker Desktop for Windows(またはMac)」を指す
このソフトウェアは、簡単に言うとWindowsやMacのOS上に、さらにLinux OSも強引に入れてしまって動かしているイメージである
Docker利用に関する基本概念
1コンテナ = 1アプリ
Dockerでは一般的に「1コンテナ = 1アプリ」で使うという考え方がある模様
例えば、WordPressは「WordPress本体」「Apache」「MySQL」といった複数のソフトウェアが必要だが、これらをそれぞれ別のコンテナで稼働させるということ
同じコンテナでも稼働させることは可能だが、メンテナンス性やDockerのメリットなどの観点を考慮するとあまり推奨はされていない
コンテナは作っては捨てる
コンテナは長く大事に使うのではなく、作っては捨てるという使い方をするもの
コンテナ内のソフトウェアで新しいバージョンがリリースされた場合、ソフトウェアをバージョンアップするのではなく、新しいバージョンのソフトウェア入りのコンテナを新規作成する方を選ぶ
この考えの背景には「せっかく構築が楽になったのに保守に時間がかかってしまうのはDockerのメリットを潰すことになる」というものがある
ちなみに、「コンテナ作成 -> 起動 -> 停止 -> 削除 -> コンテナ作成 ・・・」という一連の流れを「コンテナのライフサイクル」と呼ぶ
Dockerの仕組み
階層構造
Dockerが稼働する環境は、次のような「階層構造」になっている
コンテナに含まれるLinux OSっぽいもの
コンテナの中には「Linux OSっぽいもの」が必ず含まれている
OSは「カーネル」と呼ばれる「核」になる部分と「周辺部分」から構成され、以下のような連携を取っている
- 周辺部分がプログラムからの連絡を受け取ってカーネルに伝える
- カーネルが受け取った連絡内容を元にしてハードウェアを操作する
Dockerの場合、各コンテナは完全に分離されているため、土台となるLinux OS(第2層)の周辺部分がコンテナ内のプログラムの命令を受け取ることができない
そのため、コンテナ内にOSの周辺部分(俗にいうディストリビューション)を入れてプログラムの命令を受け取り、受け取った命令を土台のカーネルに伝える仕組みになっている
この「コンテナ内のOSの周辺部分」が「Linux OSっぽいもの」の正体である
周辺部分だけをコンテナ内に入れて、カーネルは物理マシン上のものを利用する(=カーネルはコンテナ内に入れない)ことで、コンテナの特徴である「軽い」を実現している
ちなみに、同一物理サーバ上で稼働するコンテナ間で異なるディスとリビュージョンおよび異なるバージョンが稼働することは問題ない
コンテナについて
コンテナのデータ保存
コンテナは「作っては捨てる」が基本であるため、コンテナ内のデータも削除されることになる
しかし、コンテナから物理マシンのディスクなどをマウントして、そこにデータを保存するということも可能である
これであればコンテナを削除してもデータを残すことが可能となる
ちなみに、この「コンテナ外部へデータを保存すること」を「データの永続化」と呼ぶ
記憶領域のマウント
Dockerに対して記憶領域をマウントする方法は、以下の2通りある
- ボリュームマウント
- バインドマウント
コンテナ内のマウント先は、そのソフトウェアがコンテンツを保存する場所を指定するケースが多い
マウントは「docker run」コマンドのオプションとして指定する
1. ボリュームマウント
Docker Engineが管理している領域内にボリュームを作成し、ディスクとしてコンテナにマウントする
Docker Engineの管理下にデータがあるため、誤ってデータを削除する可能性が低い
また、OSによってデータアクセスへのコマンドが変わることもないため、慣れれば手軽
その反面、ボリュームに対する操作はコンテナ経由で実施する必要があったり、バックアップ方法が複雑であったりと、操作性が悪いのが難点
そのため、「仮で使いたい」「滅多にアクセスしないが、消してはいけないファイルを保存」などのケースで使うことが多い
マウント時にボリュームが存在しない場合には自動作成されるが、事前にボリュームを作成しておくことが推奨されている
2. バインドマウント
Docker Engineが稼働するホスト側のファイルやディレクトリをコンテナにマウントする
ディレクトリに対して直接ファイルを置いたり開いたりできるため、頻繁にアクセスするファイルはこの方法で保存することが多い
ホスト側にデータを保存しているため、「誤って消してしまった」ということがないように注意
コンテナとの通信
コンテナへのネットワーク通信はデフォルトでは無効化状態になっている
例えば、コンテナをWebサーバとして稼働する場合には、そのままではアクセスできないということ
コンテナ上で80番ポートが解放されていたとしても、母体となるホスト側で受け付けていなければ接続はできない
そのため、コンテナ作成時に以下のようなコマンドでホスト側のポート(8080)とコンテナ側のポート(80)を接続しておく必要がある
$ docker run --name testapache -d -p 8080:80 httpd
これによりクライアントからの接続を一旦ホスト側で受け取って、それをコンテナに流すことが可能になる
なお、この設定は基本的にコンテナ作成後には変更できないようで、コンテナ作成時にオプションとして指定する必要がある
また、同一ホスト上で複数のWebサーバコンテナを稼働させるようなケースでは、基本的にホスト側のポートは「コンテナ1:8080」「コンテナ2:8081」のようにコンテナ毎に分ける必要がある
コンテナ同士の通信におけるネットワーク設定
Dockerの特徴である「隔離」の観点から、コンテナ同士は基本的に繋がっていない
WordPressのように「WordPressコンテナ」と「MySQLコンテナ」がそれぞれ通信をする必要がある場合、お互いのコンテナ同士を繋ぐネットワーク設定が必要
コンテナへのファイルコピー
docker cp(正式にはdocker container cp)コマンドを利用することで、コンテナを動かすホストとコンテナ間でのファイルコピーが可能
コンテナへの接続
コンテナは「作っておしまい」ではなく、コンテナ内で作業をしたいということもある
このようなケースにおいて「コンテナへ接続する方法」としては、以下のパターンがある模様
- docker execコマンドで接続
- docker attachコマンドで接続
1. docker execコマンドで接続
以下のようなコマンドで接続する
$ docker exec -it コンテナ名 シェル名
docker execコマンドでは、対象コンテナに対して新たなプロセスとして繋ぎに行く
そのため、下記コマンドで接続した場合にはPID=1(bash)とは別のプロセスとしてbashが起動することになる
(base) MacBook-Pro:~ user$ docker exec -it test /bin/bash
[root@418463c155f9 /]#
[root@418463c155f9 /]# ps au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 3740 2432 pts/0 Ss+ 08:36 0:00 /bin/bash
root 15 0.0 0.0 3740 2432 pts/1 Ss 08:36 0:00 /bin/bash
root 35 0.0 0.0 7812 2816 pts/1 R+ 08:39 0:00 ps au
2. docker attachコマンドで接続
起動中のコンテナのプロセスに対して接続することを「アタッチ」と呼ぶ
反対に、アタッチを解除することを「デタッチ」と呼ぶ
■アタッチ
docker attachコマンドで接続可能
[書式]
$ docker attach コンテナ名
これにより、指定したコンテナのPID=1のプロセスにアタッチする
(base) MacBook-Pro:~ user$ docker attach test
[root@418463c155f9 /]#
[root@418463c155f9 /]# ps au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 3740 2432 pts/0 Ss 08:36 0:00 /bin/bash
root 37 0.0 0.0 7812 2816 pts/0 R+ 08:42 0:00 ps au
■デタッチ
コンテナ内で以下のいずれかのキー入力をすることでコンテナから抜けることができる
- Ctrl + q
- Ctrl + p
苦戦メモ
物理ホストがMacの環境で「Ctrl + q」や「Ctrl + p」を実行してもデタッチできなかった
おそらく他のショートカットとして割り当て済みであるためと考えられる
ホスト側の「.docker/config.json」ファイルにて、デタッチ用のキー入力を別のキーに設定することで、Mac環境でもデタッチすることができた
▼変更前
{
"auths": {
"https://index.docker.io/v1/": {}
},
"credsStore": "desktop",
"experimental": "disabled",
"currentContext": "desktop-linux"
}
▼変更後
{
"auths": {
"https://index.docker.io/v1/": {}
},
"credsStore": "desktop",
"experimental": "disabled",
"currentContext": "desktop-linux",
"detachKeys": "ctrl-q ,q" ← この行を追記
}
参考:docker-1.10.0からデタッチキーが変更できるようになった
参考:Docker コンテナを停止せずにデタッチする方法
関連調査メモ
Docker Engine
Dockerを使うためのソフトウェア
このソフトウェアがあることで、コンテナの作成や動かしたりできるようになる
デフォルトで自動起動設定が入っているため、PC/サーバの起動と共にDocker Engineも起動する
しかし、コンテナに対しては自動起動させるような設定はない
そのため、コンテナを自動起動させたいような場合にはDocker Engineの外側にコンテナを起動するスクリプトなどを用意して対応する
Docker image
コンテナの素になるもの
ISOファイルみたいなもの
イメージからコンテナを作ることはもちろん、コンテナからイメージを作る(=書き出し)ことも可能
コンテナを削除してもイメージは残るため、放っておくと増え続けてストレージ逼迫の原因になる
そのため必要に応じて明示的に削除する必要がある
取得したイメージファイルの格納場所はホストがLinuxかMac/Windowsかで違う模様
Docker imageの作成
以下2パターンある
- 既存コンテナをcommitして書き出して作成
- Dockerfileから作成
パターン | 説明 |
---|---|
既存コンテナをcommitして書き出して作成 | 手頃ではあるがコンテナを作り込む必要がある |
Dockerfileから作成 | Dockerfileをbuildすることでイメージにする Dockerfileの用途は「イメージ作成」のみであり、記述する内容は元となるイメージ情報や実行したいコマンドなどである なお、Dockerfile内で指定しているファイル群は、Dockerfileと同じディレクトリ内に格納しておく |
Docker Imageのアップロード
docker push(正式にはdocker image push)コマンドを実行することで、レジストリにイメージをアップロードする
[書式]
$ docker push レジストリの場所/リポジトリ名:バージョン
[入力例]
$ docker push zoozoo.coomm/nyapacchi13
なお「レジストリの場所/リポジトリ名:バージョン」は「タグ名」と呼ばれるものである
Docker Hub
公式が運用しているDockerレジストリで、様々なDockerイメージが配布されている
例えば、以下のような配布パターンがある
Docker Hubは公開されているレジストリだが、社内サーバを利用してプライベートなDockerレジストリを作成することも可能
レジストリとリポジトリ
似たような名前で混同しやすいが、実際には別物である
項目 | 説明 |
---|---|
レジストリ(登記所) | ・イメージの配布場所 ・会社単位や部署単位で作成 |
リポジトリ | ・レジストリの中をさらに区切った単位 ・ソフトウェア単位で区切って作成 |
プライベートレジストリ
公開されたレジストリではなく、自社専用のレジストリが必要なケースなどにおいて作成 / 運用したりする
レジストリ用コンテナ(registry)というものがあるのでそれを利用する
利用者はレジストリにログイン後、ダウンロード元としてレジストリを指定する
プライベートレジストリは「ポート5000番」を使用する
[作成コマンド例]
$ docker run -d -p 5000:5000 registry