ハンズオン資料
- Linux基礎編
- VirtualBoxハンズオン
- Vagrantハンズオン
- Dockerハンズオン
- Docker Composeハンズオン
今回の目的
今回の目的は、VirtualBox上にVagrantを使ってUbuntu OSのインストール、PHPの実行環境の構築を行います。
YouTube版 【ペチオブ】仮想環境ハンズオン 第4回 Docker編
動画を高評価、チャンネル登録いただけるとより多くの方へオススメ表示されるので良いと思った方はご協力いただけるとありがたいです🙏
完成版
完成版はGitHubにプッシュしてます。
Dockerのインストール
Docker公式サイトからインストーラをダウンロードできます。
$ docker -v
Docker version 20.10.2, build 2291f61
$ docker-compose -v
docker-compose version 1.27.4, build 40524192
Dockerとは
コンテナ型仮想化技術の一つです。
コンテナと仮想マシンの比較
仮想マシンの概念
- 図はハイパーバイザ型の概念図
- ホスト型(VirtualBox等)はハイパーバイザ部分が仮想化ソフトウェアになる
- 仮想マシンはリソース集中型
- プロセッサ、メモリ、ストレージ等のハードウェアのエミュレートが必要
- 短時間での複製が難しい
コンテナの概念
- コンテナは1つのカーネルを共有できます。
- コンテナ・イメージに必要なのは、実行可能なものとパッケージの依存性に関する情報のみです。
- ホストシステム上へパッケージをインストールする必要は一切ありません。
- コンテナ上のプロセスはホスト上のプロセスのように軽快に動作します。
仮想マシンと比べたコンテナのメリット
- 処理が速い
- 仮想マシン毎にプロセッサやメモリ、ストレージをエミュレートする必要がなく、オーバーヘッドが少ない
- 起動が速い
- 仮想マシンのようにゲストOSを立ち上げる必要がないため
- 可搬性が高い
- Dockerエンジンさえあれば動く
- 環境構築が簡潔
- Dockerfileやdocker-compose.ymlによるインフラのコード化
- シェルスクリプトで書かれているより、可読性が高い
- イメージが軽い
- Dockerイメージはレイヤで管理されている
- Vagrantのboxファイルと比べると容量がとても少なく済む
- 構築&共有が手軽
- 起動が速い、可搬性が高い、イメージが軽いことから環境の破棄&再構築しやすい
仮想マシンと比べたコンテナのデメリット
- ホストOSのカーネルと異なるOSは動かせない
- 特殊な環境を再現しないといけない等、要件によっては仮想マシンの方が都合が良い場合がある
Docker ライフサイクル
docker初心者がいまいち理解できず調べ直したところまとめ
- 主なライフプロセス
- イメージ取得(docker pull)
- コンテナ生成(docker create)
- コンテナ起動(docker start)
- コンテナ停止(docker stop)
- コンテナ削除(docker rm)
Docker コマンド
Docker search コマンド
Dockerイメージを検索するコマンド
$ docker search hello-world
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
hello-world Hello World! (an example of minimal Dockeriz… 1158 [OK]
... 省略
Docker run コマンド
runコマンドはイメージ取得、コンテナ生成、コンテナ起動を行う。
docker run イメージ名:タグ名
と指定できる。
イメージのタグを指定しない場合 latest
がデフォルトとなる。
$ docker run hello-world
Hello from Docker!
... 省略
補足
docker run
コマンドは、 pull
, create
, start
をまとめて実行してくれます。
$ docker pull hello-world
$ docker create hello-world
$ docker start ede7a77c58214b2923267285ba3ef2acae314575248b272b18b5751d5a24e3d5
- pull, create はDockerイメージ名が引数
- start はDockerコンテナ名が引数
コンテナの中に入る
コンテナの中に入って、コマンドを実行したい場合もあります。
$ docker run -it ubuntu bash
root@eaa10b69ea7f:/# ←のようなプロンプトが表示されていればok
ユーザー名@コンテナID:ディレクトリパス名# ←表示されてます
-
-i
,--interactive
Keep STDIN open even if not attached- 標準入力(STDIN)を開き続ける
-
-t
,--tty
Allocate a pseudo-TTY- 疑似tty(teletypewriter)を割り当てる
コンテナの中でbashプロセスを新規で立ち上げ操作します。
コンテナから出る
$ exit
control
+ d
でも抜けられます。
docker ps コマンド
起動中のコンテナを表示
$ docker ps
先ほど生成したコンテナは表示されません。
hello-world
のイメージはターミナルにメッセージを表示したらコンテナを停止する仕様になっているため。
停止中のコンテナを含めてすべて表示する
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
333008bb725a hello-world "/hello" 7 minutes ago Exited (0) 7 minutes ago loving_lewin
お試し
オプションの有無での挙動
オプションの有無でどういった挙動になるか確認してみましょう
$ docker run ubuntu bash
$ docker run -i ubuntu bash
$ docker run -t ubuntu bash
-t
の場合は標準入力が効かないので、ターミナル閉じちゃってもokです。
コマンドの実行
bash 以外のコマンドも引数を渡して実行できます。
$ docker run ubuntu ls -l
Apache ウェブサーバを立てる
$ docker run -d -p 8101:80 httpd
お試し: helloのページを表示させてみる
$ docker exec -it <CONTAINER> bash
$ echo hello > /usr/local/apache2/htdocs/hello.html
$ docker ps
$ docker stop <CONTAINER>
nginx ウェブサーバを立てる
$ docker run -d -p 8102:80 nginx
お試し: helloのページを表示させてみる
$ docker exec -it <CONTAINER> bash
$ echo hello > /usr/share/nginx/html/hello.html
$ docker ps
$ docker stop <CONTAINER>
色々なイメージを取得
$ docker pull centos
$ docker pull debian
$ docker pull ubuntu
$ docker pull alpine
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 470671670cac 2 months ago 237MB
debian latest 971452c94376 4 weeks ago 114MB
ubuntu <none> 4c108a37151f 9 months ago 64.2MB
alpine latest a187dde48cd2 2 days ago 5.6MB
- centos(237MB)
- debian(114MB)
- ubuntu(64.2MB)
- alpine(5.6MB)
イメージは軽いほど、ダウンロード時間が減るので好まれる。
PHPベースイメージ
各OSのクリーンなベースイメージから作っても良いですが
DockerHubではPHPのベースイメージを用意してくれてますのでこれを使わない手はないでしょう。
コンテナのバージョン指定
PHP5.3〜最新のPHP8.0までタグ付けされている
PHPコンテナのタグ
- cli(Apacheを経由せず、直接コマンドライン上で実行)
- ウェブサーバ用途ではない
- 使い捨てコンテナ
- 他のイメージを構築するためのベースイメージ
- apache
- ウェブサーバ(Apache mpm_prefork) + アプリケーションサーバ(Apache mod_php)の構成
- PHPと組み合わせたDebianのApache httpdが含まれている
- fpm(FastCGI Process Manager)
- zts(phpがZend Thread Safetyでビルドされている)
- マルチスレッド環境に対応するためのPHPの機構です
- PHPはシングルスレッド環境(NTS)で動かす方が一般的です。
補足: nginxを使う場合は、fpmを選択します。
コンテナOS
- buster (Debian 10) (405MB)
- stretch (Debian 9) (493MB)
- alpine (Alpine Linux) (83.5MB)
用意されてるコンテナOS以外のOSを使いたい場合は自分で用意しましょう...!
Dockerハンズオン
$ mkdir docker-handson
$ cd docker-handson
Vagrantハンズオンで作成した shop
ディレクトリをコピペします。(docker-handson/shop
)
$ git clone https://github.com/ucan-lab/infra-handson-shop shop
もしくはこちらリポジトリをクローンしてください。
PHP の Docker イメージを作る
php/Dockerfile
Docker内でコマンドを実行して、save, commit する方法もありますが、今回はDockerfileにカスタマイズ内容をまとめます。
$ mkdir php
$ vim php/Dockerfile
FROM php:7.4-apache-buster
ENV DB_HOST=shop_db
ENV DB_NAME=shop
ENV DB_USER=phper
ENV DB_PASS=secret
RUN apt-get update
RUN docker-php-ext-install pdo_mysql
-
FROM
命令でベースイメージを指定する -
RUN
任意のコマンドを実行して結果をコミットして新しいレイヤを作成します。 -
docker-php-ext-install
PHP拡張ライブラリを簡単にインストール・有効化するために用意されている(便利!)- 他にも2つの便利コマンドがあります。
-
docker-php-ext-configure
(phpizeやconfigure実行してくれる) -
docker-php-ext-enable
(有効化してくれる)
ビルドしてPHPのDockerイメージを作成
$ docker build -t php_image ./php
Sending build context to Docker daemon 2.048kB
Step 1/7 : FROM php:7.4-apache-buster
---> d9ac5626debe
Step 2/7 : ENV DB_HOST=shop_db
---> Running in a0d08e6d6881
Removing intermediate container a0d08e6d6881
---> 007712462c10
Step 3/7 : ENV DB_NAME=shop
---> Running in b2f168dec5d2
Removing intermediate container b2f168dec5d2
---> a5b52fd1162b
Step 4/7 : ENV DB_USER=phper
---> Running in 75048f5ba3f1
Removing intermediate container 75048f5ba3f1
---> 4eb03c664718
Step 5/7 : ENV DB_PASS=secret
---> Running in 6c1d1c374cf2
Removing intermediate container 6c1d1c374cf2
---> 42a0d96e6301
Step 6/7 : RUN apt update
---> Running in 2880656f22a8
... 省略
Successfully built 252fe418472e
Successfully tagged php_image:latest
-
-t
,--tag
Name and optionally a tag in the 'name:tag' format- イメージ名とタグ名を設定する
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php_image latest 252fe418472e 2 minutes ago 432MB
MySQL の Docker イメージを作る
mysql/Dockerfile
$ mkdir mysql
$ vim mysql/Dockerfile
FROM mysql:8.0
ENV MYSQL_DATABASE=shop
ENV MYSQL_USER=phper
ENV MYSQL_PASSWORD=secret
ENV MYSQL_ROOT_PASSWORD=secret
COPY ./my.cnf /etc/my.cnf
mysql/my.cnf
$ vim mysql/my.cnf
[mysqld]
character_set_server = utf8mb4 # 文字コード
collation_server = utf8mb4_ja_0900_as_cs # 照合順序
ビルドしてMySQLのDockerイメージを作成
$ docker build -t mysql_image ./mysql
Sending build context to Docker daemon 3.584kB
Step 1/6 : FROM mysql:8.0
---> 791b6e40940c
Step 2/6 : ENV MYSQL_DATABASE=shop
---> Running in b10e9e956308
Removing intermediate container b10e9e956308
---> a8dd31ef7c77
Step 3/6 : ENV MYSQL_USER=phper
---> Running in e83a04cdb412
Removing intermediate container e83a04cdb412
---> e19c880a5c32
Step 4/6 : ENV MYSQL_PASSWORD=secret
---> Running in 19934b67c6bc
Removing intermediate container 19934b67c6bc
---> cb032acf278b
Step 5/6 : ENV MYSQL_ROOT_PASSWORD=secret
---> Running in 9c166ea51879
Removing intermediate container 9c166ea51879
---> cd6ff942321c
Step 6/6 : COPY ./my.cnf /etc/my.cnf
---> f98bb0415f59
Successfully built f98bb0415f59
Successfully tagged mysql_image:latest
-
-t
,--tag
Name and optionally a tag in the 'name:tag' format- イメージ名とタグ名を設定する
MySQLデータの永続化
コンテナが削除されてしまうと、MySQLのデータも一緒に消えてしまいます。
コンテナ内やコンテナ間でデータを管理するにはボリュームを使って、ホスト側のディレクトリをコンテナにマウントすると永続化ができます。
Dockerボリュームには2種類あります。
- データ・ボリュームは、ホストのディレクトリをMySQLコンテナ内にマウントする
- データ・ボリューム・コンテナは、データ格納専用コンテナを用意してMySQLコンテナ内にマウントする
$ docker volume create shop_db_storage
ネットワーク
個々のコンテナは独立しており、 php のコンテナから MySQL のコンテナに接続するようにするためには同一ネットワークを設定する必要がある。
ネットワークの作成
$ docker network create shop_network
2903e3148c552db54338803bdfecba5c3e8b603cef39e60ac6ad169a155652f6
ネットワークの一覧
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
2903e3148c55 shop_network bridge local
ネットワークの詳細
$ docker network inspect shop_network
[
{
"Name": "shop_network",
"Id": "8b4373c22b4e47593b4c3942f12d435657ceb32cd7ef911c7196225d258c8fd8",
"Created": "2020-03-31T15:34:46.7379855Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.21.0.0/16",
"Gateway": "172.21.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
PHPコンテナの作成
$ docker run -d --name shop_web --network shop_network -p 8100:80 -v $(pwd)/shop:/var/www/html php_image
$(pwd) を使うので、必ずdocker-handsonディレクトリ直下で実行してください。
-
-d
,--detach
Run container in background and print container ID- バックグランドでコンテナを起動します。(コンテナIDのみ出力します)
-
--name
Assign a name to the container- コンテナに名前を付けます。
- 指定しない場合は 形容詞_名詞 のランダムなコンテナ名になります。
- https://deeeet.com/writing/2014/07/15/docker-container-name/
-
--network
Connect a container to a network- コンテナをネットワークに接続する
-
-p
,--publish
Publish a container's port(s) to the host- コンテナのポートをホストに公開します。(ホスト:コンテナ)
-
-v
,--volume
Bind mount a volume- ボリュームをバインドマウントします。(ホスト:コンテナ)
- バインドマウント: Dockerホストのファイルやディレクトリをコンテナ上にマウントする機能です。
- 絶対パスを指定する必要があります。
- https://www.public.ne.jp/2019/02/08/docker-5/
MySQLコンテナの作成
$ docker run -d --name shop_db -v shop_db_storage:/var/lib/mysql --network shop_network mysql_image
-
-d
バックグランドでコンテナを起動します。(コンテナIDのみ出力します) -
--name
コンテナに名前を付けます。 -
-v
ボリュームコンテナを指定する。 -
--network
ネットワークを指定する。
ネットワークの確認
$ docker network inspect shop_network
[
{
"Name": "shop_network",
"Id": "8b4373c22b4e47593b4c3942f12d435657ceb32cd7ef911c7196225d258c8fd8",
"Created": "2020-03-31T15:34:46.7379855Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.21.0.0/16",
"Gateway": "172.21.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"f3c91438a5d3bd229ac43468c2a6c4ec8c60b4711dfefa8bf367d8dc833f544e": {
"Name": "shop_web",
"EndpointID": "bff8b3f921677250bbf0edad291e2dc85633f990778907604315a5fe54b893d0",
"MacAddress": "02:42:ac:15:00:02",
"IPv4Address": "172.21.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
MySQL 初期データ設定
$ docker exec -it shop_db bash
$ mysql -u root -p$MYSQL_PASSWORD $MYSQL_DATABASE
create table shop.items (
id int primary key auto_increment,
name varchar(30) comment '商品名',
stock int default 0 comment '在庫数'
) comment='商品テーブル';
INSERT INTO items (name, stock) VALUE ("Apple", 10);
INSERT INTO items (name, stock) VALUE ("Bad Apple", 1);
desc shop.items;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(30) | YES | | NULL | |
| stock | int | YES | | 0 | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
select * from shop.items;
+----+-----------+-------+
| id | name | stock |
+----+-----------+-------+
| 1 | Apple | 10 |
| 2 | Bad Apple | 1 |
+----+-----------+-------+
2 rows in set (0.00 sec)
確認
おまけ:お掃除
Docker コンテナを削除
$ docker stop shop_web shop_db
$ docker rm shop_web shop_db
or
$ docker rm -f shop_web shop_db
$ docker ps -a
Docker イメージを削除
$ docker rmi php_image mysql_image
$ docker images
Docker ボリュームを削除
$ docker volume rm shop_db_storage
$ docker volume ls
Docker ネットワークを削除
$ docker network rm shop_network
$ docker network ls
停止コンテナ、タグ無しイメージ、未使用ボリューム、未使用ネットワーク一括削除
$ docker system prune -f
おまけ:Dockerコマンドまとめ
$ docker ps -as # コンテナ一覧(停止コンテナ含む、サイズ表示)
$ docker start <CONTAINER> # コンテナを起動
$ docker restart <CONTAINER> # コンテナ再起動
$ docker stop <CONTAINER> # コンテナを停止
$ docker kill <CONTAINER> # コンテナ強制終了
$ docker attach <CONTAINER> # コンテナへ接続
$ docker top <CONTAINER> # コンテナのプロセスを表示
$ docker logs -f <CONTAINER> # コンテナのログを表示(ログ出力をfollow)
$ docker inspect <CONTAINER> # コンテナの情報を表示
$ docker rm <CONTAINER> # コンテナを削除
さいごに
Docker ハンズオンいかがでしたでしょうか。
仮想マシンに比べて起動や構築が爆速で行えるようになりましたね。
しかし、コンテナを作ったり、停止するには個々にコマンドを打つ必要があり、管理するコンテナが増えれば増えるほど大変になってきます。
Docker Compose ハンズオンに続く...