【Docker】技術書「Docker&Kubernetsのきほんのきほん」学習記録(基礎編)

2024年3月7日

こんにちは、キクです。

本記事は、僕が自己学習で学んだことをブログでアウトプットするシリーズになります。
今回は、技術書「Docker&Kubernetsのきほんのきほん」をベースにして学んだことを『Docker(基礎編)』として整理しようと思います。

実際にコマンドを使った操作については「実践編」の方で整理したので、気になる方はそちらも読んでみてください。

それでは、よろしくお願いします。

注意事項

本記事は自己学習としてのアウトプットが目的となります。

そのため、本記事には誤った情報が含まれる可能性もありますが、ご了承ください。

Dockerについて

Dockerとは

データやプログラムを隔離できる仕組み

通常、サーバ上ではApacheやMySQLなどの複数のプログラム(ソフトウェア)が同時に動いている
Dockerでは、こうした複数のプログラムやデータを「コンテナ」としてそれぞれ独立した環境に隔離することができる

また、Dockerでは「隔離」だけでなく「多重稼働」という側面もある

通常、物理マシンをWebサーバとして稼働させたい場合には1筐体が1サーバとなる
しかし、コンテナを利用することで複数のWebサーバを1筐体上で稼働させることも可能になる

Docker利用の主なメリット

  • 環境を安全に分離できる
  • 異なる環境で同じ構成のコンテナを簡単に稼働できる

隔離する主な理由

異なるシステムにおいて共通のソフトウェアを利用しているケースにおいて、片方の都合だけでソフトウェアのバージョンアップが実施できないことがある

例えば、システム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を利用することはできる

利用方法としては、主に以下のパターンがある

  1. Virtual BoxなどでLinux OSサーバを建てて、その上でDockerを利用する
  2. 専用ソフトウェアを利用してDockerを利用する

専用ソフトウェアは「Docker Desktop for Windows(またはMac)」を指す
このソフトウェアは、簡単に言うとWindowsやMacのOS上に、さらにLinux OSも強引に入れてしまって動かしているイメージである

Docker利用に関する基本概念

1コンテナ = 1アプリ

Dockerでは一般的に「1コンテナ = 1アプリ」で使うという考え方がある模様

例えば、WordPressは「WordPress本体」「Apache」「MySQL」といった複数のソフトウェアが必要だが、これらをそれぞれ別のコンテナで稼働させるということ

1コンテナ = 1アプリ

WordPress:WordPress用のコンテナで稼働

Apache:Apache用のコンテナで稼働

MySQL:MySQL用のコンテナで稼働

同じコンテナでも稼働させることは可能だが、メンテナンス性やDockerのメリットなどの観点を考慮するとあまり推奨はされていない

コンテナは作っては捨てる

コンテナは長く大事に使うのではなく、作っては捨てるという使い方をするもの

コンテナ内のソフトウェアで新しいバージョンがリリースされた場合、ソフトウェアをバージョンアップするのではなく、新しいバージョンのソフトウェア入りのコンテナを新規作成する方を選ぶ

この考えの背景には「せっかく構築が楽になったのに保守に時間がかかってしまうのはDockerのメリットを潰すことになる」というものがある

ちなみに、「コンテナ作成 -> 起動 -> 停止 -> 削除 -> コンテナ作成 ・・・」という一連の流れを「コンテナのライフサイクル」と呼ぶ

Dockerの仕組み

階層構造

Dockerが稼働する環境は、次のような「階層構造」になっている

Dockerを動かす階層構造

4層:コンテナ

3層:Docker Engine(Dockerのソフト)

2層:物理OS

1層:物理マシン

コンテナに含まれるLinux OSっぽいもの

コンテナの中には「Linux OSっぽいもの」が必ず含まれている

OSは「カーネル」と呼ばれる「核」になる部分と「周辺部分」から構成され、以下のような連携を取っている

  1. 周辺部分がプログラムからの連絡を受け取ってカーネルに伝える
  2. カーネルが受け取った連絡内容を元にしてハードウェアを操作する

Dockerの場合、各コンテナは完全に分離されているため、土台となるLinux OS(第2層)の周辺部分がコンテナ内のプログラムの命令を受け取ることができない

そのため、コンテナ内にOSの周辺部分(俗にいうディストリビューション)を入れてプログラムの命令を受け取り、受け取った命令を土台のカーネルに伝える仕組みになっている

この「コンテナ内のOSの周辺部分」が「Linux OSっぽいもの」の正体である

ソフトウェアとハードウェア間での経路の違い

■通常  :ソフトウェア -> 周辺部分 -> カーネル -> ハードウェア

■Docker :コンテナ(ソフトウェア -> 周辺部分)-> Docker Engine -> カーネル -> ハードウェア

