Dockerの基礎勉強メモ
M1チップのmac前提
概要
Dockerを使うメリット
- 環境構築時間の削減
- インフラをコード化することにより、誰でも同じ環境を構築できる
- CI、CDなどの自動化ソフトとの相性が良い
コンテナとは?
貨物船などで使われる隔離され、パッケージ化された箱
インフラのコンテナも同じで、サーバー上で隔離されたアプリ空間を作れる技術のこと。
Docker以外にも
- Linux Containers
- Hyper-Vコンテナ
- windowsコンテナ
などがあるがLinuxでの使いやすさでDockerに人気が集まっているらしい。
仮想化とコンテンナ(Docker)の違い
Docker(コンテナ)
- メモリ上に存在
- ゲストOSは存在しない
- メモリ上に存在するのでデータは一時的
- Dockerfileでコード化できる
仮想化
- ディスク上に存在
- ホストOSとゲストOSに分かれる
- 常に保存される
- コード化はできない
この記事のシリーズが最高にわかりやすい
Dockerfile、Dockerイメージ、コンテナの関係性
コンテナが隔離されたアプリの箱
Dockerイメージが設計図(レイヤーになっている静的なテンプレートファイル)
Dockerfileがそれを言語化、file化したもの
Dockerイメージがクラスでコンテナがインスタンスと言う解釈が良さそう。
Docker Hubには例えばphpの公式が用意してくれたDockerイメージなどが
用意されていてそれを入手(pull)して使える。
Dockerイメージのタグについて
タグ名 = バージョン名
ubuntu:18.04
指定しないとlatest(最新版)が入ってしまう。
配布した時期によってバージョンの違いがでるトラブルに繋がる。
docker hubについて
アカウントを作成しないとpullに制限がかかるらしいので作っておこう。
作成しただけではダメでDocker Desktopからサインインしておく。
コマンドからもログインできる。
docker login
よく使うコマンド
まずは、練習用のディレクトリを作ってその中で実行していく。
基本的には公式のリファレンスを見る。
docker run
起動したいイメージを指定して実行
docker run hello-world
イメージがローカルにない場合は自動的にdocker hubからpullして来てくれる。
docker run コマンドは、まず指定されたイメージ上に書き込み可能なコンテナ・レイヤを create (作成)します。それから、指定されたコマンドを使って start (開始)します。
docker ps
コンテナのプロセス一覧を表示する
docker ps
さっき作ったhello-worldが表示されない。
これはhello-worldが以下の表示をしたらプロセスを閉じるイメージだから。
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
以下のオプションをつけることで停止中のプロセスも表示される。
docker ps -a
プロセスに別の名前をつけることもできる。
例えば、hello-worldをkonitiwaと言う名前で走らせる。
docker run --name konitiwa hello-world
--rmをつけると停止と同時にコンテナの削除もしてくれる。
docker run --name rmtest --rm hello-world
IDとnameだけ出力したい場合
docker ps --format "{{.ID}}: {{.Names}}" -a
docker start,stop,restart
start,stop,restartを試すためにcentosイメージからコンテナを立ち上げる
# -i,-tオプションで起動しながらbashに指定してコンテナに入る
docker run -it --name mycentos centos:8 /bin/bash
# 繋がったら一旦でる
exit
# mycentosが停止していることを確認
docker ps -a
-itオプションについて
name、container idのどちらで指定しても動作することがわかる。
docker start mycentos
docker stop mycentos
docker restart 3bbb6244c880
docker exec
コンテナに入ってバージョン表示
docker exec -it mycentos /bin/bash
[root@3bbb6244c880 /]# cat /etc/redhat-release
CentOS Linux release 8.4.2105
コンテナに入らずにcentosのバージョン情報を取得
docker exec mycentos cat /etc/redhat-release
↓
CentOS Linux release 8.4.2105
docker rm
コンテナを削除-fで強制で削除できるがストップしてからやろう。
docker rm コンテナ指定
docker images
ローカルにあるイメージをすべて表示
docker images
意外と容量がデカイので定期的に確認して削除しよう。
イメージもコンテナと同じくIDを持っている。
docker rmi
Dockerイメージを削除
起動中、依存関係があるベースイメージは削除できない。
docker rmi イメージ指定
コンテナが起動中のイメージを削除しようとするとエラーがでる。
% docker rmi e6a0117ec169
Error response from daemon: conflict: unable to delete e6a0117ec169 (cannot be forced) - image is being used by running container 3bbb6244c880
docker image prune
使用していないイメージを一括で削除もできる。
% docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:bad28a0252ef2a7490c95c11
deleted: sha256:845fc4a1c9954fd36895c11
deleted: sha256:e7579523d95c1195c11
deleted: sha256:e060cc6d9995c1195c11
deleted: sha256:63cca88695c1195c1195c11
docker build
Dockerfileからイメージを生成
docker build Dockerfileのパス
docker cp
コンテナとホストマシンでファイルのやりとりを行うコピーコマンド
# 逆もできる
docker cp コンテナのファイルパス:ホストのファイルパス
docker logs
# 打ったコマンドのログが見れる
docker logs コンテナ名
# リアルタイム監視
docker logs -f コンテナ名
docker inspect
コンテナの詳細情報を確認できる。
主にトラブル時に使う模様。
docker inspect コンテナ名
docker pull
イメージをダウンロードするコマンド。
プライベートイメージをダウンロードする時などにも使う。
docker pull イメージ名:タグ [レジストリURL]
docker commit
コンテナをイメージ化するコマンド。
pushする場合は以下の形にしないとできない。
docker commit コンテナ指定 DockerHubのID/イメージ名:タグ
docker push
レジストリにイメージやリポジトリを 送信pushl します。
docker push アカウント名/イメージ名
docker history
イメージの履歴を確認。
他人が作ったイメージの中身を知りたい時に使う。
Dockerfileがない時に使う。
docker history イメージ指定
コンテナのストレージ
コンテナの永続化
コンテナは削除してしまうと保存したデータも消えてしまう。
じゃあDBなどはどうするの?
↓
ホストのボリューム(ストレージ)をオプションでコンテナにマウント
することができるのでそれで解決する。
-v フラグは現在の作業ディレクトリをコンテナ内にマウントします。
共有されるので双方向に保存される
docker run -v ホストのパス:コンテナのパス イメージ名
↓
docker run -v /GitHub/dockertest/source:/var/www/html mycentos
webサーバを冗長化している様な本番環境では、DBはコンテナ化せずに一箇所に集約
して運用することもあるらしい。
volumeはすごい分かりづらいので以下の記事を参照。
Dockerfile
RUNとCMDの違い
どちらもコマンドを実行するがタイミングが違う
RUN apt-get install -y nginx
CMD ["nginx","-g","daemon off;"]
- RUN : Dockerfile → イメージ
- CMD : イメージ → コンテナ
COPYとADDの違い
どちらファイルをイメージに追加するコマンド
- ADDはネット経由でも追加可能
- COPYはローカルからの追加
ADD と COPY の機能は似ていますが、一般的には COPY を優先します。それは ADD よりも機能が明確だからです。
ENV
環境変数を設定
- DBのユーザ名など
- アプリのバージョンの指定など
このセクションのまとめ的にMariaDBを作ってみる
mariadbと言うディレクトリを作る。
配下に以下のファイルを作成。
- Dockerfile
- my.cnf
- create-table.sql
# OSからやるより最小の公式パッケージの方がいろいろよしなにやってくれている
FROM mariadb:10.4
RUN apt-get update -y
COPY my.conf /etc/mysql/conf.d
# 初期データを配置
COPY create-table.sql /docker-entrypoint-initdb.d
ENV MYSQL_USER=root
# 最初からこのDB名で作成してくれる
ENV MYSQL_DATABASE=docker
ENV MYSQL_ROOT_PASSWORD=root
参考記事
# clientセクション: mysqlクライアントツールへの設定
[client]
port=3306
socket=/tmp/mysql.sock
# mysqldセクション: mysqlサーバーへの設定
[mysqld]
port=3306
socket=/tmp/mysql.sock
key_buffer_size=16M
max_allowed_packet=8M
# mysqldumpセクション: バックアップコマンドへの設定
[mysqldump]
quick
# mysqld_safeセクション: 起動ファイル設定
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
CREATE TABLE persons (
id int,
lastname varchar(255),
firstname varchar(255),
address varchar(255),
city varchar(255)
);
ビルドしていく。
-t でタグ名をつけて、その後にDockerfileの場所を指定。
docker build -t mymariadb mariadb
mymariadbイメージがあることを確認
docker images
mariaと言う名前で作成したmymariadbイメージを起動する。
docker run -d --name maria mymariadb
コンテナのプロセスを確認して思惑通りにコンテナが出来たことを確認。
docker ps
-----------
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6135ab07a702 mymariadb "docker-entrypoint.s…" 8 seconds ago Up 6 seconds 3306/tcp maria
コンテナに入って中身を確認していく
docker exec -it maria /bin/bash
Dockerfileに記載した通りにDBとテーブルが作成されてことを確認できる。
root@6135ab07a702:/# mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.4.25-MariaDB-1:10.4.25+maria~focal mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| docker |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.006 sec)
MariaDB [(none)]> use docker;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [docker]> show tables;
+------------------+
| Tables_in_docker |
+------------------+
| persons |
+------------------+
1 row in set (0.001 sec)
docker-compose
Compose とは、複数のコンテナを定義し実行する Docker アプリケーションのためのツールです。
以前は、コンテナをひとつずつ docker run --link で立ち上げて繋ぐと言う
方法もあったが非推奨になっている模様。
docker-composeはコンテナ間をリンクして一括で管理できる便利なやつ。
(ネットワーク機能は難しそうなので別の機会に勉強する)
docker-compose.ymlファイルとは?
アプリケーションを構成するサービスをファイル内に定義する。
インデントに意味がある書き方で、スペースで親子関係になる。
全体の設計図がyamlでDockerfileが個別の設計図みたいなイメージかな?
version: '3'
services:
app:
# buildはDockerfileのパスをymlファイルがある場所からの相対パスで指定
build: ./php
# docker run --nameと同じでコンテナ名を自由に付けられる
container_name:"php8"
# docker run -pと同じポートフォワーディング
ports:
"8080:80"
db:
# imageはDockerHubから指定
image:mariadb:10.4
# docker run -vと同じでデータの永続化
volume:
./data:/var/lib/mysql
docker-composeでコンテナ間通信できるのはなぜか?
デフォルトでネットワークに参加しているからみたい。
wordpressを試しにdocker-composeで作ってみよう
公式の内容が良いので書き写す必要も無いので参照。
my_wordpressと言うディレクトリを作成。
公式から引用して改変してwordpressのファイルも永続化している。
wordpressがlatestになっていた部分も指定した。
公式でも実運用の部分では微妙な記述もあるみたいだから注意しよう。
version: '3'
services:
db:
image: mysql:5.7
# M1macの場合に指定
platform: linux/amd64
volumes:
# 名前付きボリューム
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:6
volumes:
# バインドマウント
- ./wp-data:/var/www/html
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
volumes:
# 名前付きボリュームを定義
db_data:
色々調べているとcontainer_nameより以下のリンクの方法が良いらしいので
実践してみた。
実運用経験が乏しいのでメリットがピンと来ないがやっておこう。
コンテナ名を決める要素を .env に切り出せる、名前が機械的に決定される、という意味でもこの方法が好ましそう。
COMPOSE_PROJECT_NAME=test_project
作業ディレクトリに移動して、docker-composeを立ち上げるコマンドを実行。
cd my_wordpress
docker-compose up -d
無事wordpressが動いた。
# ymlのmysqlのところに platform: linux/amd64 を記載しないとエラーがでる
no matching manifest for linux/arm64/v8 in the manifest list entries
docker-composeのコマンド
# コンテナをストップ&削除
docker-compose down
# コンテナ全てを再起動
docker-compose restart
# コンテナ一覧を表示
docker-compose ps
# docker-compose.ymlで管理されているサービスを1つ指定してコマンドを実行
docker-compose run サービス名 実行したいコマンド
参考記事
Discussion