周辺部分だけをコンテナ内に入れて、カーネルは物理マシン上のものを利用する(=カーネルはコンテナ内に入れない)ことで、コンテナの特徴である「軽い」を実現している

ちなみに、同一物理サーバ上で稼働するコンテナ間で異なるディスとリビュージョンおよび異なるバージョンが稼働することは問題ない

コンテナについて

コンテナのデータ保存

コンテナは「作っては捨てる」が基本であるため、コンテナ内のデータも削除されることになる

しかし、コンテナから物理マシンのディスクなどをマウントして、そこにデータを保存するということも可能である
これであればコンテナを削除してもデータを残すことが可能となる

ちなみに、この「コンテナ外部へデータを保存すること」を「データの永続化」と呼ぶ

記憶領域のマウント

Dockerに対して記憶領域をマウントする方法は、以下の2通りある

  1. ボリュームマウント
  2. バインドマウント

コンテナ内のマウント先は、そのソフトウェアがコンテンツを保存する場所を指定するケースが多い
マウントは「docker run」コマンドのオプションとして指定する

マウント方法

■ボリュームマウント

$ docker run 〜 -v ボリューム名:コンテナ内の記憶領域パス イメージ名

■バインドマウント

$ docker run 〜 -v 実際の記憶領域パス:コンテナ内の記憶領域パス イメージ名

1. ボリュームマウント

Docker Engineが管理している領域内にボリュームを作成し、ディスクとしてコンテナにマウントする
Docker Engineの管理下にデータがあるため、誤ってデータを削除する可能性が低い

また、OSによってデータアクセスへのコマンドが変わることもないため、慣れれば手軽

その反面、ボリュームに対する操作はコンテナ経由で実施する必要があったり、バックアップ方法が複雑であったりと、操作性が悪いのが難点
そのため、「仮で使いたい」「滅多にアクセスしないが、消してはいけないファイルを保存」などのケースで使うことが多い

マウント時にボリュームが存在しない場合には自動作成されるが、事前にボリュームを作成しておくことが推奨されている

ボリューム操作

■ボリューム作成

$ docker volume create ボリューム名

■ボリューム削除

$ docker volume rm ボリューム名

2. バインドマウント

Docker Engineが稼働するホスト側のファイルやディレクトリをコンテナにマウントする
ディレクトリに対して直接ファイルを置いたり開いたりできるため、頻繁にアクセスするファイルはこの方法で保存することが多い

ホスト側にデータを保存しているため、「誤って消してしまった」ということがないように注意

コンテナとの通信

コンテナへのネットワーク通信はデフォルトでは無効化状態になっている

例えば、コンテナをWebサーバとして稼働する場合には、そのままではアクセスできないということ
コンテナ上で80番ポートが解放されていたとしても、母体となるホスト側で受け付けていなければ接続はできない

Icons by Icons8

そのため、コンテナ作成時に以下のようなコマンドでホスト側のポート(8080)とコンテナ側のポート(80)を接続しておく必要がある

$ docker run --name testapache -d -p 8080:80 httpd

これによりクライアントからの接続を一旦ホスト側で受け取って、それをコンテナに流すことが可能になる

Icons by Icons8

なお、この設定は基本的にコンテナ作成後には変更できないようで、コンテナ作成時にオプションとして指定する必要がある

また、同一ホスト上で複数のWebサーバコンテナを稼働させるようなケースでは、基本的にホスト側のポートは「コンテナ1:8080」「コンテナ2:8081」のようにコンテナ毎に分ける必要がある

コンテナ同士の通信におけるネットワーク設定

Dockerの特徴である「隔離」の観点から、コンテナ同士は基本的に繋がっていない

WordPressのように「WordPressコンテナ」と「MySQLコンテナ」がそれぞれ通信をする必要がある場合、お互いのコンテナ同士を繋ぐネットワーク設定が必要

基本的なネットワーク設定の流れ

  1. ネットワーク作成
  2. コンテナAの作成時に「--net」で作成したネットワークを指定
  3. コンテナBの作成時に「--net」で作成したネットワークを指定

コンテナへのファイルコピー

docker cp(正式にはdocker container cp)コマンドを利用することで、コンテナを動かすホストとコンテナ間でのファイルコピーが可能

コンテナへの接続

コンテナは「作っておしまい」ではなく、コンテナ内で作業をしたいということもある

このようなケースにおいて「コンテナへ接続する方法」としては、以下のパターンがある模様

  1. docker execコマンドで接続
  2. 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

各プロセスについて

PID=1の「/bin/bash」 :コンテナ起動時に起動したプロセス

PID=15の「/bin/bash」:docker execコマンドで接続した際に起動したプロセス

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

メモ

docker execコマンドと異なり「/bin/bash」プロセスが1つしか起動していないことが分かる

デタッチ

コンテナ内で以下のいずれかのキー入力をすることでコンテナから抜けることができる

  • Ctrl + q
  • Ctrl + p

注意点

docker attachでアタッチしたコンテナ内で「exit」や「Ctrl + D」で抜けた場合、対象コンテナのプロセスは停止するため注意

(base) MacBook-Pro:~ user$ docker ps
CONTAINER ID   IMAGE      COMMAND       CREATED          STATUS          PORTS     NAMES
418463c155f9   centos:7   "/bin/bash"   44 minutes ago   Up 34 minutes             test
(base) MacBook-Pro:~ user$ docker attach test
[root@418463c155f9 /]# 
[root@418463c155f9 /]# exit
exit
(base) MacBook-Pro:~ user$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
(base) MacBook-Pro:~ user$ docker ps -a
CONTAINER ID   IMAGE                           COMMAND                   CREATED          STATUS                      PORTS                    NAMES
418463c155f9   centos:7                        "/bin/bash"               46 minutes ago   Exited (0) 22 seconds ago                            test

なお、docker execで接続した場合には、exitしても「PID=1」のプロセスとは別プロセスが終了するだけなので問題ない

苦戦メモ

物理ホストが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 Engine

Dockerを使うためのソフトウェア

このソフトウェアがあることで、コンテナの作成や動かしたりできるようになる
デフォルトで自動起動設定が入っているため、PC/サーバの起動と共にDocker Engineも起動する

しかし、コンテナに対しては自動起動させるような設定はない
そのため、コンテナを自動起動させたいような場合にはDocker Engineの外側にコンテナを起動するスクリプトなどを用意して対応する

Docker image

コンテナの素になるもの
ISOファイルみたいなもの

イメージからコンテナを作ることはもちろん、コンテナからイメージを作る(=書き出し)ことも可能

コンテナを削除してもイメージは残るため、放っておくと増え続けてストレージ逼迫の原因になる
そのため必要に応じて明示的に削除する必要がある

取得したイメージファイルの格納場所はホストがLinuxかMac/Windowsかで違う模様

イメージファイル格納先の違い

ホストOS格納先
Linux/var/lib/docker配下
Mac / Windowsdocker desktopの「Disk image location」にて設定されたパス
Linux コンテナーやイメージを一つの大きな「ディスクイメージ」として保存している模様

[Mac環境での設定例]
/Users/user/Library/Containers/com.docker.docker/Data/vms/0/data

■Mac環境で確認

設定箇所のパス:docker desktop -> Settings(歯車マーク)-> Resources

Docker imageの作成

以下2パターンある

  1. 既存コンテナをcommitして書き出して作成
  2. Dockerfileから作成
パターン説明
既存コンテナをcommitして書き出して作成手頃ではあるがコンテナを作り込む必要がある
Dockerfileから作成Dockerfileをbuildすることでイメージにする
Dockerfileの用途は「イメージ作成」のみであり、記述する内容は元となるイメージ情報や実行したいコマンドなどである
なお、Dockerfile内で指定しているファイル群は、Dockerfileと同じディレクトリ内に格納しておく

Docker Imageのアップロード

docker push(正式にはdocker image push)コマンドを実行することで、レジストリにイメージをアップロードする

[書式]
$ docker push レジストリの場所/リポジトリ名:バージョン
[入力例]
$ docker push zoozoo.coomm/nyapacchi13

なお「レジストリの場所/リポジトリ名:バージョン」は「タグ名」と呼ばれるものである

Docker Hub

公式サイト:https://hub.docker.com

公式が運用しているDockerレジストリで、様々なDockerイメージが配布されている

例えば、以下のような配布パターンがある

配布されるイメージパターン例

  • OSっぽいもののみが含まれるイメージ
  • OSっぽいもの+ソフトウェア(Apacheなど)が含まれるイメージ
  • OSっぽいもの+複数のソフトウェアが含まれるイメージ

Docker Hubは公開されているレジストリだが、社内サーバを利用してプライベートなDockerレジストリを作成することも可能

安全なイメージの選び方

  • 公式(もしくはそれに準ずる団体)が提供しているイメージを使う
  • 必要最低限構成のイメージから自分でカスタムする

レジストリとリポジトリ

似たような名前で混同しやすいが、実際には別物である

項目説明
レジストリ(登記所)・イメージの配布場所
・会社単位や部署単位で作成
リポジトリ・レジストリの中をさらに区切った単位
・ソフトウェア単位で区切って作成

プライベートレジストリ

公開されたレジストリではなく、自社専用のレジストリが必要なケースなどにおいて作成 / 運用したりする

レジストリ用コンテナ(registry)というものがあるのでそれを利用する
利用者はレジストリにログイン後、ダウンロード元としてレジストリを指定する

プライベートレジストリは「ポート5000番」を使用する

[作成コマンド例]
$ docker run -d -p 5000:5000 registry

参考情報

-学習記録, Docker
-,